xref: /aosp_15_r20/cts/tests/app/src/android/app/cts/RequestTileServiceAddTest.kt (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.cts
18 
19 import android.Manifest.permission.STATUS_BAR
20 import android.app.Activity
21 import android.app.ActivityManager
22 import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
23 import android.app.Instrumentation
24 import android.app.StatusBarManager
25 import android.app.stubs.MockActivity
26 import android.app.stubs.NotExportedTestTileService
27 import android.app.stubs.TestTileService
28 import android.content.ComponentName
29 import android.content.Context
30 import android.content.Intent
31 import android.content.pm.PackageManager
32 import android.graphics.drawable.Icon
33 import android.permission.cts.PermissionUtils
34 import android.service.quicksettings.TileService
35 import androidx.test.InstrumentationRegistry
36 import androidx.test.ext.junit.runners.AndroidJUnit4
37 import com.android.compatibility.common.util.SystemUtil
38 import com.google.common.truth.Truth.assertThat
39 import com.google.common.util.concurrent.MoreExecutors
40 import org.junit.Assume
41 import org.junit.Before
42 import org.junit.Test
43 import org.junit.runner.RunWith
44 import java.util.concurrent.CountDownLatch
45 import java.util.concurrent.TimeUnit
46 import java.util.function.Consumer
47 
48 /**
49  * Test that the request fails in all the expected ways.
50  *
51  * These tests are for [StatusBarManager.requestAddTileService].
52  */
53 @RunWith(AndroidJUnit4::class)
54 class RequestTileServiceAddTest {
55 
56     companion object {
57         private const val LABEL = "label"
58         private const val TIME_OUT_SECONDS = 5L
59     }
60 
61     private lateinit var statusBarService: StatusBarManager
62     private lateinit var context: Context
63     private lateinit var icon: Icon
64     private lateinit var consumer: StoreIntConsumer
65     private lateinit var instrumentation: Instrumentation
66     private val executor = MoreExecutors.directExecutor()
67     private lateinit var latch: CountDownLatch
68 
69     @Before
setUpnull70     fun setUp() {
71         Assume.assumeTrue(TileService.isQuickSettingsSupported())
72 
73         instrumentation = InstrumentationRegistry.getInstrumentation()
74         context = instrumentation.getTargetContext()
75         statusBarService = context.getSystemService(StatusBarManager::class.java)!!
76 
77         icon = Icon.createWithResource(context, R.drawable.ic_android)
78         latch = CountDownLatch(1)
79         consumer = StoreIntConsumer(latch)
80     }
81 
82     @Test
testRequestBadPackageFailsnull83     fun testRequestBadPackageFails() {
84         val componentName = ComponentName("test_pkg", "test_cls")
85 
86         statusBarService.requestAddTileService(
87                 componentName,
88                 LABEL,
89                 icon,
90                 executor,
91                 consumer
92         )
93 
94         latch.await(TIME_OUT_SECONDS, TimeUnit.SECONDS)
95 
96         assertThat(consumer.result)
97                 .isEqualTo(StatusBarManager.TILE_ADD_REQUEST_ERROR_MISMATCHED_PACKAGE)
98     }
99 
100     @Test
testRequestBadComponentNamenull101     fun testRequestBadComponentName() {
102         val componentName = ComponentName(context, "test_cls")
103         statusBarService.requestAddTileService(
104                 componentName,
105                 LABEL,
106                 icon,
107                 executor,
108                 consumer
109         )
110 
111         latch.await(TIME_OUT_SECONDS, TimeUnit.SECONDS)
112 
113         assertThat(consumer.result).isEqualTo(StatusBarManager.TILE_ADD_REQUEST_ERROR_BAD_COMPONENT)
114     }
115 
116     @Test
testDisabledComponentnull117     fun testDisabledComponent() {
118         val componentName = TestTileService.getComponentName()
119         context.packageManager.setComponentEnabledSetting(
120                 componentName,
121                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
122                 PackageManager.SYNCHRONOUS or PackageManager.DONT_KILL_APP
123         )
124 
125         statusBarService.requestAddTileService(
126                 componentName,
127                 LABEL,
128                 icon,
129                 executor,
130                 consumer
131         )
132 
133         latch.await(TIME_OUT_SECONDS, TimeUnit.SECONDS)
134 
135         assertThat(consumer.result).isEqualTo(StatusBarManager.TILE_ADD_REQUEST_ERROR_BAD_COMPONENT)
136 
137         // Cleanup
138         context.packageManager.setComponentEnabledSetting(
139                 componentName,
140                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
141                 PackageManager.SYNCHRONOUS or PackageManager.DONT_KILL_APP
142         )
143     }
144 
145     @Test
testNotExportedComponentnull146     fun testNotExportedComponent() {
147         val componentName = NotExportedTestTileService.getComponentName()
148 
149         statusBarService.requestAddTileService(
150                 componentName,
151                 LABEL,
152                 icon,
153                 executor,
154                 consumer
155         )
156 
157         latch.await(TIME_OUT_SECONDS, TimeUnit.SECONDS)
158 
159         assertThat(consumer.result).isEqualTo(StatusBarManager.TILE_ADD_REQUEST_ERROR_BAD_COMPONENT)
160     }
161 
162     @Test
testAppNotInForegroundnull163     fun testAppNotInForeground() {
164         // This test is never run in foreground, so it's a good candidate for testing this
165         val componentName = TestTileService.getComponentName()
166         val activityManager = context.getSystemService(ActivityManager::class.java)!!
167         withPermission(context.packageName, android.Manifest.permission.PACKAGE_USAGE_STATS) {
168             assertThat(activityManager.getPackageImportance(context.packageName))
169                     .isNotEqualTo(IMPORTANCE_FOREGROUND)
170         }
171 
172         statusBarService.requestAddTileService(
173                 componentName,
174                 LABEL,
175                 icon,
176                 executor,
177                 consumer
178         )
179 
180         latch.await(TIME_OUT_SECONDS, TimeUnit.SECONDS)
181 
182         assertThat(consumer.result)
183                 .isEqualTo(StatusBarManager.TILE_ADD_REQUEST_ERROR_APP_NOT_IN_FOREGROUND)
184     }
185 
186     @Test
testTwoSimultaneousRequestsnull187     fun testTwoSimultaneousRequests() {
188         // We need an activity in the foreground for the first request to not be denied
189         val activity = setUpForActivity()
190         val componentName = TestTileService.getComponentName()
191 
192         statusBarService.requestAddTileService(
193                 componentName,
194                 LABEL,
195                 icon,
196                 executor,
197                 {}
198         )
199 
200         Thread.sleep(TimeUnit.SECONDS.toMillis(TIME_OUT_SECONDS))
201 
202         statusBarService.requestAddTileService(
203                 componentName,
204                 LABEL,
205                 icon,
206                 executor,
207                 consumer
208         )
209 
210         latch.await(TIME_OUT_SECONDS, TimeUnit.SECONDS)
211         assertThat(consumer.result)
212                 .isEqualTo(StatusBarManager.TILE_ADD_REQUEST_ERROR_REQUEST_IN_PROGRESS)
213 
214         SystemUtil.callWithShellPermissionIdentity(
215                 { statusBarService.cancelRequestAddTile(componentName.packageName) },
216                 STATUS_BAR
217         )
218 
219         activity.finish()
220     }
221 
withPermissionnull222     private inline fun withPermission(packageName: String, permission: String, block: () -> Unit) {
223         val isPermissionGranted = PermissionUtils.isPermissionGranted(packageName, permission)
224         try {
225             PermissionUtils.grantPermission(packageName, permission)
226             block()
227         } finally {
228             if (!isPermissionGranted) {
229                 PermissionUtils.revokePermission(packageName, permission)
230             }
231         }
232     }
233 
setUpForActivitynull234     private fun setUpForActivity(): Activity {
235         val intent = Intent(context, MockActivity::class.java)
236         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
237         val activity = instrumentation.startActivitySync(intent)
238         instrumentation.waitForIdleSync()
239         return activity
240     }
241 
242     private class StoreIntConsumer(private val latch: CountDownLatch) : Consumer<Int> {
243         var result: Int? = null
244 
acceptnull245         override fun accept(t: Int) {
246             result = t
247             latch.countDown()
248         }
249     }
250 }