• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2023 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.permissionmultidevice.cts
18 
19 import android.Manifest
20 import android.app.Instrumentation
21 import android.companion.virtual.VirtualDeviceManager
22 import android.companion.virtual.VirtualDeviceParams
23 import android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM
24 import android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT
25 import android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA
26 import android.content.ComponentName
27 import android.content.Context
28 import android.content.Intent
29 import android.content.Intent.EXTRA_RESULT_RECEIVER
30 import android.content.pm.PackageManager
31 import android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS
32 import android.hardware.display.VirtualDisplay
33 import android.os.Build
34 import android.os.Bundle
35 import android.os.RemoteCallback
36 import android.permission.PermissionManager
37 import android.permission.flags.Flags
38 import android.permissionmultidevice.cts.PackageManagementUtils.installPackage
39 import android.permissionmultidevice.cts.PackageManagementUtils.uninstallPackage
40 import android.permissionmultidevice.cts.UiAutomatorUtils.click
41 import android.permissionmultidevice.cts.UiAutomatorUtils.findTextForView
42 import android.permissionmultidevice.cts.UiAutomatorUtils.waitFindObject
43 import android.platform.test.annotations.AppModeFull
44 import android.platform.test.annotations.RequiresFlagsEnabled
45 import android.provider.Settings
46 import android.view.Display
47 import android.virtualdevice.cts.common.VirtualDeviceRule
48 import androidx.test.ext.junit.runners.AndroidJUnit4
49 import androidx.test.filters.SdkSuppress
50 import androidx.test.platform.app.InstrumentationRegistry
51 import androidx.test.uiautomator.By
52 import com.android.compatibility.common.util.SystemUtil
53 import com.google.common.truth.Truth.assertThat
54 import java.util.concurrent.CompletableFuture
55 import java.util.concurrent.TimeUnit
56 import org.junit.After
57 import org.junit.Assert
58 import org.junit.Assume.assumeFalse
59 import org.junit.Before
60 import org.junit.Rule
61 import org.junit.Test
62 import org.junit.runner.RunWith
63 
64 @RunWith(AndroidJUnit4::class)
65 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava")
66 @AppModeFull(reason = "VirtualDeviceManager cannot be accessed by instant apps")
67 open class DeviceAwarePermissionGrantTest {
68     private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
69     private val defaultDeviceContext = instrumentation.targetContext
70     private lateinit var defaultDeviceName: String
71     private lateinit var virtualDeviceManager: VirtualDeviceManager
72     private lateinit var virtualDevice: VirtualDeviceManager.VirtualDevice
73     private lateinit var virtualDisplay: VirtualDisplay
74     private lateinit var virtualDeviceName: String
75     private val permissionManager =
76         defaultDeviceContext.getSystemService(PermissionManager::class.java)!!
77 
78     @get:Rule
79     var virtualDeviceRule: VirtualDeviceRule =
80         VirtualDeviceRule.withAdditionalPermissions(Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
81 
82     @Before
83     fun setup() {
84         assumeFalse(PermissionUtils.isAutomotive(defaultDeviceContext))
85         assumeFalse(PermissionUtils.isTv(defaultDeviceContext))
86         assumeFalse(PermissionUtils.isWatch(defaultDeviceContext))
87 
88         installPackage(APP_APK_PATH_STREAMING)
89         virtualDeviceManager =
90             defaultDeviceContext.getSystemService(VirtualDeviceManager::class.java)!!
91 
92         defaultDeviceName =
93             Settings.Global.getString(
94                 defaultDeviceContext.contentResolver,
95                 Settings.Global.DEVICE_NAME,
96             )
97     }
98 
99     @After
100     fun cleanup() {
101         uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false)
102         Thread.sleep(2000)
103     }
104 
105     private fun createVirtualDevice(cameraPolicy: Int = DEVICE_POLICY_DEFAULT) {
106         virtualDevice =
107             virtualDeviceRule.createManagedVirtualDevice(
108                 VirtualDeviceParams.Builder()
109                     .setDevicePolicy(POLICY_TYPE_CAMERA, cameraPolicy)
110                     .build()
111             )
112         virtualDisplay =
113             virtualDeviceRule.createManagedVirtualDisplay(
114                 virtualDevice,
115                 VirtualDeviceRule.createTrustedVirtualDisplayConfigBuilder(),
116             )!!
117         virtualDeviceName =
118             virtualDeviceManager.getVirtualDevice(virtualDevice.deviceId)!!.displayName.toString()
119     }
120 
121     @Test
122     fun deviceAwarePermission_onHost_requestHostPermission() {
123         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
124         testMultiDevicePermissionGrant(
125             permission = Manifest.permission.CAMERA,
126             initialDefaultDevicePermission = false,
127             initialVirtualDevicePermission = false,
128             requestingFromDevice = DEVICE_ID_DEFAULT,
129             requestingForDevice = DEVICE_ID_DEFAULT,
130             dialogDeviceName = DEVICE_ID_INVALID,
131             expectPermissionGrantedOnDefaultDevice = true,
132             expectPermissionGrantedOnVirtualDevice = false,
133         )
134     }
135 
136     @Test
137     fun deviceAwarePermission_onHost_withRemotePermission_requestHostPermission() {
138         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
139         testMultiDevicePermissionGrant(
140             permission = Manifest.permission.CAMERA,
141             initialDefaultDevicePermission = false,
142             initialVirtualDevicePermission = true,
143             requestingFromDevice = DEVICE_ID_DEFAULT,
144             requestingForDevice = DEVICE_ID_DEFAULT,
145             dialogDeviceName = DEVICE_ID_INVALID,
146             expectPermissionGrantedOnDefaultDevice = true,
147             expectPermissionGrantedOnVirtualDevice = true,
148         )
149     }
150 
151     @Test
152     fun deviceAwarePermission_onHost_requestPermissionWithoutDeviceId() {
153         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
154         testMultiDevicePermissionGrant(
155             permission = Manifest.permission.CAMERA,
156             initialDefaultDevicePermission = false,
157             initialVirtualDevicePermission = false,
158             requestingFromDevice = DEVICE_ID_DEFAULT,
159             requestingForDevice = DEVICE_ID_INVALID,
160             dialogDeviceName = DEVICE_ID_INVALID,
161             expectPermissionGrantedOnDefaultDevice = true,
162             expectPermissionGrantedOnVirtualDevice = false,
163         )
164     }
165 
166     @Test
167     fun deviceAwarePermission_onHost_withRemotePermission_requestPermissionWithoutDeviceId() {
168         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
169         testMultiDevicePermissionGrant(
170             permission = Manifest.permission.CAMERA,
171             initialDefaultDevicePermission = false,
172             initialVirtualDevicePermission = true,
173             requestingFromDevice = DEVICE_ID_DEFAULT,
174             requestingForDevice = DEVICE_ID_INVALID,
175             dialogDeviceName = DEVICE_ID_INVALID,
176             expectPermissionGrantedOnDefaultDevice = true,
177             expectPermissionGrantedOnVirtualDevice = true,
178         )
179     }
180 
181     @Test
182     fun deviceAwarePermission_onHost_requestRemotePermission() {
183         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
184         testMultiDevicePermissionGrant(
185             permission = Manifest.permission.CAMERA,
186             initialDefaultDevicePermission = false,
187             initialVirtualDevicePermission = false,
188             requestingFromDevice = DEVICE_ID_DEFAULT,
189             requestingForDevice = virtualDevice.deviceId,
190             dialogDeviceName = virtualDevice.deviceId,
191             expectPermissionGrantedOnDefaultDevice = false,
192             expectPermissionGrantedOnVirtualDevice = true,
193         )
194     }
195 
196     @Test
197     fun deviceAwarePermission_onHost_withHostPermission_requestRemotePermission() {
198         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
199         testMultiDevicePermissionGrant(
200             permission = Manifest.permission.CAMERA,
201             initialDefaultDevicePermission = true,
202             initialVirtualDevicePermission = false,
203             requestingFromDevice = DEVICE_ID_DEFAULT,
204             requestingForDevice = virtualDevice.deviceId,
205             dialogDeviceName = virtualDevice.deviceId,
206             expectPermissionGrantedOnDefaultDevice = true,
207             expectPermissionGrantedOnVirtualDevice = true,
208         )
209     }
210 
211     @Test
212     fun deviceAwarePermission_onRemote_requestRemotePermission() {
213         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
214         testMultiDevicePermissionGrant(
215             permission = Manifest.permission.CAMERA,
216             initialDefaultDevicePermission = false,
217             initialVirtualDevicePermission = false,
218             requestingFromDevice = virtualDevice.deviceId,
219             requestingForDevice = virtualDevice.deviceId,
220             dialogDeviceName = virtualDevice.deviceId,
221             expectPermissionGrantedOnDefaultDevice = false,
222             expectPermissionGrantedOnVirtualDevice = true,
223         )
224     }
225 
226     @Test
227     fun deviceAwarePermission_onRemote_withHostPermission_requestRemotePermission() {
228         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
229         testMultiDevicePermissionGrant(
230             permission = Manifest.permission.CAMERA,
231             initialDefaultDevicePermission = true,
232             initialVirtualDevicePermission = false,
233             requestingFromDevice = virtualDevice.deviceId,
234             requestingForDevice = virtualDevice.deviceId,
235             dialogDeviceName = virtualDevice.deviceId,
236             expectPermissionGrantedOnDefaultDevice = true,
237             expectPermissionGrantedOnVirtualDevice = true,
238         )
239     }
240 
241     @Test
242     fun deviceAwarePermission_onRemote_requestPermissionWithoutDeviceId() {
243         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
244         testMultiDevicePermissionGrant(
245             permission = Manifest.permission.CAMERA,
246             initialDefaultDevicePermission = false,
247             initialVirtualDevicePermission = false,
248             requestingFromDevice = virtualDevice.deviceId,
249             requestingForDevice = DEVICE_ID_INVALID,
250             dialogDeviceName = virtualDevice.deviceId,
251             expectPermissionGrantedOnDefaultDevice = false,
252             expectPermissionGrantedOnVirtualDevice = true,
253         )
254     }
255 
256     @Test
257     fun deviceAwarePermission_onRemote_withHostPermission_requestPermissionWithoutDeviceId() {
258         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
259         testMultiDevicePermissionGrant(
260             permission = Manifest.permission.CAMERA,
261             initialDefaultDevicePermission = true,
262             initialVirtualDevicePermission = false,
263             requestingFromDevice = virtualDevice.deviceId,
264             requestingForDevice = DEVICE_ID_INVALID,
265             dialogDeviceName = virtualDevice.deviceId,
266             expectPermissionGrantedOnDefaultDevice = true,
267             expectPermissionGrantedOnVirtualDevice = true,
268         )
269     }
270 
271     @RequiresFlagsEnabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES)
272     @Test
273     fun deviceAwarePermission_onRemote_requestHostPermission() {
274         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
275         testMultiDevicePermissionGrant(
276             permission = Manifest.permission.CAMERA,
277             initialDefaultDevicePermission = false,
278             initialVirtualDevicePermission = false,
279             requestingFromDevice = virtualDevice.deviceId,
280             requestingForDevice = DEVICE_ID_DEFAULT,
281             dialogDeviceName = DEVICE_ID_DEFAULT,
282             expectPermissionGrantedOnDefaultDevice = true,
283             expectPermissionGrantedOnVirtualDevice = false,
284         )
285     }
286 
287     @RequiresFlagsEnabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES)
288     @Test
289     fun deviceAwarePermission_onRemote_withRemotePermission_requestHostPermission() {
290         createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
291         testMultiDevicePermissionGrant(
292             permission = Manifest.permission.CAMERA,
293             initialDefaultDevicePermission = false,
294             initialVirtualDevicePermission = true,
295             requestingFromDevice = virtualDevice.deviceId,
296             requestingForDevice = DEVICE_ID_DEFAULT,
297             dialogDeviceName = DEVICE_ID_DEFAULT,
298             expectPermissionGrantedOnDefaultDevice = true,
299             expectPermissionGrantedOnVirtualDevice = true,
300         )
301     }
302 
303     @Test
304     fun deviceAwarePermissionWithoutCapability_onHost_requestHostPermission() {
305         createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
306         testMultiDevicePermissionGrant(
307             permission = Manifest.permission.CAMERA,
308             initialDefaultDevicePermission = false,
309             initialVirtualDevicePermission = false,
310             requestingFromDevice = DEVICE_ID_DEFAULT,
311             requestingForDevice = DEVICE_ID_DEFAULT,
312             dialogDeviceName = DEVICE_ID_INVALID,
313             expectPermissionGrantedOnDefaultDevice = true,
314             expectPermissionGrantedOnVirtualDevice = true,
315         )
316     }
317 
318     @Test
319     fun deviceAwarePermissionWithoutCapability_onHost_requestPermissionWithoutDeviceId() {
320         createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
321         testMultiDevicePermissionGrant(
322             permission = Manifest.permission.CAMERA,
323             initialDefaultDevicePermission = false,
324             initialVirtualDevicePermission = false,
325             requestingFromDevice = DEVICE_ID_DEFAULT,
326             requestingForDevice = DEVICE_ID_INVALID,
327             dialogDeviceName = DEVICE_ID_INVALID,
328             expectPermissionGrantedOnDefaultDevice = true,
329             expectPermissionGrantedOnVirtualDevice = true,
330         )
331     }
332 
333     @RequiresFlagsEnabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES)
334     @Test
335     fun deviceAwarePermissionWithoutCapability_onHost_requestRemotePermission() {
336         createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
337         testMultiDevicePermissionGrant(
338             permission = Manifest.permission.CAMERA,
339             initialDefaultDevicePermission = false,
340             initialVirtualDevicePermission = false,
341             requestingFromDevice = DEVICE_ID_DEFAULT,
342             requestingForDevice = virtualDevice.deviceId,
343             dialogDeviceName = DEVICE_ID_INVALID,
344             expectPermissionGrantedOnDefaultDevice = true,
345             expectPermissionGrantedOnVirtualDevice = true,
346         )
347     }
348 
349     @RequiresFlagsEnabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES)
350     @Test
351     fun deviceAwarePermissionWithoutCapability_onRemote_requestRemotePermission() {
352         createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
353         testMultiDevicePermissionGrant(
354             permission = Manifest.permission.CAMERA,
355             initialDefaultDevicePermission = false,
356             initialVirtualDevicePermission = false,
357             requestingFromDevice = virtualDevice.deviceId,
358             requestingForDevice = virtualDevice.deviceId,
359             dialogDeviceName = DEVICE_ID_DEFAULT,
360             expectPermissionGrantedOnDefaultDevice = true,
361             expectPermissionGrantedOnVirtualDevice = true,
362         )
363     }
364 
365     @RequiresFlagsEnabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES)
366     @Test
367     fun deviceAwarePermissionWithoutCapability_onRemote_requestPermissionWithoutDeviceId() {
368         createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
369         testMultiDevicePermissionGrant(
370             permission = Manifest.permission.CAMERA,
371             initialDefaultDevicePermission = false,
372             initialVirtualDevicePermission = false,
373             requestingFromDevice = virtualDevice.deviceId,
374             requestingForDevice = DEVICE_ID_INVALID,
375             dialogDeviceName = DEVICE_ID_DEFAULT,
376             expectPermissionGrantedOnDefaultDevice = true,
377             expectPermissionGrantedOnVirtualDevice = true,
378         )
379     }
380 
381     @RequiresFlagsEnabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES)
382     @Test
383     fun deviceAwarePermissionWithoutCapability_onRemote_requestHostPermission() {
384         createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
385         testMultiDevicePermissionGrant(
386             permission = Manifest.permission.CAMERA,
387             initialDefaultDevicePermission = false,
388             initialVirtualDevicePermission = false,
389             requestingFromDevice = virtualDevice.deviceId,
390             requestingForDevice = DEVICE_ID_DEFAULT,
391             dialogDeviceName = DEVICE_ID_DEFAULT,
392             expectPermissionGrantedOnDefaultDevice = true,
393             expectPermissionGrantedOnVirtualDevice = true,
394         )
395     }
396 
397     @Test
398     fun nonDeviceAwarePermission_onHost_requestHostPermission() {
399         createVirtualDevice()
400         testMultiDevicePermissionGrant(
401             permission = Manifest.permission.READ_CONTACTS,
402             initialDefaultDevicePermission = false,
403             initialVirtualDevicePermission = false,
404             requestingFromDevice = DEVICE_ID_DEFAULT,
405             requestingForDevice = DEVICE_ID_DEFAULT,
406             dialogDeviceName = DEVICE_ID_INVALID,
407             expectPermissionGrantedOnDefaultDevice = true,
408             expectPermissionGrantedOnVirtualDevice = true,
409         )
410     }
411 
412     @Test
413     fun nonDeviceAwarePermission_onHost_requestPermissionWithoutDeviceId() {
414         createVirtualDevice()
415         testMultiDevicePermissionGrant(
416             permission = Manifest.permission.READ_CONTACTS,
417             initialDefaultDevicePermission = false,
418             initialVirtualDevicePermission = false,
419             requestingFromDevice = DEVICE_ID_DEFAULT,
420             requestingForDevice = DEVICE_ID_INVALID,
421             dialogDeviceName = DEVICE_ID_INVALID,
422             expectPermissionGrantedOnDefaultDevice = true,
423             expectPermissionGrantedOnVirtualDevice = true,
424         )
425     }
426 
427     @RequiresFlagsEnabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES)
428     @Test
429     fun nonDeviceAwarePermission_onHost_requestRemotePermission() {
430         createVirtualDevice()
431         testMultiDevicePermissionGrant(
432             permission = Manifest.permission.READ_CONTACTS,
433             initialDefaultDevicePermission = false,
434             initialVirtualDevicePermission = false,
435             requestingFromDevice = DEVICE_ID_DEFAULT,
436             requestingForDevice = virtualDevice.deviceId,
437             dialogDeviceName = DEVICE_ID_INVALID,
438             expectPermissionGrantedOnDefaultDevice = true,
439             expectPermissionGrantedOnVirtualDevice = true,
440         )
441     }
442 
443     @RequiresFlagsEnabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES)
444     @Test
445     fun nonDeviceAwarePermission_onRemote_requestRemotePermission() {
446         createVirtualDevice()
447         testMultiDevicePermissionGrant(
448             permission = Manifest.permission.READ_CONTACTS,
449             initialDefaultDevicePermission = false,
450             initialVirtualDevicePermission = false,
451             requestingFromDevice = virtualDevice.deviceId,
452             requestingForDevice = virtualDevice.deviceId,
453             dialogDeviceName = DEVICE_ID_DEFAULT,
454             expectPermissionGrantedOnDefaultDevice = true,
455             expectPermissionGrantedOnVirtualDevice = true,
456         )
457     }
458 
459     @RequiresFlagsEnabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES)
460     @Test
461     fun nonDeviceAwarePermission_onRemote_requestPermissionWithoutDeviceId() {
462         createVirtualDevice()
463         testMultiDevicePermissionGrant(
464             permission = Manifest.permission.READ_CONTACTS,
465             initialDefaultDevicePermission = false,
466             initialVirtualDevicePermission = false,
467             requestingFromDevice = virtualDevice.deviceId,
468             requestingForDevice = DEVICE_ID_INVALID,
469             dialogDeviceName = DEVICE_ID_DEFAULT,
470             expectPermissionGrantedOnDefaultDevice = true,
471             expectPermissionGrantedOnVirtualDevice = true,
472         )
473     }
474 
475     @RequiresFlagsEnabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES)
476     @Test
477     fun nonDeviceAwarePermission_onRemote_requestHostPermission() {
478         createVirtualDevice()
479         testMultiDevicePermissionGrant(
480             permission = Manifest.permission.READ_CONTACTS,
481             initialDefaultDevicePermission = false,
482             initialVirtualDevicePermission = false,
483             requestingFromDevice = virtualDevice.deviceId,
484             requestingForDevice = DEVICE_ID_DEFAULT,
485             dialogDeviceName = DEVICE_ID_DEFAULT,
486             expectPermissionGrantedOnDefaultDevice = true,
487             expectPermissionGrantedOnVirtualDevice = true,
488         )
489     }
490 
491     private fun testMultiDevicePermissionGrant(
492         permission: String,
493         initialDefaultDevicePermission: Boolean,
494         initialVirtualDevicePermission: Boolean,
495         requestingFromDevice: Int,
496         requestingForDevice: Int,
497         dialogDeviceName: Int,
498         expectPermissionGrantedOnDefaultDevice: Boolean,
499         expectPermissionGrantedOnVirtualDevice: Boolean,
500     ) {
501         if (initialDefaultDevicePermission) {
502             instrumentation.uiAutomation.grantRuntimePermission(APP_PACKAGE_NAME, permission)
503         }
504         if (initialVirtualDevicePermission) {
505             grantRuntimePermissionOnVirtualDevice(permission)
506         }
507         assertAppHasPermissionForDevice(
508             DEVICE_ID_DEFAULT,
509             permission,
510             initialDefaultDevicePermission,
511         )
512         assertAppHasPermissionForDevice(
513             virtualDevice.deviceId,
514             permission,
515             initialVirtualDevicePermission,
516         )
517 
518         val displayId =
519             if (requestingFromDevice == DEVICE_ID_DEFAULT) {
520                 Display.DEFAULT_DISPLAY
521             } else {
522                 virtualDisplay.display.displayId
523             }
524 
525         val future = requestPermissionOnDevice(displayId, requestingForDevice, permission)
526 
527         if (dialogDeviceName != DEVICE_ID_INVALID) {
528             val expectedDeviceNameInDialog =
529                 if (dialogDeviceName == DEVICE_ID_DEFAULT) {
530                     defaultDeviceName
531                 } else {
532                     virtualDeviceName
533                 }
534             assertPermissionMessageContainsDeviceName(displayId, expectedDeviceNameInDialog)
535         } else {
536             assertPermissionMessageDoesNotContainDeviceName(displayId)
537         }
538 
539         // Click the allow button in the dialog to grant permission
540         val allowButton =
541             if (permission == Manifest.permission.CAMERA) ALLOW_BUTTON_FOREGROUND else ALLOW_BUTTON
542         SystemUtil.eventually { click(By.displayId(displayId).res(allowButton)) }
543 
544         // Validate permission grant result returned from callback
545         val grantPermissionResult = future.get(TIMEOUT, TimeUnit.MILLISECONDS)
546         assertThat(
547                 grantPermissionResult.getStringArray(
548                     TestConstants.PERMISSION_RESULT_KEY_PERMISSIONS
549                 )
550             )
551             .isEqualTo(arrayOf(permission))
552         assertThat(
553                 grantPermissionResult.getIntArray(TestConstants.PERMISSION_RESULT_KEY_GRANT_RESULTS)
554             )
555             .isEqualTo(arrayOf(PackageManager.PERMISSION_GRANTED).toIntArray())
556 
557         val expectedPermissionResultDeviceId =
558             if (requestingForDevice == DEVICE_ID_INVALID) {
559                 requestingFromDevice
560             } else {
561                 requestingForDevice
562             }
563         assertThat(grantPermissionResult.getInt(TestConstants.PERMISSION_RESULT_KEY_DEVICE_ID))
564             .isEqualTo(expectedPermissionResultDeviceId)
565 
566         // Validate whether permission is granted as expected
567         assertAppHasPermissionForDevice(
568             DEVICE_ID_DEFAULT,
569             permission,
570             expectPermissionGrantedOnDefaultDevice,
571         )
572         assertAppHasPermissionForDevice(
573             virtualDevice.deviceId,
574             permission,
575             expectPermissionGrantedOnVirtualDevice,
576         )
577     }
578 
579     private fun requestPermissionOnDevice(
580         displayId: Int,
581         targetDeviceId: Int,
582         permission: String,
583     ): CompletableFuture<Bundle> {
584         val future = CompletableFuture<Bundle>()
585         val callback = RemoteCallback { result: Bundle? -> future.complete(result) }
586         val permissions = mutableListOf(permission).toTypedArray()
587         val intent =
588             Intent()
589                 .setComponent(
590                     ComponentName(APP_PACKAGE_NAME, "$APP_PACKAGE_NAME.RequestPermissionActivity")
591                 )
592                 .putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID, targetDeviceId)
593                 .putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES, permissions)
594                 .putExtra(EXTRA_RESULT_RECEIVER, callback)
595                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
596 
597         virtualDeviceRule.sendIntentToDisplay(intent, displayId)
598         virtualDeviceRule.waitAndAssertActivityResumed(getPermissionDialogComponentName())
599 
600         return future
601     }
602 
603     private fun assertPermissionMessageContainsDeviceName(displayId: Int, deviceName: String) {
604         waitFindObject(By.displayId(displayId).res(PERMISSION_MESSAGE_ID))
605         val text = findTextForView(By.displayId(displayId).res(PERMISSION_MESSAGE_ID))
606         assertThat(text).contains(deviceName)
607     }
608 
609     private fun assertPermissionMessageDoesNotContainDeviceName(displayId: Int) {
610         waitFindObject(By.displayId(displayId).res(PERMISSION_MESSAGE_ID))
611         val text = findTextForView(By.displayId(displayId).res(PERMISSION_MESSAGE_ID))
612         assertThat(text).doesNotContain(virtualDeviceName)
613         assertThat(text).doesNotContain(defaultDeviceName)
614     }
615 
616     private fun assertAppHasPermissionForDevice(
617         deviceId: Int,
618         permission: String,
619         expectPermissionGranted: Boolean,
620     ) {
621         val checkPermissionResult =
622             defaultDeviceContext
623                 .createDeviceContext(deviceId)
624                 .packageManager
625                 .checkPermission(permission, APP_PACKAGE_NAME)
626 
627         if (expectPermissionGranted) {
628             Assert.assertEquals(PackageManager.PERMISSION_GRANTED, checkPermissionResult)
629         } else {
630             Assert.assertEquals(PackageManager.PERMISSION_DENIED, checkPermissionResult)
631         }
632     }
633 
634     private fun getPermissionDialogComponentName(): ComponentName {
635         val intent = Intent(ACTION_REQUEST_PERMISSIONS)
636         intent.setPackage(defaultDeviceContext.packageManager.getPermissionControllerPackageName())
637         return intent.resolveActivity(defaultDeviceContext.packageManager)
638     }
639 
640     private fun grantRuntimePermissionOnVirtualDevice(permission: String) {
641         permissionManager.grantRuntimePermission(
642             APP_PACKAGE_NAME,
643             permission,
644             virtualDevice.persistentDeviceId!!,
645         )
646     }
647 
648     companion object {
649         const val APK_DIRECTORY = "/data/local/tmp/cts-permissionmultidevice"
650         const val APP_APK_PATH_STREAMING = "${APK_DIRECTORY}/CtsAccessRemoteDeviceCamera.apk"
651         const val APP_PACKAGE_NAME = "android.permissionmultidevice.cts.accessremotedevicecamera"
652         const val PERMISSION_MESSAGE_ID = "com.android.permissioncontroller:id/permission_message"
653         const val ALLOW_BUTTON_FOREGROUND =
654             "com.android.permissioncontroller:id/permission_allow_foreground_only_button"
655         const val ALLOW_BUTTON = "com.android.permissioncontroller:id/permission_allow_button"
656         const val DEVICE_ID_DEFAULT = Context.DEVICE_ID_DEFAULT
657         const val DEVICE_ID_INVALID = Context.DEVICE_ID_INVALID
658         const val PERSISTENT_DEVICE_ID_DEFAULT = VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
659         const val TIMEOUT = 5000L
660     }
661 }
662