diff options
Diffstat (limited to 'tests')
3 files changed, 154 insertions, 39 deletions
diff --git a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt index 44eef2144..5c7573a0b 100644 --- a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt +++ b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt @@ -33,6 +33,7 @@ import android.hardware.display.VirtualDisplay import android.os.Build import android.os.Bundle import android.os.RemoteCallback +import android.permission.PermissionManager import android.permission.flags.Flags import android.permissionmultidevice.cts.PackageManagementUtils.installPackage import android.permissionmultidevice.cts.PackageManagementUtils.uninstallPackage @@ -71,8 +72,12 @@ class DeviceAwarePermissionGrantTest { private lateinit var virtualDevice: VirtualDeviceManager.VirtualDevice private lateinit var virtualDisplay: VirtualDisplay private lateinit var deviceDisplayName: String + private val permissionManager = + defaultDeviceContext.getSystemService(PermissionManager::class.java)!! - @get:Rule var virtualDeviceRule = VirtualDeviceRule.createDefault() + @get:Rule + var virtualDeviceRule: VirtualDeviceRule = + VirtualDeviceRule.withAdditionalPermissions(Manifest.permission.GRANT_RUNTIME_PERMISSIONS) @Before fun setup() { @@ -110,6 +115,7 @@ class DeviceAwarePermissionGrantTest { @After fun cleanup() { uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false) + Thread.sleep(2000) } @RequiresFlagsEnabled( @@ -118,6 +124,9 @@ class DeviceAwarePermissionGrantTest { ) @Test fun onHostDevice_requestPermissionForHostDevice_shouldGrantPermission() { + assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false) + assertAppHasPermissionForDevice(virtualDevice.deviceId, false) + testGrantPermissionForDevice( Display.DEFAULT_DISPLAY, DEVICE_ID_DEFAULT, @@ -134,6 +143,9 @@ class DeviceAwarePermissionGrantTest { ) @Test fun onHostDevice_requestPermissionForRemoteDevice_shouldGrantPermission() { + assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false) + assertAppHasPermissionForDevice(virtualDevice.deviceId, false) + testGrantPermissionForDevice( Display.DEFAULT_DISPLAY, virtualDevice.deviceId, @@ -144,6 +156,44 @@ class DeviceAwarePermissionGrantTest { ) } + @Test + fun onHostDevice_requestPermissionForRemoteDeviceAfterPermissionGrantedToHostDevice() { + instrumentation.uiAutomation.grantRuntimePermission(APP_PACKAGE_NAME, PERMISSION) + + assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, true) + assertAppHasPermissionForDevice(virtualDevice.deviceId, false) + + testGrantPermissionForDevice( + Display.DEFAULT_DISPLAY, + virtualDevice.deviceId, + true, + deviceDisplayName, + expectPermissionGrantedOnDefaultDevice = true, + expectPermissionGrantedOnRemoteDevice = true, + ) + } + + @Test + fun onHostDevice_requestPermissionForHostDeviceAfterPermissionGrantedToRemoteDevice() { + permissionManager.grantRuntimePermission( + APP_PACKAGE_NAME, + PERMISSION, + virtualDevice.persistentDeviceId!!, + ) + + assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false) + assertAppHasPermissionForDevice(virtualDevice.deviceId, true) + + testGrantPermissionForDevice( + Display.DEFAULT_DISPLAY, + DEVICE_ID_DEFAULT, + false, + "", + expectPermissionGrantedOnDefaultDevice = true, + expectPermissionGrantedOnRemoteDevice = true, + ) + } + @RequiresFlagsEnabled( Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED, @@ -151,6 +201,9 @@ class DeviceAwarePermissionGrantTest { @RequiresFlagsDisabled(Flags.FLAG_ALLOW_HOST_PERMISSION_DIALOGS_ON_VIRTUAL_DEVICES) @Test fun onRemoteDevice_requestPermissionForHostDevice_shouldShowWarningDialog() { + assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false) + assertAppHasPermissionForDevice(virtualDevice.deviceId, false) + requestPermissionOnDevice(virtualDisplay.display.displayId, DEVICE_ID_DEFAULT) val displayId = virtualDisplay.display.displayId @@ -165,6 +218,8 @@ class DeviceAwarePermissionGrantTest { @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 = @@ -192,6 +247,9 @@ class DeviceAwarePermissionGrantTest { ) @Test fun onRemoteDevice_requestPermissionForRemoteDevice_shouldGrantPermission() { + assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false) + assertAppHasPermissionForDevice(virtualDevice.deviceId, false) + testGrantPermissionForDevice( virtualDisplay.display.displayId, virtualDevice.deviceId, @@ -210,12 +268,7 @@ class DeviceAwarePermissionGrantTest { expectPermissionGrantedOnDefaultDevice: Boolean, expectPermissionGrantedOnRemoteDevice: Boolean, ) { - // Assert no permission granted to either default device or virtual device at the beginning - assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false) - assertAppHasPermissionForDevice(virtualDevice.deviceId, false) - val future = requestPermissionOnDevice(displayId, targetDeviceId) - virtualDeviceRule.waitAndAssertActivityResumed(getPermissionDialogComponentName()) if (showDeviceName) { assertPermissionMessageContainsDeviceName(displayId, expectedDeviceNameInDialog) @@ -261,7 +314,9 @@ class DeviceAwarePermissionGrantTest { .putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID, targetDeviceId) .putExtra(EXTRA_RESULT_RECEIVER, callback) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + virtualDeviceRule.sendIntentToDisplay(intent, displayId) + virtualDeviceRule.waitAndAssertActivityResumed(getPermissionDialogComponentName()) return future } diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt index 9f76479e3..09941722b 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt @@ -39,6 +39,7 @@ import com.android.compatibility.common.util.SystemUtil.eventually import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity import com.android.compatibility.common.util.UiAutomatorUtils2 import org.junit.AfterClass +import org.junit.Assert import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue @@ -68,7 +69,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { NAMESPACE_PRIVACY, PICKER_ENABLED_SETTING, true.toString(), - false + false, ) } photoUri = PhotoPickerUtils.createImage(context) @@ -85,7 +86,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { NAMESPACE_PRIVACY, PICKER_ENABLED_SETTING, false.toString(), - false + false, ) } } @@ -110,7 +111,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { val permissions = packageInfo.requestedPermissions?.toList() ?: emptyList<String>() assertFalse( "Expected app to not request READ_MEDIA_VISUAL_USER_SELECTED", - permissions.contains(READ_MEDIA_VISUAL_USER_SELECTED) + permissions.contains(READ_MEDIA_VISUAL_USER_SELECTED), ) } } @@ -125,7 +126,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { val permissions = packageInfo.requestedPermissions?.toList() ?: emptyList<String>() assertTrue( "Expected app to request READ_MEDIA_VISUAL_USER_SELECTED", - permissions.contains(READ_MEDIA_VISUAL_USER_SELECTED) + permissions.contains(READ_MEDIA_VISUAL_USER_SELECTED), ) } } @@ -145,7 +146,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { requestAppPermissionsAndAssertResult( arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VISUAL_USER_SELECTED), arrayOf(READ_MEDIA_IMAGES to false, READ_MEDIA_VISUAL_USER_SELECTED to false), - waitForWindowTransition = false + waitForWindowTransition = false, ) { doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) } findImageOrVideo(expected = true) @@ -161,7 +162,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { requestAppPermissionsAndAssertResult( arrayOf(READ_MEDIA_IMAGES), arrayOf(READ_MEDIA_IMAGES to true), - waitForWindowTransition = false + waitForWindowTransition = false, ) { doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) } clickImageOrVideo() @@ -174,17 +175,17 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { assertPermissionFlags( READ_MEDIA_IMAGES, FLAG_PERMISSION_ONE_TIME to true, - FLAG_PERMISSION_REVOKED_COMPAT to true + FLAG_PERMISSION_REVOKED_COMPAT to true, ) assertPermissionFlags( READ_MEDIA_VIDEO, FLAG_PERMISSION_ONE_TIME to true, - FLAG_PERMISSION_REVOKED_COMPAT to true + FLAG_PERMISSION_REVOKED_COMPAT to true, ) assertPermissionFlags( READ_MEDIA_VISUAL_USER_SELECTED, FLAG_PERMISSION_ONE_TIME to false, - FLAG_PERMISSION_REVOKED_COMPAT to false + FLAG_PERMISSION_REVOKED_COMPAT to false, ) } } @@ -209,7 +210,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { requestAppPermissionsAndAssertResult( arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VISUAL_USER_SELECTED), arrayOf(READ_MEDIA_IMAGES to false, READ_MEDIA_VISUAL_USER_SELECTED to true), - waitForWindowTransition = false + waitForWindowTransition = false, ) { doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) } clickImageOrVideo() @@ -265,7 +266,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE) requestAppPermissionsAndAssertResult( arrayOf(READ_MEDIA_IMAGES), - arrayOf(READ_MEDIA_IMAGES to true) + arrayOf(READ_MEDIA_IMAGES to true), ) { click(By.res(ALLOW_ALL_BUTTON)) } @@ -278,7 +279,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { installPackage(APP_APK_PATH_LATEST) requestAppPermissionsAndAssertResult( arrayOf(READ_MEDIA_IMAGES, READ_MEDIA_VISUAL_USER_SELECTED), - arrayOf(READ_MEDIA_IMAGES to true, READ_MEDIA_VISUAL_USER_SELECTED to true) + arrayOf(READ_MEDIA_IMAGES to true, READ_MEDIA_VISUAL_USER_SELECTED to true), ) { click(By.res(ALLOW_ALL_BUTTON)) } @@ -338,7 +339,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { .toList() assertTrue( "Expected package to have USER_SELECTED", - requestedPerms.contains(READ_MEDIA_VISUAL_USER_SELECTED) + requestedPerms.contains(READ_MEDIA_VISUAL_USER_SELECTED), ) } @@ -363,7 +364,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { .toList() assertTrue( "Expected package to have USER_SELECTED", - requestedPerms.contains(READ_MEDIA_VISUAL_USER_SELECTED) + requestedPerms.contains(READ_MEDIA_VISUAL_USER_SELECTED), ) } @@ -381,14 +382,14 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { installPackage(APP_APK_PATH_IMPLICIT_USER_SELECT_STORAGE) requestAppPermissionsAndAssertResult( READ_MEDIA_VISUAL_USER_SELECTED to false, - waitForWindowTransition = false + waitForWindowTransition = false, ) {} uninstallPackage(APP_PACKAGE_NAME) installPackage(APP_APK_PATH_LATEST) requestAppPermissionsAndAssertResult( READ_MEDIA_VISUAL_USER_SELECTED to false, ACCESS_MEDIA_LOCATION to false, - waitForWindowTransition = false + waitForWindowTransition = false, ) {} } @@ -399,7 +400,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { requestAppPermissionsAndAssertResult( READ_MEDIA_IMAGES to true, READ_MEDIA_VIDEO to true, - waitForWindowTransition = false + waitForWindowTransition = false, ) {} } @@ -410,7 +411,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { READ_MEDIA_IMAGES to false, ACCESS_MEDIA_LOCATION to true, READ_MEDIA_VISUAL_USER_SELECTED to true, - waitForWindowTransition = false + waitForWindowTransition = false, ) { doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) } clickImageOrVideo() @@ -427,7 +428,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { requestAppPermissionsAndAssertResult( ACCESS_MEDIA_LOCATION to false, READ_MEDIA_VISUAL_USER_SELECTED to false, - waitForWindowTransition = false + waitForWindowTransition = false, ) { findView(By.res(SELECT_BUTTON), expected = false) } @@ -440,7 +441,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { READ_MEDIA_IMAGES to false, ACCESS_MEDIA_LOCATION to true, READ_MEDIA_VISUAL_USER_SELECTED to true, - waitForWindowTransition = false + waitForWindowTransition = false, ) { doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) } clickImageOrVideo() @@ -459,7 +460,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { requestAppPermissionsAndAssertResult( READ_MEDIA_IMAGES to false, READ_MEDIA_VISUAL_USER_SELECTED to true, - waitForWindowTransition = false + waitForWindowTransition = false, ) { doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) } clickImageOrVideo() @@ -474,7 +475,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { requestAppPermissionsAndAssertResult( READ_MEDIA_IMAGES to false, READ_MEDIA_VISUAL_USER_SELECTED to true, - waitForWindowTransition = false + waitForWindowTransition = false, ) { doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) } try { @@ -506,18 +507,32 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { } private fun clickImageOrVideo() { - click(By.res(PhotoPickerUtils.getImageOrVideoResId(context))) + PhotoPickerUtils.clickAndWait(uiDevice, PhotoPickerUtils.getMediaItem(uiDevice)) } private fun clickAllow() { - click(By.res(PhotoPickerUtils.getAllowId(context))) + PhotoPickerUtils.clickAndWait(uiDevice, PhotoPickerUtils.findAddOrDoneButton()) } private fun findImageOrVideo(expected: Boolean) { - findView(By.res(PhotoPickerUtils.getImageOrVideoResId(context)), expected) + eventually { + val item = PhotoPickerUtils.getMediaItem(uiDevice) + if (!expected && item.exists()) { + Assert.fail("Found image or video, when not expecting it") + } else if (expected && !item.exists()) { + Assert.fail("Failed to find image or video") + } + } } private fun findVideo(expected: Boolean) { - findView(By.res(PhotoPickerUtils.getVideoResId(context)), expected) + eventually { + val item = PhotoPickerUtils.getVideoItem(uiDevice) + if (!expected && item.exists()) { + Assert.fail("Found video, when not expecting it") + } else if (expected && !item.exists()) { + Assert.fail("Failed to find video") + } + } } } diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerUtils.kt b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerUtils.kt index db6c412db..aea5637df 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerUtils.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerUtils.kt @@ -21,23 +21,27 @@ import android.content.pm.PackageManager import android.net.Uri import android.os.Bundle import android.os.FileUtils +import android.provider.DeviceConfig import android.provider.MediaStore import android.provider.cts.media.MediaProviderTestUtils import android.provider.cts.media.MediaStoreUtils +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiObject +import androidx.test.uiautomator.UiSelector import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity import java.io.IOException +import org.junit.Assert +// TODO: b/393428835: We need to merge these utils with the Photo Picker CTS ones object PhotoPickerUtils { private const val DISPLAY_NAME_PREFIX = "ctsPermissionPhotoPicker" private const val VIDEO_ICON_ID = ":id/icon_video" - private const val IMAGE_CHECK_BOX_ID = ":id/icon_check" private const val ALLOW_ID = ":id/button_add" + private const val REGEX_MEDIA_ITEM_CONTENT_DESCRIPTION = "^(Media|Photo|Video|GIF|Motion)[^s].*" + private const val REGEX_VIDEO_ITEM_CONTENT_DESCRIPTION = "^(Video)[^s].*" + private const val REGEX_CONTAINS_DONE = ".*[Dd]one.*" private var mediaProviderPkgName: String? = null - fun getImageOrVideoResId(context: Context): String { - return "${getMediaProviderPkgName(context)!!}$IMAGE_CHECK_BOX_ID" - } - fun getVideoResId(context: Context): String { return "${getMediaProviderPkgName(context)!!}$VIDEO_ICON_ID" } @@ -70,7 +74,7 @@ object PhotoPickerUtils { context, R.raw.lg_g4_iso_800_jpg, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - "image/jpeg" + "image/jpeg", ) .first } @@ -81,7 +85,7 @@ object PhotoPickerUtils { context, R.raw.test_video, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, - "video/mp4" + "video/mp4", ) .first } @@ -108,6 +112,7 @@ object PhotoPickerUtils { stageMedia(context, resId, collectionUri, mimeType) } } + @Throws(IOException::class) private fun stageMedia( context: Context, @@ -125,4 +130,44 @@ object PhotoPickerUtils { return session.publish() to displayName } } + + /** Find a media item to perform click events */ + @Throws(Exception::class) + fun getMediaItem(device: UiDevice): UiObject { + val mediaItemSelector = + UiSelector().descriptionMatches(REGEX_MEDIA_ITEM_CONTENT_DESCRIPTION) + return device.findObject(mediaItemSelector) + } + + /** Find a media item to perform click events */ + @Throws(Exception::class) + fun getVideoItem(device: UiDevice): UiObject { + val mediaItemSelector = + UiSelector().descriptionMatches(REGEX_VIDEO_ITEM_CONTENT_DESCRIPTION) + return device.findObject(mediaItemSelector) + } + + fun findAddOrDoneButton(): UiObject { + if (isModernPickerEnabled()) { + return UiObject(UiSelector().textMatches(REGEX_CONTAINS_DONE)) + } + return UiObject(UiSelector().resourceIdMatches("$mediaProviderPkgName:id/button_add")) + } + + @Throws(Exception::class) + fun clickAndWait(uiDevice: UiDevice, uiObject: UiObject) { + uiObject.click() + uiDevice.waitForIdle() + } + + fun isModernPickerEnabled(): Boolean { + return try { + callWithShellPermissionIdentity { + DeviceConfig.getBoolean("mediaprovider", "enable_modern_picker", false) + } + } catch (e: Exception) { + Assert.fail("Failed to check if modern media provider is enabled") + false + } + } } |