diff options
10 files changed, 223 insertions, 117 deletions
diff --git a/PermissionController/AndroidManifest.xml b/PermissionController/AndroidManifest.xml index 4bd7720d0..a0f7563bd 100644 --- a/PermissionController/AndroidManifest.xml +++ b/PermissionController/AndroidManifest.xml @@ -283,6 +283,13 @@ </intent-filter> </activity> + <activity android:name="com.android.permissioncontroller.permission.ui.PermissionDialogStreamingBlockedActivity" + android:theme="@style/PermissionDialog.FilterTouches" + android:excludeFromRecents="true" + android:exported="false" + android:enabled="@bool/is_at_least_v"> + </activity> + <activity android:name="com.android.permissioncontroller.ecm.EnhancedConfirmationDialog" android:theme="@style/GrantPermissions.FilterTouches" android:excludeFromRecents="true" diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml index 6e8005ad0..a3592bdc4 100644 --- a/PermissionController/res/values/strings.xml +++ b/PermissionController/res/values/strings.xml @@ -1982,4 +1982,10 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo <string name="help_url_action_disabled_by_restricted_settings" translatable="false"></string> <!-- END ENHANCED CONFIRMATION DIALOG --> + + <!-- Title for the warning dialog that shows when permission grant dialog is blocked from streaming to a remote device [CHAR LIMIT=70]--> + <string name="permission_grant_dialog_streaming_blocked_title">Permission request suppressed</string> + + <!-- Descriptions for the warning dialog that shows when permission grant dialog is blocked from streaming to a remote device [CHAR LIMIT=200] --> + <string name="permission_grant_dialog_streaming_blocked_description">This app is requesting additional permissions, but permissions can’t be granted in a streaming session. Grant the permission on your phone first.</string> </resources> diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt index ef0a36583..f97cbed65 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/data/LightPackageInfoLiveData.kt @@ -233,7 +233,7 @@ private constructor( val deviceContext = ContextCompat.createDeviceContext(app, deviceId) for ((idx, permName) in requestedPermissions.withIndex()) { - if (isPermissionDeviceAware(permName)) { + if (isPermissionDeviceAware(deviceContext, deviceId, permName)) { val result = deviceContext.checkPermission(permName, -1, uid) if (result == PackageManager.PERMISSION_GRANTED) { diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java index 4fd62dc05..ee4318bf0 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java @@ -20,7 +20,6 @@ import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission_group.LOCATION; import static android.Manifest.permission_group.READ_MEDIA_VISUAL; -import static android.content.Intent.getIntent; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; @@ -37,6 +36,7 @@ import static com.android.permissioncontroller.permission.ui.GrantPermissionsVie import static com.android.permissioncontroller.permission.ui.model.GrantPermissionsViewModel.APP_PERMISSION_REQUEST_CODE; import static com.android.permissioncontroller.permission.ui.model.GrantPermissionsViewModel.ECM_REQUEST_CODE; import static com.android.permissioncontroller.permission.ui.model.GrantPermissionsViewModel.PHOTO_PICKER_REQUEST_CODE; +import static com.android.permissioncontroller.permission.utils.MultiDeviceUtils.isDeviceAwarePermissionSupported; import static com.android.permissioncontroller.permission.utils.Utils.getRequestMessage; import android.Manifest; @@ -50,7 +50,6 @@ import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.drawable.Icon; -import android.os.Build; import android.os.Bundle; import android.os.Process; import android.permission.flags.Flags; @@ -68,6 +67,8 @@ import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -222,6 +223,16 @@ public class GrantPermissionsActivity extends SettingsActivity /** Which device the permission will affect. Default is the primary device. */ private int mTargetDeviceId = ContextCompat.DEVICE_ID_DEFAULT; + private ActivityResultLauncher<Intent> mShowWarningDialog = + registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> { + int resultCode = result.getResultCode(); + if (resultCode == RESULT_OK) { + finishAfterTransition(); + } + }); + @Override public void onCreate(Bundle icicle) { if (DeviceUtils.isAuto(this)) { @@ -241,7 +252,6 @@ public class GrantPermissionsActivity extends SettingsActivity getWindow().addFlags(FLAG_ALT_FOCUSABLE_IM); } - int permissionsSdkLevel; if (PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(getIntent().getAction())) { mIsSystemTriggered = true; mTargetPackage = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME); @@ -251,9 +261,6 @@ public class GrantPermissionsActivity extends SettingsActivity finishAfterTransition(); return; } - // We don't want to do any filtering in this case. - // These calls are coming from the system on behalf of the app. - permissionsSdkLevel = Build.VERSION_CODES.CUR_DEVELOPMENT; } else { // Cache this as this can only read on onCreate, not later. mTargetPackage = getCallingPackage(); @@ -265,7 +272,6 @@ public class GrantPermissionsActivity extends SettingsActivity } try { PackageInfo packageInfo = getPackageManager().getPackageInfo(mTargetPackage, 0); - permissionsSdkLevel = packageInfo.applicationInfo.targetSdkVersion; } catch (PackageManager.NameNotFoundException e) { Log.e(LOG_TAG, "Unable to get package info for the calling package.", e); finishAfterTransition(); @@ -281,8 +287,49 @@ public class GrantPermissionsActivity extends SettingsActivity } mRequestedPermissions = removeNullOrEmptyPermissions(requestedPermissionsArray); - if (mIsSystemTriggered) { - mSystemRequestedPermissions.addAll(mRequestedPermissions); + mOriginalRequestedPermissions = mRequestedPermissions.toArray(new String[0]); + + // Do validation if permissions are requested for a remote device or the dialog is being + // streamed to a remote device. + if (isDeviceAwarePermissionSupported(getApplicationContext())) { + mTargetDeviceId = getIntent().getIntExtra( + PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID, + ContextCompat.DEVICE_ID_DEFAULT); + + // When the dialog is streamed to a remote device, verify requested permissions are all + // device aware and target device is the same as the remote device. Otherwise show a + // warning dialog. + if (getDeviceId() != ContextCompat.DEVICE_ID_DEFAULT) { + boolean showWarningDialog = mTargetDeviceId != getDeviceId(); + + for (String permission : mRequestedPermissions) { + if (!MultiDeviceUtils.isPermissionDeviceAware( + getApplicationContext(), mTargetDeviceId, permission)) { + showWarningDialog = true; + } + } + + if (showWarningDialog) { + mShowWarningDialog.launch( + new Intent(this, PermissionDialogStreamingBlockedActivity.class)); + return; + } + } else if (mTargetDeviceId != ContextCompat.DEVICE_ID_DEFAULT) { + // On the default device, when requested permissions are for a remote device, + // filter out non-device aware permissions. + for (int i = mRequestedPermissions.size() - 1; i >= 0; i--) { + if (!MultiDeviceUtils.isPermissionDeviceAware( + getApplicationContext(), + mTargetDeviceId, + mRequestedPermissions.get(i))) { + Log.e( + LOG_TAG, + "non-device aware permission is requested for a remote device: " + + mRequestedPermissions.get(i)); + mRequestedPermissions.remove(i); + } + } + } } if (mRequestedPermissions.isEmpty()) { @@ -290,36 +337,10 @@ public class GrantPermissionsActivity extends SettingsActivity return; } - if (MultiDeviceUtils.isDeviceAwareGrantFlowEnabled()) { - mTargetDeviceId = - getIntent() - .getIntExtra( - PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID, - ContextCompat.DEVICE_ID_DEFAULT); - } - - // If the permissions requested are for a remote device, check if each permission is device - // aware. - if (mTargetDeviceId != ContextCompat.DEVICE_ID_DEFAULT) { - if (!MultiDeviceUtils.isDeviceAwareGrantFlowEnabled()) { - Log.e(LOG_TAG, "targetDeviceId should be the default device if device aware grant" - + " flow is not enabled"); - finishAfterTransition(); - return; - } - - for (String permission : mRequestedPermissions) { - if (!MultiDeviceUtils.isPermissionDeviceAware(permission)) { - Log.e(LOG_TAG, "When target device is external, permission " + permission - + " needs to be device aware."); - finishAfterTransition(); - return; - } - } + if (mIsSystemTriggered) { + mSystemRequestedPermissions.addAll(mRequestedPermissions); } - mOriginalRequestedPermissions = mRequestedPermissions.toArray(new String[0]); - if (SdkLevel.isAtLeastV() && Flags.enhancedConfirmationModeApisEnabled()) { EnhancedConfirmationManager ecm = getEnhancedConfirmationManager(); diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/PermissionDialogStreamingBlockedActivity.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/PermissionDialogStreamingBlockedActivity.kt new file mode 100644 index 000000000..29f9ed2c7 --- /dev/null +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/PermissionDialogStreamingBlockedActivity.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.permissioncontroller.permission.ui + +import android.app.AlertDialog +import android.os.Bundle +import androidx.fragment.app.FragmentActivity +import com.android.permissioncontroller.R + +/** + * In some scenarios we want to prevent the permission grant dialog from streaming to a remote + * device. If the streaming is blocked show a warning dialog rendered by this activity. + */ +class PermissionDialogStreamingBlockedActivity : FragmentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + AlertDialog.Builder(this) + .setTitle(R.string.permission_grant_dialog_streaming_blocked_title) + .setMessage(R.string.permission_grant_dialog_streaming_blocked_description) + .setPositiveButton(R.string.ongoing_usage_dialog_ok, null) + .setOnDismissListener() { + setResult(RESULT_OK) + finish() + } + .create() + .show() + } +} diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/MultiDeviceUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/MultiDeviceUtils.kt index ba5ba1c23..117a6c8ed 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/utils/MultiDeviceUtils.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/MultiDeviceUtils.kt @@ -7,7 +7,7 @@ import android.os.Build import android.provider.Settings import androidx.annotation.ChecksSdkIntAtLeast import com.android.modules.utils.build.SdkLevel -import com.android.permission.flags.Flags +import com.android.permissioncontroller.DeviceUtils object MultiDeviceUtils { const val DEFAULT_REMOTE_DEVICE_NAME = "remote device" @@ -21,13 +21,32 @@ object MultiDeviceUtils { setOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO) @JvmStatic - fun isPermissionDeviceAware(permission: String): Boolean = - permission in DEVICE_AWARE_PERMISSIONS + fun isDeviceAwarePermissionSupported(context: Context): Boolean = + SdkLevel.isAtLeastV() && + !(DeviceUtils.isTelevision(context) || + DeviceUtils.isAuto(context) || + DeviceUtils.isWear(context)) @JvmStatic @ChecksSdkIntAtLeast(Build.VERSION_CODES.VANILLA_ICE_CREAM) - fun isDeviceAwareGrantFlowEnabled(): Boolean { - return SdkLevel.isAtLeastV() && Flags.deviceAwarePermissionGrantEnabled() + fun isPermissionDeviceAware(context: Context, deviceId: Int, permission: String): Boolean { + if (!SdkLevel.isAtLeastV()) { + return false + } + + if (permission !in DEVICE_AWARE_PERMISSIONS) { + return false + } + + val virtualDevice = + context.getSystemService(VirtualDeviceManager::class.java)!!.getVirtualDevice(deviceId) + ?: return false + + return when (permission) { + Manifest.permission.CAMERA -> virtualDevice.hasCustomCameraSupport() + Manifest.permission.RECORD_AUDIO -> virtualDevice.hasCustomAudioInputSupport() + else -> false + } } @JvmStatic diff --git a/flags/flags.aconfig b/flags/flags.aconfig index 3077dd290..337936fd4 100644 --- a/flags/flags.aconfig +++ b/flags/flags.aconfig @@ -2,14 +2,6 @@ package: "com.android.permission.flags" container: "com.android.permission" flag { - name: "device_aware_permission_grant_enabled" - is_fixed_read_only: true - namespace: "permissions" - description: "Enables device aware grant permission flow" - bug: "292252664" -} - -flag { name: "private_profile_supported" namespace: "permissions" description: "This flag is used to support private profile in safety center" diff --git a/tests/cts/permissionmultidevice/AndroidTest.xml b/tests/cts/permissionmultidevice/AndroidTest.xml index 2b43fd01c..d86bea2d5 100644 --- a/tests/cts/permissionmultidevice/AndroidTest.xml +++ b/tests/cts/permissionmultidevice/AndroidTest.xml @@ -37,13 +37,6 @@ <option name="disable-device-config-sync" value="true" /> </target_preparer> - <target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer"> - <option name="flag-value" - value="permissions/com.android.permission.flags.device_aware_permission_grant=true"/> - <option name="flag-value" - value="virtual_devices/android.companion.virtual.flags.stream_permissions=true"/> - </target_preparer> - <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="CtsPermissionMultiDeviceTestCases.apk" /> diff --git a/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PermissionUtils.kt b/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PermissionUtils.kt index 0ae0fd8e0..cffc0617c 100644 --- a/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PermissionUtils.kt +++ b/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PermissionUtils.kt @@ -1,16 +1,12 @@ package android.permissionmultidevice.cts import android.content.Context +import android.content.pm.PackageManager import android.permission.PermissionManager import android.permission.PermissionManager.PermissionState -import android.provider.Settings import com.android.compatibility.common.util.SystemUtil object PermissionUtils { - fun getHostDeviceName(context: Context): String { - return Settings.Global.getString(context.contentResolver, Settings.Global.DEVICE_NAME) - } - fun getAllPermissionStates( context: Context, packageName: String, @@ -21,4 +17,13 @@ object PermissionUtils { permissionManager.getAllPermissionStates(packageName, companionDeviceId) } } + + fun isAutomotive(context: Context): Boolean = + context.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) + + fun isTv(context: Context): Boolean = + context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) + + fun isWatch(context: Context): Boolean = + context.packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH) } diff --git a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt index c199c7660..191e69367 100644 --- a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt +++ b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt @@ -17,33 +17,37 @@ package android.permissionmultidevice.cts import android.Manifest -import android.app.ActivityOptions import android.app.Instrumentation import android.companion.virtual.VirtualDeviceManager +import android.companion.virtual.VirtualDeviceParams +import android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM +import android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA import android.content.ComponentName -import android.content.Context import android.content.Intent 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.permission.flags.Flags import android.permissionmultidevice.cts.PackageManagementUtils.installPackage import android.permissionmultidevice.cts.PackageManagementUtils.uninstallPackage -import android.permissionmultidevice.cts.PermissionUtils.getHostDeviceName 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.RequiresFlagsEnabled -import android.platform.test.flag.junit.DeviceFlagsValueProvider import android.view.Display +import android.virtualdevice.cts.common.VirtualDeviceRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SdkSuppress import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By -import com.android.compatibility.common.util.AdoptShellPermissionsRule import com.android.compatibility.common.util.SystemUtil import com.google.common.truth.Truth import org.junit.After import org.junit.Assert +import org.junit.Assume.assumeFalse import org.junit.Before import org.junit.Rule import org.junit.Test @@ -51,24 +55,49 @@ 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 { private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() private val defaultDeviceContext = instrumentation.targetContext + private lateinit var mVirtualDeviceManager: VirtualDeviceManager + private lateinit var mVirtualDevice: VirtualDeviceManager.VirtualDevice + private lateinit var mVirtualDisplay: VirtualDisplay + private lateinit var mDeviceDisplayName: String - @get:Rule(order = 0) - val mAdoptShellPermissionsRule = - AdoptShellPermissionsRule( - instrumentation.uiAutomation, - Manifest.permission.CREATE_VIRTUAL_DEVICE - ) - - @get:Rule(order = 1) var mFakeVirtualDeviceRule = FakeVirtualDeviceRule() - - @Rule @JvmField val mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + @get:Rule var mVirtualDeviceRule = VirtualDeviceRule.createDefault() @Before fun setup() { + assumeFalse(PermissionUtils.isAutomotive(defaultDeviceContext)) + assumeFalse(PermissionUtils.isTv(defaultDeviceContext)) + assumeFalse(PermissionUtils.isWatch(defaultDeviceContext)) + installPackage(APP_APK_PATH_STREAMING) + mVirtualDeviceManager = + defaultDeviceContext.getSystemService(VirtualDeviceManager::class.java)!! + mVirtualDevice = + mVirtualDeviceRule.createManagedVirtualDevice( + VirtualDeviceParams.Builder() + .setDevicePolicy(POLICY_TYPE_CAMERA, DEVICE_POLICY_CUSTOM) + .build() + ) + + val displayConfig = + 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 + ) + .build() + + mVirtualDisplay = + mVirtualDeviceRule.createManagedVirtualDisplay(mVirtualDevice, displayConfig)!! + mDeviceDisplayName = + mVirtualDeviceManager.getVirtualDevice(mVirtualDevice.deviceId)!!.displayName.toString() } @After @@ -100,9 +129,9 @@ class DeviceAwarePermissionGrantTest { fun onHostDevice_requestPermissionForRemoteDevice_shouldGrantPermission() { testGrantPermissionForDevice( Display.DEFAULT_DISPLAY, - mFakeVirtualDeviceRule.virtualDevice.deviceId, + mVirtualDevice.deviceId, true, - mFakeVirtualDeviceRule.deviceDisplayName, + mDeviceDisplayName, expectPermissionGrantedOnDefaultDevice = false, expectPermissionGrantedOnRemoteDevice = true ) @@ -113,15 +142,11 @@ class DeviceAwarePermissionGrantTest { Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED ) @Test - fun onRemoteDevice_requestPermissionForHostDevice_shouldGrantPermission() { - testGrantPermissionForDevice( - mFakeVirtualDeviceRule.virtualDisplayId, - DEVICE_ID_DEFAULT, - true, - getHostDeviceName(defaultDeviceContext), - expectPermissionGrantedOnDefaultDevice = true, - expectPermissionGrantedOnRemoteDevice = false - ) + fun onRemoteDevice_requestPermissionForHostDevice_shouldShowWarningDialog() { + requestPermissionOnDevice(mVirtualDisplay.display.displayId, DEVICE_ID_DEFAULT) + + val displayId = mVirtualDisplay.display.displayId + waitFindObject(By.displayId(displayId).textContains("Permission request suppressed")) } @RequiresFlagsEnabled( @@ -131,10 +156,10 @@ class DeviceAwarePermissionGrantTest { @Test fun onRemoteDevice_requestPermissionForRemoteDevice_shouldGrantPermission() { testGrantPermissionForDevice( - mFakeVirtualDeviceRule.virtualDisplayId, - mFakeVirtualDeviceRule.virtualDevice.deviceId, + mVirtualDisplay.display.displayId, + mVirtualDevice.deviceId, true, - mFakeVirtualDeviceRule.deviceDisplayName, + mDeviceDisplayName, expectPermissionGrantedOnDefaultDevice = false, expectPermissionGrantedOnRemoteDevice = true ) @@ -148,15 +173,12 @@ class DeviceAwarePermissionGrantTest { expectPermissionGrantedOnDefaultDevice: Boolean, expectPermissionGrantedOnRemoteDevice: Boolean ) { - assertAppHasPermissionForDevice(defaultDeviceContext, DEVICE_ID_DEFAULT, false) - - assertAppHasPermissionForDevice( - defaultDeviceContext, - mFakeVirtualDeviceRule.virtualDevice.deviceId, - false - ) + // Assert no permission granted to either default device or virtual device + assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false) + assertAppHasPermissionForDevice(mVirtualDevice.deviceId, false) requestPermissionOnDevice(displayId, targetDeviceId) + mVirtualDeviceRule.waitAndAssertActivityResumed(getPermissionDialogComponentName()) if (showDeviceName) { assertPermissionMessageContainsDeviceName(displayId, expectedDeviceNameInDialog) @@ -164,22 +186,14 @@ class DeviceAwarePermissionGrantTest { SystemUtil.eventually { click(By.displayId(displayId).res(ALLOW_BUTTON)) } + assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, expectPermissionGrantedOnDefaultDevice) assertAppHasPermissionForDevice( - defaultDeviceContext, - DEVICE_ID_DEFAULT, - expectPermissionGrantedOnDefaultDevice - ) - - assertAppHasPermissionForDevice( - defaultDeviceContext, - mFakeVirtualDeviceRule.virtualDevice.deviceId, + mVirtualDevice.deviceId, expectPermissionGrantedOnRemoteDevice ) } private fun requestPermissionOnDevice(displayId: Int, targetDeviceId: Int) { - val options = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle() - val intent = Intent() .setComponent( @@ -187,7 +201,7 @@ class DeviceAwarePermissionGrantTest { ) .putExtra(PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID, targetDeviceId) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) - defaultDeviceContext.startActivity(intent, options) + mVirtualDeviceRule.sendIntentToDisplay(intent, displayId) } private fun assertPermissionMessageContainsDeviceName(displayId: Int, deviceName: String) { @@ -196,16 +210,12 @@ class DeviceAwarePermissionGrantTest { Truth.assertThat(text).contains(deviceName) } - private fun assertAppHasPermissionForDevice( - context: Context, - deviceId: Int, - expectPermissionGranted: Boolean - ) { + private fun assertAppHasPermissionForDevice(deviceId: Int, expectPermissionGranted: Boolean) { val checkPermissionResult = - context + defaultDeviceContext .createDeviceContext(deviceId) .packageManager - .checkPermission(Manifest.permission.CAMERA, APP_PACKAGE_NAME) + .checkPermission(DEVICE_AWARE_PERMISSION, APP_PACKAGE_NAME) if (expectPermissionGranted) { Assert.assertEquals(PackageManager.PERMISSION_GRANTED, checkPermissionResult) @@ -214,6 +224,12 @@ class DeviceAwarePermissionGrantTest { } } + private fun getPermissionDialogComponentName(): ComponentName { + val intent = Intent(ACTION_REQUEST_PERMISSIONS) + intent.setPackage(defaultDeviceContext.packageManager.getPermissionControllerPackageName()) + return intent.resolveActivity(defaultDeviceContext.packageManager) + } + companion object { const val APK_DIRECTORY = "/data/local/tmp/cts-permissionmultidevice" const val APP_APK_PATH_STREAMING = "${APK_DIRECTORY}/CtsAccessRemoteDeviceCamera.apk" @@ -223,5 +239,8 @@ class DeviceAwarePermissionGrantTest { "com.android.permissioncontroller:id/permission_allow_foreground_only_button" const val DEVICE_ID_DEFAULT = 0 const val PERSISTENT_DEVICE_ID_DEFAULT = VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT + const val DEVICE_AWARE_PERMISSION = Manifest.permission.CAMERA + private const val DISPLAY_HEIGHT = 1920 + private const val DISPLAY_WIDTH = 1080 } } |