summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
author Vladimir Komsiyski <vladokom@google.com> 2025-03-11 00:21:47 -0700
committer Vladimir Komsiyski <vladokom@google.com> 2025-03-11 00:21:47 -0700
commitdb9f5e553fc8fc1bd683aac053be70c33eb7d273 (patch)
tree08ab4fe9fd3ec1ba7734e83bd1568d9e4a58a1ae /tests
parentc85d32e09875ec2e849c60ea881913915fa7a6c0 (diff)
Exhaustive multi-device permission CTS
- Fix GrantPermissionsActivity for non-device-aware permissions. Such requests should not be ignored, but should fallback to the default device. - Fix the permission check for passing grant results. When requesting default device aware permission from virtual device, the call to checkPermission uses the wrong context. It can simply use mPackageManager, which is always associated with the target device. Fix: 401540899 Test: atest Relnote: n/a Flag: EXEMPT bugfix Change-Id: Ib5de5ce0cf09f6ad1e445b01ca2443bf102ab598
Diffstat (limited to 'tests')
-rw-r--r--tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/AndroidManifest.xml1
-rw-r--r--tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/src/android/permissionmultidevice/cts/accessremotedevicecamera/RequestPermissionActivity.kt18
-rw-r--r--tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt50
-rw-r--r--tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt579
4 files changed, 472 insertions, 176 deletions
diff --git a/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/AndroidManifest.xml b/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/AndroidManifest.xml
index 211e415bd..c31bfdaf3 100644
--- a/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/AndroidManifest.xml
+++ b/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/AndroidManifest.xml
@@ -21,6 +21,7 @@
package="android.permissionmultidevice.cts.accessremotedevicecamera">
<uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
<application>
<activity android:name=".RequestPermissionActivity" android:exported="true" />
diff --git a/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/src/android/permissionmultidevice/cts/accessremotedevicecamera/RequestPermissionActivity.kt b/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/src/android/permissionmultidevice/cts/accessremotedevicecamera/RequestPermissionActivity.kt
index fa1d1f83c..33daa1253 100644
--- a/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/src/android/permissionmultidevice/cts/accessremotedevicecamera/RequestPermissionActivity.kt
+++ b/tests/cts/permissionmultidevice/AccessRemoteDeviceCameraApp/src/android/permissionmultidevice/cts/accessremotedevicecamera/RequestPermissionActivity.kt
@@ -16,7 +16,6 @@
package android.permissionmultidevice.cts.accessremotedevicecamera
-import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.Intent
@@ -33,17 +32,24 @@ class RequestPermissionActivity : Activity() {
val deviceId =
intent.getIntExtra(
PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID,
- Context.DEVICE_ID_DEFAULT
+ Context.DEVICE_ID_INVALID,
)
- requestPermissions(DEVICE_AWARE_PERMISSIONS, 1001, deviceId)
+ val permissions =
+ intent.getStringArrayExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES)!!
+
+ if (deviceId != Context.DEVICE_ID_INVALID) {
+ requestPermissions(permissions, 1001, deviceId)
+ } else {
+ requestPermissions(permissions, 1001)
+ }
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray,
- deviceId: Int
+ deviceId: Int,
) {
val resultReceiver =
intent.getParcelableExtra(Intent.EXTRA_RESULT_RECEIVER, RemoteCallback::class.java)
@@ -57,8 +63,4 @@ class RequestPermissionActivity : Activity() {
resultReceiver?.sendResult(result)
finish()
}
-
- companion object {
- private val DEVICE_AWARE_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
- }
}
diff --git a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt
index 907917f6f..76c86df76 100644
--- a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt
+++ b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt
@@ -108,7 +108,7 @@ class AppPermissionsTest {
@RequiresFlagsEnabled(
Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
- Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
+ Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
)
@Test
fun externalDevicePermissionGrantTest() {
@@ -123,7 +123,7 @@ class AppPermissionsTest {
verifyRadioButtonStates(
allowForegroundChecked = true,
askChecked = false,
- denyChecked = false
+ denyChecked = false,
)
UiAutomatorUtils2.getUiDevice().pressBack()
@@ -131,14 +131,14 @@ class AppPermissionsTest {
mapOf(
"Allowed" to listOf(externalDeviceCameraText),
"Ask every time" to emptyList(),
- "Not allowed" to listOf("Camera")
+ "Not allowed" to listOf("Camera", "Contacts"),
)
assertEquals(expectedGrantInfoMap, getGrantInfoMap())
}
@RequiresFlagsEnabled(
Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
- Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
+ Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
)
@Test
fun externalDevicePermissionChangeToAskTest() {
@@ -153,7 +153,7 @@ class AppPermissionsTest {
@RequiresFlagsEnabled(
Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
- Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
+ Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
)
@Test
fun externalDevicePermissionChangeToDenyTest() {
@@ -168,7 +168,7 @@ class AppPermissionsTest {
@RequiresFlagsEnabled(
Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
- Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
+ Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
)
@Test
fun externalDevicePermissionChangeToAllowTest() {
@@ -180,7 +180,7 @@ class AppPermissionsTest {
verifyRadioButtonStates(
allowForegroundChecked = false,
askChecked = true,
- denyChecked = false
+ denyChecked = false,
)
clickAllowForegroundButton()
@@ -189,7 +189,7 @@ class AppPermissionsTest {
@RequiresFlagsEnabled(
Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
- Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
+ Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
)
@Test
fun externalDevicePermissionNotDisplayedInitiallyTest() {
@@ -200,14 +200,14 @@ class AppPermissionsTest {
mapOf(
"Allowed" to emptyList(),
"Ask every time" to emptyList(),
- "Not allowed" to listOf("Camera")
+ "Not allowed" to listOf("Camera", "Contacts"),
)
assertEquals(expectedGrantInfoMap, getGrantInfoMap())
}
@RequiresFlagsEnabled(
Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
- Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED
+ Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
)
@Test
fun externalDevicePermissionStickyOnGrantTest() {
@@ -219,7 +219,7 @@ class AppPermissionsTest {
verifyRadioButtonStates(
allowForegroundChecked = true,
askChecked = false,
- denyChecked = false
+ denyChecked = false,
)
clickDenyButton()
@@ -232,7 +232,7 @@ class AppPermissionsTest {
mapOf(
"Allowed" to emptyList(),
"Ask every time" to emptyList(),
- "Not allowed" to listOf("Camera", externalDeviceCameraText)
+ "Not allowed" to listOf("Camera", externalDeviceCameraText, "Contacts"),
)
assertEquals(expectedGrantInfoMap, getGrantInfoMap())
}
@@ -243,7 +243,7 @@ class AppPermissionsTest {
verifyRadioButtonStates(
allowForegroundChecked = false,
askChecked = true,
- denyChecked = false
+ denyChecked = false,
)
UiAutomatorUtils2.getUiDevice().pressBack()
@@ -252,7 +252,7 @@ class AppPermissionsTest {
mapOf(
"Allowed" to emptyList(),
"Ask every time" to listOf(externalDeviceCameraText),
- "Not allowed" to listOf("Camera")
+ "Not allowed" to listOf("Camera", "Contacts"),
)
assertEquals(expectedGrantInfoMap, getGrantInfoMap())
@@ -270,7 +270,7 @@ class AppPermissionsTest {
verifyRadioButtonStates(
allowForegroundChecked = false,
askChecked = false,
- denyChecked = true
+ denyChecked = true,
)
UiAutomatorUtils2.getUiDevice().pressBack()
@@ -279,7 +279,7 @@ class AppPermissionsTest {
mapOf(
"Allowed" to emptyList(),
"Ask every time" to emptyList(),
- "Not allowed" to listOf("Camera", externalDeviceCameraText)
+ "Not allowed" to listOf("Camera", externalDeviceCameraText, "Contacts"),
)
assertEquals(expectedGrantInfoMap, getGrantInfoMap())
@@ -297,7 +297,7 @@ class AppPermissionsTest {
verifyRadioButtonStates(
allowForegroundChecked = true,
askChecked = false,
- denyChecked = false
+ denyChecked = false,
)
UiAutomatorUtils2.getUiDevice().pressBack()
@@ -306,7 +306,7 @@ class AppPermissionsTest {
mapOf(
"Allowed" to listOf(externalDeviceCameraText),
"Ask every time" to emptyList(),
- "Not allowed" to listOf("Camera")
+ "Not allowed" to listOf("Camera", "Contacts"),
)
assertEquals(expectedGrantInfoMap, getGrantInfoMap())
@@ -327,7 +327,7 @@ class AppPermissionsTest {
mapOf(
"Allowed" to mutableListOf<String>(),
"Ask every time" to mutableListOf(),
- "Not allowed" to mutableListOf()
+ "Not allowed" to mutableListOf(),
)
val outOfScopeTitles = setOf("Unused app settings", "Manage app if unused")
@@ -360,21 +360,21 @@ class AppPermissionsTest {
private fun verifyRadioButtonStates(
allowForegroundChecked: Boolean,
askChecked: Boolean,
- denyChecked: Boolean
+ denyChecked: Boolean,
) {
eventually {
assertEquals(
allowForegroundChecked,
UiAutomatorUtils2.waitFindObject(By.res(ALLOW_FOREGROUND_ONLY_RADIO_BUTTON))
- .isChecked
+ .isChecked,
)
assertEquals(
askChecked,
- UiAutomatorUtils2.waitFindObject(By.res(ASK_RADIO_BUTTON)).isChecked
+ UiAutomatorUtils2.waitFindObject(By.res(ASK_RADIO_BUTTON)).isChecked,
)
assertEquals(
denyChecked,
- UiAutomatorUtils2.waitFindObject(By.res(DENY_RADIO_BUTTON)).isChecked
+ UiAutomatorUtils2.waitFindObject(By.res(DENY_RADIO_BUTTON)).isChecked,
)
}
}
@@ -392,7 +392,7 @@ class AppPermissionsTest {
)
},
Until.newWindow(),
- NEW_WINDOW_TIMEOUT_MILLIS
+ NEW_WINDOW_TIMEOUT_MILLIS,
)
}
@@ -418,7 +418,7 @@ class AppPermissionsTest {
permissionManager.grantRuntimePermission(
APP_PACKAGE_NAME,
DEVICE_AWARE_PERMISSION,
- persistentDeviceId
+ persistentDeviceId,
)
private fun getPermState(): Map<String, PermissionManager.PermissionState> =
diff --git a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt
index 5c7573a0b..e1068e19a 100644
--- a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt
+++ b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt
@@ -24,11 +24,11 @@ import android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM
import android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT
import android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA
import android.content.ComponentName
+import android.content.Context
import android.content.Intent
import android.content.Intent.EXTRA_RESULT_RECEIVER
import android.content.pm.PackageManager
import android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS
-import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
import android.os.Build
import android.os.Bundle
@@ -41,7 +41,6 @@ import android.permissionmultidevice.cts.UiAutomatorUtils.click
import android.permissionmultidevice.cts.UiAutomatorUtils.findTextForView
import android.permissionmultidevice.cts.UiAutomatorUtils.waitFindObject
import android.platform.test.annotations.AppModeFull
-import android.platform.test.annotations.RequiresFlagsDisabled
import android.platform.test.annotations.RequiresFlagsEnabled
import android.provider.Settings
import android.view.Display
@@ -65,13 +64,19 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName = "VanillaIceCream")
@AppModeFull(reason = "VirtualDeviceManager cannot be accessed by instant apps")
-class DeviceAwarePermissionGrantTest {
+@RequiresFlagsEnabled(
+ Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
+ Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
+ Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES,
+)
+open class DeviceAwarePermissionGrantTest {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val defaultDeviceContext = instrumentation.targetContext
+ private lateinit var defaultDeviceName: String
private lateinit var virtualDeviceManager: VirtualDeviceManager
private lateinit var virtualDevice: VirtualDeviceManager.VirtualDevice
private lateinit var virtualDisplay: VirtualDisplay
- private lateinit var deviceDisplayName: String
+ private lateinit var virtualDeviceName: String
private val permissionManager =
defaultDeviceContext.getSystemService(PermissionManager::class.java)!!
@@ -88,194 +93,449 @@ class DeviceAwarePermissionGrantTest {
installPackage(APP_APK_PATH_STREAMING)
virtualDeviceManager =
defaultDeviceContext.getSystemService(VirtualDeviceManager::class.java)!!
+
+ defaultDeviceName =
+ Settings.Global.getString(
+ defaultDeviceContext.contentResolver,
+ Settings.Global.DEVICE_NAME,
+ )
+ }
+
+ @After
+ fun cleanup() {
+ uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false)
+ Thread.sleep(2000)
+ }
+
+ private fun createVirtualDevice(cameraPolicy: Int = DEVICE_POLICY_DEFAULT) {
virtualDevice =
virtualDeviceRule.createManagedVirtualDevice(
VirtualDeviceParams.Builder()
- .setDevicePolicy(POLICY_TYPE_CAMERA, DEVICE_POLICY_CUSTOM)
+ .setDevicePolicy(POLICY_TYPE_CAMERA, cameraPolicy)
.build()
)
-
- val displayConfigBuilder =
- VirtualDeviceRule.createDefaultVirtualDisplayConfigBuilder(
- DISPLAY_WIDTH,
- DISPLAY_HEIGHT,
- )
- .setFlags(
- DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC or
- DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED or
- DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
- )
-
virtualDisplay =
- virtualDeviceRule.createManagedVirtualDisplay(virtualDevice, displayConfigBuilder)!!
- deviceDisplayName =
+ virtualDeviceRule.createManagedVirtualDisplay(
+ virtualDevice,
+ VirtualDeviceRule.createTrustedVirtualDisplayConfigBuilder(),
+ )!!
+ virtualDeviceName =
virtualDeviceManager.getVirtualDevice(virtualDevice.deviceId)!!.displayName.toString()
}
- @After
- fun cleanup() {
- uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false)
- Thread.sleep(2000)
+ @Test
+ fun deviceAwarePermission_onHost_requestHostPermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = DEVICE_ID_DEFAULT,
+ dialogDeviceName = DEVICE_ID_INVALID,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = false,
+ )
}
- @RequiresFlagsEnabled(
- Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
- Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
- )
@Test
- fun onHostDevice_requestPermissionForHostDevice_shouldGrantPermission() {
- assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false)
- assertAppHasPermissionForDevice(virtualDevice.deviceId, false)
+ fun deviceAwarePermission_onHost_withRemotePermission_requestHostPermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = true,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = DEVICE_ID_DEFAULT,
+ dialogDeviceName = DEVICE_ID_INVALID,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
- testGrantPermissionForDevice(
- Display.DEFAULT_DISPLAY,
- DEVICE_ID_DEFAULT,
- false,
- "",
+ @Test
+ fun deviceAwarePermission_onHost_requestPermissionWithoutDeviceId() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = DEVICE_ID_INVALID,
+ dialogDeviceName = DEVICE_ID_INVALID,
expectPermissionGrantedOnDefaultDevice = true,
- expectPermissionGrantedOnRemoteDevice = false,
+ expectPermissionGrantedOnVirtualDevice = false,
)
}
- @RequiresFlagsEnabled(
- Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
- Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
- )
@Test
- fun onHostDevice_requestPermissionForRemoteDevice_shouldGrantPermission() {
- assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false)
- assertAppHasPermissionForDevice(virtualDevice.deviceId, false)
+ fun deviceAwarePermission_onHost_withRemotePermission_requestPermissionWithoutDeviceId() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = true,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = DEVICE_ID_INVALID,
+ dialogDeviceName = DEVICE_ID_INVALID,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
- testGrantPermissionForDevice(
- Display.DEFAULT_DISPLAY,
- virtualDevice.deviceId,
- true,
- deviceDisplayName,
+ @Test
+ fun deviceAwarePermission_onHost_requestRemotePermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = virtualDevice.deviceId,
+ dialogDeviceName = virtualDevice.deviceId,
expectPermissionGrantedOnDefaultDevice = false,
- expectPermissionGrantedOnRemoteDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
)
}
@Test
- fun onHostDevice_requestPermissionForRemoteDeviceAfterPermissionGrantedToHostDevice() {
- instrumentation.uiAutomation.grantRuntimePermission(APP_PACKAGE_NAME, PERMISSION)
+ fun deviceAwarePermission_onHost_withHostPermission_requestRemotePermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = true,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = virtualDevice.deviceId,
+ dialogDeviceName = virtualDevice.deviceId,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
- assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, true)
- assertAppHasPermissionForDevice(virtualDevice.deviceId, false)
+ @Test
+ fun deviceAwarePermission_onRemote_requestRemotePermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = virtualDevice.deviceId,
+ dialogDeviceName = virtualDevice.deviceId,
+ expectPermissionGrantedOnDefaultDevice = false,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
- testGrantPermissionForDevice(
- Display.DEFAULT_DISPLAY,
- virtualDevice.deviceId,
- true,
- deviceDisplayName,
+ @Test
+ fun deviceAwarePermission_onRemote_withHostPermission_requestRemotePermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = true,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = virtualDevice.deviceId,
+ dialogDeviceName = virtualDevice.deviceId,
expectPermissionGrantedOnDefaultDevice = true,
- expectPermissionGrantedOnRemoteDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
)
}
@Test
- fun onHostDevice_requestPermissionForHostDeviceAfterPermissionGrantedToRemoteDevice() {
- permissionManager.grantRuntimePermission(
- APP_PACKAGE_NAME,
- PERMISSION,
- virtualDevice.persistentDeviceId!!,
+ fun deviceAwarePermission_onRemote_requestPermissionWithoutDeviceId() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = DEVICE_ID_INVALID,
+ dialogDeviceName = virtualDevice.deviceId,
+ expectPermissionGrantedOnDefaultDevice = false,
+ expectPermissionGrantedOnVirtualDevice = true,
)
+ }
- assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false)
- assertAppHasPermissionForDevice(virtualDevice.deviceId, true)
+ @Test
+ fun deviceAwarePermission_onRemote_withHostPermission_requestPermissionWithoutDeviceId() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = true,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = DEVICE_ID_INVALID,
+ dialogDeviceName = virtualDevice.deviceId,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
- testGrantPermissionForDevice(
- Display.DEFAULT_DISPLAY,
- DEVICE_ID_DEFAULT,
- false,
- "",
+ // TODO: Receives PERMISSION_DENIED but it's fine if remote permission is held??
+ @Test
+ fun deviceAwarePermission_onRemote_requestHostPermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = DEVICE_ID_DEFAULT,
+ dialogDeviceName = DEVICE_ID_DEFAULT,
expectPermissionGrantedOnDefaultDevice = true,
- expectPermissionGrantedOnRemoteDevice = true,
+ expectPermissionGrantedOnVirtualDevice = false,
)
}
- @RequiresFlagsEnabled(
- Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
- Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
- )
- @RequiresFlagsDisabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES)
@Test
- fun onRemoteDevice_requestPermissionForHostDevice_shouldShowWarningDialog() {
- assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false)
- assertAppHasPermissionForDevice(virtualDevice.deviceId, false)
+ fun deviceAwarePermission_onRemote_withRemotePermission_requestHostPermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_CUSTOM)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = true,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = DEVICE_ID_DEFAULT,
+ dialogDeviceName = DEVICE_ID_DEFAULT,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
- requestPermissionOnDevice(virtualDisplay.display.displayId, DEVICE_ID_DEFAULT)
+ @Test
+ fun deviceAwarePermissionWithoutCapability_onHost_requestHostPermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = DEVICE_ID_DEFAULT,
+ dialogDeviceName = DEVICE_ID_INVALID,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
- val displayId = virtualDisplay.display.displayId
- waitFindObject(By.displayId(displayId).textContains("Permission request suppressed"))
+ @Test
+ fun deviceAwarePermissionWithoutCapability_onHost_requestPermissionWithoutDeviceId() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = DEVICE_ID_INVALID,
+ dialogDeviceName = DEVICE_ID_INVALID,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
}
- @RequiresFlagsEnabled(
- Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
- Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
- Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES,
- )
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava")
@Test
- fun onRemoteDevice_requestPermissionForHostDevice_shouldGrantPermission() {
- assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false)
- assertAppHasPermissionForDevice(virtualDevice.deviceId, false)
- // Create a virtual device with default policy, so that camera permission request will
- // correspond to default device camera access.
- virtualDevice =
- virtualDeviceRule.createManagedVirtualDevice(
- VirtualDeviceParams.Builder()
- .setDevicePolicy(POLICY_TYPE_CAMERA, DEVICE_POLICY_DEFAULT)
- .build()
- )
- testGrantPermissionForDevice(
- virtualDisplay.display.displayId,
- virtualDevice.deviceId,
- true,
- Settings.Global.getString(
- defaultDeviceContext.contentResolver,
- Settings.Global.DEVICE_NAME,
- ),
+ fun deviceAwarePermissionWithoutCapability_onHost_requestRemotePermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = virtualDevice.deviceId,
+ dialogDeviceName = DEVICE_ID_INVALID,
expectPermissionGrantedOnDefaultDevice = true,
- expectPermissionGrantedOnRemoteDevice = false,
+ expectPermissionGrantedOnVirtualDevice = true,
)
}
- @RequiresFlagsEnabled(
- Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED,
- Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED,
- )
@Test
- fun onRemoteDevice_requestPermissionForRemoteDevice_shouldGrantPermission() {
- assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false)
- assertAppHasPermissionForDevice(virtualDevice.deviceId, false)
+ fun deviceAwarePermissionWithoutCapability_onRemote_requestRemotePermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = virtualDevice.deviceId,
+ dialogDeviceName = DEVICE_ID_DEFAULT,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
- testGrantPermissionForDevice(
- virtualDisplay.display.displayId,
- virtualDevice.deviceId,
- true,
- deviceDisplayName,
- expectPermissionGrantedOnDefaultDevice = false,
- expectPermissionGrantedOnRemoteDevice = true,
+ @Test
+ fun deviceAwarePermissionWithoutCapability_onRemote_requestPermissionWithoutDeviceId() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = DEVICE_ID_INVALID,
+ dialogDeviceName = DEVICE_ID_DEFAULT,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
)
}
- private fun testGrantPermissionForDevice(
- displayId: Int,
- targetDeviceId: Int,
- showDeviceName: Boolean,
- expectedDeviceNameInDialog: String,
+ @Test
+ fun deviceAwarePermissionWithoutCapability_onRemote_requestHostPermission() {
+ createVirtualDevice(cameraPolicy = DEVICE_POLICY_DEFAULT)
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.CAMERA,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = DEVICE_ID_DEFAULT,
+ dialogDeviceName = DEVICE_ID_DEFAULT,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
+
+ @Test
+ fun nonDeviceAwarePermission_onHost_requestHostPermission() {
+ createVirtualDevice()
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.READ_CONTACTS,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = DEVICE_ID_DEFAULT,
+ dialogDeviceName = DEVICE_ID_INVALID,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
+
+ @Test
+ fun nonDeviceAwarePermission_onHost_requestPermissionWithoutDeviceId() {
+ createVirtualDevice()
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.READ_CONTACTS,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = DEVICE_ID_INVALID,
+ dialogDeviceName = DEVICE_ID_INVALID,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
+
+ @Test
+ fun nonDeviceAwarePermission_onHost_requestRemotePermission() {
+ createVirtualDevice()
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.READ_CONTACTS,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = DEVICE_ID_DEFAULT,
+ requestingForDevice = virtualDevice.deviceId,
+ dialogDeviceName = DEVICE_ID_INVALID,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
+
+ @Test
+ fun nonDeviceAwarePermission_onRemote_requestRemotePermission() {
+ createVirtualDevice()
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.READ_CONTACTS,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = virtualDevice.deviceId,
+ dialogDeviceName = DEVICE_ID_DEFAULT,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
+
+ @Test
+ fun nonDeviceAwarePermission_onRemote_requestPermissionWithoutDeviceId() {
+ createVirtualDevice()
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.READ_CONTACTS,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = DEVICE_ID_INVALID,
+ dialogDeviceName = DEVICE_ID_DEFAULT,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
+
+ @Test
+ fun nonDeviceAwarePermission_onRemote_requestHostPermission() {
+ createVirtualDevice()
+ testMultiDevicePermissionGrant(
+ permission = Manifest.permission.READ_CONTACTS,
+ initialDefaultDevicePermission = false,
+ initialVirtualDevicePermission = false,
+ requestingFromDevice = virtualDevice.deviceId,
+ requestingForDevice = DEVICE_ID_DEFAULT,
+ dialogDeviceName = DEVICE_ID_DEFAULT,
+ expectPermissionGrantedOnDefaultDevice = true,
+ expectPermissionGrantedOnVirtualDevice = true,
+ )
+ }
+
+ private fun testMultiDevicePermissionGrant(
+ permission: String,
+ initialDefaultDevicePermission: Boolean,
+ initialVirtualDevicePermission: Boolean,
+ requestingFromDevice: Int,
+ requestingForDevice: Int,
+ dialogDeviceName: Int,
expectPermissionGrantedOnDefaultDevice: Boolean,
- expectPermissionGrantedOnRemoteDevice: Boolean,
+ expectPermissionGrantedOnVirtualDevice: Boolean,
) {
- val future = requestPermissionOnDevice(displayId, targetDeviceId)
+ if (initialDefaultDevicePermission) {
+ instrumentation.uiAutomation.grantRuntimePermission(APP_PACKAGE_NAME, permission)
+ }
+ if (initialVirtualDevicePermission) {
+ grantRuntimePermissionOnVirtualDevice(permission)
+ }
+ assertAppHasPermissionForDevice(
+ DEVICE_ID_DEFAULT,
+ permission,
+ initialDefaultDevicePermission,
+ )
+ assertAppHasPermissionForDevice(
+ virtualDevice.deviceId,
+ permission,
+ initialVirtualDevicePermission,
+ )
- if (showDeviceName) {
+ val displayId =
+ if (requestingFromDevice == DEVICE_ID_DEFAULT) {
+ Display.DEFAULT_DISPLAY
+ } else {
+ virtualDisplay.display.displayId
+ }
+
+ val future = requestPermissionOnDevice(displayId, requestingForDevice, permission)
+
+ if (dialogDeviceName != DEVICE_ID_INVALID) {
+ val expectedDeviceNameInDialog =
+ if (dialogDeviceName == DEVICE_ID_DEFAULT) {
+ defaultDeviceName
+ } else {
+ virtualDeviceName
+ }
assertPermissionMessageContainsDeviceName(displayId, expectedDeviceNameInDialog)
+ } else {
+ assertPermissionMessageDoesNotContainDeviceName(displayId)
}
// Click the allow button in the dialog to grant permission
- SystemUtil.eventually { click(By.displayId(displayId).res(ALLOW_BUTTON)) }
+ val allowButton =
+ if (permission == Manifest.permission.CAMERA) ALLOW_BUTTON_FOREGROUND else ALLOW_BUTTON
+ SystemUtil.eventually { click(By.displayId(displayId).res(allowButton)) }
// Validate permission grant result returned from callback
val grantPermissionResult = future.get(TIMEOUT, TimeUnit.MILLISECONDS)
@@ -284,34 +544,49 @@ class DeviceAwarePermissionGrantTest {
TestConstants.PERMISSION_RESULT_KEY_PERMISSIONS
)
)
- .isEqualTo(arrayOf(PERMISSION))
+ .isEqualTo(arrayOf(permission))
assertThat(
grantPermissionResult.getIntArray(TestConstants.PERMISSION_RESULT_KEY_GRANT_RESULTS)
)
.isEqualTo(arrayOf(PackageManager.PERMISSION_GRANTED).toIntArray())
+
+ val expectedPermissionResultDeviceId =
+ if (requestingForDevice == DEVICE_ID_INVALID) {
+ requestingFromDevice
+ } else {
+ requestingForDevice
+ }
assertThat(grantPermissionResult.getInt(TestConstants.PERMISSION_RESULT_KEY_DEVICE_ID))
- .isEqualTo(targetDeviceId)
+ .isEqualTo(expectedPermissionResultDeviceId)
// Validate whether permission is granted as expected
- assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, expectPermissionGrantedOnDefaultDevice)
+ assertAppHasPermissionForDevice(
+ DEVICE_ID_DEFAULT,
+ permission,
+ expectPermissionGrantedOnDefaultDevice,
+ )
assertAppHasPermissionForDevice(
virtualDevice.deviceId,
- expectPermissionGrantedOnRemoteDevice,
+ permission,
+ expectPermissionGrantedOnVirtualDevice,
)
}
private fun requestPermissionOnDevice(
displayId: Int,
targetDeviceId: Int,
+ permission: String,
): CompletableFuture<Bundle> {
val future = CompletableFuture<Bundle>()
val callback = RemoteCallback { result: Bundle? -> future.complete(result) }
+ val permissions = mutableListOf(permission).toTypedArray()
val intent =
Intent()
.setComponent(
ComponentName(APP_PACKAGE_NAME, "$APP_PACKAGE_NAME.RequestPermissionActivity")
)
.putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID, targetDeviceId)
+ .putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES, permissions)
.putExtra(EXTRA_RESULT_RECEIVER, callback)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
@@ -327,12 +602,23 @@ class DeviceAwarePermissionGrantTest {
assertThat(text).contains(deviceName)
}
- private fun assertAppHasPermissionForDevice(deviceId: Int, expectPermissionGranted: Boolean) {
+ private fun assertPermissionMessageDoesNotContainDeviceName(displayId: Int) {
+ waitFindObject(By.displayId(displayId).res(PERMISSION_MESSAGE_ID))
+ val text = findTextForView(By.displayId(displayId).res(PERMISSION_MESSAGE_ID))
+ assertThat(text).doesNotContain(virtualDeviceName)
+ assertThat(text).doesNotContain(defaultDeviceName)
+ }
+
+ private fun assertAppHasPermissionForDevice(
+ deviceId: Int,
+ permission: String,
+ expectPermissionGranted: Boolean,
+ ) {
val checkPermissionResult =
defaultDeviceContext
.createDeviceContext(deviceId)
.packageManager
- .checkPermission(PERMISSION, APP_PACKAGE_NAME)
+ .checkPermission(permission, APP_PACKAGE_NAME)
if (expectPermissionGranted) {
Assert.assertEquals(PackageManager.PERMISSION_GRANTED, checkPermissionResult)
@@ -347,18 +633,25 @@ class DeviceAwarePermissionGrantTest {
return intent.resolveActivity(defaultDeviceContext.packageManager)
}
+ private fun grantRuntimePermissionOnVirtualDevice(permission: String) {
+ permissionManager.grantRuntimePermission(
+ APP_PACKAGE_NAME,
+ permission,
+ virtualDevice.persistentDeviceId!!,
+ )
+ }
+
companion object {
const val APK_DIRECTORY = "/data/local/tmp/cts-permissionmultidevice"
const val APP_APK_PATH_STREAMING = "${APK_DIRECTORY}/CtsAccessRemoteDeviceCamera.apk"
const val APP_PACKAGE_NAME = "android.permissionmultidevice.cts.accessremotedevicecamera"
const val PERMISSION_MESSAGE_ID = "com.android.permissioncontroller:id/permission_message"
- const val ALLOW_BUTTON =
+ const val ALLOW_BUTTON_FOREGROUND =
"com.android.permissioncontroller:id/permission_allow_foreground_only_button"
- const val DEVICE_ID_DEFAULT = 0
+ const val ALLOW_BUTTON = "com.android.permissioncontroller:id/permission_allow_button"
+ const val DEVICE_ID_DEFAULT = Context.DEVICE_ID_DEFAULT
+ const val DEVICE_ID_INVALID = Context.DEVICE_ID_INVALID
const val PERSISTENT_DEVICE_ID_DEFAULT = VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
- const val PERMISSION = Manifest.permission.CAMERA
const val TIMEOUT = 5000L
- private const val DISPLAY_HEIGHT = 1920
- private const val DISPLAY_WIDTH = 1080
}
}