diff options
Diffstat (limited to 'tests')
114 files changed, 6890 insertions, 1854 deletions
diff --git a/tests/apex/Android.bp b/tests/apex/Android.bp index 18f1bea75..9dfbdf589 100644 --- a/tests/apex/Android.bp +++ b/tests/apex/Android.bp @@ -31,6 +31,8 @@ android_test { "androidx.test.rules", "androidx.test.ext.junit", "androidx.test.ext.truth", + "com.android.permission.flags-aconfig-java", + "flag-junit", "mockito-target-extended-minus-junit4", ], jni_libs: [ diff --git a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt index 6500b3926..e9c93a33a 100644 --- a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt +++ b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt @@ -20,12 +20,18 @@ import android.content.ApexEnvironment import android.content.Context import android.os.Process import android.os.UserHandle +import android.platform.test.annotations.RequiresFlagsDisabled +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.DeviceFlagsValueProvider import androidx.test.platform.app.InstrumentationRegistry import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession +import com.android.permission.flags.Flags import com.google.common.truth.Truth.assertThat import java.io.File import org.junit.After +import org.junit.Assume.assumeFalse import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized @@ -49,11 +55,22 @@ class RolesPersistenceTest { private val persistence = RolesPersistenceImpl {} private val defaultRoles = mapOf(ROLE_NAME to setOf(HOLDER_1, HOLDER_2)) + private val activeUserIds = mapOf(ROLE_NAME to USER_ID) private val stateVersionUndefined = RolesState(VERSION_UNDEFINED, PACKAGE_HASH, defaultRoles) private val stateVersionFallbackMigrated = RolesState(VERSION_FALLBACK_MIGRATED, PACKAGE_HASH, defaultRoles, setOf(ROLE_NAME)) + private val stateVersionActiveUserIds = + RolesState( + VERSION_ACTIVE_USER_IDS, + PACKAGE_HASH, + defaultRoles, + setOf(ROLE_NAME), + activeUserIds, + ) private val user = Process.myUserHandle() + @get:Rule val flagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + @Before fun setUp() { createMockDataDirectory() @@ -84,16 +101,41 @@ class RolesPersistenceTest { mockitoSession.finishMocking() } + @RequiresFlagsDisabled(Flags.FLAG_CROSS_USER_ROLE_ENABLED) @Test fun testWriteRead() { + assumeFalse(stateVersion == StateVersion.VERSION_ACTIVE_USER_IDS) persistence.writeForUser(state, user) val persistedState = persistence.readForUser(user) assertThat(persistedState).isEqualTo(state) } + @RequiresFlagsEnabled(Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @Test + fun testWriteRead_supportsActiveUser() { + persistence.writeForUser(state, user) + val persistedState = persistence.readForUser(user) + + assertThat(persistedState).isEqualTo(state) + } + + @RequiresFlagsDisabled(Flags.FLAG_CROSS_USER_ROLE_ENABLED) @Test fun testWriteCorruptReadFromReserveCopy() { + assumeFalse(stateVersion == StateVersion.VERSION_ACTIVE_USER_IDS) + persistence.writeForUser(state, user) + // Corrupt the primary file. + RolesPersistenceImpl.getFile(user) + .writeText("<roles version=\"-1\"><role name=\"com.foo.bar\"><holder") + val persistedState = persistence.readForUser(user) + + assertThat(persistedState).isEqualTo(state) + } + + @RequiresFlagsEnabled(Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @Test + fun testWriteCorruptReadFromReserveCopy_supportsActiveUser() { persistence.writeForUser(state, user) // Corrupt the primary file. RolesPersistenceImpl.getFile(user) @@ -116,11 +158,13 @@ class RolesPersistenceTest { when (stateVersion) { StateVersion.VERSION_UNDEFINED -> stateVersionUndefined StateVersion.VERSION_FALLBACK_MIGRATED -> stateVersionFallbackMigrated + StateVersion.VERSION_ACTIVE_USER_IDS -> stateVersionActiveUserIds } enum class StateVersion { VERSION_UNDEFINED, - VERSION_FALLBACK_MIGRATED + VERSION_FALLBACK_MIGRATED, + VERSION_ACTIVE_USER_IDS, } companion object { @@ -130,10 +174,12 @@ class RolesPersistenceTest { private const val VERSION_UNDEFINED = -1 private const val VERSION_FALLBACK_MIGRATED = 1 + private const val VERSION_ACTIVE_USER_IDS = 2 private const val APEX_MODULE_NAME = "com.android.permission" private const val PACKAGE_HASH = "packagesHash" private const val ROLE_NAME = "roleName" private const val HOLDER_1 = "holder1" private const val HOLDER_2 = "holder2" + private const val USER_ID = 10 } } diff --git a/tests/cts/permission/AndroidManifest.xml b/tests/cts/permission/AndroidManifest.xml index bb027b5f2..43fd97bb2 100644 --- a/tests/cts/permission/AndroidManifest.xml +++ b/tests/cts/permission/AndroidManifest.xml @@ -51,9 +51,6 @@ android:label="@string/perm_group_c" android:name="android.permission.cts.groupC"/> - <!-- for android.permission.cts.DevicePermissionsTest --> - <uses-permission android:name="android.permission.CREATE_VIRTUAL_DEVICE"/> - <uses-permission android:name="android.permission.INJECT_EVENTS"/> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> <application> diff --git a/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java index aabdd8565..55c2d9f31 100644 --- a/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java +++ b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java @@ -384,7 +384,7 @@ public class PermissionUtils { simulateReboot(packageName, intentAction, broadcastReceiver); while ((System.currentTimeMillis() - startTime) < timeout - && !jobStatus.contains("waiting")) { + && !isJobScheduled(jobStatus)) { String cmd = "cmd jobscheduler get-job-state -u " + Process.myUserHandle().getIdentifier() + " " + packageName + " " + jobId; @@ -396,11 +396,16 @@ public class PermissionUtils { // ignore interrupt } } - if (!jobStatus.contains("waiting")) { + if (!isJobScheduled(jobStatus)) { throw new IllegalStateException("The job didn't get scheduled in time."); } } + private static boolean isJobScheduled(String jobStatus) throws Exception { + return jobStatus.contains("waiting") || jobStatus.contains("pending") + || jobStatus.contains("ready") || jobStatus.contains("active"); + } + private static void simulateReboot(@NonNull String packageName, @NonNull String intentAction, @NonNull String broadcastReceiver) { Intent jobSetupReceiverIntent = new Intent(intentAction); diff --git a/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/TestUtils.java b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/TestUtils.java index 48ccbe79f..96b3c4cc4 100644 --- a/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/TestUtils.java +++ b/tests/cts/permission/permissionTestUtilLib/src/android/permission/cts/TestUtils.java @@ -19,7 +19,10 @@ package android.permission.cts; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import android.app.UiAutomation; +import android.content.res.Configuration; +import android.content.res.Resources; import android.os.Process; +import android.util.DisplayMetrics; import android.util.Log; import androidx.annotation.NonNull; @@ -202,4 +205,47 @@ public class TestUtils { throw new RuntimeException(e); } } + + /** + * This method checks for the minimum screen size described in <a href="https://source.android.com/docs/compatibility/14/android-14-cdd#7111_screen_size_and_shape">CDD</a> + */ + public static boolean isCddCompliantScreenSize() { + if ((Resources.getSystem().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK) + == Configuration.UI_MODE_TYPE_WATCH) { + Log.d(LOG_TAG, "UI mode is UI_MODE_TYPE_WATCH, skipping the min dp check"); + return true; + } + + int screenSize = Resources.getSystem().getConfiguration().screenLayout + & Configuration.SCREENLAYOUT_SIZE_MASK; + return switch (screenSize) { + case Configuration.SCREENLAYOUT_SIZE_SMALL -> hasMinScreenSize(426, 320); + case Configuration.SCREENLAYOUT_SIZE_NORMAL -> hasMinScreenSize(480, 320); + case Configuration.SCREENLAYOUT_SIZE_LARGE -> hasMinScreenSize(640, 480); + case Configuration.SCREENLAYOUT_SIZE_XLARGE -> hasMinScreenSize(960, 720); + default -> { + Log.e(LOG_TAG, "Unknown screen size: " + screenSize); + yield true; + } + }; + } + + private static boolean hasMinScreenSize(int minWidthDp, int minHeightDp) { + DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); + float widthDp = (160f / metrics.densityDpi) * metrics.widthPixels; + float heightDp = (160f / metrics.densityDpi) * metrics.heightPixels; + + // CDD does not seem to follow width & height convention correctly, hence checking both ways + boolean hasMinScreenSize = (widthDp >= minWidthDp && heightDp >= minHeightDp) + || (widthDp >= minHeightDp && heightDp >= minWidthDp); + if (!hasMinScreenSize) { + Log.d(LOG_TAG, + "Does not meet min screen size criteria, actual width/height = " + + metrics.widthPixels + "/" + metrics.heightPixels + + " expected minimum width/height = " + minWidthDp + "/" + minHeightDp + + " dpi=" + + metrics.densityDpi); + } + return hasMinScreenSize; + } } diff --git a/tests/cts/permission/src/android/permission/cts/BackgroundPermissionsTest.java b/tests/cts/permission/src/android/permission/cts/BackgroundPermissionsTest.java index f3f47631c..f4bed4ada 100644 --- a/tests/cts/permission/src/android/permission/cts/BackgroundPermissionsTest.java +++ b/tests/cts/permission/src/android/permission/cts/BackgroundPermissionsTest.java @@ -24,6 +24,7 @@ import static android.app.AppOpsManager.MODE_FOREGROUND; import static android.app.AppOpsManager.MODE_IGNORED; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.content.pm.PermissionInfo.PROTECTION_INTERNAL; +import static android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP; import static android.permission.cts.PermissionUtils.getAppOp; import static android.permission.cts.PermissionUtils.grantPermission; import static android.permission.cts.PermissionUtils.install; @@ -31,6 +32,7 @@ import static android.permission.cts.PermissionUtils.uninstallApp; import static com.android.compatibility.common.util.SystemUtil.eventually; +import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertNotEquals; @@ -43,14 +45,21 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; +import android.os.Build; +import android.permission.flags.Flags; import android.platform.test.annotations.AppModeFull; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.ArrayMap; import android.util.Log; +import androidx.test.filters.SdkSuppress; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import org.junit.After; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -72,6 +81,9 @@ public class BackgroundPermissionsTest { private static final UiAutomation sUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @After public void uninstallTestApp() { uninstallApp(APP_PKG); @@ -79,9 +91,24 @@ public class BackgroundPermissionsTest { @Test @AppModeFull(reason = "Instant apps cannot read properties of other packages") - public void verifybackgroundPermissionsProperties() throws Exception { + public void verifyBackgroundPropertiesForPlatformPermissions() throws Exception { + verifyBackgroundPermissionsProperties("android"); + } + + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @RequiresFlagsEnabled({Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED}) + @Test + @AppModeFull(reason = "Instant apps cannot read properties of other packages") + public void verifyBackgroundPropertiesForHealthPermissions() throws Exception { + String healthPackageName = sContext.getPackageManager().getPermissionGroupInfo( + HEALTH_PERMISSION_GROUP, /* flags= */ 0).packageName; + verifyBackgroundPermissionsProperties(healthPackageName); + } + + private void verifyBackgroundPermissionsProperties(String packageName) + throws Exception { PackageInfo pkg = sContext.getPackageManager().getPackageInfo( - "android", PackageManager.GET_PERMISSIONS); + packageName, PackageManager.GET_PERMISSIONS); ArrayMap<String, String> potentialBackgroundPermissionsToGroup = new ArrayMap<>(); int numPermissions = pkg.permissions.length; @@ -97,11 +124,13 @@ public class BackgroundPermissionsTest { } } + int backgroundPermissionCount = 0; for (int i = 0; i < numPermissions; i++) { PermissionInfo permission = pkg.permissions[i]; String backgroundPermissionName = permission.backgroundPermission; if (backgroundPermissionName != null) { + backgroundPermissionCount += 1; Log.i(LOG_TAG, permission.name + "->" + backgroundPermissionName); // foreground permissions must be dangerous @@ -115,6 +144,8 @@ public class BackgroundPermissionsTest { .containsKey(backgroundPermissionName)); } } + // Tested packages must have at least one permission linked with a background permission. + assertThat(backgroundPermissionCount).isGreaterThan(0); } /** diff --git a/tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt b/tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt index ff333c6a0..145936382 100644 --- a/tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt +++ b/tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt @@ -22,6 +22,10 @@ import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_S import android.app.Instrumentation import android.companion.virtual.VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT import android.companion.virtual.VirtualDeviceManager.VirtualDevice +import android.companion.virtual.VirtualDeviceParams +import android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM +import android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT +import android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO import android.content.Context import android.content.Intent import android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME @@ -33,10 +37,7 @@ import android.content.pm.PackageManager.PERMISSION_GRANTED import android.os.Build import android.os.UserHandle import android.permission.PermissionManager -import android.permission.flags.Flags import android.platform.test.annotations.AppModeFull -import android.platform.test.annotations.RequiresFlagsDisabled -import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.DeviceFlagsValueProvider import android.virtualdevice.cts.common.VirtualDeviceRule import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -66,18 +67,25 @@ class DevicePermissionsTest { private lateinit var permissionManager: PermissionManager @get:Rule - var mVirtualDeviceRule = VirtualDeviceRule.withAdditionalPermissions( + var mVirtualDeviceRule = + VirtualDeviceRule.withAdditionalPermissions( Manifest.permission.GRANT_RUNTIME_PERMISSIONS, Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS, Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, - Manifest.permission.GET_RUNTIME_PERMISSIONS + Manifest.permission.GET_RUNTIME_PERMISSIONS, ) @Rule @JvmField val mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() @Before fun setup() { - virtualDevice = mVirtualDeviceRule.createManagedVirtualDevice() + virtualDevice = + mVirtualDeviceRule.createManagedVirtualDevice( + // Without custom audio policy, the RECORD_AUDIO permission won't be device aware. + VirtualDeviceParams.Builder() + .setDevicePolicy(POLICY_TYPE_AUDIO, DEVICE_POLICY_CUSTOM) + .build() + ) virtualDeviceContext = defaultDeviceContext.createDeviceContext(virtualDevice.deviceId) permissionManager = virtualDeviceContext.getSystemService(PermissionManager::class.java)!! persistentDeviceId = virtualDevice.persistentDeviceId!! @@ -89,43 +97,47 @@ class DevicePermissionsTest { runShellCommandOrThrow("pm uninstall $TEST_PACKAGE_NAME") } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testDeviceAwareRuntimePermissionIsGranted() { - grantPermissionAndAssertGranted(Manifest.permission.CAMERA, virtualDeviceContext) + fun virtualDeviceDefaultPolicy_deviceAwarePermissionFallsBackToDefaultDevice() { + virtualDevice = + mVirtualDeviceRule.createManagedVirtualDevice( + // With default audio policy, the RECORD_AUDIO permission won't be device aware. + VirtualDeviceParams.Builder() + .setDevicePolicy(POLICY_TYPE_AUDIO, DEVICE_POLICY_DEFAULT) + .build() + ) + virtualDeviceContext = defaultDeviceContext.createDeviceContext(virtualDevice.deviceId) + + grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, defaultDeviceContext) + assertPermission(DEVICE_AWARE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext) } - @RequiresFlagsDisabled(Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED) @Test - fun testDeviceAwareRuntimePermissionGrantIsInherited() { - grantPermissionAndAssertGranted(Manifest.permission.CAMERA, defaultDeviceContext) + fun virtualDeviceCustomPolicy_deviceAwarePermissionGrantedOnVirtualDevice() { + // When a device aware permission is granted on the default device, it's not automatically + // granted on the virtual device. + grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, defaultDeviceContext) + assertPermission(DEVICE_AWARE_PERMISSION, PERMISSION_DENIED, virtualDeviceContext) - assertPermission(Manifest.permission.CAMERA, PERMISSION_GRANTED, virtualDeviceContext) + grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, virtualDeviceContext) } @Test - fun testNonDeviceAwareRuntimePermissionGrantIsInherited() { + fun normalPermissionGrantedOnDefaultDevice_isGrantedOnVirtualDevice() { grantPermissionAndAssertGranted(NON_DEVICE_AWARE_PERMISSION, defaultDeviceContext) assertPermission(NON_DEVICE_AWARE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext) } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testDeviceAwareRuntimePermissionIsRevoked() { + fun virtualDeviceCustomPolicy_deviceAwarePermissionIsRevoked() { grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, virtualDeviceContext) revokePermissionAndAssertDenied(DEVICE_AWARE_PERMISSION, virtualDeviceContext) } @Test - fun testNonDeviceAwareRuntimePermissionIsRevokedForDefaultDevice() { + fun normalPermissionRevokedFromVirtualDevice_isAlsoRevokedOnDefaultDevice() { grantPermissionAndAssertGranted(NON_DEVICE_AWARE_PERMISSION, defaultDeviceContext) assertPermission(NON_DEVICE_AWARE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext) // Revoke call from virtualDeviceContext should revoke for default device as well. @@ -134,24 +146,24 @@ class DevicePermissionsTest { } @Test - fun testNormalPermissionGrantIsInherited() { + fun normalPermission_isInheritedOnVirtualDevice() { assertPermission(Manifest.permission.INTERNET, PERMISSION_GRANTED, virtualDeviceContext) } @Test - fun testSignaturePermissionGrantIsInherited() { + fun signaturePermission_isInheritedOnVirtualDevice() { assertPermission(CUSTOM_SIGNATURE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext) } @Test - fun testOneTimePermissionIsRevoked() { + fun virtualDeviceCustomPolicy_oneTimePermissionIsRevoked() { grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, virtualDeviceContext) virtualDeviceContext.packageManager.updatePermissionFlags( DEVICE_AWARE_PERMISSION, TEST_PACKAGE_NAME, FLAG_PERMISSION_ONE_TIME, FLAG_PERMISSION_ONE_TIME, - UserHandle.of(virtualDeviceContext.userId) + UserHandle.of(virtualDeviceContext.userId), ) permissionManager.startOneTimePermissionSession( @@ -159,19 +171,15 @@ class DevicePermissionsTest { 0, 0, IMPORTANCE_FOREGROUND, - IMPORTANCE_FOREGROUND_SERVICE + IMPORTANCE_FOREGROUND_SERVICE, ) eventually { assertPermission(DEVICE_AWARE_PERMISSION, PERMISSION_DENIED, virtualDeviceContext) } } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testRevokeSelfPermissionOnKill() { + fun virtualDeviceCustomPolicy_revokeSelfPermissionOnKill_permissionIsRevoked() { grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, virtualDeviceContext) revokeSelfPermission(DEVICE_AWARE_PERMISSION, virtualDeviceContext) @@ -180,105 +188,90 @@ class DevicePermissionsTest { } } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testGrantAndRevokeDeviceAwarePermissionByPersistentDeviceId() { - val deviceAwarePermission = DEVICE_AWARE_PERMISSION - + fun usePersistentDeviceIdToRevokeDeviceAwarePermission_permissionIsRevoked() { permissionManager.grantRuntimePermission( TEST_PACKAGE_NAME, - deviceAwarePermission, - persistentDeviceId + DEVICE_AWARE_PERMISSION, + persistentDeviceId, ) assertThat( permissionManager.checkPermission( - deviceAwarePermission, + DEVICE_AWARE_PERMISSION, TEST_PACKAGE_NAME, - virtualDevice.persistentDeviceId!! + virtualDevice.persistentDeviceId!!, ) ) .isEqualTo(PERMISSION_GRANTED) assertThat( permissionManager.checkPermission( - deviceAwarePermission, + DEVICE_AWARE_PERMISSION, TEST_PACKAGE_NAME, - PERSISTENT_DEVICE_ID_DEFAULT + PERSISTENT_DEVICE_ID_DEFAULT, ) ) .isEqualTo(PERMISSION_DENIED) permissionManager.revokeRuntimePermission( TEST_PACKAGE_NAME, - deviceAwarePermission, + DEVICE_AWARE_PERMISSION, persistentDeviceId, - "test" + "test", ) assertThat( permissionManager.checkPermission( - deviceAwarePermission, + DEVICE_AWARE_PERMISSION, TEST_PACKAGE_NAME, - virtualDevice.persistentDeviceId!! + virtualDevice.persistentDeviceId!!, ) ) .isEqualTo(PERMISSION_DENIED) } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testUpdateAndGetPermissionFlagsByPersistentDeviceId() { - val deviceAwarePermission = DEVICE_AWARE_PERMISSION + fun updateAndGetPermissionFlagsByPersistentDeviceId() { val flagMask = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_USER_FIXED val flag = FLAG_PERMISSION_USER_SET assertThat( permissionManager.getPermissionFlags( TEST_PACKAGE_NAME, - deviceAwarePermission, - persistentDeviceId + DEVICE_AWARE_PERMISSION, + persistentDeviceId, ) ) .isEqualTo(0) permissionManager.updatePermissionFlags( TEST_PACKAGE_NAME, - deviceAwarePermission, + DEVICE_AWARE_PERMISSION, persistentDeviceId, flagMask, - flag + flag, ) assertThat( permissionManager.getPermissionFlags( TEST_PACKAGE_NAME, - deviceAwarePermission, - persistentDeviceId + DEVICE_AWARE_PERMISSION, + persistentDeviceId, ) ) .isEqualTo(FLAG_PERMISSION_USER_SET) } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testAllPermissionStatesApiGrantForVirtualDevice() { + fun permissionGrantedOnVirtualDevice_reflectedInGetAllPermissionStatesApi() { // Setting a flag explicitly so that the permission consistently stays in the state permissionManager.updatePermissionFlags( TEST_PACKAGE_NAME, DEVICE_AWARE_PERMISSION, PERSISTENT_DEVICE_ID_DEFAULT, FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, - FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED + FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, ) assertThat( @@ -291,7 +284,7 @@ class DevicePermissionsTest { permissionManager.grantRuntimePermission( TEST_PACKAGE_NAME, DEVICE_AWARE_PERMISSION, - persistentDeviceId + persistentDeviceId, ) val permissionStateMap = @@ -312,7 +305,7 @@ class DevicePermissionsTest { TEST_PACKAGE_NAME, DEVICE_AWARE_PERMISSION, persistentDeviceId, - "test" + "test", ) assertThat( @@ -323,12 +316,8 @@ class DevicePermissionsTest { .isFalse() } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testAllPermissionStatesApiFlagsForVirtualDevice() { + fun setPermissionFlagOnVirtualDevice_reflectedInGetAllPermissionStatesApi() { val flagMask = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_USER_FIXED val flag = FLAG_PERMISSION_USER_SET @@ -340,7 +329,7 @@ class DevicePermissionsTest { DEVICE_AWARE_PERMISSION, persistentDeviceId, flagMask, - flag + flag, ) assertThat( @@ -349,7 +338,7 @@ class DevicePermissionsTest { .getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId)[ DEVICE_AWARE_PERMISSION]!! .flags, - flag + flag, ) ) .isTrue() @@ -360,15 +349,14 @@ class DevicePermissionsTest { .getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId)[ DEVICE_AWARE_PERMISSION]!! .flags, - FLAG_PERMISSION_USER_FIXED + FLAG_PERMISSION_USER_FIXED, ) ) .isFalse() } - @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) @Test - fun testAllPermissionStatesApiGrantForDefaultDevice() { + fun permissionGrantedOnDefaultDevice_reflectedInGetAllPermissionStatesApi() { // Setting a flag explicitly so that the permission consistently stays in the state upon // revoke permissionManager.updatePermissionFlags( @@ -376,13 +364,13 @@ class DevicePermissionsTest { DEVICE_AWARE_PERMISSION, PERSISTENT_DEVICE_ID_DEFAULT, FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, - FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED + FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, ) permissionManager.grantRuntimePermission( TEST_PACKAGE_NAME, DEVICE_AWARE_PERMISSION, - PERSISTENT_DEVICE_ID_DEFAULT + PERSISTENT_DEVICE_ID_DEFAULT, ) assertThat( @@ -404,7 +392,7 @@ class DevicePermissionsTest { TEST_PACKAGE_NAME, DEVICE_AWARE_PERMISSION, PERSISTENT_DEVICE_ID_DEFAULT, - "test" + "test", ) assertThat( @@ -416,9 +404,8 @@ class DevicePermissionsTest { .isFalse() } - @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) @Test - fun testAllPermissionStatesApiFlagsForDefaultDevice() { + fun setPermissionFlagOnDefaultDevice_reflectedInGetAllPermissionStatesApi() { val flagMask = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_USER_FIXED val flag = FLAG_PERMISSION_USER_SET @@ -434,7 +421,7 @@ class DevicePermissionsTest { DEVICE_AWARE_PERMISSION, PERSISTENT_DEVICE_ID_DEFAULT, flagMask, - flag + flag, ) assertThat( @@ -443,7 +430,7 @@ class DevicePermissionsTest { .getAllPermissionStates(TEST_PACKAGE_NAME, PERSISTENT_DEVICE_ID_DEFAULT)[ DEVICE_AWARE_PERMISSION]!! .flags, - flag + flag, ) ) .isTrue() @@ -454,19 +441,18 @@ class DevicePermissionsTest { .getAllPermissionStates(TEST_PACKAGE_NAME, PERSISTENT_DEVICE_ID_DEFAULT)[ DEVICE_AWARE_PERMISSION]!! .flags, - FLAG_PERMISSION_USER_FIXED + FLAG_PERMISSION_USER_FIXED, ) ) .isFalse() } - @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) @Test - fun testAllPermissionStatesApiThatNonDeviceAwareRuntimePermissionGrantIsNotInherited() { + fun getAllPermissionStates_normalPermissionIsNotInherited() { permissionManager.grantRuntimePermission( TEST_PACKAGE_NAME, NON_DEVICE_AWARE_PERMISSION, - PERSISTENT_DEVICE_ID_DEFAULT + PERSISTENT_DEVICE_ID_DEFAULT, ) assertThat( @@ -501,7 +487,7 @@ class DevicePermissionsTest { context.packageManager.grantRuntimePermission( TEST_PACKAGE_NAME, permissionName, - UserHandle.of(context.userId) + UserHandle.of(context.userId), ) assertPermission(permissionName, PERMISSION_GRANTED, context) } @@ -510,18 +496,14 @@ class DevicePermissionsTest { context.packageManager.revokeRuntimePermission( TEST_PACKAGE_NAME, permissionName, - UserHandle.of(context.userId) + UserHandle.of(context.userId), ) assertPermission(permissionName, PERMISSION_DENIED, context) } - private fun assertPermission( - permissionName: String, - permissionState: Int, - context: Context, - ) { - assertThat(context.packageManager.checkPermission(permissionName, TEST_PACKAGE_NAME)) - .isEqualTo(permissionState) + private fun assertPermission(permissionName: String, permissionState: Int, context: Context) { + val uid = defaultDeviceContext.packageManager.getApplicationInfo(TEST_PACKAGE_NAME, 0).uid + assertThat(context.checkPermission(permissionName, -1, uid)).isEqualTo(permissionState) } companion object { diff --git a/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java index a0637827c..9fff22747 100644 --- a/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoWifiStatePermissionTest.java @@ -30,9 +30,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; -import com.android.compatibility.common.util.UserHelper; - -import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -217,11 +214,6 @@ public class NoWifiStatePermissionTest { */ @Test(expected = SecurityException.class) public void testSetWifiEnabled() { - // Skip the test for passenger on Multi-user-multi-display devices for Automotive - UserHelper userHelper = new UserHelper(sContext); - Assume.assumeFalse( - "Skipped for visible background User as wifi is disabled for visible background " - + "user.", userHelper.isVisibleBackgroundUser()); mWifiManager.setWifiEnabled(true); } } diff --git a/tests/cts/permission/src/android/permission/cts/OneTimePermissionTest.java b/tests/cts/permission/src/android/permission/cts/OneTimePermissionTest.java index 2692c6e7c..291633aab 100644 --- a/tests/cts/permission/src/android/permission/cts/OneTimePermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/OneTimePermissionTest.java @@ -290,34 +290,18 @@ public class OneTimePermissionTest { } private void exitApp() { - boolean[] hasExited = {false}; - try { - new Thread(() -> { - while (!hasExited[0]) { - DreamManager mDreamManager = mContext.getSystemService(DreamManager.class); - mUiDevice.pressBack(); - runWithShellPermissionIdentity(() -> { - if (mDreamManager.isDreaming()) { - mDreamManager.stopDream(); - } - }); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } + eventually(() -> { + mUiDevice.pressBack(); + runWithShellPermissionIdentity(() -> { + DreamManager mDreamManager = mContext.getSystemService(DreamManager.class); + if (mDreamManager.isDreaming()) { + mDreamManager.stopDream(); } - }).start(); - eventually(() -> { - runWithShellPermissionIdentity(() -> { - if (mActivityManager.getPackageImportance(APP_PKG_NAME) - <= IMPORTANCE_FOREGROUND) { - throw new AssertionError("Unable to exit application"); - } - }); + Assert.assertFalse("Unable to exit application", + mActivityManager.getPackageImportance(APP_PKG_NAME) + <= IMPORTANCE_FOREGROUND); }); - } finally { - hasExited[0] = true; - } + }); } private void clickOneTimeButton() throws Throwable { diff --git a/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java b/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java index 4325ace79..86b8fa895 100644 --- a/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java +++ b/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java @@ -18,10 +18,10 @@ package android.permission.cts; import static com.android.compatibility.common.util.ShellUtils.runShellCommand; import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow; -import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; import static com.google.common.truth.Truth.assertThat; +import android.Manifest; import android.companion.virtual.VirtualDeviceManager; import android.companion.virtual.VirtualDeviceManager.VirtualDevice; import android.content.Context; @@ -30,8 +30,6 @@ import android.content.pm.PackageManager.OnPermissionsChangedListener; import android.permission.flags.Flags; import android.platform.test.annotations.AppModeFull; import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.virtualdevice.cts.common.VirtualDeviceRule; import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner; @@ -69,10 +67,10 @@ public class PermissionUpdateListenerTest { private int mTestAppUid; @Rule - public VirtualDeviceRule mVirtualDeviceRule = VirtualDeviceRule.createDefault(); - - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + public VirtualDeviceRule mVirtualDeviceRule = VirtualDeviceRule.withAdditionalPermissions( + "android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS", + Manifest.permission.GRANT_RUNTIME_PERMISSIONS, + Manifest.permission.REVOKE_RUNTIME_PERMISSIONS); @Before public void setup() throws PackageManager.NameNotFoundException, InterruptedException { @@ -99,15 +97,11 @@ public class PermissionUpdateListenerTest { } }; - runWithShellPermissionIdentity(() -> { - mPackageManager.addOnPermissionsChangeListener(permissionsChangedListener); - mPackageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, - mDefaultContext.getUser()); - }); + mPackageManager.addOnPermissionsChangeListener(permissionsChangedListener); + mPackageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, + mDefaultContext.getUser()); countDownLatch.await(TIMEOUT, TimeUnit.MILLISECONDS); - runWithShellPermissionIdentity(() -> { - mPackageManager.removeOnPermissionsChangeListener(permissionsChangedListener); - }); + mPackageManager.removeOnPermissionsChangeListener(permissionsChangedListener); assertThat(countDownLatch.getCount()).isEqualTo(0); } @@ -132,16 +126,12 @@ public class PermissionUpdateListenerTest { final PackageManager packageManager = context.getPackageManager(); TestOnPermissionsChangedListener permissionsChangedListener = new TestOnPermissionsChangedListener(1); - runWithShellPermissionIdentity(() -> { - packageManager.addOnPermissionsChangeListener(permissionsChangedListener); - packageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, - mDefaultContext.getUser()); - }); + packageManager.addOnPermissionsChangeListener(permissionsChangedListener); + packageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, + mDefaultContext.getUser()); permissionsChangedListener.waitForPermissionChangedCallbacks(); - runWithShellPermissionIdentity(() -> { - packageManager.removeOnPermissionsChangeListener(permissionsChangedListener); - }); + packageManager.removeOnPermissionsChangeListener(permissionsChangedListener); String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid); assertThat(deviceId).isEqualTo(expectedDeviceId); @@ -168,17 +158,14 @@ public class PermissionUpdateListenerTest { final PackageManager packageManager = context.getPackageManager(); TestOnPermissionsChangedListener permissionsChangedListener = new TestOnPermissionsChangedListener(1); - runWithShellPermissionIdentity(() -> { - packageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, - mDefaultContext.getUser()); - packageManager.addOnPermissionsChangeListener(permissionsChangedListener); - packageManager.revokeRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, - mDefaultContext.getUser()); - }); + packageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, + mDefaultContext.getUser()); + packageManager.addOnPermissionsChangeListener(permissionsChangedListener); + packageManager.revokeRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, + mDefaultContext.getUser()); + permissionsChangedListener.waitForPermissionChangedCallbacks(); - runWithShellPermissionIdentity(() -> { - packageManager.removeOnPermissionsChangeListener(permissionsChangedListener); - }); + packageManager.removeOnPermissionsChangeListener(permissionsChangedListener); String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid); assertThat(deviceId).isEqualTo(expectedDeviceId); @@ -205,16 +192,12 @@ public class PermissionUpdateListenerTest { TestOnPermissionsChangedListener permissionsChangedListener = new TestOnPermissionsChangedListener(1); final PackageManager packageManager = context.getPackageManager(); - runWithShellPermissionIdentity(() -> { - packageManager.addOnPermissionsChangeListener(permissionsChangedListener); - int flag = PackageManager.FLAG_PERMISSION_USER_SET; - packageManager.updatePermissionFlags(PERMISSION_NAME, PACKAGE_NAME, flag, flag, - mDefaultContext.getUser()); - }); + packageManager.addOnPermissionsChangeListener(permissionsChangedListener); + int flag = PackageManager.FLAG_PERMISSION_USER_SET; + packageManager.updatePermissionFlags(PERMISSION_NAME, PACKAGE_NAME, flag, flag, + mDefaultContext.getUser()); permissionsChangedListener.waitForPermissionChangedCallbacks(); - runWithShellPermissionIdentity(() -> { - packageManager.removeOnPermissionsChangeListener(permissionsChangedListener); - }); + packageManager.removeOnPermissionsChangeListener(permissionsChangedListener); String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid); assertThat(deviceId).isEqualTo(expectedDeviceId); diff --git a/tests/cts/permission/src/android/permission/cts/SplitPermissionsSystemTest.java b/tests/cts/permission/src/android/permission/cts/SplitPermissionsSystemTest.java index 776a1065e..f2d59cbe7 100755 --- a/tests/cts/permission/src/android/permission/cts/SplitPermissionsSystemTest.java +++ b/tests/cts/permission/src/android/permission/cts/SplitPermissionsSystemTest.java @@ -45,9 +45,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assume.assumeTrue; import android.content.Context; +import android.health.connect.HealthPermissions; import android.os.Build; import android.permission.PermissionManager; import android.permission.PermissionManager.SplitPermissionInfo; +import android.permission.flags.Flags; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SdkSuppress; @@ -56,6 +62,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.compatibility.common.util.ApiLevelUtil; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -71,6 +78,9 @@ public class SplitPermissionsSystemTest { private List<SplitPermissionInfo> mSplitPermissions; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Before public void before() { Context context = InstrumentationRegistry.getContext(); @@ -87,9 +97,14 @@ public class SplitPermissionsSystemTest { for (SplitPermissionInfo split : mSplitPermissions) { String splitPermission = split.getSplitPermission(); - boolean isAndroid = splitPermission.startsWith("android"); - if (!isAndroid) { + // Due to limitation with accessing flag values in tests, BODY_SENSORS relevant splits + // are handled in its dedicated tests. + boolean shouldSkip = + !splitPermission.startsWith("android") + || splitPermission.equals(BODY_SENSORS) + || splitPermission.equals(BODY_SENSORS_BACKGROUND); + if (shouldSkip) { continue; } @@ -149,9 +164,6 @@ public class SplitPermissionsSystemTest { case BLUETOOTH_SCAN: assertSplit(split, Build.VERSION_CODES.S, BLUETOOTH, BLUETOOTH_ADMIN); break; - case BODY_SENSORS: - assertSplit(split, Build.VERSION_CODES.TIRAMISU, BODY_SENSORS_BACKGROUND); - break; case ACCESS_MEDIA_LOCATION: case READ_MEDIA_IMAGES: case READ_MEDIA_VIDEO: @@ -160,7 +172,56 @@ public class SplitPermissionsSystemTest { } } - assertEquals(24, seenSplits.size()); + assertEquals(23, seenSplits.size()); + } + + @RequiresFlagsDisabled({Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED}) + @Test + public void + validateBodySensors_beforeGranularHealthPermissions_isSplitToBodySensorsBackground() { + assumeTrue(ApiLevelUtil.isAtLeast(Build.VERSION_CODES.Q)); + + mSplitPermissions.stream() + .filter(split -> split.getSplitPermission().equals(BODY_SENSORS)) + .findFirst() + .ifPresent( + split -> + assertSplit( + split, + Build.VERSION_CODES.TIRAMISU, + BODY_SENSORS_BACKGROUND)); + } + + @RequiresFlagsEnabled({Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED}) + @Test + public void validateBodySensors_afterGranularHealthPermissions_isSplitToReadHeartRate() { + // TODO: Change this to Baklava when available. + assumeTrue(ApiLevelUtil.isAtLeast(36)); + + SplitPermissionInfo legacyBodySensorPermissionInfo = null; + SplitPermissionInfo readHeartRatePermissionInfo = null; + SplitPermissionInfo bodySensorBackgroundPermissionInfo = null; + for (SplitPermissionInfo split : mSplitPermissions) { + if (split.getSplitPermission().equals(BODY_SENSORS) + && split.getNewPermissions().contains(BODY_SENSORS_BACKGROUND)) { + legacyBodySensorPermissionInfo = split; + } else if (split.getSplitPermission().equals(BODY_SENSORS) + && split.getNewPermissions().contains(HealthPermissions.READ_HEART_RATE)) { + readHeartRatePermissionInfo = split; + } else if (split.getSplitPermission().equals(BODY_SENSORS_BACKGROUND)) { + bodySensorBackgroundPermissionInfo = split; + } + } + // Assert BODY_SENSORS is split to BODY_SENSORS_BACKGROUND and READ_HEART_RATE. + assertSplit( + legacyBodySensorPermissionInfo, + Build.VERSION_CODES.TIRAMISU, + BODY_SENSORS_BACKGROUND); + assertSplit(readHeartRatePermissionInfo, HealthPermissions.READ_HEART_RATE); + // Assert BODY_SENSORS_BACKGROUND is split to READ_HEALTH_DATA_IN_BACKGROUND. + assertSplit( + bodySensorBackgroundPermissionInfo, + HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND); } private void assertSplit(SplitPermissionInfo split, int targetSdk, String... permission) { diff --git a/tests/cts/permissionmultidevice/AndroidManifest.xml b/tests/cts/permissionmultidevice/AndroidManifest.xml index 7d04d140e..9bad85813 100644 --- a/tests/cts/permissionmultidevice/AndroidManifest.xml +++ b/tests/cts/permissionmultidevice/AndroidManifest.xml @@ -24,8 +24,6 @@ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> - <uses-permission android:name="android.permission.CREATE_VIRTUAL_DEVICE" /> - <uses-permission android:name="android.permission.ADD_TRUSTED_DISPLAY" /> <application> <uses-library android:name="android.test.runner" /> 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 8a6290212..dd2d3e645 100644 --- a/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PermissionUtils.kt +++ b/tests/cts/permissionmultidevice/TestUtils/src/android/permissionmultidevice/cts/PermissionUtils.kt @@ -18,9 +18,6 @@ package android.permissionmultidevice.cts import android.content.Context import android.content.pm.PackageManager -import android.content.res.Configuration -import android.content.res.Resources -import android.util.Log object PermissionUtils { private val TAG = PermissionUtils::class.java.getSimpleName() @@ -33,42 +30,4 @@ object PermissionUtils { fun isWatch(context: Context): Boolean = context.packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH) - - /** - * This method checks for the minimum screen size described in CDD {@see - * https://source.android.com/docs/compatibility/14/android-14-cdd#7111_screen_size_and_shape} - */ - fun isCddCompliantScreenSize(): Boolean { - if ( - Resources.getSystem().configuration.uiMode and Configuration.UI_MODE_TYPE_MASK == - Configuration.UI_MODE_TYPE_WATCH - ) { - Log.d(TAG, "UI mode is UI_MODE_TYPE_WATCH, skipping the min dp check") - return true - } - - val screenSize = - Resources.getSystem().configuration.screenLayout and - Configuration.SCREENLAYOUT_SIZE_MASK - return when (screenSize) { - Configuration.SCREENLAYOUT_SIZE_SMALL -> hasMinScreenSize(426, 320) - Configuration.SCREENLAYOUT_SIZE_NORMAL -> hasMinScreenSize(480, 320) - Configuration.SCREENLAYOUT_SIZE_LARGE -> hasMinScreenSize(640, 480) - Configuration.SCREENLAYOUT_SIZE_XLARGE -> hasMinScreenSize(960, 720) - else -> { - Log.e(TAG, "Unknown screen size: $screenSize") - true - } - } - } - - private fun hasMinScreenSize(minWidthDp: Int, minHeightDp: Int): Boolean { - val dpi = Resources.getSystem().displayMetrics.densityDpi - val widthDp = (160f / dpi) * Resources.getSystem().displayMetrics.widthPixels - val heightDp = (160f / dpi) * Resources.getSystem().displayMetrics.heightPixels - - // CDD does seem to follow width & height convention correctly, hence checking both ways - return (widthDp >= minWidthDp && heightDp >= minHeightDp) || - (widthDp >= minHeightDp && heightDp >= minWidthDp) - } } diff --git a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt index ac5564e37..907917f6f 100644 --- a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt +++ b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/AppPermissionsTest.kt @@ -26,8 +26,8 @@ import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.permission.PermissionManager +import android.permission.cts.TestUtils import android.permission.flags.Flags -import android.permissionmultidevice.cts.PermissionUtils.isCddCompliantScreenSize import android.platform.test.annotations.RequiresFlagsEnabled import android.virtualdevice.cts.common.VirtualDeviceRule import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -79,7 +79,7 @@ class AppPermissionsTest { assumeFalse(PermissionUtils.isAutomotive(defaultDeviceContext)) assumeFalse(PermissionUtils.isTv(defaultDeviceContext)) assumeFalse(PermissionUtils.isWatch(defaultDeviceContext)) - assumeTrue(isCddCompliantScreenSize()) + assumeTrue(TestUtils.isCddCompliantScreenSize()) PackageManagementUtils.installPackage(APP_APK_PATH_STREAMING) diff --git a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt index f0a0e3fc1..5c7573a0b 100644 --- a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt +++ b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt @@ -21,6 +21,7 @@ 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.DEVICE_POLICY_DEFAULT import android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA import android.content.ComponentName import android.content.Intent @@ -32,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 @@ -39,7 +41,9 @@ 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 import android.virtualdevice.cts.common.VirtualDeviceRule import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -47,7 +51,6 @@ import androidx.test.filters.SdkSuppress import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By import com.android.compatibility.common.util.SystemUtil -import com.google.common.truth.Truth import com.google.common.truth.Truth.assertThat import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit @@ -69,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() { @@ -91,7 +98,7 @@ class DeviceAwarePermissionGrantTest { val displayConfigBuilder = VirtualDeviceRule.createDefaultVirtualDisplayConfigBuilder( DISPLAY_WIDTH, - DISPLAY_HEIGHT + DISPLAY_HEIGHT, ) .setFlags( DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC or @@ -108,46 +115,95 @@ class DeviceAwarePermissionGrantTest { @After fun cleanup() { uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false) + Thread.sleep(2000) } @RequiresFlagsEnabled( Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED + Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED, ) @Test fun onHostDevice_requestPermissionForHostDevice_shouldGrantPermission() { + assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false) + assertAppHasPermissionForDevice(virtualDevice.deviceId, false) + testGrantPermissionForDevice( Display.DEFAULT_DISPLAY, DEVICE_ID_DEFAULT, false, "", expectPermissionGrantedOnDefaultDevice = true, - expectPermissionGrantedOnRemoteDevice = false + expectPermissionGrantedOnRemoteDevice = false, ) } @RequiresFlagsEnabled( Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED + Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED, ) @Test fun onHostDevice_requestPermissionForRemoteDevice_shouldGrantPermission() { + assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, false) + assertAppHasPermissionForDevice(virtualDevice.deviceId, false) + testGrantPermissionForDevice( Display.DEFAULT_DISPLAY, virtualDevice.deviceId, true, deviceDisplayName, expectPermissionGrantedOnDefaultDevice = false, - expectPermissionGrantedOnRemoteDevice = true + expectPermissionGrantedOnRemoteDevice = true, + ) + } + + @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 + 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) + requestPermissionOnDevice(virtualDisplay.display.displayId, DEVICE_ID_DEFAULT) val displayId = virtualDisplay.display.displayId @@ -156,17 +212,51 @@ class DeviceAwarePermissionGrantTest { @RequiresFlagsEnabled( Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_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, + ), + expectPermissionGrantedOnDefaultDevice = true, + expectPermissionGrantedOnRemoteDevice = false, + ) + } + + @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) + testGrantPermissionForDevice( virtualDisplay.display.displayId, virtualDevice.deviceId, true, deviceDisplayName, expectPermissionGrantedOnDefaultDevice = false, - expectPermissionGrantedOnRemoteDevice = true + expectPermissionGrantedOnRemoteDevice = true, ) } @@ -176,14 +266,9 @@ class DeviceAwarePermissionGrantTest { showDeviceName: Boolean, expectedDeviceNameInDialog: String, expectPermissionGrantedOnDefaultDevice: Boolean, - expectPermissionGrantedOnRemoteDevice: 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) @@ -199,7 +284,7 @@ class DeviceAwarePermissionGrantTest { TestConstants.PERMISSION_RESULT_KEY_PERMISSIONS ) ) - .isEqualTo(arrayOf(DEVICE_AWARE_PERMISSION)) + .isEqualTo(arrayOf(PERMISSION)) assertThat( grantPermissionResult.getIntArray(TestConstants.PERMISSION_RESULT_KEY_GRANT_RESULTS) ) @@ -211,13 +296,13 @@ class DeviceAwarePermissionGrantTest { assertAppHasPermissionForDevice(DEVICE_ID_DEFAULT, expectPermissionGrantedOnDefaultDevice) assertAppHasPermissionForDevice( virtualDevice.deviceId, - expectPermissionGrantedOnRemoteDevice + expectPermissionGrantedOnRemoteDevice, ) } private fun requestPermissionOnDevice( displayId: Int, - targetDeviceId: Int + targetDeviceId: Int, ): CompletableFuture<Bundle> { val future = CompletableFuture<Bundle>() val callback = RemoteCallback { result: Bundle? -> future.complete(result) } @@ -229,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 } @@ -237,7 +324,7 @@ class DeviceAwarePermissionGrantTest { private fun assertPermissionMessageContainsDeviceName(displayId: Int, deviceName: String) { waitFindObject(By.displayId(displayId).res(PERMISSION_MESSAGE_ID)) val text = findTextForView(By.displayId(displayId).res(PERMISSION_MESSAGE_ID)) - Truth.assertThat(text).contains(deviceName) + assertThat(text).contains(deviceName) } private fun assertAppHasPermissionForDevice(deviceId: Int, expectPermissionGranted: Boolean) { @@ -245,7 +332,7 @@ class DeviceAwarePermissionGrantTest { defaultDeviceContext .createDeviceContext(deviceId) .packageManager - .checkPermission(DEVICE_AWARE_PERMISSION, APP_PACKAGE_NAME) + .checkPermission(PERMISSION, APP_PACKAGE_NAME) if (expectPermissionGranted) { Assert.assertEquals(PackageManager.PERMISSION_GRANTED, checkPermissionResult) @@ -269,7 +356,7 @@ 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 + const val PERMISSION = Manifest.permission.CAMERA const val TIMEOUT = 5000L private const val DISPLAY_HEIGHT = 1920 private const val DISPLAY_WIDTH = 1080 diff --git a/tests/cts/permissionmultiuser/Android.bp b/tests/cts/permissionmultiuser/Android.bp index b86b02205..23aafb7e0 100644 --- a/tests/cts/permissionmultiuser/Android.bp +++ b/tests/cts/permissionmultiuser/Android.bp @@ -33,6 +33,7 @@ android_test { "compatibility-device-util-axt", "ctstestrunner-axt", "Harrier", + "bedstead-multiuser", "modules-utils-build_system", "Nene", ], diff --git a/tests/cts/permissionmultiuser/AndroidTest.xml b/tests/cts/permissionmultiuser/AndroidTest.xml index 10fd4e7a5..f6834036b 100644 --- a/tests/cts/permissionmultiuser/AndroidTest.xml +++ b/tests/cts/permissionmultiuser/AndroidTest.xml @@ -63,8 +63,8 @@ <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="android.permissionmultiuser.cts" /> - <option name="exclude-annotation" value="com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile" /> - <option name="exclude-annotation" value="com.android.bedstead.harrier.annotations.RequireRunOnSecondaryUser" /> + <option name="exclude-annotation" value="com.android.bedstead.enterprise.annotations.RequireRunOnWorkProfile" /> + <option name="exclude-annotation" value="com.android.bedstead.multiuser.annotations.RequireRunOnSecondaryUser" /> <option name="runtime-hint" value="5m" /> </test> diff --git a/tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt b/tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt index 2169f0f72..f3309bd3c 100644 --- a/tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt +++ b/tests/cts/permissionmultiuser/src/android/permissionmultiuser/cts/AppDataSharingUpdatesTest.kt @@ -50,15 +50,16 @@ import android.support.test.uiautomator.UiObject2 import android.util.Log import androidx.test.filters.SdkSuppress import androidx.test.platform.app.InstrumentationRegistry +import com.android.bedstead.enterprise.annotations.RequireRunOnWorkProfile import com.android.bedstead.harrier.BedsteadJUnit4 import com.android.bedstead.harrier.DeviceState import com.android.bedstead.permissions.annotations.EnsureHasPermission import com.android.bedstead.harrier.annotations.EnsureSecureSettingSet import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeature import com.android.bedstead.harrier.annotations.RequireNotWatch -import com.android.bedstead.harrier.annotations.RequireRunOnAdditionalUser -import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile import com.android.bedstead.harrier.annotations.RequireSdkVersion +import com.android.bedstead.multiuser.additionalUser +import com.android.bedstead.multiuser.annotations.RequireRunOnAdditionalUser import com.android.bedstead.permissions.CommonPermissions.INTERACT_ACROSS_USERS import com.android.compatibility.common.util.ApiTest import com.android.compatibility.common.util.DeviceConfigStateChangerRule diff --git a/tests/cts/permissionpolicy/Android.bp b/tests/cts/permissionpolicy/Android.bp index 4249f3c9d..07fde8bff 100644 --- a/tests/cts/permissionpolicy/Android.bp +++ b/tests/cts/permissionpolicy/Android.bp @@ -37,6 +37,7 @@ android_test { "permission-test-util-lib", "androidx.test.rules", "flag-junit", + "android.app.flags-aconfig", "android.permission.flags-aconfig-java-export", ], srcs: [ diff --git a/tests/cts/permissionpolicy/res/raw/android_manifest.xml b/tests/cts/permissionpolicy/res/raw/android_manifest.xml index d820ce10a..2547b9786 100644 --- a/tests/cts/permissionpolicy/res/raw/android_manifest.xml +++ b/tests/cts/permissionpolicy/res/raw/android_manifest.xml @@ -154,6 +154,8 @@ <protected-broadcast android:name="android.app.backup.intent.INIT" /> <protected-broadcast android:name="android.bluetooth.intent.DISCOVERABLE_TIMEOUT" /> + <protected-broadcast android:name="android.bluetooth.action.AUTO_ON_STATE_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" /> @@ -177,6 +179,8 @@ <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REPLY" /> <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL" /> <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" /> + <protected-broadcast android:name="android.bluetooth.device.action.KEY_MISSING" /> + <protected-broadcast android:name="android.bluetooth.device.action.ENCRYPTION_CHANGE" /> <protected-broadcast android:name="android.bluetooth.device.action.SDP_RECORD" /> <protected-broadcast android:name="android.bluetooth.device.action.BATTERY_LEVEL_CHANGED" /> <protected-broadcast android:name="android.bluetooth.device.action.REMOTE_ISSUE_OCCURRED" /> @@ -238,6 +242,8 @@ <protected-broadcast android:name="android.bluetooth.avrcp-controller.profile.action.FOLDER_LIST" /> <protected-broadcast + android:name="android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING" /> + <protected-broadcast android:name="android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT" /> <protected-broadcast android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" /> @@ -264,6 +270,7 @@ <protected-broadcast android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.action.HAP_CONNECTION_STATE_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.action.HAP_DEVICE_AVAILABLE" /> <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONF_CHANGED" /> @@ -297,6 +304,9 @@ <protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" /> + <protected-broadcast android:name="android.hardware.hdmi.action.OSD_MESSAGE" /> + <protected-broadcast android:name="android.hardware.hdmi.action.ON_ACTIVE_SOURCE_RECOVERED_DISMISS_UI" /> + <protected-broadcast android:name="android.hardware.usb.action.USB_STATE" /> <protected-broadcast android:name="android.hardware.usb.action.USB_PORT_CHANGED" /> <protected-broadcast android:name="android.hardware.usb.action.USB_PORT_COMPLIANCE_CHANGED" /> @@ -787,6 +797,7 @@ <protected-broadcast android:name="com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO" /> <protected-broadcast android:name="com.android.internal.telephony.ACTION_CARRIER_CERTIFICATE_DOWNLOAD" /> <protected-broadcast android:name="com.android.internal.telephony.action.COUNTRY_OVERRIDE" /> + <protected-broadcast android:name="com.android.internal.telephony.action.SILENCE_WIFI_CALLING_NOTIFICATION"/> <protected-broadcast android:name="com.android.internal.telephony.OPEN_DEFAULT_SMS_APP" /> <protected-broadcast android:name="com.android.internal.telephony.ACTION_TEST_OVERRIDE_CARRIER_ID" /> <protected-broadcast android:name="android.telephony.action.SIM_CARD_STATE_CHANGED" /> @@ -837,6 +848,12 @@ <protected-broadcast android:name="android.intent.action.PROFILE_UNAVAILABLE" /> <protected-broadcast android:name="android.app.action.CONSOLIDATED_NOTIFICATION_POLICY_CHANGED" /> <protected-broadcast android:name="android.intent.action.MAIN_USER_LOCKSCREEN_KNOWLEDGE_FACTOR_CHANGED" /> + <protected-broadcast android:name="com.android.uwb.uwbcountrycode.GEOCODE_RETRY" /> + <protected-broadcast android:name="android.telephony.satellite.action.SATELLITE_SUBSCRIBER_ID_LIST_CHANGED" /> + <protected-broadcast android:name="android.service.ondeviceintelligence.MODEL_LOADED" /> + <protected-broadcast android:name="android.service.ondeviceintelligence.MODEL_UNLOADED" /> + <protected-broadcast android:name="android.telephony.satellite.action.SATELLITE_START_NON_EMERGENCY_SESSION" /> + <!-- ====================================================================== --> <!-- RUNTIME PERMISSIONS --> @@ -898,13 +915,26 @@ android:featureFlag="android.provider.user_keys" /> <!-- Allows an application to set default account for new contacts. - <p> This permission is only granted to system applications fulfilling the Contacts app role. + <p>This permission is only granted to system applications fulfilling the Contacts app role. <p>Protection level: internal|role @SystemApi @hide --> <permission android:name="android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS" - android:protectionLevel="internal|role" /> + android:protectionLevel="internal|role" + android:featureFlag="!android.provider.new_default_account_api_enabled"/> + + <!-- Allows an application to set default account for new contacts. + <p>This permission is only granted to system applications fulfilling the Contacts app role + and the application with known signers. + <p>Protection level: internal|role|knownSigner + @SystemApi + @hide + --> + <permission android:name="android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS" + android:protectionLevel="internal|role|knownSigner" + android:knownCerts="@array/config_setContactsDefaultAccountKnownSigners" + android:featureFlag="android.provider.new_default_account_api_enabled"/> <!-- ====================================================================== --> <!-- Permissions for accessing user's calendar --> @@ -1064,6 +1094,62 @@ <permission android:name="android.permission.SATELLITE_COMMUNICATION" android:protectionLevel="role|signature|privileged" /> + <!-- ================================== --> + <!-- Permissions associated with picture and sound profiles --> + <!-- ================================== --> + <eat-comment /> + + <!-- @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES) + Allows an app to apply a {@link MediaQualityManager.PictureProfile} to a layer via + {@link MediaCodec.PARAMETER_KEY_PICTURE_PROFILE} and, additionally, system apps via + {@link SurfaceControl.Transaction#setPictureProfileHandle}. + --> + <permission android:name="android.permission.APPLY_PICTURE_PROFILE" + android:protectionLevel="normal" + android:featureFlag="android.media.tv.flags.apply_picture_profiles"/> + + <!-- @hide + Allows MediaQualityService to observe any {@link MediaQualityManager.PictureProfile} + applied to any layer in the system by apps via + {@link MediaCodec.PARAMETER_KEY_PICTURE_PROFILE} and by system apps via + {@link SurfaceControl.Transaction#setPictureProfileHandle}. + --> + <permission android:name="android.permission.OBSERVE_PICTURE_PROFILES" + android:protectionLevel="signature|privileged" + android:featureFlag="android.media.tv.flags.apply_picture_profiles"/> + + <!-- + @SystemApi + @FlaggedApi("android.media.tv.flags.media_quality_fw") + Allows an application to access its picture profile from the media quality database. + <p> Protection level: signature|privileged|vendor privileged + @hide + --> + <permission android:name="android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE" + android:protectionLevel="signature|privileged|vendorPrivileged" + android:featureFlag="android.media.tv.flags.media_quality_fw"/> + + <!-- + @SystemApi + @FlaggedApi("android.media.tv.flags.media_quality_fw") + Allows an application to access its sound profile from the media quality database. + <p> Protection level: signature|privileged|vendor privileged + @hide + --> + <permission android:name="android.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE" + android:protectionLevel="signature|privileged|vendorPrivileged" + android:featureFlag="android.media.tv.flags.media_quality_fw"/> + + <!-- + @FlaggedApi(android.media.tv.flags.Flags.FLAG_MEDIA_QUALITY_FW) + Allows an application to read the aggregated color zones on the screen for use cases like + TV ambient backlight usages. + <p> Protection level: normal + --> + <permission android:name="android.permission.READ_COLOR_ZONES" + android:protectionLevel="normal" + android:featureFlag="android.media.tv.flags.media_quality_fw"/> + <!-- ====================================================================== --> <!-- Permissions for accessing external storage --> <!-- ====================================================================== --> @@ -1479,8 +1565,8 @@ android:description="@string/permdesc_readBasicPhoneState" android:protectionLevel="normal" /> - <!-- Allows read access to the device's phone number(s). This is a subset of the capabilities - granted by {@link #READ_PHONE_STATE} but is exposed to instant applications. + <!-- Allows read access to the device's phone number(s), + which is exposed to instant applications. <p>Protection level: dangerous--> <permission android:name="android.permission.READ_PHONE_NUMBERS" android:permissionGroup="android.permission-group.UNDEFINED" @@ -2070,6 +2156,21 @@ <permission android:name="android.permission.CONTROL_AUTOMOTIVE_GNSS" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi @hide Allows an application to bind to a + android.service.PopulationDensityProviderService for the purpose of + querying population density. This prevents arbitrary clients connecting + to the service. The system server checks that the provider's intent + service explicitly sets this permission via the android:permission + attribute of the service. + This is only expected to be possessed by the system server outside of + tests. + @FlaggedApi(android.location.flags.Flags.FLAG_POPULATION_DENSITY_PROVIDER) + <p>Protection level: signature + --> + <permission android:name="android.permission.BIND_POPULATION_DENSITY_PROVIDER_SERVICE" + android:featureFlag="android.location.flags.population_density_provider" + android:protectionLevel="signature" /> + <!-- ======================================= --> <!-- Permissions for accessing networks --> <!-- ======================================= --> @@ -2396,7 +2497,7 @@ android:label="@string/permlab_nearby_wifi_devices" android:protectionLevel="dangerous" /> - <!-- Required to be able to range to devices using any ranging technology. + <!-- Required to be able to range to devices using generic ranging module. @FlaggedApi("android.permission.flags.ranging_permission_enabled") <p>Protection level: dangerous --> <permission android:name="android.permission.RANGING" @@ -2404,7 +2505,7 @@ android:description="@string/permdesc_ranging" android:label="@string/permlab_ranging" android:protectionLevel="dangerous" - android:featureFlag="android.permission.flags.ranging_permission_enabled" /> + android:featureFlag="android.permission.flags.ranging_permission_enabled"/> <!-- @SystemApi @TestApi Allows an application to suspend other apps, which will prevent the user from using them until they are unsuspended. @@ -2574,6 +2675,22 @@ android:label="@string/permlab_getAccounts" /> <uses-permission android:name="android.permission.GET_ACCOUNTS"/> + <!-- @SystemApi Allows access to remove an account. + @FlaggedApi(android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED) + <p>Not for use by third-party applications. + @hide --> + <permission android:name="android.permission.REMOVE_ACCOUNTS" + android:protectionLevel="signature|role" + android:featureFlag="android.app.admin.flags.split_create_managed_profile_enabled" /> + + <!-- @SystemApi Allows access to copy an account to another user. + @FlaggedApi(android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED) + <p>Not for use by third-party applications. + @hide --> + <permission android:name="android.permission.COPY_ACCOUNTS" + android:protectionLevel="signature|role" + android:featureFlag="android.app.admin.flags.split_create_managed_profile_enabled" /> + <!-- Allows applications to call into AccountAuthenticators. <p>Not for use by third-party applications. --> <permission android:name="android.permission.ACCOUNT_MANAGER" @@ -2616,12 +2733,22 @@ <!-- @SystemApi Allows access to perform vendor effects in the vibrator. <p>Protection level: signature + @FlaggedApi(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS) @hide --> <permission android:name="android.permission.VIBRATE_VENDOR_EFFECTS" android:protectionLevel="signature|privileged" android:featureFlag="android.os.vibrator.vendor_vibration_effects" /> + <!-- @SystemApi Allows access to start a vendor vibration session. + <p>Protection level: signature + @FlaggedApi(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS) + @hide + --> + <permission android:name="android.permission.START_VIBRATION_SESSIONS" + android:protectionLevel="signature|privileged" + android:featureFlag="android.os.vibrator.vendor_vibration_effects" /> + <!-- @SystemApi Allows access to the vibrator state. <p>Protection level: signature @hide @@ -3261,16 +3388,20 @@ <permission android:name="android.permission.INTERACT_ACROSS_PROFILES" android:protectionLevel="signature|appop" /> - <!-- Allows applications to access profiles with ACCESS_HIDDEN_PROFILES user property - <p>Protection level: normal - @FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles") --> + <!-- Allows applications to access profiles with + {@code android.content.pm.UserProperties#PROFILE_API_VISIBILITY_HIDDEN} user property, e.g. + {@link android.os.UserManager#USER_TYPE_PROFILE_PRIVATE}. + <p>Protection level: normal + @FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles") --> <permission android:name="android.permission.ACCESS_HIDDEN_PROFILES" android:label="@string/permlab_accessHiddenProfile" android:description="@string/permdesc_accessHiddenProfile" android:protectionLevel="normal" /> - <!-- @SystemApi @hide Allows privileged applications to get details about hidden profile - users. + <!-- @SystemApi @hide Allows privileged applications to get details about profiles with + {@code android.content.pm.UserProperties#PROFILE_API_VISIBILITY_HIDDEN} user property, e.g. + {@link android.os.UserManager#USER_TYPE_PROFILE_PRIVATE}. Removes extra requirements such + as having {@link android.app.role.RoleManager#ROLE_HOME} role for LauncherApps APIs. @FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles") --> <permission android:name="android.permission.ACCESS_HIDDEN_PROFILES_FULL" @@ -3334,13 +3465,18 @@ <!-- Allows an application to manage device policy relating to time. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call - APIs protected by this permission on users different to the calling user.--> + APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. + --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_TIME" android:protectionLevel="internal|role" /> <!-- Allows an application to set the grant state of runtime permissions on packages. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS" android:protectionLevel="internal|role" /> @@ -3348,6 +3484,8 @@ <!-- Allows an application to manage the identity of the managing organization. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY" android:protectionLevel="internal|role" /> @@ -3356,6 +3494,8 @@ active policy. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE" android:protectionLevel="internal|role" /> @@ -3363,6 +3503,8 @@ <!-- Allows an application to manage backup service policy. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_BACKUP_SERVICE" android:protectionLevel="internal|role" /> @@ -3370,6 +3512,8 @@ <!-- Allows an application to manage lock task policy. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_TASK" android:protectionLevel="internal|role" /> @@ -3377,6 +3521,8 @@ <!-- Allows an application to manage policy regarding modifying applications. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL" android:protectionLevel="internal|role" /> @@ -3384,6 +3530,8 @@ <!-- Allows an application to manage installing from unknown sources policy. <p>MANAGE_SECURITY_CRITICAL_DEVICE_POLICY_ACROSS_USERS is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES" android:protectionLevel="internal|role" /> @@ -3391,6 +3539,8 @@ <!-- Allows an application to manage application restrictions. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS" android:protectionLevel="internal|role" /> @@ -3398,6 +3548,8 @@ <!-- Allows an application to manage calling policy. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CALLS" android:protectionLevel="internal|role" /> @@ -3405,6 +3557,8 @@ <!-- Allows an application to manage debugging features policy. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES" android:protectionLevel="internal|role" /> @@ -3412,6 +3566,8 @@ <!-- Allows an application to manage policy preventing users from modifying users. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS" android:protectionLevel="internal|role" /> @@ -3419,6 +3575,8 @@ <!-- Allows an application to manage safe boot policy. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SAFE_BOOT" android:protectionLevel="internal|role" /> @@ -3427,6 +3585,8 @@ enable and disable the microphone. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MICROPHONE" android:protectionLevel="internal|role" /> @@ -3435,6 +3595,8 @@ enable and disable the camera. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CAMERA" android:protectionLevel="internal|role" /> @@ -3442,6 +3604,8 @@ <!-- Allows an application to manage policy related to keyguard. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEYGUARD" android:protectionLevel="internal|role" /> @@ -3449,6 +3613,8 @@ <!-- Allows an application to set policy related to account management. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT" android:protectionLevel="internal|role" /> @@ -3456,6 +3622,8 @@ <!-- Allows an application to set policy related to hiding and suspending packages. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE" android:protectionLevel="internal|role" /> @@ -3464,17 +3632,24 @@ challenge on current user. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD" android:protectionLevel="internal|role" /> - <!-- Allows an application to set policy related to the status bar.--> + <!-- Allows an application to set policy related to the status bar. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. + --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_STATUS_BAR" android:protectionLevel="internal|role" /> <!-- Allows an application to set policy related to bluetooth. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_BLUETOOTH" android:protectionLevel="internal|role" /> @@ -3482,6 +3657,8 @@ <!-- Allows an application to set policy related to fun. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_FUN" android:protectionLevel="internal|role" /> @@ -3489,6 +3666,8 @@ <!-- Allows an application to set policy related to airplane mode. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_AIRPLANE_MODE" android:protectionLevel="internal|role" /> @@ -3496,6 +3675,8 @@ <!-- Allows an application to set policy related to mobile networks. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK" android:protectionLevel="internal|role" /> @@ -3503,6 +3684,8 @@ <!-- Allows an application to set policy related to physical media. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA" android:protectionLevel="internal|role" /> @@ -3510,6 +3693,8 @@ <!-- Allows an application to set policy related to sms. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SMS" android:protectionLevel="internal|role" /> @@ -3517,6 +3702,8 @@ <!-- Allows an application to set policy related to usb file transfers. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER" android:protectionLevel="internal|role" /> @@ -3524,6 +3711,8 @@ <!-- Allows an application to set policy related to lock credentials. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS" android:protectionLevel="internal|role" /> @@ -3531,6 +3720,8 @@ <!-- Allows an application to set policy related to Wifi. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIFI" android:protectionLevel="internal|role" /> @@ -3538,6 +3729,8 @@ <!-- Allows an application to set policy related to screen capture. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SCREEN_CAPTURE" android:protectionLevel="internal|role" /> @@ -3545,6 +3738,8 @@ <!-- Allows an application to set policy related to input methods. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_INPUT_METHODS" android:protectionLevel="internal|role" /> @@ -3553,6 +3748,8 @@ private DNS. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS" android:protectionLevel="internal|role" /> @@ -3560,6 +3757,8 @@ <!-- Allows an application to set policy related to the default sms application. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS" android:protectionLevel="internal|role" /> @@ -3567,6 +3766,8 @@ <!-- Allows an application to set policy related to profiles. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROFILES" android:protectionLevel="internal|role" /> @@ -3575,6 +3776,8 @@ cross-profile copy and paste). <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION" android:protectionLevel="internal|role" /> @@ -3582,6 +3785,8 @@ <!-- Allows an application to set policy related to VPNs. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_VPN" android:protectionLevel="internal|role" /> @@ -3589,6 +3794,8 @@ <!-- Allows an application to set policy related to audio output. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT" android:protectionLevel="internal|role" /> @@ -3596,6 +3803,8 @@ <!-- Allows an application to set policy related to the display. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_DISPLAY" android:protectionLevel="internal|role" /> @@ -3603,6 +3812,8 @@ <!-- Allows an application to set policy related to location. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCATION" android:protectionLevel="internal|role" /> @@ -3610,6 +3821,8 @@ <!-- Allows an application to set policy related to factory reset. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_FACTORY_RESET" android:protectionLevel="internal|role" /> @@ -3617,6 +3830,8 @@ <!-- Allows an application to set policy related to the wallpaper. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_WALLPAPER" android:protectionLevel="internal|role" /> @@ -3624,6 +3839,8 @@ <!-- Allows an application to set policy related to the usage of the contents of the screen. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SCREEN_CONTENT" android:protectionLevel="internal|role" /> @@ -3631,6 +3848,8 @@ <!-- Allows an application to set policy related to system dialogs. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS" android:protectionLevel="internal|role" /> @@ -3638,6 +3857,8 @@ <!-- Allows an application to set policy related to users running in the background. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_RUN_IN_BACKGROUND" android:protectionLevel="internal|role" /> @@ -3645,6 +3866,8 @@ <!-- Allows an application to set policy related to printing. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PRINTING" android:protectionLevel="internal|role" /> @@ -3653,12 +3876,16 @@ nearby streaming). <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION" android:protectionLevel="internal|role" /> <!-- Allows an application to set policy related to <a href="https://www.threadgroup.org">Thread</a> network. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK" @@ -3666,6 +3893,8 @@ <!-- Allows an application to set policy related to sending assist content to a privileged app such as the Assistant app. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ASSIST_CONTENT" android:protectionLevel="internal|role" /> @@ -3673,6 +3902,8 @@ <!-- Allows an application to set policy related to windows. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_WINDOWS" android:protectionLevel="internal|role" /> @@ -3680,6 +3911,8 @@ <!-- Allows an application to set policy related to locale. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCALE" android:protectionLevel="internal|role" /> @@ -3687,6 +3920,8 @@ <!-- Allows an application to set policy related to autofill. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUTOFILL" android:protectionLevel="internal|role" /> @@ -3694,6 +3929,8 @@ <!-- Allows an application to set policy related to users. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_USERS" android:protectionLevel="internal|role" /> @@ -3701,6 +3938,8 @@ <!-- Allows an application to set policy related to certificates. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CERTIFICATES" android:protectionLevel="internal|role" /> @@ -3708,6 +3947,8 @@ <!-- Allows an application to set policy related to override APNs. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_OVERRIDE_APN" android:protectionLevel="internal|role" /> @@ -3715,6 +3956,8 @@ <!-- Allows an application to set policy related to security logging. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING" android:protectionLevel="internal|role" /> @@ -3729,6 +3972,8 @@ <!-- Allows an application to set policy related to system updates. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES" android:protectionLevel="internal|role" /> @@ -3736,6 +3981,8 @@ <!-- Allows an application query system updates. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES" android:protectionLevel="internal|role" /> @@ -3743,6 +3990,8 @@ <!-- Allows an application to set policy related to private DNS. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PRIVATE_DNS" android:protectionLevel="internal|role" /> @@ -3750,6 +3999,8 @@ <!-- Allows an application to set policy related to settings. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SETTINGS" android:protectionLevel="internal|role" /> @@ -3757,17 +4008,24 @@ <!-- Allows an application to set policy related to network logging. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_NETWORK_LOGGING" android:protectionLevel="internal|role" /> - <!-- Allows an application to set policy related to usb data signalling.--> + <!-- Allows an application to set policy related to usb data signalling. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. + --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING" android:protectionLevel="internal|role" /> <!-- Allows an application to set policy related to suspending personal apps. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SUSPEND_PERSONAL_APPS" android:protectionLevel="internal|role" /> @@ -3775,13 +4033,17 @@ <!-- Allows an application to set policy related to keeping uninstalled packages. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEEP_UNINSTALLED_PACKAGES" android:protectionLevel="internal|role" /> <!-- Allows an application to manage policy related to accessibility. - <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call - APIs protected by this permission on users different to the calling user. + <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to + call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACCESSIBILITY" android:protectionLevel="internal|role" /> @@ -3789,6 +4051,8 @@ <!-- Allows an application to manage policy related to common criteria mode. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE" android:protectionLevel="internal|role" /> @@ -3796,6 +4060,8 @@ <!-- Allows an application to manage policy related to metered data. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_METERED_DATA" android:protectionLevel="internal|role" /> @@ -3803,6 +4069,8 @@ <!-- Allows an application to set a network-independent global HTTP proxy. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROXY" android:protectionLevel="internal|role" /> @@ -3810,6 +4078,8 @@ <!-- Allows an application to request bugreports with user consent. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_BUGREPORT" android:protectionLevel="internal|role" /> @@ -3817,6 +4087,8 @@ <!-- Allows an application to manage policy related to application user data. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_USER_DATA" android:protectionLevel="internal|role" /> @@ -3825,6 +4097,8 @@ permission. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK" android:protectionLevel="internal|role" /> @@ -3840,6 +4114,8 @@ <!-- Allows an application to manage policy related to system apps. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_APPS" android:protectionLevel="internal|role" /> @@ -3847,16 +4123,23 @@ <!-- Allows an application to manage policy related to wiping data. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIPE_DATA" android:protectionLevel="internal|role" /> <!-- Allows an application to manage policy related to the Memory Tagging Extension (MTE). + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MTE" android:protectionLevel="internal|role" /> - <!-- Allows an application to manage policy related to device identifiers. --> + <!-- Allows an application to manage policy related to device identifiers. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. + --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS" android:protectionLevel="internal|role" /> @@ -3867,38 +4150,62 @@ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION" android:protectionLevel="internal|role" /> + <!-- Allows an application to manage policy related to AppFunctions. + <p>Protection level: internal|role + @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) + --> + <permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_FUNCTIONS" + android:featureFlag="android.app.appfunctions.flags.enable_app_function_manager" + android:protectionLevel="internal|role" /> + <!-- Allows an application to set policy related to subscriptions downloaded by an admin. <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call - APIs protected by this permission on users different to the calling user. + APIs protected by this permission on users different to the calling user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS" android:protectionLevel="internal|role" /> - <!-- Allows an application to manage policy related to block package uninstallation. --> + <!-- Allows an application to manage policy related to block package uninstallation. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. + --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL" android:protectionLevel="internal|role" /> - <!-- Allows an application to manage policy related to camera toggle. --> + <!-- Allows an application to manage policy related to camera toggle. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. + --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE" android:protectionLevel="internal|role" /> - <!-- Allows an application to manage policy related to microphone toggle. --> + <!-- Allows an application to manage policy related to microphone toggle. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. + --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE" android:protectionLevel="internal|role" /> <!-- Allows an application to set device policies outside the current user that are critical for securing data within the current user. <p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_* - permissions across all users on the device provided they are required for securing data - within the current user.--> + permissions across all users on the device provided they are required for securing data + within the current user. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. + --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL" android:protectionLevel="internal|role" /> <!-- Allows an application to set device policies outside the current user that are required for securing device ownership without accessing user data. <p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_* - permissions across all users on the device provided they do not grant access to user - data. --> + permissions across all users on the device provided they do not grant access to user data. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. + --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS" android:protectionLevel="internal|role" /> @@ -3906,7 +4213,10 @@ <p>Fuller form of {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} that removes the restriction on accessing user data. <p>Holding this permission allows the use of any other held MANAGE_DEVICE_POLICY_* - permissions across all users on the device.--> + permissions across all users on the device. + <p>Protection level: internal|role + <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only. + --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL" android:protectionLevel="internal|role" /> @@ -3925,6 +4235,56 @@ android:protectionLevel="signature|installer" /> <uses-permission android:name="android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES" /> + <!-- Allows an application to modify the device's advanced protection mode status, and query + the list of enabled features + @FlaggedApi(android.security.Flags.FLAG_AAPM_API) + @SystemApi + @hide --> + <permission android:name="android.permission.MANAGE_ADVANCED_PROTECTION_MODE" + android:protectionLevel="signature|privileged" + android:featureFlag="android.security.aapm_api"/> + <uses-permission android:name="android.permission.MANAGE_ADVANCED_PROTECTION_MODE" + android:featureFlag="android.security.aapm_api"/> + + <!-- Allows an application to query the device's advanced protection mode status. + @FlaggedApi(android.security.Flags.FLAG_AAPM_API) --> + <permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE" + android:protectionLevel="normal" + android:featureFlag="android.security.aapm_api"/> + <uses-permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE" + android:featureFlag="android.security.aapm_api"/> + + <!-- Allows an application to read the state of the IntrusionDetectionService + @FlaggedApi(android.security.Flags.FLAG_AFL_API) + @SystemApi + @hide --> + <permission android:name="android.permission.READ_INTRUSION_DETECTION_STATE" + android:featureFlag="android.security.afl_api" + android:protectionLevel="signature|privileged" /> + <uses-permission android:name="android.permission.READ_INTRUSION_DETECTION_STATE" + android:featureFlag="android.security.afl_api"/> + + <!-- Allows an application to change the state of the IntrusionDetectionService + @FlaggedApi(android.security.Flags.FLAG_AFL_API) + @SystemApi + @hide --> + <permission android:name="android.permission.MANAGE_INTRUSION_DETECTION_STATE" + android:featureFlag="android.security.afl_api" + android:protectionLevel="signature|privileged" /> + <uses-permission android:name="android.permission.MANAGE_INTRUSION_DETECTION_STATE" + android:featureFlag="android.security.afl_api"/> + + <!-- Must be required by any IntrusionDetectionEventTransportService to ensure that + only the system can bind to it. + @FlaggedApi(android.security.Flags.FLAG_AFL_API) + @SystemApi + @hide --> + <permission android:name="android.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE" + android:featureFlag="android.security.afl_api" + android:protectionLevel="signature" /> + <uses-permission android:name="android.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE" + android:featureFlag="android.security.afl_api"/> + <!-- @SystemApi @hide Allows an application to set a device owner on retail demo devices.--> <permission android:name="android.permission.PROVISION_DEMO_DEVICE" android:protectionLevel="signature|setup|knownSigner" @@ -4176,11 +4536,11 @@ <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_GLASSES" android:protectionLevel="normal" /> - <!-- Allows application to request to be associated with a virtual display capable of streaming + <!-- Allows application to request to be associated with a virtual device capable of streaming Android applications ({@link android.companion.AssociationRequest#DEVICE_PROFILE_APP_STREAMING}) by {@link android.companion.CompanionDeviceManager}. - <p>Not for use by third-party applications. + <p>Not for use by third-party applications. --> <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING" android:protectionLevel="signature|privileged" /> @@ -4188,16 +4548,26 @@ <!-- Allows application to request to stream content from an Android host to a nearby device ({@link android.companion.AssociationRequest#DEVICE_PROFILE_NEARBY_DEVICE_STREAMING}) by {@link android.companion.CompanionDeviceManager}. - <p>Not for use by third-party applications. + <p>Not for use by third-party applications. --> <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_NEARBY_DEVICE_STREAMING" android:protectionLevel="signature|privileged" /> + <!-- Allows application to request to stream content from an Android host to a nearby device + ({@link android.companion.AssociationRequest#DEVICE_PROFILE_SENSOR_DEVICE_STREAMING}) + by {@link android.companion.CompanionDeviceManager}. + <p>Not for use by third-party applications. + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ENABLE_LIMITED_VDM_ROLE) + --> + <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_SENSOR_DEVICE_STREAMING" + android:protectionLevel="signature|privileged" + android:featureFlag="android.companion.virtualdevice.flags.enable_limited_vdm_role" /> + <!-- Allows application to request to be associated with a vehicle head unit capable of automotive projection ({@link android.companion.AssociationRequest#DEVICE_PROFILE_AUTOMOTIVE_PROJECTION}) by {@link android.companion.CompanionDeviceManager}. - <p>Not for use by third-party applications. + <p>Not for use by third-party applications. --> <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION" android:protectionLevel="internal|role" /> @@ -4206,7 +4576,7 @@ and/or data with other devices, such as notifications, photos and media ({@link android.companion.AssociationRequest#DEVICE_PROFILE_COMPUTER}) by {@link android.companion.CompanionDeviceManager}. - <p>Not for use by third-party applications. + <p>Not for use by third-party applications. --> <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_COMPUTER" android:protectionLevel="signature|privileged" /> @@ -4244,6 +4614,18 @@ android:description="@string/permdesc_hideOverlayWindows" android:protectionLevel="normal" /> + <!-- Allows an app to enter Picture-in-Picture mode when the user is not explicitly requesting + it. This includes using {@link PictureInPictureParams.Builder#setAutoEnterEnabled} as well + as lifecycle methods such as {@link Activity#onUserLeaveHint} and {@link Activity#onPause} + to enter PiP when the user leaves the app. + This permission should only be used for certain PiP + <a href="{@docRoot}training/tv/get-started/multitasking#usage-types">usage types</a>. + @FlaggedApi(android.app.Flags.FLAG_ENABLE_TV_IMPLICIT_ENTER_PIP_RESTRICTION) + --> + <permission android:name="android.permission.TV_IMPLICIT_ENTER_PIP" + android:protectionLevel="normal" + android:featureFlag="android.app.enable_tv_implicit_enter_pip_restriction" /> + <!-- ================================== --> <!-- Permissions affecting the system wallpaper --> <!-- ================================== --> @@ -4706,7 +5088,7 @@ <permission android:name="android.permission.REQUEST_UNIQUE_ID_ATTESTATION" android:protectionLevel="signature" /> - <!-- Allows the caller to bind with Remote Key Provisioning service. + <!-- Allows an application to use the RemoteKeyProvisioningService. @hide --> <permission android:name="android.permission.BIND_RKP_SERVICE" android:protectionLevel="signature" /> @@ -4750,6 +5132,27 @@ <permission android:name="android.permission.PROVIDE_REMOTE_CREDENTIALS" android:protectionLevel="signature|privileged|role" /> + <!-- @FlaggedApi(com.android.settingslib.flags.Flags.FLAG_SETTINGS_CATALYST) + Allows an application to access the Settings Preference services to read settings exposed + by the system Settings app and system apps that contribute settings surfaced by the + Settings app. + <p>This allows the calling application to read settings values through the host + application, agnostic of underlying storage. --> + <permission android:name="android.permission.READ_SYSTEM_PREFERENCES" + android:protectionLevel="signature|privileged|role" + android:featureFlag="com.android.settingslib.flags.settings_catalyst" /> + + <!-- @FlaggedApi(com.android.settingslib.flags.Flags.FLAG_WRITE_SYSTEM_PREFERENCE_PERMISSION_ENABLED) + Allows an application to access the Settings Preference services to write settings + values exposed by the system Settings app and system apps that contribute settings surfaced + in the Settings app. + <p>This allows the calling application to write settings values + through the host application, agnostic of underlying storage. + <p>Protection Level: signature|privileged|appop --> + <permission android:name="android.permission.WRITE_SYSTEM_PREFERENCES" + android:protectionLevel="signature|privileged|appop" + android:featureFlag="com.android.settingslib.flags.write_system_preference_permission_enabled" /> + <!-- ========================================= --> <!-- Permissions for special development tools --> <!-- ========================================= --> @@ -4827,6 +5230,182 @@ android:protectionLevel="signature|privileged" /> <!-- ==================================== --> + <!-- Permissions for XR perception data --> + <!-- ==================================== --> + <eat-comment /> + + <!-- Used for permissions that are associated with accessing XR + tracked information about the person using the device and the + environment around them. + + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) --> + <permission-group android:name="android.permission-group.XR_TRACKING" + android:label="@string/permgrouplab_xr_tracking" + android:description="@string/permgroupdesc_xr_tracking" + android:priority="100" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Allows an application to get approximate eye gaze. + + <p>Protection level: dangerous + + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) --> + <permission android:name="android.permission.EYE_TRACKING_COARSE" + android:protectionLevel="dangerous" + android:permissionGroup="android.permission-group.UNDEFINED" + android:label="@string/permlab_eye_tracking_coarse" + android:description="@string/permdesc_eye_tracking_coarse" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Allows an application to get face tracking data. + + <p>Protection level: dangerous + + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) --> + <permission android:name="android.permission.FACE_TRACKING" + android:protectionLevel="dangerous" + android:permissionGroup="android.permission-group.UNDEFINED" + android:label="@string/permlab_face_tracking" + android:description="@string/permdesc_face_tracking" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Allows an application to get hand tracking data. + + <p>Protection level: dangerous + + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) --> + <permission android:name="android.permission.HAND_TRACKING" + android:protectionLevel="dangerous" + android:permissionGroup="android.permission-group.UNDEFINED" + android:label="@string/permlab_hand_tracking" + android:description="@string/permdesc_hand_tracking" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Allows an application to get data derived by sensing the + user's environment. + + <p>Protection level: dangerous + + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) --> + <permission android:name="android.permission.SCENE_UNDERSTANDING_COARSE" + android:protectionLevel="dangerous" + android:permissionGroup="android.permission-group.UNDEFINED" + android:description="@string/permdesc_scene_understanding_coarse" + android:label="@string/permlab_scene_understanding_coarse" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Used for permissions that are associated with accessing + particularly sensitive XR tracking data. + + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) --> + <permission-group android:name="android.permission-group.XR_TRACKING_SENSITIVE" + android:label="@string/permgrouplab_xr_tracking_sensitive" + android:description="@string/permgroupdesc_xr_tracking_sensitive" + android:priority="100" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Allows an application to get precise eye gaze data. + + <p>Protection level: dangerous + + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) --> + <permission android:name="android.permission.EYE_TRACKING_FINE" + android:protectionLevel="dangerous" + android:permissionGroup="android.permission-group.UNDEFINED" + android:label="@string/permlab_eye_tracking_fine" + android:description="@string/permdesc_eye_tracking_fine" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Allows an application to get head tracking data. Unmanaged + activities (OpenXR activities with the manifest property + "android.window.PROPERTY_XR_ACTIVITY_START_MODE" set to + "XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED") do not require + this permission to get head tracking data. + + {@see https://developer.android.com/develop/xr/get-started#property_activity_xr_start_mode_property} + + <p>Protection level: dangerous + + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) --> + <permission android:name="android.permission.HEAD_TRACKING" + android:protectionLevel="dangerous" + android:permissionGroup="android.permission-group.UNDEFINED" + android:label="@string/permlab_head_tracking" + android:description="@string/permdesc_head_tracking" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Allows an application to get highly precise data derived by sensing the + user's environment, such as a depth map. + + <p>Protection level: dangerous + + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) --> + <permission android:name="android.permission.SCENE_UNDERSTANDING_FINE" + android:protectionLevel="dangerous" + android:permissionGroup="android.permission-group.UNDEFINED" + android:description="@string/permdesc_scene_understanding_fine" + android:label="@string/permlab_scene_understanding_fine" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Allows an application to trigger Eye Calibration, which + calibrates for IPD (inter-pupillary distance) adjustment and + eye tracking. + + <p>Protection level: signature|privileged + + @SystemApi + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) + @hide --> + <permission android:name="android.permission.EYE_CALIBRATION" + android:protectionLevel="signature|privileged" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Allows an application to trigger Face Tracking Calibration. + + <p>Protection level: signature|privileged + + @SystemApi + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) + @hide --> + <permission android:name="android.permission.FACE_TRACKING_CALIBRATION" + android:protectionLevel="signature|privileged" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Allows an application to import an anchor created and + exported by another application. + + <p>Protection level: signature|privileged + + @SystemApi + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) + @hide --> + <permission android:name="android.permission.IMPORT_XR_ANCHOR" + android:protectionLevel="signature|privileged" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- Allows an application to access XR tracking data while in the + background. Without this permission, XR tracking data such as + head tracking, hand tracking, eye tracking, or face tracking + is only available to an activity it is in the + foreground. With this permission, such data is also available + to services and to activities that are in the background. + + <p>This permission must be granted in addition to the + corresponding permission such as {@link #HEAD_TRACKING} or + {@link #FACE_TRACKING} for the data being accessed. + + <p>Protection level: normal|appop + + @SystemApi + @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES) + @hide --> + <permission android:name="android.permission.XR_TRACKING_IN_BACKGROUND" + android:protectionLevel="normal|appop" + android:description="@string/permdesc_xr_tracking_in_background" + android:label="@string/permlab_xr_tracking_in_background" + android:featureFlag="android.xr.xr_manifest_entries" /> + + <!-- ==================================== --> <!-- Private permissions --> <!-- ==================================== --> <eat-comment /> @@ -5003,10 +5582,9 @@ <permission android:name="android.permission.CHANGE_ACCESSIBILITY_VOLUME" android:protectionLevel="signature" /> - <!-- @FlaggedApi("com.android.server.accessibility.motion_event_observing") - @hide - @TestApi - Allows an accessibility service to observe motion events without consuming them. --> + <!-- @TestApi Allows an accessibility service to observe motion events + without consuming them. + @hide --> <permission android:name="android.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING" android:protectionLevel="signature" /> @@ -5245,12 +5823,23 @@ <permission android:name="android.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE" android:protectionLevel="signature" /> - <!-- Allows an application to subscribe to keyguard locked (i.e., showing) state. - <p>Protection level: signature|role - <p>Intended for use by ROLE_ASSISTANT and signature apps only. + <!-- Allows an application to subscribe to device locked and keyguard locked (i.e., showing) + state. + <p>Protection level: signature|module|role + <p>Intended for use by ROLE_ASSISTANT, VDM, and signature apps only. + --> + <permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" + android:protectionLevel="signature|module|role" + android:featureFlag="!android.security.subscribe_to_keyguard_locked_state_perm_priv_flag"/> + + <!-- Allows an application to subscribe to device locked and keyguard locked (i.e., showing) + state. + <p>Protection level: signature|privileged|module|role + <p>Intended for use by ROLE_ASSISTANT, VDM, and signature / privileged apps only. --> <permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" - android:protectionLevel="signature|module|role"/> + android:protectionLevel="signature|privileged|module|role" + android:featureFlag="android.security.subscribe_to_keyguard_locked_state_perm_priv_flag"/> <!-- Must be required by a {@link android.service.autofill.AutofillService}, to ensure that only the system can bind to it. @@ -5424,6 +6013,17 @@ <permission android:name="android.permission.BIND_TV_INPUT" android:protectionLevel="signature|privileged" /> + <!-- This permission is required among systems services to always keep the + binding with TvInputManagerService. + <p>This should only be used by the OEM TvInputService. + @FlaggedApi("android.media.tv.flags.tif_unbind_inactive_tis") + <p>Protection level: signature|privileged|vendorPrivileged + @hide + --> + <permission android:name="android.permission.ALWAYS_BOUND_TV_INPUT" + android:protectionLevel="signature|privileged|vendorPrivileged" + android:featureFlag="android.media.tv.flags.tif_unbind_inactive_tis"/> + <!-- Must be required by a {@link android.media.tv.interactive.TvInteractiveAppService} to ensure that only the system can bind to it. <p>Protection level: signature|privileged @@ -5481,15 +6081,6 @@ <permission android:name="android.permission.TUNER_RESOURCE_ACCESS" android:protectionLevel="signature|privileged|vendorPrivileged" /> - <!-- This permission is required among systems services to always keep the - binding with TvInputManagerService. - <p>Protection level: signature|privileged|vendorPrivileged - <p>This should only be used by the OEM TvInputService. - @hide --> - <permission android:name="android.permission.ALWAYS_BOUND_TV_INPUT" - android:protectionLevel="signature|privileged|vendorPrivileged" - android:featureFlag="android.media.tv.flags.tif_unbind_inactive_tis"/> - <!-- @SystemApi This permission is required by Media Resource Manager Service when system services create MediaCodecs on behalf of other processes and apps. <p>Protection level: signature|privileged|vendorPrivileged @@ -5917,7 +6508,7 @@ <!-- Allows an application to subscribe to notifications about the nearby devices' presence status change base on the UUIDs. <p>Not for use by third-party applications.</p> - @FlaggedApi("android.companion.flags.device_presence") + @FlaggedApi("android.companion.device_presence") --> <permission android:name="android.permission.REQUEST_OBSERVE_DEVICE_UUID_PRESENCE" android:protectionLevel="signature|privileged" /> @@ -5930,8 +6521,7 @@ android:protectionLevel="normal" /> <!-- Allows an application to send and receive messages via CDM transports. - @hide - --> + @hide --> <permission android:name="android.permission.USE_COMPANION_TRANSPORTS" android:protectionLevel="signature" /> @@ -6148,6 +6738,15 @@ <permission android:name="android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT" android:protectionLevel="signature|privileged|role" /> + <!-- @SystemApi Allows an application to bypass concurrency restrictions while + recording audio. For example, apps with this permission can continue to record + while a voice call is active.</p> + @FlaggedApi(android.media.audio.Flags.FLAG_CONCURRENT_AUDIO_RECORD_BYPASS_PERMISSION) + @hide --> + <permission android:name="android.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION" + android:featureFlag="android.media.audio.concurrent_audio_record_bypass_permission" + android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Allows an application to capture audio for hotword detection. <p>Not for use by third-party applications.</p> @hide --> @@ -6450,6 +7049,13 @@ <permission android:name="android.permission.BATTERY_STATS" android:protectionLevel="signature|privileged|development" /> + <!-- @SystemApi @hide Allows an application to collect high-precision PowerMonitor readings + <p>Protection level: signature|privileged|development + @FlaggedApi(android.permission.flags.Flags.FLAG_FINE_POWER_MONITOR_PERMISSION) --> + <permission android:name="android.permission.ACCESS_FINE_POWER_MONITORS" + android:protectionLevel="signature|privileged|development" + android:featureFlag="android.permission.flags.fine_power_monitor_permission" /> + <!--Allows an application to manage statscompanion. <p>Not for use by third-party applications. @hide --> @@ -6827,9 +7433,8 @@ android:protectionLevel="signature" /> <!-- Allows an application to set the advanced features on BiometricDialog (SystemUI), including - logo, logo description. + logo, logo description, and content view with more options button. <p>Not for use by third-party applications. - @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") --> <permission android:name="android.permission.SET_BIOMETRIC_DIALOG_ADVANCED" android:protectionLevel="signature|privileged" /> @@ -7154,7 +7759,17 @@ @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") @hide --> <permission android:name="android.permission.READ_BLOCKED_NUMBERS" - android:protectionLevel="signature" /> + android:protectionLevel="signature" + android:featureFlag="!android.permission.flags.grant_read_blocked_numbers_to_system_ui_intelligence" /> + + <!-- Allows the holder to read blocked numbers. See + {@link android.provider.BlockedNumberContract}. + @SystemApi + @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") + @hide --> + <permission android:name="android.permission.READ_BLOCKED_NUMBERS" + android:protectionLevel="signature|role" + android:featureFlag="android.permission.flags.grant_read_blocked_numbers_to_system_ui_intelligence" /> <!-- Allows the holder to write blocked numbers. See {@link android.provider.BlockedNumberContract}. @@ -7259,9 +7874,9 @@ <permission android:name="android.permission.ACCESS_SMARTSPACE" android:protectionLevel="signature|privileged|development" /> - <!-- @SystemApi Allows an application to access the contextual search - service as a client. - @hide <p>Not for use by third-party applications.</p> --> + <!-- @SystemApi Allows an application to start a contextual search. + @FlaggedApi("android.app.contextualsearch.flags.enable_service") + @hide <p>Not for use by third-party applications.</p> --> <permission android:name="android.permission.ACCESS_CONTEXTUAL_SEARCH" android:protectionLevel="signature|privileged" android:featureFlag="android.app.contextualsearch.flags.enable_service"/> @@ -7478,7 +8093,8 @@ <permission android:name="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" android:protectionLevel="signature" /> - <!-- Must be required by an {@link android.service.watchdog.ExplicitHealthCheckService} to + <!-- @FlaggedApi(android.crashrecovery.flags.Flags.FLAG_ENABLE_CRASHRECOVERY) @SystemApi + Must be required by an {@link android.service.watchdog.ExplicitHealthCheckService} to ensure that only the system can bind to it. @hide This is not a third-party API (intended for OEMs and system apps). --> @@ -7598,7 +8214,31 @@ <!-- @SystemApi Allows an application to access shared libraries. @hide --> <permission android:name="android.permission.ACCESS_SHARED_LIBRARIES" - android:protectionLevel="signature|installer" /> + android:protectionLevel="signature|installer" + android:featureFlag="!android.content.pm.sdk_dependency_installer" /> + + <!-- @SystemApi Allows an application to access shared libraries. + @hide --> + <permission android:name="android.permission.ACCESS_SHARED_LIBRARIES" + android:protectionLevel="signature|installer|role" + android:featureFlag="android.content.pm.sdk_dependency_installer" /> + + <!-- @SystemApi Permission held by the system to allow binding to the dependency installer role + holder. + @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER) + @hide --> + <permission android:name="android.permission.BIND_DEPENDENCY_INSTALLER" + android:protectionLevel="signature" + android:featureFlag="android.content.pm.sdk_dependency_installer" /> + + <!-- @SystemApi Allows an application to install shared libraries of types + {@link android.content.pm.SharedLibraryInfo#TYPE_STATIC} or + {@link android.content.pm.SharedLibraryInfo#TYPE_SDK_PACKAGE}. + @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER) + @hide --> + <permission android:name="android.permission.INSTALL_DEPENDENCY_SHARED_LIBRARIES" + android:protectionLevel="signature|role" + android:featureFlag="android.content.pm.sdk_dependency_installer" /> <!-- Allows an app to log compat change usage. @hide <p>Not for use by third-party applications.</p> --> @@ -7673,6 +8313,13 @@ <permission android:name="android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY" android:protectionLevel="signature|role"/> + <!-- Allows an application to create displays that mirror other displays' content. + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ENABLE_LIMITED_VDM_ROLE) + @hide @SystemApi --> + <permission android:name="android.permission.ADD_MIRROR_DISPLAY" + android:protectionLevel="internal|role" + android:featureFlag="android.companion.virtualdevice.flags.enable_limited_vdm_role" /> + <!-- @hide @SystemApi Allows an application to access locusId events in the usage stats. --> <permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS" android:protectionLevel="signature|role" /> @@ -7847,32 +8494,14 @@ android:featureFlag="android.app.appfunctions.flags.enable_app_function_manager" android:protectionLevel="signature" /> - <!-- @SystemApi Allows a trusted application to perform actions on behalf of users inside of - applications with privacy guarantees from the system. - <p>This permission is currently only granted to system packages in the - {@link android.app.role.SYSTEM_UI_INTELLIGENCE} role which complies with privacy - requirements outlined in the Android CDD section "9.8.6 Content Capture". - <p>Apps are not able to opt-out from caller having this permission. - <p>Protection level: internal|role - @hide - @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") --> - <permission android:name="android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED" - android:featureFlag="android.app.appfunctions.flags.enable_app_function_manager" - android:protectionLevel="internal|role" /> - - <!-- @SystemApi Allows an application to perform actions on behalf of users inside of + <!-- Allows an application to perform actions on behalf of users inside of applications. - <p>This permission is currently only granted to preinstalled / system apps having the - {@link android.app.role.ASSISTANT} role. - <p>Apps contributing app functions can opt to disallow callers with this permission, - limiting to only callers with {@link android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} - instead. - <p>Protection level: internal|role - @hide - @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") --> + <p>This permission is currently only granted to privileged system apps. + <p>Protection level: internal|privileged + @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) --> <permission android:name="android.permission.EXECUTE_APP_FUNCTIONS" android:featureFlag="android.app.appfunctions.flags.enable_app_function_manager" - android:protectionLevel="internal|role" /> + android:protectionLevel="internal|privileged" /> <!-- Allows an application to display its suggestions using the autofill framework. <p>For now, this permission is only granted to the Browser application. @@ -7996,13 +8625,21 @@ <permission android:name="android.permission.MONITOR_STICKY_MODIFIER_STATE" android:protectionLevel="signature" /> - <!-- Allows low-level access to manage key gestures + <!-- Allows low-level access to manage key gestures. <p>Not for use by third-party applications. @hide --> <permission android:name="android.permission.MANAGE_KEY_GESTURES" android:protectionLevel="signature" android:featureFlag="com.android.hardware.input.manage_key_gestures" /> + <!-- Allows applications to register listeners for key activeness through + InputManagerService. + <p>Protection level: signature + @hide --> + <permission android:name="android.permission.LISTEN_FOR_KEY_ACTIVITY" + android:protectionLevel="signature" + android:featureFlag="com.android.hardware.input.key_event_activity_detection" /> + <uses-permission android:name="android.permission.HANDLE_QUERY_PACKAGE_RESTART" /> <!-- Allows financed device kiosk apps to perform actions on the Device Lock service @@ -8089,6 +8726,26 @@ android:protectionLevel="signature|knownSigner" android:knownCerts="@array/config_healthConnectMigrationKnownSigners" /> + <!-- @hide @SystemApi Allows permitted apps to back up Health Connect data and settings. + <p>Protection level: signature|knownSigner + @FlaggedApi("android.permission.flags.health_connect_backup_restore_permission_enabled") + --> + <permission + android:name="android.permission.BACKUP_HEALTH_CONNECT_DATA_AND_SETTINGS" + android:protectionLevel="signature|knownSigner" + android:knownCerts="@array/config_backupHealthConnectDataAndSettingsKnownSigners" + android:featureFlag="android.permission.flags.health_connect_backup_restore_permission_enabled" /> + + <!-- @hide @SystemApi Allows permitted apps to restore Health Connect data and settings. + <p>Protection level: signature|knownSigner + @FlaggedApi("android.permission.flags.health_connect_backup_restore_permission_enabled") + --> + <permission + android:name="android.permission.RESTORE_HEALTH_CONNECT_DATA_AND_SETTINGS" + android:protectionLevel="signature|knownSigner" + android:knownCerts="@array/config_restoreHealthConnectDataAndSettingsKnownSigners" + android:featureFlag="android.permission.flags.health_connect_backup_restore_permission_enabled" /> + <!-- @SystemApi Allows an app to query apps in clone profile. The permission is bidirectional in nature, i.e. cloned apps would be able to query apps in root user. The permission is not meant for 3P apps as of now. @@ -8203,16 +8860,8 @@ <permission android:name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW" android:protectionLevel="signature|privileged" /> - <!-- Allows internal applications to restrict display modes - <p>Protection level: signature - @FlaggedApi("com.android.server.display.feature.flags.enable_restrict_display_modes") - @hide - --> - <permission android:name="android.permission.RESTRICT_DISPLAY_MODES" - android:protectionLevel="signature" /> - <!-- @hide @SystemApi - @FlaggedApi("com.android.server.notification.flags.redact_otp_notifications_from_untrusted_listeners") + @FlaggedApi("android.view.flags.sensitive_content_app_protection_api") Allows apps with a NotificationListenerService to receive notifications with sensitive information <p>Apps with a NotificationListenerService without this permission will not be able @@ -8252,6 +8901,14 @@ <permission android:name="android.permission.EMERGENCY_INSTALL_PACKAGES" android:protectionLevel="signature|privileged"/> + <!-- Allows internal applications to restrict display modes + <p>Not for use by third-party applications. + <p>Protection level: signature + @hide + --> + <permission android:name="android.permission.RESTRICT_DISPLAY_MODES" + android:protectionLevel="signature" /> + <!-- Allows internal applications to override screen timeout temporarily <p>Protection level: signature <p>Not for use by third-party applications. @@ -8270,6 +8927,49 @@ <permission android:name="android.permission.SETUP_FSVERITY" android:protectionLevel="signature|privileged"/> + <!-- @SystemApi + @FlaggedApi(android.security.Flags.FLAG_SECURE_LOCKDOWN) + Allows an application to lock down the device into an enhanced security state. + <p>Not for use by third-party applications. + <p>Protection level: signature|privileged + @hide + --> + <permission android:name="android.permission.MANAGE_SECURE_LOCK_DEVICE" + android:protectionLevel="signature|privileged" + android:featureFlag="android.security.secure_lockdown" /> + + <!-- Allows app to enter trade-in-mode. + <p>Protection level: signature + @hide + --> + <permission android:name="android.permission.ENTER_TRADE_IN_MODE" + android:protectionLevel="signature|privileged" + android:featureFlag="com.android.tradeinmode.flags.enable_trade_in_mode" /> + + <!-- @SystemApi + @FlaggedApi(com.android.art.flags.Flags.FLAG_EXECUTABLE_METHOD_FILE_OFFSETS) + Ability to read program metadata and attach dynamic instrumentation. + <p>Protection level: signature + @hide + --> + <permission android:name="android.permission.DYNAMIC_INSTRUMENTATION" + android:protectionLevel="signature" + android:featureFlag="com.android.art.flags.executable_method_file_offsets" /> + + <!-- + @SystemApi + @FlaggedApi(android.content.pm.Flags.FLAG_UID_BASED_PROVIDER_LOOKUP) + Allows an app to resolve components (e.g ContentProviders) on behalf of + other UIDs + <p>Protection level: signature|privileged + @hide + --> + <permission + android:name="android.permission.RESOLVE_COMPONENT_FOR_UID" + android:protectionLevel="signature|privileged" + android:featureFlag="android.content.pm.uid_based_provider_lookup" /> + <uses-permission android:name="android.permission.RESOLVE_COMPONENT_FOR_UID" /> + <!-- @TestApi Signature permission reserved for testing. This should never be used to @@ -8281,6 +8981,29 @@ <permission android:name="android.permission.RESERVED_FOR_TESTING_SIGNATURE" android:protectionLevel="signature"/> + <!-- @SystemApi + @FlaggedApi("android.media.tv.flags.kids_mode_tvdb_sharing") + This permission is required when accessing information related to + singleUser-ed TIS session. + <p>This should only be used by OEM. + <p>Protection level: signature|privileged|vendorPrivileged + @hide + --> + <permission android:name="android.permission.SINGLE_USER_TIS_ACCESS" + android:protectionLevel="signature|privileged|vendorPrivileged" + android:featureFlag="android.media.tv.flags.kids_mode_tvdb_sharing"/> + + <!-- @SystemApi + @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") + This permission is required to access the specific text classifier from the + TextClassificationManager. + <p>Protection level: signature|role|privileged + @hide + --> + <permission android:name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE" + android:protectionLevel="signature|role|privileged" + android:featureFlag="android.permission.flags.text_classifier_choice_api_enabled"/> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> @@ -8334,7 +9057,7 @@ </activity> <activity android:name="com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity" android:exported="false" - android:theme="@style/Theme.DeviceDefault.Resolver" + android:theme="@style/AccessibilityButtonChooserDialog" android:finishOnCloseSystemDialogs="true" android:excludeFromRecents="true" android:documentLaunchMode="never" @@ -8438,7 +9161,7 @@ <activity android:name="android.accounts.GrantCredentialsPermissionActivity" android:excludeFromRecents="true" android:exported="true" - android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge" + android:theme="@style/GrantCredentialsPermissionActivity" android:process=":ui" android:visibleToInstantApps="true"> </activity> @@ -8514,9 +9237,11 @@ android:process=":ui"> </activity> + <!-- BlockedAppStreamingActivity is launched as the system user. --> <activity android:name="com.android.internal.app.BlockedAppStreamingActivity" android:theme="@style/Theme.Dialog.Confirmation" android:excludeFromRecents="true" + android:showForAllUsers="true" android:process=":ui"> </activity> @@ -8614,15 +9339,6 @@ </intent-filter> </receiver> - <receiver android:name="com.android.server.updates.CertificateTransparencyLogInstallReceiver" - android:exported="true" - android:permission="android.permission.UPDATE_CONFIG"> - <intent-filter> - <action android:name="android.intent.action.UPDATE_CT_LOGS" /> - <data android:scheme="content" android:host="*" android:mimeType="*/*" /> - </intent-filter> - </receiver> - <receiver android:name="com.android.server.updates.LangIdInstallReceiver" android:exported="true" android:permission="android.permission.UPDATE_CONFIG"> @@ -8717,6 +9433,11 @@ android:permission="android.permission.BIND_JOB_SERVICE" > </service> + <service android:name="com.android.server.memory.ZramMaintenance" + android:exported="false" + android:permission="android.permission.BIND_JOB_SERVICE" > + </service> + <service android:name="com.android.server.ZramWriteback" android:exported="false" android:permission="android.permission.BIND_JOB_SERVICE" > @@ -8873,6 +9594,7 @@ <service android:name="com.android.server.companion.datatransfer.contextsync.CallMetadataSyncInCallService" android:permission="android.permission.BIND_INCALL_SERVICE" + android:enabled="@bool/config_enableContextSyncInCall" android:exported="true"> <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS" android:value="true" /> @@ -8881,6 +9603,17 @@ </intent-filter> </service> + <service android:name="com.android.ecm.EnhancedConfirmationCallTrackerService" + android:permission="android.permission.BIND_INCALL_SERVICE" + android:featureFlag="android.permission.flags.enhanced_confirmation_in_call_apis_enabled" + android:exported="true"> + <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS" + android:value="true" /> + <intent-filter> + <action android:name="android.telecom.InCallService"/> + </intent-filter> + </service> + <service android:name="com.android.server.companion.datatransfer.contextsync.CallMetadataSyncConnectionService" android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE" android:exported="true"> diff --git a/tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml b/tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml index 783cd7f6b..2b40d3ed7 100644 --- a/tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml +++ b/tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml @@ -80,6 +80,12 @@ android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_control_car_seats" android:description="@string/car_permission_desc_control_car_seats"/> + <permission android:name="android.car.permission.READ_CAR_SEATS" + android:permissionGroup="android.car.permission-group.CAR_MONITORING" + android:protectionLevel="dangerous" + android:label="@string/car_permission_label_read_car_seats" + android:description="@string/car_permission_desc_read_car_seats" + android:featureFlag="android.car.feature.vehicle_property_25q2_3p_permissions"/> <permission android:name="android.car.permission.CONTROL_CAR_AIRBAGS" android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_control_car_airbags" @@ -88,14 +94,55 @@ android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_mileage" android:description="@string/car_permission_desc_mileage"/> + <permission android:name="android.car.permission.CAR_MILEAGE_3P" + android:permissionGroup="android.permission-group.LOCATION" + android:protectionLevel="dangerous" + android:label="@string/car_permission_label_mileage_3p" + android:description="@string/car_permission_desc_mileage_3p" + android:featureFlag="android.car.feature.android_b_vehicle_properties" /> + <permission android:name="android.car.permission.READ_CAR_HORN" + android:permissionGroup="android.car.permission-group.CAR_MONITORING" + android:protectionLevel="dangerous" + android:label="@string/car_permission_label_read_car_horn" + android:description="@string/car_permission_desc_read_car_horn" + android:featureFlag="android.car.feature.android_b_vehicle_properties" /> + <permission android:name="android.car.permission.CONTROL_CAR_HORN" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_control_car_horn" + android:description="@string/car_permission_desc_control_car_horn" + android:featureFlag="android.car.feature.android_b_vehicle_properties" /> + <permission android:name="android.car.permission.READ_CAR_PEDALS" + android:permissionGroup="android.car.permission-group.CAR_MONITORING" + android:protectionLevel="dangerous" + android:label="@string/car_permission_label_read_car_pedals" + android:description="@string/car_permission_desc_read_car_pedals" + android:featureFlag="android.car.feature.android_b_vehicle_properties" /> + <permission android:name="android.car.permission.READ_BRAKE_INFO" + android:permissionGroup="android.car.permission-group.CAR_MONITORING" + android:protectionLevel="dangerous" + android:label="@string/car_permission_label_read_brake_info" + android:description="@string/car_permission_desc_read_brake_info" + android:featureFlag="android.car.feature.android_b_vehicle_properties" /> <permission android:name="android.car.permission.CAR_TIRES" android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_car_tires" android:description="@string/car_permission_desc_car_tires"/> + <permission android:name="android.car.permission.CAR_TIRES_3P" + android:permissionGroup="android.car.permission-group.CAR_MONITORING" + android:protectionLevel="dangerous" + android:label="@string/car_permission_label_car_tires_3p" + android:description="@string/car_permission_desc_car_tires_3p" + android:featureFlag="android.car.feature.vehicle_property_25q2_3p_permissions"/> <permission android:name="android.car.permission.READ_CAR_STEERING" android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_car_steering" android:description="@string/car_permission_desc_car_steering"/> + <permission android:name="android.car.permission.READ_CAR_STEERING_3P" + android:permissionGroup="android.permission-group.LOCATION" + android:protectionLevel="dangerous" + android:label="@string/car_permission_label_read_car_steering_3p" + android:description="@string/car_permission_desc_read_car_steering_3p" + android:featureFlag="android.car.feature.vehicle_property_25q2_3p_permissions"/> <permission android:name="android.car.permission.READ_CAR_DISPLAY_UNITS" android:protectionLevel="normal" android:label="@string/car_permission_label_read_car_display_units" @@ -121,6 +168,12 @@ android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_car_engine_detailed" android:description="@string/car_permission_desc_car_engine_detailed"/> + <permission android:name="android.car.permission.CAR_ENGINE_DETAILED_3P" + android:permissionGroup="android.car.permission-group.CAR_MONITORING" + android:protectionLevel="dangerous" + android:label="@string/car_permission_label_car_engine_detailed_3p" + android:description="@string/car_permission_desc_car_engine_detailed_3p" + android:featureFlag="android.car.feature.vehicle_property_25q2_3p_permissions"/> <permission android:name="android.car.permission.CAR_DYNAMICS_STATE" android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_vehicle_dynamics_state" @@ -186,6 +239,12 @@ android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_control_car_exterior_lights" android:description="@string/car_permission_desc_control_car_exterior_lights"/> + <permission android:name="android.car.permission.READ_CAR_EXTERIOR_LIGHTS" + android:permissionGroup="android.car.permission-group.CAR_MONITORING" + android:protectionLevel="dangerous" + android:label="@string/car_permission_label_read_car_exterior_lights" + android:description="@string/car_permission_desc_car_read_exterior_lights" + android:featureFlag="android.car.feature.android_b_vehicle_properties" /> <permission android:name="android.car.permission.READ_CAR_INTERIOR_LIGHTS" android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_car_interior_lights" @@ -270,6 +329,12 @@ android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_driving_state" android:description="@string/car_permission_desc_driving_state"/> + <permission android:name="android.car.permission.CAR_DRIVING_STATE_3P" + android:permissionGroup="android.car.permission-group.CAR_MONITORING" + android:protectionLevel="dangerous" + android:label="@string/car_permission_label_driving_state_3p" + android:description="@string/car_permission_desc_driving_state_3p" + android:featureFlag="android.car.feature.vehicle_property_25q2_3p_permissions"/> <permission android:name="android.car.permission.USE_CAR_TELEMETRY_SERVICE" android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_use_telemetry_service" @@ -602,6 +667,12 @@ android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_read_windshield_wipers" android:description="@string/car_permission_desc_read_windshield_wipers"/> + <permission android:name="android.car.permission.READ_WINDSHIELD_WIPERS_3P" + android:permissionGroup="android.car.permission-group.CAR_MONITORING" + android:protectionLevel="dangerous" + android:label="@string/car_permission_label_read_windshield_wipers_3p" + android:description="@string/car_permission_desc_read_windshield_wipers_3p" + android:featureFlag="android.car.feature.vehicle_property_25q2_3p_permissions"/> <permission android:name="android.car.permission.CONTROL_WINDSHIELD_WIPERS" android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_control_windshield_wipers" @@ -620,4 +691,16 @@ android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_bind_app_card_provider" android:description="@string/car_permission_desc_bind_app_card_provider" /> + <permission + android:name="android.car.permission.RECORD_VEHICLE_PROPERTIES" + android:protectionLevel="signature" + android:label="@string/car_permission_label_record_vehicle_properties" + android:description="@string/car_permission_desc_record_vehicle_properties" + android:featureFlag="android.car.feature.car_property_simulation" /> + <permission + android:name="android.car.permission.INJECT_VEHICLE_PROPERTIES" + android:protectionLevel="signature" + android:label="@string/car_permission_label_inject_vehicle_properties" + android:description="@string/car_permission_desc_inject_vehicle_properties" + android:featureFlag="android.car.feature.car_property_simulation" /> </manifest> diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt index 70832b6ba..2ce48af44 100644 --- a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt +++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt @@ -59,6 +59,7 @@ import android.app.AppOpsManager.permissionToOp import android.content.pm.PackageManager.GET_PERMISSIONS import android.content.pm.PermissionInfo.PROTECTION_DANGEROUS import android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP +import android.health.connect.HealthPermissions import android.os.Build import android.permission.flags.Flags import android.permission.PermissionManager @@ -195,6 +196,18 @@ class RuntimePermissionProperties { expectedPerms.add(RANGING) } - assertThat(expectedPerms).containsExactlyElementsIn(platformRuntimePerms.map { it.name }) + // Separately check health permissions. + if (Flags.replaceBodySensorPermissionEnabled()) { + assertThat(expectedPerms).contains(HealthPermissions.READ_HEART_RATE); + assertThat(expectedPerms).contains(HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND); + + // Remove these from the expected list once we've confirmed their + // present. These are not permissions owned by "android" so won't be + // in the list of platform runtime permissions. + expectedPerms.remove(HealthPermissions.READ_HEART_RATE); + expectedPerms.remove(HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND); + } + + assertThat(platformRuntimePerms.map { it.name }).containsExactlyElementsIn(expectedPerms) } } diff --git a/tests/cts/permissionui/AndroidManifest.xml b/tests/cts/permissionui/AndroidManifest.xml index 3b80b8d8b..b5c9e2ad0 100644 --- a/tests/cts/permissionui/AndroidManifest.xml +++ b/tests/cts/permissionui/AndroidManifest.xml @@ -25,6 +25,7 @@ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> + <uses-permission android:name="android.permission.MANAGE_OWN_CALLS" /> <application> @@ -78,6 +79,23 @@ <meta-data android:name="android.accessibilityservice" android:resource="@xml/test_accessibilityservice"/> </service> + <service android:name=".VoipHelperTestConnectionService" + android:exported="true" + android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"> + <intent-filter> + <action android:name="android.telecom.ConnectionService" /> + </intent-filter> + </service> + + <service android:name=".EcmInCallTestInCallService" + android:permission="android.permission.BIND_INCALL_SERVICE" + android:exported="true"> + <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS" + android:value="true" /> + <intent-filter> + <action android:name="android.telecom.InCallService"/> + </intent-filter> + </service> </application> diff --git a/tests/cts/permissionui/UsePermissionApp30WithBackground/AndroidManifest.xml b/tests/cts/permissionui/UsePermissionApp30WithBackground/AndroidManifest.xml index 5949d08f2..6b9b9f41f 100644 --- a/tests/cts/permissionui/UsePermissionApp30WithBackground/AndroidManifest.xml +++ b/tests/cts/permissionui/UsePermissionApp30WithBackground/AndroidManifest.xml @@ -24,6 +24,8 @@ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> + <uses-permission android:name="android.permission.BODY_SENSORS" /> + <uses-permission android:name="android.permission.BODY_SENSORS_BACKGROUND" /> <application> <activity android:name=".RequestPermissionsActivity" android:exported="true" /> diff --git a/tests/cts/permissionui/src/android/permissionui/cts/AppDataSharingUpdatesTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/AppDataSharingUpdatesTest.kt index 0db639d49..421e93e2d 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/AppDataSharingUpdatesTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/AppDataSharingUpdatesTest.kt @@ -311,6 +311,7 @@ class AppDataSharingUpdatesTest : BaseUsePermissionTest() { } @Test + @Ignore("b/381298073") fun clickUpdate_opensAppLocationPermissionPage() { installAndWaitTillPackageAdded( APP_APK_NAME_31, diff --git a/tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt index f0c12171c..05c824072 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/AppPermissionTest.kt @@ -18,7 +18,9 @@ package android.permissionui.cts import android.Manifest.permission.ACCESS_COARSE_LOCATION import android.Manifest.permission_group.SMS +import android.app.AppOpsManager import android.os.Build +import android.os.Process import android.permission.flags.Flags import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.CheckFlagsRule @@ -31,8 +33,11 @@ import androidx.test.filters.SdkSuppress import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.compatibility.common.util.DeviceConfigStateChangerRule +import com.android.compatibility.common.util.SystemUtil.eventually +import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity import com.android.modules.utils.build.SdkLevel import com.google.common.truth.Truth +import org.junit.Assert.assertEquals import org.junit.Assume import org.junit.Before import org.junit.Rule @@ -296,6 +301,9 @@ class AppPermissionTest : BaseUsePermissionTest() { APP_APK_NAME_LATEST ) + // TODO: b/388960315 - Remove wait after addressing race condition + waitForModeDefault(APP_PACKAGE_NAME) + navigateToIndividualPermissionSetting(SMS) assertAllowButtonIsDisabledAndRestrictedSettingDialogPoppedUp() @@ -311,6 +319,8 @@ class AppPermissionTest : BaseUsePermissionTest() { @Test fun installFromLocalFile_disabledAllowRadioButtonAndIfClickedAndRestrictedSettingDialog_SMSPermGroup() { installPackageWithInstallSourceAndMetadataFromLocalFile(APP_APK_NAME_LATEST) + // TODO: b/388960315 - Remove wait after addressing race condition + waitForModeDefault(APP_PACKAGE_NAME) navigateToIndividualPermissionSetting(SMS) @@ -341,6 +351,28 @@ class AppPermissionTest : BaseUsePermissionTest() { ) } + private fun waitForModeDefault(packageName: String) { + val appOpsManager = context.getSystemService(AppOpsManager::class.java)!! + eventually { + val uid = context.packageManager.getApplicationInfoAsUser( + packageName, + /* flags */ 0, + Process.myUserHandle() + ).uid + runWithShellPermissionIdentity { + assertEquals( + "Timed out waiting for package mode to change to MODE_DEFAULT", + appOpsManager.checkOpNoThrow( + AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS, + uid, + packageName, + ), + AppOpsManager.MODE_DEFAULT, + ) + } + } + } + companion object { private const val PERMISSION_RATIONALE_ENABLED = "permission_rationale_enabled" private val ENHANCED_CONFIRMATION_DIALOG_SELECTOR = By.res( diff --git a/tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt index d8eb153bf..69528f83d 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt @@ -37,6 +37,7 @@ import android.content.pm.PackageManager import android.content.res.Resources import android.os.PersistableBundle import android.os.SystemClock +import android.permission.cts.TestUtils import android.platform.test.rule.ScreenRecordRule import android.provider.DeviceConfig import android.provider.Settings @@ -72,6 +73,7 @@ import org.junit.After import org.junit.Assert import org.junit.Assert.assertEquals import org.junit.Assert.assertNotEquals +import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Rule @@ -121,7 +123,7 @@ abstract class BasePermissionTest { /* PackageManager.FEATURE_CAR_SPLITSCREEN_MULTITASKING */ "android.software.car.splitscreen_multitasking") @JvmStatic - private val isAutomotiveVisibleBackgroundUser = isAutomotive && + protected val isAutomotiveVisibleBackgroundUser = isAutomotive && UserHelper(context).isVisibleBackgroundUser() // TODO(b/382327037):find a way to avoid specifying the display ID for each UiSelector. @@ -157,6 +159,7 @@ abstract class BasePermissionTest { @Before fun setUp() { + assumeTrue(TestUtils.isCddCompliantScreenSize()) runWithShellPermissionIdentity { screenTimeoutBeforeTest = Settings.System.getLong(context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT) @@ -191,6 +194,9 @@ abstract class BasePermissionTest { @After fun tearDown() { + if (!TestUtils.isCddCompliantScreenSize()) { + return; + } runWithShellPermissionIdentity { Settings.System.putLong( context.contentResolver, diff --git a/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt index 68bd91546..f52e32344 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt @@ -38,6 +38,7 @@ import android.provider.DeviceConfig import android.provider.Settings import android.text.Spanned import android.text.style.ClickableSpan +import android.util.Log import android.view.View import android.view.accessibility.AccessibilityNodeInfo import androidx.test.uiautomator.By @@ -51,6 +52,7 @@ import com.android.compatibility.common.util.SystemUtil import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity import com.android.compatibility.common.util.SystemUtil.eventually import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity +import com.android.compatibility.common.util.UiDumpUtils import com.android.modules.utils.build.SdkLevel import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit @@ -64,6 +66,7 @@ import org.junit.Before abstract class BaseUsePermissionTest : BasePermissionTest() { companion object { + const val LOG_TAG = "BaseUsePermissionTest" const val APP_APK_NAME_31 = "CtsUsePermissionApp31.apk" const val APP_APK_NAME_31_WITH_ASL = "CtsUsePermissionApp31WithAsl.apk" const val APP_APK_NAME_LATEST = "CtsUsePermissionAppLatest.apk" @@ -148,6 +151,9 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { const val APP_PERMISSION_RATIONALE_TITLE_TEXT = "app_location_permission_rationale_title" const val APP_PERMISSION_RATIONALE_SUBTITLE_TEXT = "app_location_permission_rationale_subtitle" + const val HEALTH_PERMISSION_SELECT_HEART_RATE_PLAIN_TEXT = "Heart rate" + const val HEALTH_PERMISSION_ALLOW_ALL_PLAIN_TEXT = "Allow all" + const val HEALTH_PERMISSION_ALLOW_ALWAYS_PLAIN_TEXT = "Allow all the time" const val GRANT_DIALOG_PERMISSION_RATIONALE_CONTAINER_VIEW = "com.android.permissioncontroller:id/permission_rationale_container" const val PERMISSION_RATIONALE_ACTIVITY_TITLE_VIEW = @@ -315,7 +321,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { reinstall: Boolean, grantRuntimePermissions: Boolean, expectSuccess: Boolean, - installSource: String? + installSource: String?, ) { installPackage( apkPath, @@ -333,7 +339,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { grantRuntimePermissions: Boolean = false, expectSuccess: Boolean = true, installSource: String? = null, - skipClearLowSdkDialog: Boolean = false + skipClearLowSdkDialog: Boolean = false, ) { super.installPackage( apkPath, @@ -463,7 +469,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { } protected fun installPackageWithInstallSourceFromDownloadedFileAndAllowHardRestrictedPerms( - apkName: String + apkName: String, ) { installPackageViaSession( apkName, @@ -506,7 +512,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { } protected fun installPackageWithInstallSourceAndMetadataWithoutTopLevelVersion( - apkName: String + apkName: String, ) { installPackageViaSession( apkName, @@ -515,7 +521,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { } protected fun installPackageWithInstallSourceAndMetadataWithInvalidTopLevelVersion( - apkName: String + apkName: String, ) { installPackageViaSession( apkName, @@ -524,7 +530,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { } protected fun installPackageWithInstallSourceAndMetadataWithoutSafetyLabelVersion( - apkName: String + apkName: String, ) { installPackageViaSession( apkName, @@ -533,7 +539,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { } protected fun installPackageWithInstallSourceAndMetadataWithInvalidSafetyLabelVersion( - apkName: String + apkName: String, ) { installPackageViaSession( apkName, @@ -552,7 +558,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { } protected fun assertPermissionRationaleActivityDataSharingSourceSectionVisible( - expected: Boolean + expected: Boolean, ) { findView(By.res(DATA_SHARING_SOURCE_TITLE_ID).displayId(displayId), expected = expected) findView(By.res(DATA_SHARING_SOURCE_MESSAGE_ID).displayId(displayId), expected = expected) @@ -577,7 +583,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { protected fun assertPermissionRationaleDialogIsVisible( expected: Boolean, - showSettingsSection: Boolean = true + showSettingsSection: Boolean = true, ) { assertPermissionRationaleActivityTitleIsVisible(expected) assertPermissionRationaleActivityDataSharingSourceSectionVisible(expected) @@ -623,7 +629,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { protected inline fun startAppActivityAndAssertResultCode( expectedResultCode: Int, - block: () -> Unit + block: () -> Unit, ) { val future = startActivityForFuture( @@ -641,7 +647,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { protected inline fun requestAppPermissionsForNoResult( vararg permissions: String?, - crossinline block: () -> Unit + crossinline block: () -> Unit, ) { // Request the permissions doAndWaitForWindowTransition { @@ -665,7 +671,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { vararg permissions: String?, askTwice: Boolean = false, waitForWindowTransition: Boolean = !isWatch, - crossinline block: () -> Unit + crossinline block: () -> Unit, ): Instrumentation.ActivityResult { // Request the permissions lateinit var future: CompletableFuture<Instrumentation.ActivityResult> @@ -700,7 +706,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { permissionAndExpectedGrantResults: Array<out Pair<String?, Boolean>>, askTwice: Boolean = false, waitForWindowTransition: Boolean = !isWatch, - crossinline block: () -> Unit + crossinline block: () -> Unit, ) { var shouldWaitForWindowTransition = waitForWindowTransition // Do not wait for windowTransition after action is performed on auto, when permissions @@ -766,7 +772,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { vararg permissionAndExpectedGrantResults: Pair<String?, Boolean>, askTwice: Boolean = false, waitForWindowTransition: Boolean = !isWatch, - crossinline block: () -> Unit + crossinline block: () -> Unit, ) { requestAppPermissionsAndAssertResult( permissionAndExpectedGrantResults.map { it.first }.toTypedArray(), @@ -788,6 +794,9 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { ) if (timeoutOccurred) { + val uiDump = StringBuilder() + UiDumpUtils.dumpNodes(uiDump) + Log.w(LOG_TAG, "Timed out waiting for window transition, UI dump: $uiDump") throw RuntimeException("Timed out waiting for window transition.") } } @@ -801,8 +810,11 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { } } - protected fun clickPermissionRequestAllowButton(timeoutMillis: Long = 20000) { - if (isAutomotive || isWatch) { + protected fun clickPermissionRequestAllowButton( + timeoutMillis: Long = 20000, + isHealthPermission: Boolean = false, + ) { + if (isAutomotive || isWatch || isHealthPermission) { click(By.text(getPermissionControllerString(ALLOW_BUTTON_TEXT)).displayId(displayId), timeoutMillis) } else { @@ -973,6 +985,37 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { assertTrue("Could not click on the settings link correctly", clickedOnLink) } + protected fun clickAllowReadHeartRate() { + eventually { + scrollToBottom() + + // Phone UI has allow all, toggle, and allow button. Watch UI only has allow button. + if (!isWatch) { + // Check "Allow all" button is visible. + val allowAllNode = + uiAutomation.rootInActiveWindow.findAccessibilityNodeInfosByText( + HEALTH_PERMISSION_ALLOW_ALL_PLAIN_TEXT + )[0] + assertTrue(allowAllNode.isVisibleToUser) + + // Select "Heart rate" toggle and click "Allow" button. + click(By.text(HEALTH_PERMISSION_SELECT_HEART_RATE_PLAIN_TEXT).displayId(displayId)) + } + + clickPermissionRequestAllowButton(isHealthPermission = true) + } + } + + protected fun clickAlwaysAllowReadHealthDataInBackground() { + eventually { + if (isWatch) { + click(By.text(HEALTH_PERMISSION_ALLOW_ALWAYS_PLAIN_TEXT).displayId(displayId)) + } else { + clickPermissionRequestAllowButton(isHealthPermission = true) + } + } + } + protected fun clickPermissionRequestDenyAndDontAskAgainButton() { if (isAutomotive) { scrollToBottom() @@ -1011,7 +1054,8 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { protected fun clickPermissionRationaleContentInAppPermission() { clickAndWaitForWindowTransition( By.text(getPermissionControllerString(APP_PERMISSION_RATIONALE_SUBTITLE_TEXT)) - .displayId(displayId)) + .displayId(displayId) + ) } protected fun clickPermissionRationaleViewInGrantDialog() { @@ -1031,7 +1075,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { protected fun revokeAppPermissionsByUi( vararg permissions: String, - isLegacyApp: Boolean = false + isLegacyApp: Boolean = false, ) { setAppPermissionState( *permissions, @@ -1091,10 +1135,17 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { } } } + protected fun navigateToIndividualPermissionSetting( + permission: String, + manuallyNavigate: Boolean = false, + ) { + navigateToIndividualPermissionSetting(permission, APP_PACKAGE_NAME, manuallyNavigate) + } protected fun navigateToIndividualPermissionSetting( permission: String, - manuallyNavigate: Boolean = false + packageName: String, + manuallyNavigate: Boolean = false, ) { val useLegacyNavigation = isWatch || isAutomotive || manuallyNavigate if (useLegacyNavigation) { @@ -1112,7 +1163,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { runWithShellPermissionIdentity { context.startActivity( Intent(Intent.ACTION_MANAGE_APP_PERMISSION).apply { - putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME) + putExtra(Intent.EXTRA_PACKAGE_NAME, packageName) putExtra(Intent.EXTRA_PERMISSION_NAME, permission) putExtra(Intent.EXTRA_USER, Process.myUserHandle()) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) @@ -1367,7 +1418,8 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION, - android.Manifest.permission.ACCESS_BACKGROUND_LOCATION -> true + android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, + -> true else -> false } @@ -1378,7 +1430,8 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { return when (permission) { Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED, Manifest.permission.READ_MEDIA_IMAGES, - Manifest.permission.READ_MEDIA_VIDEO -> true + Manifest.permission.READ_MEDIA_VIDEO, + -> true else -> false } } @@ -1386,7 +1439,8 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { private fun showsForegroundOnlyButton(permission: String): Boolean = when (permission) { android.Manifest.permission.CAMERA, - android.Manifest.permission.RECORD_AUDIO -> true + android.Manifest.permission.RECORD_AUDIO, + -> true else -> false } @@ -1419,7 +1473,7 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { protected fun findAccessibilityNodeInfosByTextForSurfaceView( node: AccessibilityNodeInfo, - text: String + text: String, ): AccessibilityNodeInfo? { if (node.text != null && node.text.contains(text)) return node for (i in 0 until node.childCount) { diff --git a/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt index b9d1cb305..798b1942f 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt @@ -23,6 +23,7 @@ import android.content.AttributionSource import android.content.Context import android.content.Intent import android.content.pm.PackageManager +import android.content.res.Resources import android.hardware.camera2.CameraManager import android.os.Build import android.os.Process @@ -34,7 +35,6 @@ import android.platform.test.annotations.AsbSecurityTest import android.platform.test.rule.ScreenRecordRule import android.provider.DeviceConfig import android.provider.Settings -import android.safetycenter.SafetyCenterManager import android.server.wm.WindowManagerStateHelper import android.util.Log import androidx.annotation.RequiresApi @@ -146,7 +146,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { DeviceConfig.getString( DeviceConfig.NAMESPACE_PRIVACY, SAFETY_CENTER_ENABLED, - false.toString() + false.toString(), )!! } @@ -162,7 +162,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { @Before fun setUp() { - // Camera and Mic are not supported for secondary user visible as a background user. + // Skip the tests as Camera and Mic are not supported for visible background users. assumeFalse(isCar && UserHelper(context).isVisibleBackgroundUser()) runWithShellPermissionIdentity { screenTimeoutBeforeTest = @@ -170,7 +170,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { Settings.System.putLong( context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT, - 1800000L + 1800000L, ) } @@ -188,7 +188,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { "feature not present on this device", callWithShellPermissionIdentity { CompatChanges.isChangeEnabled(PERMISSION_INDICATORS_NOT_PRESENT, Process.SYSTEM_UID) - } + }, ) install() } @@ -203,7 +203,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { DeviceConfig.NAMESPACE_PRIVACY, INDICATORS_FLAG, shouldBeEnabled.toString(), - false + false, ) } } @@ -212,7 +212,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { @After fun tearDown() { - // Camera and Mic are not supported for secondary user visible as a background user. + // Skip the tests as Camera and Mic are not supported for visible background users. if (isCar && UserHelper(context).isVisibleBackgroundUser()) { return } @@ -223,7 +223,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { } eventually( { assertIndicatorsShown(false, false, false) }, - AUTO_MIC_INDICATOR_DISMISSAL_TIMEOUT_MS + AUTO_MIC_INDICATOR_DISMISSAL_TIMEOUT_MS, ) if (!wasEnabled) { setIndicatorsEnabledStateIfNeeded(false) @@ -232,7 +232,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { Settings.System.putLong( context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT, - screenTimeoutBeforeTest + screenTimeoutBeforeTest, ) } changeSafetyCenterFlag(safetyCenterEnabled) @@ -248,7 +248,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { useMic: Boolean, useCamera: Boolean, useHotword: Boolean, - finishEarly: Boolean = false + finishEarly: Boolean = false, ) { context.startActivity( Intent(USE_INTENT_ACTION).apply { @@ -289,7 +289,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { useMic = true, useCamera = false, finishEarly = true, - safetyCenterEnabled = getSafetyCenterEnabled() + safetyCenterEnabled = getSafetyCenterEnabled(), ) } @@ -350,7 +350,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { useMic = false, useCamera = false, useHotword = true, - safetyCenterEnabled = true + safetyCenterEnabled = true, ) } @@ -365,7 +365,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { useMic = false, useCamera = true, chainUsage = true, - safetyCenterEnabled = true + safetyCenterEnabled = true, ) } @@ -375,12 +375,12 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { useHotword: Boolean = false, chainUsage: Boolean = false, safetyCenterEnabled: Boolean = false, - finishEarly: Boolean = false + finishEarly: Boolean = false, ) { Log.d( TAG, "testCameraAndMicIndicator useMic=$useMic useCamera=$useCamera " + - "safetyCenterEnabled=$safetyCenterEnabled finishEarly=$finishEarly" + "safetyCenterEnabled=$safetyCenterEnabled finishEarly=$finishEarly", ) // If camera is not available skip the test if (useCamera) { @@ -409,7 +409,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { permissionManager.checkPermissionForStartDataDelivery( Manifest.permission.RECORD_AUDIO, chainAttribution!!, - "" + "", ) assertEquals(PermissionManager.PERMISSION_GRANTED, ret) } @@ -442,7 +442,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { runWithShellPermissionIdentity { permissionManager.finishDataDelivery( Manifest.permission.RECORD_AUDIO, - chainAttribution + chainAttribution, ) } } @@ -481,7 +481,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { micInUse, useCamera, chainUsage, - safetyCenterEnabled + safetyCenterEnabled, ) uiDevice.pressBack() } @@ -490,7 +490,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { private fun assertWatchIndicatorsShown( useMic: Boolean, useCamera: Boolean, - useHotword: Boolean + useHotword: Boolean, ) { if (useMic || useHotword || (!useMic && !useCamera && !useHotword)) { val iconView = UiAutomatorUtils2.waitFindObjectOrNull(By.descContains(WEAR_MIC_LABEL)) @@ -530,7 +530,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { useMic: Boolean, useCamera: Boolean, useHotword: Boolean, - chainUsage: Boolean + chainUsage: Boolean, ) { eventually { // Ensure the privacy chip is present (or not) @@ -575,17 +575,17 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { val micLabelView = uiDevice.findObject(UiSelector().textContains(micLabel)) assertFalse( "View with text $micLabel found, but did not expect to", - micLabelView.exists() + micLabelView.exists(), ) val cameraLabelView = uiDevice.findObject(UiSelector().textContains(cameraLabel)) assertFalse( "View with text $cameraLabel found, but did not expect to", - cameraLabelView.exists() + cameraLabelView.exists(), ) val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL)) assertFalse( "View with text $APP_LABEL found, but did not expect to", - appView.exists() + appView.exists(), ) } } @@ -595,7 +595,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { useMic: Boolean, useCamera: Boolean, chainUsage: Boolean, - safetyCenterEnabled: Boolean = false + safetyCenterEnabled: Boolean = false, ) { // Ensure the privacy chip is present if (useCamera || useMic) { @@ -655,7 +655,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { context.packageName, null, null, - permissionManager.registerAttributionSource(childAttribution) + permissionManager.registerAttributionSource(childAttribution), ) attrSource = permissionManager.registerAttributionSource(attribution) } catch (e: PackageManager.NameNotFoundException) { @@ -705,7 +705,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { DeviceConfig.NAMESPACE_PRIVACY, SAFETY_CENTER_ENABLED, safetyCenterEnabled, - false + false, ) } } @@ -720,9 +720,21 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { } private fun getSafetyCenterEnabled(): Boolean { - val safetyCenterManager = - context.getSystemService(SafetyCenterManager::class.java) ?: return false - return runWithShellPermissionIdentity<Boolean> { safetyCenterManager.isSafetyCenterEnabled } + if (!SdkLevel.isAtLeastT()) { + // Safety Center does not exist below T. + return false + } + val systemResources = Resources.getSystem() + val resId = systemResources.getIdentifier("config_enableSafetyCenter", "bool", "android") + val safetyCenterSupported = context.getResources().getBoolean(resId) + if (!SdkLevel.isAtLeastU()) { + // On T, Safety Center is controlled by the DeviceConfig flag. + return safetyCenterSupported && safetyCenterEnabled.toBoolean() + } + // On UDC+, Safety Center is no longer controlled by DeviceConfig. + // The only way it can be disabled is if the OEM suppresses it at the + // config level using config_enableSafetyCenter. + return safetyCenterSupported } protected fun waitFindObject(selector: BySelector): UiObject2? { @@ -731,7 +743,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { private fun findObjectWithRetry( automatorMethod: (timeoutMillis: Long) -> UiObject2?, - timeoutMillis: Long = TIMEOUT_MILLIS + timeoutMillis: Long = TIMEOUT_MILLIS, ): UiObject2? { val startTime = SystemClock.elapsedRealtime() return try { @@ -754,7 +766,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { permissionControllerContext.resources.getIdentifier( resourceName, "string", - "com.android.permissioncontroller" + "com.android.permissioncontroller", ) return permissionControllerContext.getString(resourceId) } catch (e: PackageManager.NameNotFoundException) { @@ -767,7 +779,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { val micView = waitFindObject(byOneOfText(originalMicLabel, safetyCenterMicLabel)) assertNotNull( "View with text '$originalMicLabel' or '$safetyCenterMicLabel' not found", - micView + micView, ) } @@ -776,7 +788,7 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase { val cameraView = waitFindObject(byOneOfText(originalCameraLabel, safetyCenterCameraLabel)) assertNotNull( "View with text '$originalCameraLabel' or '$safetyCenterCameraLabel' not found", - cameraView + cameraView, ) } diff --git a/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationInCallTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationInCallTest.kt new file mode 100644 index 000000000..9a4908c79 --- /dev/null +++ b/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationInCallTest.kt @@ -0,0 +1,233 @@ +/* + * 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 android.permissionui.cts + +import android.app.AppOpsManager +import android.app.Instrumentation +import android.app.ecm.EnhancedConfirmationManager +import android.content.ContentProviderOperation +import android.content.Context +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Build +import android.os.Process +import android.permission.flags.Flags +import android.platform.test.annotations.AppModeFull +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.CheckFlagsRule +import android.platform.test.flag.junit.DeviceFlagsValueProvider +import android.provider.ContactsContract +import android.provider.ContactsContract.CommonDataKinds +import android.provider.ContactsContract.Data +import android.provider.ContactsContract.RawContacts +import androidx.test.filters.SdkSuppress +import androidx.test.platform.app.InstrumentationRegistry +import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity +import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity +import org.junit.After +import org.junit.AfterClass +import org.junit.Assert +import org.junit.Assume +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Rule +import org.junit.Test + +/** + * This test verifies the behavior of the Enhanced Confirmation Manager APIs that deal with unknown + * callers + */ +@AppModeFull(reason = "Instant apps cannot install packages") +@SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") +@RequiresFlagsEnabled(Flags.FLAG_UNKNOWN_CALL_PACKAGE_INSTALL_BLOCKING_ENABLED) +// @CddTest(requirement = "TBD") +class EnhancedConfirmationInCallTest { + private val ecm = context.getSystemService(EnhancedConfirmationManager::class.java)!! + private val aom = context.getSystemService(AppOpsManager::class.java)!! + private val packageManager = context.packageManager + private val addedContacts = mutableMapOf<String, List<Uri>>() + private val phoneOnlyRestrictedSetting = AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES + private val phoneAndEcmRestrictedSetting = AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES + + @JvmField + @Rule + val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + + @Before + fun assumeNotAutoOrTv() { + Assume.assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) + Assume.assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) + } + + companion object { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val context: Context = instrumentation.targetContext + private lateinit var voipService: VoipCallHelper + + @JvmStatic + @BeforeClass + fun setupVoipService() { + voipService = VoipCallHelper(context) + voipService.registerPhoneAccount() + } + + @JvmStatic + @AfterClass + fun tearDownVoipService() { + voipService.removePhoneAccount() + } + + const val CONTACT_DISPLAY_NAME = "Alice Bobson" + const val NON_CONTACT_DISPLAY_NAME = "Eve McEve" + const val CONTACT_PHONE_NUMBER = "8888888888" + const val NON_CONTACT_PHONE_NUMBER = "1111111111" + } + + private fun addContact(displayName: String, phoneNumber: String) { + runWithShellPermissionIdentity { + val ops: ArrayList<ContentProviderOperation> = ArrayList() + ops.add( + ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) + .withValue(RawContacts.ACCOUNT_TYPE, "test type") + .withValue(RawContacts.ACCOUNT_NAME, "test account") + .build() + ) + ops.add( + ContentProviderOperation.newInsert(Data.CONTENT_URI) + .withValueBackReference(Data.RAW_CONTACT_ID, 0) + .withValue(Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE) + .withValue(CommonDataKinds.StructuredName.DISPLAY_NAME, displayName) + .build() + ) + ops.add( + ContentProviderOperation.newInsert(Data.CONTENT_URI) + .withValueBackReference(Data.RAW_CONTACT_ID, 0) + .withValue(Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE) + .withValue(CommonDataKinds.Phone.NUMBER, phoneNumber) + .build() + ) + val results = context.contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) + val resultsForDisplayName = mutableListOf<Uri>() + results.forEach { resultsForDisplayName.add(it.uri!!) } + addedContacts[displayName] = resultsForDisplayName + } + } + + private fun removeContact(displayName: String) { + runWithShellPermissionIdentity { + var totalRowsRemoved = 0 + for (data in addedContacts[displayName] ?: emptyList()) { + totalRowsRemoved += context.contentResolver.delete(data, null) + } + // There are multiple contacts tables, and removing from the raw_contacts table + // can cause row removals from the data table, so we may get some uris that don't + // report a delete, but we should get at least one, and not more than the number of uris + Assert.assertNotEquals( + "Expected at least one contact row to be removed", + 0, + totalRowsRemoved, + ) + Assert.assertTrue( + "Unexpectedly large number of contact rows removed", + totalRowsRemoved <= (addedContacts[displayName]?.size ?: 0), + ) + addedContacts.remove(displayName) + } + } + + @After + fun tearDown() { + voipService.endCallAndWaitForInactive() + addedContacts.keys.forEach { removeContact(it) } + runWithShellPermissionIdentity { + aom.setUidMode( + AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS, + Process.myUid(), + AppOpsManager.MODE_ALLOWED, + ) + } + } + + private fun isSettingRestricted(settingsIdentifier: String): Boolean { + return callWithShellPermissionIdentity { + ecm.isRestricted(context.packageName, settingsIdentifier) + } + } + + private fun areSettingsRestricted(): Boolean { + return isSettingRestricted(phoneOnlyRestrictedSetting) && + isSettingRestricted(phoneAndEcmRestrictedSetting) + } + + @Test + fun testIncomingCall_NonContact() { + voipService.createCallAndWaitForActive(NON_CONTACT_DISPLAY_NAME, NON_CONTACT_PHONE_NUMBER) + Assert.assertTrue(areSettingsRestricted()) + voipService.endCallAndWaitForInactive() + Assert.assertFalse(areSettingsRestricted()) + } + + @Test + fun testIncomingCall_Contact_DisplayNameMatches_PhoneNotGiven() { + addContact(CONTACT_DISPLAY_NAME, CONTACT_PHONE_NUMBER) + // If no phone number is given, the display name will be checked + voipService.createCallAndWaitForActive(CONTACT_DISPLAY_NAME, CONTACT_PHONE_NUMBER) + Assert.assertFalse(areSettingsRestricted()) + voipService.endCallAndWaitForInactive() + Assert.assertFalse(areSettingsRestricted()) + } + + @Test + fun testIncomingCall_Contact_PhoneNumberMatches() { + addContact(CONTACT_DISPLAY_NAME, CONTACT_PHONE_NUMBER) + // If the phone number matches, the display name is not checked + voipService.createCallAndWaitForActive(NON_CONTACT_DISPLAY_NAME, CONTACT_PHONE_NUMBER) + Assert.assertFalse(areSettingsRestricted()) + voipService.endCallAndWaitForInactive() + Assert.assertFalse(areSettingsRestricted()) + } + + @Test + fun testCall_DoesntBecomeTrustedIfCallerAddedDuringCall() { + val tempContactDisplay = "TEMP CONTACT" + val tempContactPhone = "999-999-9999" + voipService.createCallAndWaitForActive(tempContactDisplay, tempContactPhone) + addContact(tempContactDisplay, tempContactPhone) + // State should not be recomputed just because the contact is newly added + Assert.assertTrue(areSettingsRestricted()) + voipService.endCallAndWaitForInactive() + voipService.createCallAndWaitForActive(tempContactDisplay, tempContactPhone) + // A new call should recognize our contact, and mark the call as trusted + Assert.assertFalse(areSettingsRestricted()) + } + + @Test + fun testCallOnlyRestrictedSetting_notRestrictedIfEcmSet() { + // Set the current app to be restricted by ECM + runWithShellPermissionIdentity { + aom.setUidMode( + AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS, + Process.myUid(), + AppOpsManager.MODE_ERRORED, + ) + } + // The ecm and phone restricted setting is restricted + Assert.assertFalse(isSettingRestricted(phoneOnlyRestrictedSetting)) + // But the phone only restriction is not + Assert.assertFalse(isSettingRestricted(phoneAndEcmRestrictedSetting)) + } +} diff --git a/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationManagerTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationManagerTest.kt index cde2b6d6a..596178b70 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationManagerTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationManagerTest.kt @@ -29,6 +29,7 @@ import android.platform.test.annotations.AppModeFull import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.CheckFlagsRule import android.platform.test.flag.junit.DeviceFlagsValueProvider +import androidx.test.filters.FlakyTest import androidx.test.filters.SdkSuppress import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By @@ -204,6 +205,7 @@ class EnhancedConfirmationManagerTest : BaseUsePermissionTest() { } @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) + @FlakyTest(bugId = 387927331) @Test fun grantDialogBlocksRestrictedGroupsThenRequestsUnrestrictedGroupsDespiteOutOfOrderRequest() { installPackageWithInstallSourceFromDownloadedFileAndAllowHardRestrictedPerms( @@ -219,6 +221,8 @@ class EnhancedConfirmationManagerTest : BaseUsePermissionTest() { waitForWindowTransition = false ) { clickECMAlertDialogOKButton() + // TODO: b/387927331 - On some targets, grant dialog hangs after this click + Thread.sleep(3_000L) clickPermissionRequestDenyButton() } assertTrue(isClearRestrictionAllowed(APP_PACKAGE_NAME)) @@ -234,6 +238,7 @@ class EnhancedConfirmationManagerTest : BaseUsePermissionTest() { } @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) + @FlakyTest(bugId = 387927331) @Test fun grantDialogBlocksRestrictedGroupsThenRequestsUnrestrictedHighPriorityGroups() { installPackageWithInstallSourceFromDownloadedFileAndAllowHardRestrictedPerms( @@ -247,12 +252,15 @@ class EnhancedConfirmationManagerTest : BaseUsePermissionTest() { waitForWindowTransition = false ) { clickECMAlertDialogOKButton() + // TODO: b/387927331 - On some targets, grant dialog hangs after this click + Thread.sleep(3_000L) clickPermissionRequestAllowForegroundButton() } assertTrue(isClearRestrictionAllowed(APP_PACKAGE_NAME)) } @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) + @FlakyTest(bugId = 390440965) @Test fun grantDialogBlocksRestrictedGroupsThenRequestsUnrestrictedLowPriorityGroups() { installPackageWithInstallSourceFromDownloadedFileAndAllowHardRestrictedPerms( @@ -266,6 +274,8 @@ class EnhancedConfirmationManagerTest : BaseUsePermissionTest() { waitForWindowTransition = false ) { clickECMAlertDialogOKButton() + // TODO: b/387927331 - On some targets, grant dialog hangs after this click + Thread.sleep(3_000L) clickPermissionRequestAllowForegroundButton() } assertTrue(isClearRestrictionAllowed(APP_PACKAGE_NAME)) @@ -311,7 +321,7 @@ class EnhancedConfirmationManagerTest : BaseUsePermissionTest() { Manifest.permission.ACCESS_FINE_LOCATION private const val GROUP_3_PERMISSION_2_UNRESTRICTED = Manifest.permission.ACCESS_COARSE_LOCATION - private const val GROUP_4_PERMISSION_1_UNRESTRICTED = Manifest.permission.BODY_SENSORS + private const val GROUP_4_PERMISSION_1_UNRESTRICTED = Manifest.permission.CAMERA private const val NON_PROTECTED_SETTING = "example_setting_which_is_not_protected" private const val PROTECTED_SETTING = "android:bind_accessibility_service" diff --git a/tests/cts/permissionui/src/android/permissionui/cts/LocationAccuracyTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/LocationAccuracyTest.kt index 176010cf5..4781fb895 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/LocationAccuracyTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/LocationAccuracyTest.kt @@ -25,6 +25,7 @@ import com.android.modules.utils.build.SdkLevel import org.junit.Assume.assumeFalse import org.junit.Assume.assumeTrue import org.junit.Before +import org.junit.Ignore import org.junit.Test @FlakyTest @@ -50,6 +51,8 @@ class LocationAccuracyTest : BaseUsePermissionTest() { } @Test + @Ignore("b/390440965") + // Ignore this test until the cause of flakiness is identified. fun testCoarsePermissionIsGranted() { installPackage(APP_APK_PATH_31) @@ -69,16 +72,20 @@ class LocationAccuracyTest : BaseUsePermissionTest() { } @Test + @Ignore("b/396478581") + // Ignore this test until the cause of flakiness is identified. fun testPrecisePermissionIsGranted() { installPackage(APP_APK_PATH_31) assertAppHasPermission(ACCESS_FINE_LOCATION, false) assertAppHasPermission(ACCESS_COARSE_LOCATION, false) assertAppHasPermission(ACCESS_BACKGROUND_LOCATION, false) + val waitForWindowTransition = SdkLevel.isAtLeastB(); requestAppPermissionsAndAssertResult( ACCESS_FINE_LOCATION to true, - ACCESS_COARSE_LOCATION to true + ACCESS_COARSE_LOCATION to true, + waitForWindowTransition = waitForWindowTransition ) { clickPreciseLocationRadioButton() clickCoarseLocationRadioButton() diff --git a/tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionTest.kt index d41c7454f..5e2e40d20 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/MediaPermissionTest.kt @@ -17,12 +17,18 @@ package android.permissionui.cts import android.Manifest +import android.app.role.RoleManager +import android.content.pm.PackageManager import android.os.Build +import android.platform.test.annotations.AsbSecurityTest import androidx.test.filters.FlakyTest import androidx.test.filters.SdkSuppress +import androidx.test.uiautomator.By import com.android.compatibility.common.util.CddTest import com.android.compatibility.common.util.SystemUtil +import org.junit.Assert import org.junit.Assume +import org.junit.Assume.assumeTrue import org.junit.Test /** @@ -180,4 +186,33 @@ class MediaPermissionTest : BaseUsePermissionTest() { assertAppHasPermission(Manifest.permission.READ_MEDIA_VIDEO, true) assertAppHasPermission(Manifest.permission.READ_MEDIA_IMAGES, true) } + + + @Test + @AsbSecurityTest(cveBugId = [315320090]) + fun testGalleryAppListedAsFixed() { + val galleryPkgs = SystemUtil.callWithShellPermissionIdentity { + context.getSystemService(RoleManager::class.java) + .getRoleHolders(SYSTEM_GALLERY_ROLE_NAME) + } + assumeTrue(galleryPkgs.isNotEmpty()) + val galleryPkg = galleryPkgs[0] + val checkPermissionResult = SystemUtil.callWithShellPermissionIdentity { + packageManager.checkPermission(Manifest.permission.READ_MEDIA_IMAGES, galleryPkg) + } + assumeTrue(checkPermissionResult == PackageManager.PERMISSION_GRANTED) + navigateToIndividualPermissionSetting(Manifest.permission.READ_MEDIA_IMAGES, galleryPkg) + // Attempt to deny the permission. It should not show the + // "denying default permission dialog" + click(By.res(DENY_RADIO_BUTTON)) + try { + waitFindObject(By.res(CANCEL_BUTTON_ID), 1000L) + Assert.fail("expected not to find the default deny dialog") + } catch (_: Exception) {} + } + + companion object { + private val SYSTEM_GALLERY_ROLE_NAME = "android.app.role.SYSTEM_GALLERY" + private val CANCEL_BUTTON_ID = "android:id/button1" + } } diff --git a/tests/cts/permissionui/src/android/permissionui/cts/NotificationPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/NotificationPermissionTest.kt index c8298b19a..75a8914bf 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/NotificationPermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/NotificationPermissionTest.kt @@ -141,7 +141,7 @@ class NotificationPermissionTest : BaseUsePermissionTest() { launchApp() killTestApp() launchApp() - waitFindObject(By.textContains(ALLOW)) + waitFindObject(By.textContains(ALLOW).displayId(displayId)) clickPermissionRequestAllowButton() } @@ -201,9 +201,10 @@ class NotificationPermissionTest : BaseUsePermissionTest() { installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true) launchApp(startSecondActivity = true) if (isAutomotive || isWatch) { - waitFindObject(By.text(getPermissionControllerString(ALLOW_BUTTON_TEXT))) + waitFindObject( + By.text(getPermissionControllerString(ALLOW_BUTTON_TEXT)).displayId(displayId)) } else { - waitFindObject(By.res(ALLOW_BUTTON)) + waitFindObject(By.res(ALLOW_BUTTON).displayId(displayId)) } pressBack() clickPermissionRequestAllowButton() @@ -239,7 +240,7 @@ class NotificationPermissionTest : BaseUsePermissionTest() { try { // Watch does not have app bar if (!isWatch) { - waitFindObject(By.textContains(SECOND_ACTIVITY_LABEL)) + waitFindObject(By.textContains(SECOND_ACTIVITY_LABEL).displayId(displayId)) } assertDialogNotShowing() } finally { @@ -400,7 +401,7 @@ class NotificationPermissionTest : BaseUsePermissionTest() { // Watch does not have app bar if (!isWatch) { - waitFindObject(By.textContains(ACTIVITY_LABEL)) + waitFindObject(By.textContains(ACTIVITY_LABEL).displayId(displayId)) } } diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionRationalePermissionGrantDialogTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionRationalePermissionGrantDialogTest.kt index 751c56b3c..9a12765c0 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/PermissionRationalePermissionGrantDialogTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionRationalePermissionGrantDialogTest.kt @@ -41,8 +41,7 @@ import org.junit.Test @FlakyTest class PermissionRationalePermissionGrantDialogTest : BaseUsePermissionTest() { - @get:Rule - val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + @get:Rule val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() @get:Rule val deviceConfigPermissionRationaleEnabled = @@ -50,7 +49,7 @@ class PermissionRationalePermissionGrantDialogTest : BaseUsePermissionTest() { context, DeviceConfig.NAMESPACE_PRIVACY, PERMISSION_RATIONALE_ENABLED, - true.toString() + true.toString(), ) @Before @@ -248,8 +247,10 @@ class PermissionRationalePermissionGrantDialogTest : BaseUsePermissionTest() { } } - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName = - "VanillaIceCream") + @SdkSuppress( + minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, + codeName = "VanillaIceCream", + ) @RequiresFlagsEnabled(android.content.pm.Flags.FLAG_ASL_IN_APK_APP_METADATA_SOURCE) @Test fun requestCoarseLocationPerm_hasAslInApk_packageSourceUnspecified() { @@ -262,8 +263,10 @@ class PermissionRationalePermissionGrantDialogTest : BaseUsePermissionTest() { } } - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName = - "VanillaIceCream") + @SdkSuppress( + minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, + codeName = "VanillaIceCream", + ) @RequiresFlagsEnabled(android.content.pm.Flags.FLAG_ASL_IN_APK_APP_METADATA_SOURCE) @Test fun requestCoarseLocationPerm_hasAslInApk_packageSourceStore() { @@ -276,8 +279,10 @@ class PermissionRationalePermissionGrantDialogTest : BaseUsePermissionTest() { } } - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName = - "VanillaIceCream") + @SdkSuppress( + minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, + codeName = "VanillaIceCream", + ) @RequiresFlagsEnabled(android.content.pm.Flags.FLAG_ASL_IN_APK_APP_METADATA_SOURCE) @Test fun requestCoarseLocationPerm_hasAslInApk_packageSourceLocalFile() { @@ -290,8 +295,10 @@ class PermissionRationalePermissionGrantDialogTest : BaseUsePermissionTest() { } } - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName = - "VanillaIceCream") + @SdkSuppress( + minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, + codeName = "VanillaIceCream", + ) @RequiresFlagsEnabled(android.content.pm.Flags.FLAG_ASL_IN_APK_APP_METADATA_SOURCE) @Test fun requestCoarseLocationPerm_hasAslInApk_packageSourceDownloadedFile() { @@ -304,8 +311,10 @@ class PermissionRationalePermissionGrantDialogTest : BaseUsePermissionTest() { } } - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName = - "VanillaIceCream") + @SdkSuppress( + minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, + codeName = "VanillaIceCream", + ) @RequiresFlagsEnabled(android.content.pm.Flags.FLAG_ASL_IN_APK_APP_METADATA_SOURCE) @Test fun requestCoarseLocationPerm_hasAslInApk_packageSourceOther() { @@ -338,7 +347,6 @@ class PermissionRationalePermissionGrantDialogTest : BaseUsePermissionTest() { requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) { clickPermissionRationaleViewInGrantDialog() assertPermissionRationaleDialogIsVisible(true) - assertPermissionRationaleContainerOnGrantDialogIsVisible(false) } } diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt index d509add3a..17cef0e31 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt @@ -16,16 +16,33 @@ package android.permissionui.cts +import android.content.pm.PackageManager +import android.health.connect.HealthPermissions import android.os.Build +import android.permission.flags.Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED +import android.platform.test.annotations.RequiresFlagsDisabled +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.DeviceFlagsValueProvider import androidx.test.filters.FlakyTest import androidx.test.filters.SdkSuppress import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue import org.junit.Before +import org.junit.Rule import org.junit.Test /** Runtime permission behavior tests for permission splits. */ @FlakyTest class PermissionSplitTest : BaseUsePermissionTest() { + + companion object { + @JvmStatic + private val supportHeartrate = + packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_HEART_RATE) + } + + @Rule @JvmField val mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + @Before fun assumeNotTv() { assumeFalse(isTv) @@ -55,25 +72,113 @@ class PermissionSplitTest : BaseUsePermissionTest() { testLocationPermissionSplit(false) } - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu") + // TODO: b/388596433 - Update maxSdkVersion to VANILLA_ICE_CREAM after SDK bumps. + // TODO: b/383440585 - Remove this test when flag annotation issue is fixed. + @SdkSuppress( + minSdkVersion = Build.VERSION_CODES.TIRAMISU, + maxSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, + ) + @Test + fun testBodySensorSplitOnTToU() { + installPackage(APP_APK_PATH_31) + testBodySensorPermissionSplitToBodySensorsBackground(true) + } + + // Before SDK_INT bumps to 36, the in-development B images are using SDK_INT=35(V). This will + // cause test failures on main builds where replaceBodySensor flag is enabled to remove Sensor + // group UI. As a workaround, we move SDK_INT=35 tests out and requires replaceBodySensor flag + // disabled when running on these images. + // TODO: b/388596433 - Update minSdkVersion to BAKLAVA after SDK bumps. + // TODO: b/383440585 - Update minSdkVersion to TIRAMISU when flag annotation issue is fixed. + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + @RequiresFlagsDisabled(FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED) @Test - fun testBodySensorSplit() { + fun testBodySensorSplitPostV_replaceBodySensorFlagDisabled() { installPackage(APP_APK_PATH_31) - testBodySensorPermissionSplit(true) + testBodySensorPermissionSplitToBodySensorsBackground(true) } - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu") + // TODO: b/388596433 - Update maxSdkVersion to VANILLA_ICE_CREAM after SDK bumps. + // TODO: b/383440585 - Remove this test when flag annotation issue is fixed. + @SdkSuppress( + minSdkVersion = Build.VERSION_CODES.TIRAMISU, + maxSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, + ) @Test - fun testBodySensorSplit32() { + fun testBodySensorSplit32OnTToU() { installPackage(APP_APK_PATH_32) - testBodySensorPermissionSplit(true) + testBodySensorPermissionSplitToBodySensorsBackground(true) + } + + // Before SDK_INT bumps to 36, the in-development B images are using SDK_INT=35(V). This will + // cause test failures on main builds where replaceBodySensor flag is enabled to remove Sensor + // group UI. As a workaround, we move SDK_INT=35 tests out and requires replaceBodySensor flag + // disabled when running on these images. + // TODO: b/388596433 - Update minSdkVersion to BAKLAVA after SDK bumps. + // TODO: b/383440585 - Update minSdkVersion to TIRAMISU when flag annotation issue is fixed. + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + @RequiresFlagsDisabled(FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED) + @Test + fun testBodySensorSplit32PostV_replaceBodySensorFlagDisabled() { + installPackage(APP_APK_PATH_32) + testBodySensorPermissionSplitToBodySensorsBackground(true) + } + + // TODO: b/388596433 - Update maxSdkVersion to VANILLA_ICE_CREAM after SDK bumps. + // TODO: b/383440585 - Remove this test when flag annotation issue is fixed. + @SdkSuppress( + minSdkVersion = Build.VERSION_CODES.TIRAMISU, + maxSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, + ) + @Test + fun testBodySensorNonSplitOnTToU() { + installPackage(APP_APK_PATH_LATEST) + testBodySensorPermissionSplitToBodySensorsBackground(false) } - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu") + // Before SDK_INT bumps to 36, the in-development B images are using SDK_INT=35(V). This will + // cause test failures on main builds where replaceBodySensor flag is enabled to remove Sensor + // group UI. As a workaround, we move SDK_INT=35 tests out and requires replaceBodySensor flag + // disabled when running on these images. + // TODO: b/388596433 - Update minSdkVersion to BAKLAVA after SDK bumps. + // TODO: b/383440585 - Update minSdkVersion to TIRAMISU when flag annotation issue is fixed. + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + @RequiresFlagsDisabled(FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED) @Test - fun testBodySensorNonSplit() { + fun testBodySensorNonSplitPostV_replaceBodySensorFlagDisabled() { installPackage(APP_APK_PATH_LATEST) - testBodySensorPermissionSplit(false) + testBodySensorPermissionSplitToBodySensorsBackground(false) + } + + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @RequiresFlagsEnabled(FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED) + @Test + fun testBodySensorSplitOnBaklava_splitToReadHeartRate() { + assumeTrue(supportHeartrate) + installPackage(APP_APK_PATH_30_WITH_BACKGROUND) + assertAppHasPermission(android.Manifest.permission.BODY_SENSORS, false) + assertAppHasPermission(HealthPermissions.READ_HEART_RATE, false) + assertAppHasPermission(android.Manifest.permission.BODY_SENSORS_BACKGROUND, false) + assertAppHasPermission(HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND, false) + + requestAppPermissionsAndAssertResult( + android.Manifest.permission.BODY_SENSORS to true, + waitForWindowTransition = false, + ) { + clickAllowReadHeartRate() + } + + requestAppPermissionsAndAssertResult( + android.Manifest.permission.BODY_SENSORS_BACKGROUND to true, + waitForWindowTransition = false, + ) { + clickAlwaysAllowReadHealthDataInBackground() + } + + assertAppHasPermission(android.Manifest.permission.BODY_SENSORS, true) + assertAppHasPermission(HealthPermissions.READ_HEART_RATE, true) + assertAppHasPermission(android.Manifest.permission.BODY_SENSORS_BACKGROUND, true) + assertAppHasPermission(HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND, true) } private fun testLocationPermissionSplit(expectSplit: Boolean) { @@ -82,7 +187,7 @@ class PermissionSplitTest : BaseUsePermissionTest() { requestAppPermissionsAndAssertResult( android.Manifest.permission.ACCESS_FINE_LOCATION to true, - waitForWindowTransition = false + waitForWindowTransition = false, ) { if (expectSplit) { clickPermissionRequestSettingsLinkAndAllowAlways() @@ -98,13 +203,14 @@ class PermissionSplitTest : BaseUsePermissionTest() { assertAppHasPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, expectSplit) } - private fun testBodySensorPermissionSplit(expectSplit: Boolean) { + private fun testBodySensorPermissionSplitToBodySensorsBackground(expectSplit: Boolean) { + assumeTrue(supportHeartrate) assertAppHasPermission(android.Manifest.permission.BODY_SENSORS, false) assertAppHasPermission(android.Manifest.permission.BODY_SENSORS_BACKGROUND, false) requestAppPermissionsAndAssertResult( android.Manifest.permission.BODY_SENSORS to true, - waitForWindowTransition = false + waitForWindowTransition = false, ) { if (expectSplit) { clickPermissionRequestSettingsLinkAndAllowAlways() diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt index baebfe06f..68af60dde 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt @@ -52,14 +52,17 @@ class PermissionTapjackingTest : BaseUsePermissionTest() { requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {} val buttonCenter = - waitFindObject(By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT)) - .displayId(displayId)) + waitFindObject( + By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT)) + .displayId(displayId) + ) .visibleCenter // Wait for overlay to hide the dialog context.sendBroadcast(Intent(ACTION_SHOW_OVERLAY).putExtra(EXTRA_FULL_OVERLAY, true)) waitFindObject( - By.res("android.permissionui.cts.usepermission:id/overlay").displayId(displayId)) + By.res("android.permissionui.cts.usepermission:id/overlay").displayId(displayId) + ) tryClicking(buttonCenter) } @@ -76,18 +79,19 @@ class PermissionTapjackingTest : BaseUsePermissionTest() { assertAppHasPermission(ACCESS_FINE_LOCATION, false) requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {} - val foregroundButtonCenter = - waitFindObject(By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT)) - .displayId(displayId)) - .visibleCenter val oneTimeButton = - waitFindObjectOrNull(By.text(getPermissionControllerString(ALLOW_ONE_TIME_BUTTON_TEXT)) - .displayId(displayId)) + waitFindObjectOrNull( + By.text(getPermissionControllerString(ALLOW_ONE_TIME_BUTTON_TEXT)) + .displayId(displayId) + ) + // If one-time button is not available, fallback to deny button val overlayButtonBounds = oneTimeButton?.visibleBounds - ?: waitFindObject(By.text(getPermissionControllerString(DENY_BUTTON_TEXT)) - .displayId(displayId)) + ?: waitFindObject( + By.text(getPermissionControllerString(DENY_BUTTON_TEXT)) + .displayId(displayId) + ) .visibleBounds // Wait for overlay to hide the dialog @@ -100,7 +104,15 @@ class PermissionTapjackingTest : BaseUsePermissionTest() { .putExtra(OVERLAY_BOTTOM, overlayButtonBounds.bottom) ) waitFindObject( - By.res("android.permissionui.cts.usepermission:id/overlay").displayId(displayId)) + By.res("android.permissionui.cts.usepermission:id/overlay").displayId(displayId) + ) + + val foregroundButtonCenter = + waitFindObject( + By.text(getPermissionControllerString(ALLOW_FOREGROUND_BUTTON_TEXT)) + .displayId(displayId) + ) + .visibleCenter tryClicking(foregroundButtonCenter) } @@ -119,7 +131,7 @@ class PermissionTapjackingTest : BaseUsePermissionTest() { } assertAppHasPermission(ACCESS_FINE_LOCATION, true) }, - 10000 + 10000, ) } catch (e: RuntimeException) { // expected @@ -140,22 +152,26 @@ class PermissionTapjackingTest : BaseUsePermissionTest() { } assertAppHasPermission(ACCESS_FINE_LOCATION, true) }, - 10000 + 10000, ) } private fun click(buttonCenter: Point) { - val downTime = SystemClock.uptimeMillis() - val x= buttonCenter.x.toFloat() - val y = buttonCenter.y.toFloat() - var event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN,x , y, 0) - event.displayId = displayId - uiAutomation.injectInputEvent(event, true) - - val upTime = SystemClock.uptimeMillis() - event = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP, x, y, 0) - event.displayId = displayId - uiAutomation.injectInputEvent(event, true) + if (isAutomotiveVisibleBackgroundUser) { + val downTime = SystemClock.uptimeMillis() + val x = buttonCenter.x.toFloat() + val y = buttonCenter.y.toFloat() + var event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0) + event.displayId = displayId + uiAutomation.injectInputEvent(event, true) + + val upTime = SystemClock.uptimeMillis() + event = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP, x, y, 0) + event.displayId = displayId + uiAutomation.injectInputEvent(event, true) + } else { + uiDevice.click(buttonCenter.x, buttonCenter.y) + } } companion object { diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt index 9f76479e3..4a95a962a 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt @@ -39,16 +39,19 @@ 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 import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.BeforeClass +import org.junit.Ignore import org.junit.Test @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake") @FlakyTest +@Ignore("b/393428835") class PhotoPickerPermissionTest : BaseUsePermissionTest() { companion object { @@ -68,7 +71,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { NAMESPACE_PRIVACY, PICKER_ENABLED_SETTING, true.toString(), - false + false, ) } photoUri = PhotoPickerUtils.createImage(context) @@ -85,7 +88,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { NAMESPACE_PRIVACY, PICKER_ENABLED_SETTING, false.toString(), - false + false, ) } } @@ -110,7 +113,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 +128,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 +148,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 +164,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 +177,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 +212,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 +268,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 +281,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 +341,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 +366,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 +384,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 +402,7 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { requestAppPermissionsAndAssertResult( READ_MEDIA_IMAGES to true, READ_MEDIA_VIDEO to true, - waitForWindowTransition = false + waitForWindowTransition = false, ) {} } @@ -410,7 +413,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 +430,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 +443,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 +462,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 +477,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 +509,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 + } + } } diff --git a/tests/cts/permissionui/src/android/permissionui/cts/ReviewAccessibilityServicesTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/ReviewAccessibilityServicesTest.kt index e434e9c70..55f028e17 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/ReviewAccessibilityServicesTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/ReviewAccessibilityServicesTest.kt @@ -190,7 +190,7 @@ class ReviewAccessibilityServicesTest { !uiDevice.performActionAndWait( { block() }, Until.newWindow(), - NEW_WINDOW_TIMEOUT_MILLIS + NEW_WINDOW_TIMEOUT_MILLIS, ) if (timeoutOccurred) { @@ -212,17 +212,11 @@ class ReviewAccessibilityServicesTest { private fun waitForSettingsButtonToDisappear() { SystemUtil.eventually { - findPCObjectByClassAndText(false, - "android.widget.Button", - "Settings" - ) + findPCObjectByClassAndText(false, "android.widget.Button", "Settings") } } - private fun findObjectByTextWithoutRetry( - shouldBePresent: Boolean, - text: String, - ): UiObject2? { + private fun findObjectByTextWithoutRetry(shouldBePresent: Boolean, text: String): UiObject2? { val containsWithoutCaseSelector = By.text(Pattern.compile(".*$text.*", Pattern.CASE_INSENSITIVE)) val view = @@ -235,7 +229,7 @@ class ReviewAccessibilityServicesTest { assertEquals( "Expected to find view with text $text: $shouldBePresent", shouldBePresent, - view != null + view != null, ) return view } @@ -251,15 +245,16 @@ class ReviewAccessibilityServicesTest { private fun findPCObjectByClassAndText( shouldBePresent: Boolean, className: String, - text: String + text: String, ): UiObject2? { - val selector = By.pkg(packageName) - .clazz(className) - .text(text) + val selector = By.pkg(packageName).clazz(className).text(text) val view = waitFindObjectOrNull(selector) assertEquals( "Expected to find view with packageName '$packageName' className '$className' " + - "text '$text' : $shouldBePresent", shouldBePresent, view != null) + "text '$text' : $shouldBePresent", + shouldBePresent, + view != null, + ) return view } } diff --git a/tests/cts/permissionui/src/android/permissionui/cts/VoipCallHelper.kt b/tests/cts/permissionui/src/android/permissionui/cts/VoipCallHelper.kt new file mode 100644 index 000000000..480d7bff3 --- /dev/null +++ b/tests/cts/permissionui/src/android/permissionui/cts/VoipCallHelper.kt @@ -0,0 +1,171 @@ +/* + * 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 android.permissionui.cts + +import android.content.ComponentName +import android.content.Context +import android.net.Uri +import android.os.Bundle +import android.os.Process +import android.permissionui.cts.VoipCallHelper.Companion.EXTRA_DISPLAY_NAME +import android.permissionui.cts.VoipCallHelper.Companion.awaitingCallStateLatch +import android.permissionui.cts.VoipCallHelper.Companion.currentActiveConnection +import android.telecom.Connection +import android.telecom.ConnectionRequest +import android.telecom.ConnectionService +import android.telecom.DisconnectCause +import android.telecom.PhoneAccount +import android.telecom.PhoneAccountHandle +import android.telecom.TelecomManager +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import org.junit.Assert + +/** A helper class which can register a phone account, and make/end VOIP phone calls */ +class VoipCallHelper(val context: Context) { + private val telecomManager by lazy { context.getSystemService(TelecomManager::class.java) } + private lateinit var phoneAccount: PhoneAccount + private val accountHandle = + PhoneAccountHandle( + ComponentName(context, VoipHelperTestConnectionService::class.java), + "cts-voip-helper-test", + Process.myUserHandle(), + ) + + init { + registerPhoneAccount() + } + + companion object { + var currentActiveConnection: VoIPConnection? = null + var awaitingCallStateLatch: CallPlacedLatch? = null + + const val EXTRA_DISPLAY_NAME = "display_name" + const val CUSTOM_ADDRESS_SCHEMA = "custom_schema" + const val CALL_STATE_WAIT_MS = 1000L + const val CALL_TIMEOUT_MS = 10000L + } + + fun registerPhoneAccount() { + val phoneAccountBuilder = PhoneAccount.builder(accountHandle, "CTS VOIP HELPER") + phoneAccountBuilder.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED) + // see b/343674176. Some OEMs expect the PhoneAccount.getExtras() to be non-null + val defaultBundle = Bundle() + phoneAccountBuilder.setExtras(defaultBundle) + + // build and register the PhoneAccount via the Platform API + phoneAccount = phoneAccountBuilder.build() + telecomManager.registerPhoneAccount(phoneAccount) + } + + fun removePhoneAccount() { + telecomManager.unregisterPhoneAccount(phoneAccount.accountHandle) + } + + fun createCallAndWaitForActive(displayName: String?, phoneNumber: String?) { + val extras = Bundle() + + val phoneUri = + if (phoneNumber != null) { + Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null) + } else { + // If we don't have a phone number, provide a custom address URI, like many VOIP + // apps that aren't tied to a phone number do + Uri.fromParts(CUSTOM_ADDRESS_SCHEMA, "custom_address", null) + } + if (displayName != null) { + extras.putString(EXTRA_DISPLAY_NAME, displayName) + } + extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, phoneUri) + awaitingCallStateLatch = CallPlacedLatch(phoneUri, displayName) + telecomManager.addNewIncomingCall(phoneAccount.accountHandle, extras) + Assert.assertTrue( + "Timed out waiting for call to start", + awaitingCallStateLatch!!.await(CALL_TIMEOUT_MS, TimeUnit.MILLISECONDS), + ) + // TODO b/379941144: Replace wait with waiting until a test InCallService gets a callback + Thread.sleep(CALL_STATE_WAIT_MS) + } + + fun endCallAndWaitForInactive() { + currentActiveConnection?.let { connection -> + connection.setDisconnected(DisconnectCause(DisconnectCause.LOCAL)) + connection.destroy() + // TODO b/379941144: Replace wait with waiting until a test InCallService gets a + // callback + Thread.sleep(CALL_STATE_WAIT_MS) + } + currentActiveConnection = null + } +} + +class CallPlacedLatch(val address: Uri?, val displayName: String?) : CountDownLatch(1) { + fun nameAndNumberMatch(connection: Connection): Boolean { + return connection.address == address && connection.callerDisplayName == displayName + } +} + +class VoIPConnection : Connection() { + init { + setConnectionProperties(PROPERTY_SELF_MANAGED) + setAudioModeIsVoip(true) + setActive() + } + + override fun onShowIncomingCallUi() { + super.onShowIncomingCallUi() + setActive() + currentActiveConnection = this + if (awaitingCallStateLatch?.nameAndNumberMatch(this) == true) { + awaitingCallStateLatch?.countDown() + } + } +} + +class VoipHelperTestConnectionService : ConnectionService() { + override fun onCreateOutgoingConnection( + connectionManagerPhoneAccount: PhoneAccountHandle, + request: ConnectionRequest, + ): Connection { + return createConnection(request) + } + + override fun onCreateIncomingConnection( + connectionManagerPhoneAccount: PhoneAccountHandle?, + request: ConnectionRequest?, + ): Connection { + return createConnection(request) + } + + private fun createConnection(request: ConnectionRequest?): Connection { + val connection = VoIPConnection() + if (request?.extras?.containsKey(EXTRA_DISPLAY_NAME) == true) { + connection.setCallerDisplayName( + request.extras.getString(EXTRA_DISPLAY_NAME), + TelecomManager.PRESENTATION_ALLOWED, + ) + connection.setAddress( + request.extras.getParcelable( + TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, + Uri::class.java, + ), + TelecomManager.PRESENTATION_ALLOWED, + ) + } + return connection + } +} diff --git a/tests/cts/role/Android.bp b/tests/cts/role/Android.bp index f0095b7dd..ea9af5d8e 100644 --- a/tests/cts/role/Android.bp +++ b/tests/cts/role/Android.bp @@ -30,11 +30,16 @@ android_test { static_libs: [ "android.permission.flags-aconfig-java-export", "androidx.test.rules", + "com.android.permission.flags-aconfig-java-export", "compatibility-device-util-axt", "ctstestrunner-axt", "Harrier", + "bedstead-multiuser", + "flag-junit", "platform-test-annotations", + "platform-test-rules", "truth", + "uiautomator-helpers", ], test_suites: [ @@ -45,9 +50,17 @@ android_test { ], data: [ + ":CtsDefaultNotesApp", ":CtsRoleTestApp", ":CtsRoleTestApp28", ":CtsRoleTestApp33WithoutInCallService", ":CtsRoleTestAppClone", ], } + +filegroup { + name: "CtsRoleTestUtils", + srcs: [ + "src/android/app/role/cts/RoleManagerUtil.kt", + ], +} diff --git a/tests/cts/role/AndroidManifest.xml b/tests/cts/role/AndroidManifest.xml index a8c8c8e3d..7ea4287dc 100644 --- a/tests/cts/role/AndroidManifest.xml +++ b/tests/cts/role/AndroidManifest.xml @@ -22,6 +22,7 @@ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <application> diff --git a/tests/cts/role/AndroidTest.xml b/tests/cts/role/AndroidTest.xml index 73f23dd1b..9a60b09e3 100644 --- a/tests/cts/role/AndroidTest.xml +++ b/tests/cts/role/AndroidTest.xml @@ -32,6 +32,8 @@ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="CtsRoleTestCases.apk" /> + <option name="install-arg" value="-t" /> + <option name="test-file-name" value="CtsDefaultNotesApp.apk" /> </target_preparer> <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> @@ -40,6 +42,7 @@ </target_preparer> <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> <option name="cleanup" value="true" /> + <option name="push" value="CtsDefaultNotesApp.apk->/data/local/tmp/cts-role/CtsDefaultNotesApp.apk" /> <option name="push" value="CtsRoleTestApp.apk->/data/local/tmp/cts-role/CtsRoleTestApp.apk" /> <option name="push" value="CtsRoleTestApp28.apk->/data/local/tmp/cts-role/CtsRoleTestApp28.apk" /> <option name="push" value="CtsRoleTestApp33WithoutInCallService.apk->/data/local/tmp/cts-role/CtsRoleTestApp33WithoutInCallService.apk" /> diff --git a/tests/cts/role/src/android/app/role/cts/ChooseNoteRoleAppTest.kt b/tests/cts/role/src/android/app/role/cts/ChooseNoteRoleAppTest.kt new file mode 100644 index 000000000..18003d1d9 --- /dev/null +++ b/tests/cts/role/src/android/app/role/cts/ChooseNoteRoleAppTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2025 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 android.app.role.cts + +import android.content.Intent +import android.platform.test.rule.NotesRoleManagerRule +import android.platform.uiautomatorhelpers.WaitUtils.ensureThat +import android.provider.Settings +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.By.text +import com.android.compatibility.common.util.UiAutomatorUtils2.getUiDevice +import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +class ChooseNoteRoleAppTest { + + @[Rule JvmField] + val rule = NotesRoleManagerRule(requiredNotesRoleHolderPackage = NOTES_APP_PACKAGE_NAME) + + @Before + fun setUp() { + rule.utils.clearRoleHolder() + InstrumentationRegistry.getInstrumentation() + .context + .startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + } + + @After + fun after() { + getUiDevice().pressHome() + } + + @Test + fun chooseNoteRoleHolderApp() { + ensureThat { rule.utils.getRoleHolderPackageName().isEmpty() } + + // Scroll to "Notes app" item in Default apps screen and click on it + waitFindObject(text("Notes app")).click() + // Scroll to "CtsDefaultNotesApp" item and click on it + waitFindObject(text("CtsDefaultNotesApp")).click() + + assertEquals(rule.utils.getRoleHolderPackageName(), NOTES_APP_PACKAGE_NAME) + } + + private companion object { + const val NOTES_APP_PACKAGE_NAME = "com.android.cts.notesapp" + } +} diff --git a/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java b/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java index e31659dbc..5e61c66be 100644 --- a/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java +++ b/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java @@ -16,7 +16,9 @@ package android.app.role.cts; +import static com.android.bedstead.multiuser.MultiUserDeviceStateExtensionsKt.privateProfile; import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity; +import static com.android.compatibility.common.util.SystemUtil.eventually; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow; import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; @@ -25,6 +27,7 @@ import static com.android.compatibility.common.util.UiAutomatorUtils2.waitFindOb import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; @@ -66,7 +69,7 @@ import androidx.test.uiautomator.Until; import com.android.bedstead.harrier.BedsteadJUnit4; import com.android.bedstead.harrier.DeviceState; -import com.android.bedstead.harrier.annotations.EnsureHasPrivateProfile; +import com.android.bedstead.multiuser.annotations.EnsureHasPrivateProfile; import com.android.bedstead.nene.types.OptionalBoolean; import com.android.compatibility.common.util.DisableAnimationRule; import com.android.compatibility.common.util.FreezeRotationRule; @@ -103,6 +106,8 @@ public class RoleManagerTest { private static final String ROLE_NAME = RoleManager.ROLE_BROWSER; private static final String ROLE_PHONE_NAME = RoleManager.ROLE_DIALER; private static final String ROLE_SMS_NAME = RoleManager.ROLE_SMS; + private static final String PROFILE_GROUP_EXCLUSIVE_ROLE_NAME = + RoleManager.ROLE_RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY; private static final String ROLE_SHORT_LABEL = "Browser app"; private static final String APP_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestApp.apk"; @@ -164,6 +169,9 @@ public class RoleManagerTest { ? By.text("Don\u2019t ask again") : By.res("com.android.permissioncontroller:id/dont_ask_again"); + private static final BySelector PERMISSION_APP_LABEL = + By.pkg(sPackageManager.getPermissionControllerPackageName()).text(APP_LABEL); + @Rule public CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Rule @@ -184,6 +192,7 @@ public class RoleManagerTest { @Before public void setUp() throws Exception { + assumeTrue(RoleManagerUtil.INSTANCE.isCddCompliantScreenSize()); saveRoleHolder(); installApp(); wakeUpScreen(); @@ -281,6 +290,10 @@ public class RoleManagerTest { public void requestRoleThenBlockRequestRoleDialogByRestrictedSettingDialog() throws Exception { assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)); assumeFalse(sIsWatch || sIsAutomotive || sIsTelevision); + // TODO: b/388960315 - Remove wait after addressing race condition + runWithShellPermissionIdentity( + () -> waitForEnhancedConfirmationRestrictedAppOpMode(sContext, APP_PACKAGE_NAME, + AppOpsManager.MODE_DEFAULT)); runWithShellPermissionIdentity( () -> setEnhancedConfirmationRestrictedAppOpMode(sContext, APP_PACKAGE_NAME, AppOpsManager.MODE_ERRORED)); @@ -462,7 +475,7 @@ public class RoleManagerTest { private void respondToRoleRequest(boolean allow) throws InterruptedException, UiObjectNotFoundException { if (allow) { - waitFindObject(By.text(APP_LABEL)).click(); + waitFindObject(PERMISSION_APP_LABEL).click(); } Pair<Integer, Intent> result = clickButtonAndWaitForResult(allow); int expectedResult = allow ? Activity.RESULT_OK : Activity.RESULT_CANCELED; @@ -708,6 +721,10 @@ public class RoleManagerTest { throws Exception { assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER)); assumeFalse(sIsWatch || sIsAutomotive || sIsTelevision); + // TODO: b/388960315 - Remove wait after addressing race condition + runWithShellPermissionIdentity( + () -> waitForEnhancedConfirmationRestrictedAppOpMode(sContext, APP_PACKAGE_NAME, + AppOpsManager.MODE_DEFAULT)); runWithShellPermissionIdentity( () -> setEnhancedConfirmationRestrictedAppOpMode(sContext, APP_PACKAGE_NAME, AppOpsManager.MODE_ERRORED)); @@ -864,7 +881,7 @@ public class RoleManagerTest { return; } - UserHandle privateProfile = sDeviceState.privateProfile().userHandle(); + UserHandle privateProfile = privateProfile(sDeviceState).userHandle(); assertThat(privateProfile).isNotNull(); installPackage(APP_APK_PATH, privateProfile); installPackage(APP_CLONE_APK_PATH, privateProfile); @@ -918,6 +935,19 @@ public class RoleManagerTest { pressBack(); } + private void waitForEnhancedConfirmationRestrictedAppOpMode(@NonNull Context context, + @NonNull String packageName, int expectedMode) + throws PackageManager.NameNotFoundException { + final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); + eventually(() -> { + int uid = context.getPackageManager().getApplicationInfo(packageName, 0).uid; + int actualMode = appOpsManager.checkOpNoThrow( + AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS, uid, packageName); + assertEquals("Even after waiting, a test app's post-install" + + " ACCESS_RESTRICTED_SETTINGS op mode is incorrect", expectedMode, actualMode); + }); + } + private void setEnhancedConfirmationRestrictedAppOpMode(@NonNull Context context, @NonNull String packageName, int mode) throws PackageManager.NameNotFoundException { @@ -1347,6 +1377,241 @@ public class RoleManagerTest { }); } + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetActiveUserForRoleWithoutPermission() throws Exception { + assertThrows(SecurityException.class, () -> + sRoleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME)); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetActiveUserForNonProfileGroupExclusiveRole() throws Exception { + runWithShellPermissionIdentity(() -> + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.getActiveUserForRole( + RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER))); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetActiveUserForRoleWithoutPermission() throws Exception { + assertThrows(SecurityException.class, () -> + sRoleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + Process.myUserHandle(), 0)); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetActiveUserForNonProfileGroupExclusiveRole() throws Exception { + runWithShellPermissionIdentity(() -> + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.setActiveUserForRole( + RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER, Process.myUserHandle(), + 0))); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void setAndGetActiveUserForRole() throws Exception { + runWithShellPermissionIdentity(() -> { + sRoleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + Process.myUserHandle(), 0); + assertThat(sRoleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME)) + .isEqualTo(Process.myUserHandle()); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetDefaultHoldersForTestNoPermissions() throws Exception { + assertThrows(SecurityException.class, () -> + sRoleManager.getDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME)); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetDefaultHoldersForTestEmptyRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.getDefaultHoldersForTest("")); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetDefaultHoldersForTestNonTestRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.getDefaultHoldersForTest( + RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetDefaultHoldersForTestNoPermissions() throws Exception { + List<String> testRoleHolders = List.of("a", "b", "c"); + assertThrows(SecurityException.class, () -> + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + testRoleHolders)); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetDefaultHoldersForTestEmptyRoleName() throws Exception { + List<String> testRoleHolders = List.of("a", "b", "c"); + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.setDefaultHoldersForTest("", testRoleHolders)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetDefaultHoldersForTestNonTestRoleName() throws Exception { + List<String> testRoleHolders = List.of("a", "b", "c"); + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.setDefaultHoldersForTest( + RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER, testRoleHolders)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetDefaultHoldersForTestNullPackageNames() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(NullPointerException.class, () -> + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + null)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void setAndGetDefaultHolders() throws Exception { + List<String> testRoleHolders = List.of("a", "b", "c"); + runWithShellPermissionIdentity(() -> { + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + testRoleHolders); + List<String> roleHolders = + sRoleManager.getDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME); + assertThat(roleHolders).isEqualTo(testRoleHolders); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void setAndGetDefaultHoldersNoRoleHolders() throws Exception { + List<String> initialRoleHolders = List.of("a", "b", "c"); + List<String> testRoleHolders = Collections.emptyList(); + runWithShellPermissionIdentity(() -> { + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + initialRoleHolders); + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + testRoleHolders); + List<String> roleHolders = + sRoleManager.getDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME); + assertThat(roleHolders).isEqualTo(testRoleHolders); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetIsRoleVisibleForTestNoPermissions() throws Exception { + assertThrows(SecurityException.class, () -> + sRoleManager.isRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME)); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetIsRoleVisibleForTestEmptyRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.isRoleVisibleForTest("")); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetIsRoleVisibleForTestNonTestRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.isRoleVisibleForTest(RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetRoleVisibleForTestNoPermissions() throws Exception { + assertThrows(SecurityException.class, () -> + sRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, false)); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetRoleVisibleForTestEmptyRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.setRoleVisibleForTest("", false)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetRoleVisibleForTestNonTestRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.setRoleVisibleForTest(RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER, + false)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void setAndGetIsRoleVisibleForTestSetTrue() throws Exception { + runWithShellPermissionIdentity(() -> { + sRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, true); + boolean isRoleVisibleForTest = + sRoleManager.isRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME); + assertThat(isRoleVisibleForTest).isEqualTo(true); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void setAndGetIsRoleVisibleForTestSetFalse() throws Exception { + runWithShellPermissionIdentity(() -> { + sRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, false); + boolean isRoleVisibleForTest = + sRoleManager.isRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME); + assertThat(isRoleVisibleForTest).isEqualTo(false); + }); + } + @NonNull private List<String> getRoleHolders(@NonNull String roleName) throws Exception { return callWithShellPermissionIdentity(() -> sRoleManager.getRoleHolders(roleName)); diff --git a/tests/cts/role/src/android/app/role/cts/RoleManagerUtil.kt b/tests/cts/role/src/android/app/role/cts/RoleManagerUtil.kt new file mode 100644 index 000000000..10a3834a2 --- /dev/null +++ b/tests/cts/role/src/android/app/role/cts/RoleManagerUtil.kt @@ -0,0 +1,62 @@ +/* + * 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 android.app.role.cts + +import android.content.res.Configuration +import android.content.res.Resources +import android.util.Log + +object RoleManagerUtil { + private val TAG = RoleManagerUtil::class.java.getSimpleName() + + /** + * This method checks for the minimum screen size described in CDD {@see + * https://source.android.com/docs/compatibility/14/android-14-cdd#7111_screen_size_and_shape} + */ + fun isCddCompliantScreenSize(): Boolean { + if ( + Resources.getSystem().configuration.uiMode and Configuration.UI_MODE_TYPE_MASK == + Configuration.UI_MODE_TYPE_WATCH + ) { + Log.d(TAG, "UI mode is UI_MODE_TYPE_WATCH, skipping the min dp check") + return true + } + + val screenSize = + Resources.getSystem().configuration.screenLayout and + Configuration.SCREENLAYOUT_SIZE_MASK + return when (screenSize) { + Configuration.SCREENLAYOUT_SIZE_SMALL -> hasMinScreenSize(426, 320) + Configuration.SCREENLAYOUT_SIZE_NORMAL -> hasMinScreenSize(480, 320) + Configuration.SCREENLAYOUT_SIZE_LARGE -> hasMinScreenSize(640, 480) + Configuration.SCREENLAYOUT_SIZE_XLARGE -> hasMinScreenSize(960, 720) + else -> { + Log.e(TAG, "Unknown screen size: $screenSize") + true + } + } + } + + private fun hasMinScreenSize(minWidthDp: Int, minHeightDp: Int): Boolean { + val dpi = Resources.getSystem().displayMetrics.densityDpi + val widthDp = (160f / dpi) * Resources.getSystem().displayMetrics.widthPixels + val heightDp = (160f / dpi) * Resources.getSystem().displayMetrics.heightPixels + + // CDD does seem to follow width & height convention correctly, hence checking both ways + return (widthDp >= minWidthDp && heightDp >= minHeightDp) || + (widthDp >= minHeightDp && heightDp >= minWidthDp) + } +} diff --git a/tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt b/tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt index 83d4f78ad..c9dc97b8f 100644 --- a/tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt +++ b/tests/cts/role/src/android/app/role/cts/RoleShellCommandTest.kt @@ -19,15 +19,19 @@ package android.app.role.cts import android.app.role.RoleManager import android.os.Build import android.os.UserHandle +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.DeviceFlagsValueProvider import androidx.test.InstrumentationRegistry import androidx.test.filters.SdkSuppress import androidx.test.runner.AndroidJUnit4 import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow +import com.android.permission.flags.Flags import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Assert.assertThrows import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -43,6 +47,8 @@ class RoleShellCommandTest { private var roleHolder: String? = null private var wasBypassingRoleQualification: Boolean = false + @get:Rule val flagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + @Before public fun setUp() { saveRoleHolder() @@ -156,6 +162,31 @@ class RoleShellCommandTest { assertThat(isBypassingRoleQualification()).isFalse() } + @RequiresFlagsEnabled(Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + fun setActiveUserForProfileGroupExclusiveRoleAsUser() { + val activeUser = userId + setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, activeUser) + + val currentActiveUserId = getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + assertThat(currentActiveUserId).isEqualTo(activeUser) + } + + @RequiresFlagsEnabled(Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + fun setActiveUserForNonProfileGroupExclusiveRoleThenFails() { + assertThrows(AssertionError::class.java) { setActiveUserForRole(ROLE_NAME, userId) } + } + + @RequiresFlagsEnabled(Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + fun getActiveUserForNonProfileGroupExclusiveRoleThenFails() { + assertThrows(AssertionError::class.java) { getActiveUserForRole(ROLE_NAME) } + } + private fun addRoleHolder(packageName: String = APP_PACKAGE_NAME) { runShellCommandOrThrow("cmd role add-role-holder --user $userId $ROLE_NAME $packageName") } @@ -204,8 +235,22 @@ class RoleShellCommandTest { callWithShellPermissionIdentity { roleManager.setBypassingRoleQualification(value) } } + private fun getActiveUserForRole(roleName: String): Int? { + return runShellCommandOrThrow("cmd role get-active-user-for-role --user $userId $roleName") + .trim() + .toIntOrNull() + } + + private fun setActiveUserForRole(roleName: String, activeUserId: Int) { + runShellCommandOrThrow( + "cmd role set-active-user-for-role --user $userId $roleName $activeUserId" + ) + } + companion object { private const val ROLE_NAME = RoleManager.ROLE_BROWSER + private const val PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME = + RoleManager.ROLE_RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY private const val APP_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestApp.apk" private const val APP_PACKAGE_NAME = "android.app.role.cts.app" private const val APP_CLONE_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestAppClone.apk" diff --git a/tests/cts/rolemultiuser/Android.bp b/tests/cts/rolemultiuser/Android.bp new file mode 100644 index 000000000..51eff83b9 --- /dev/null +++ b/tests/cts/rolemultiuser/Android.bp @@ -0,0 +1,51 @@ +// 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_test { + name: "CtsRoleMultiUserTestCases", + defaults: ["mts-target-sdk-version-current"], + sdk_version: "test_current", + min_sdk_version: "30", + + srcs: [ + "src/**/*.kt", + ":CtsRoleTestUtils", + ], + + static_libs: [ + "bedstead-flags", + "bedstead-multiuser", + "com.android.permission.flags-aconfig-java-export", + "ctstestrunner-axt", + "Harrier", + "flag-junit", + "Nene", + "truth", + ], + + test_suites: [ + "cts", + "general-tests", + "mts-permission", + "mcts-permission", + ], + + data: [ + ":CtsRoleTestApp", + ], +} diff --git a/tests/cts/rolemultiuser/AndroidManifest.xml b/tests/cts/rolemultiuser/AndroidManifest.xml new file mode 100644 index 000000000..77710a5aa --- /dev/null +++ b/tests/cts/rolemultiuser/AndroidManifest.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + * 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. + --> + +<manifest + xmlns:android="http://schemas.android.com/apk/res/android" + package="android.app.rolemultiuser.cts"> + + <application> + <uses-library android:name="android.test.runner" /> + + <activity + android:name=".WaitForResultActivity" + android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"/> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.app.rolemultiuser.cts" + android:label="CTS multi-user tests of android.app.role"> + </instrumentation> +</manifest> diff --git a/tests/cts/rolemultiuser/AndroidTest.xml b/tests/cts/rolemultiuser/AndroidTest.xml new file mode 100644 index 000000000..510b70fdb --- /dev/null +++ b/tests/cts/rolemultiuser/AndroidTest.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ 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. + --> + +<configuration description="Config for CTS role multi-user test cases"> + + <option name="test-suite-tag" value="cts" /> + <option name="config-descriptor:metadata" key="component" value="permissions" /> + <option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" /> + <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" /> + <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" /> + <option name="config-descriptor:metadata" key="parameter" value="multiuser" /> + <option name="config-descriptor:metadata" key="parameter" value="secondary_user" /> + <option name="config-descriptor:metadata" key="parameter" value="run_on_sdk_sandbox" /> + <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.permission.apex" /> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" /> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="CtsRoleMultiUserTestCases.apk" /> + </target_preparer> + + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="run-command" value="mkdir -p /data/local/tmp/cts-role" /> + <option name="teardown-command" value="rm -rf /data/local/tmp/cts-role"/> + </target_preparer> + + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> + <option name="cleanup" value="true" /> + <option name="push" value="CtsRoleTestApp.apk->/data/local/tmp/cts-role/CtsRoleTestApp.apk" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="android.app.rolemultiuser.cts" /> + <option name="exclude-annotation" value="com.android.bedstead.enterprise.annotations.RequireRunOnWorkProfile" /> + <option name="exclude-annotation" value="com.android.bedstead.multiuser.annotations.RequireRunOnSecondaryUser" /> + <option name="runtime-hint" value="5m" /> + </test> +</configuration> diff --git a/tests/cts/rolemultiuser/TEST_MAPPING b/tests/cts/rolemultiuser/TEST_MAPPING new file mode 100644 index 000000000..b45469e14 --- /dev/null +++ b/tests/cts/rolemultiuser/TEST_MAPPING @@ -0,0 +1,17 @@ +{ + "presubmit": [ + { + "name": "CtsRoleMultiUserTestCases" + } + ], + "mainline-presubmit": [ + { + "name": "CtsRoleMultiUserTestCases[com.google.android.permission.apex]" + } + ], + "permission-mainline-presubmit": [ + { + "name": "CtsRoleMultiUserTestCases" + } + ] +} diff --git a/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt new file mode 100644 index 000000000..3e24d5025 --- /dev/null +++ b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt @@ -0,0 +1,2412 @@ +/* + * 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 android.app.rolemultiuser.cts + +import android.app.Activity +import android.app.role.RoleManager +import android.app.role.cts.RoleManagerUtil +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import android.os.Process +import android.os.UserHandle +import android.os.UserManager.DISALLOW_CONFIG_DEFAULT_APPS +import android.provider.Settings +import android.util.Log +import android.util.Pair +import androidx.test.filters.SdkSuppress +import androidx.test.rule.ActivityTestRule +import androidx.test.uiautomator.By +import com.android.bedstead.enterprise.annotations.EnsureDoesNotHaveUserRestriction +import com.android.bedstead.enterprise.annotations.EnsureHasNoWorkProfile +import com.android.bedstead.enterprise.annotations.EnsureHasUserRestriction +import com.android.bedstead.enterprise.annotations.EnsureHasWorkProfile +import com.android.bedstead.enterprise.annotations.RequireRunOnWorkProfile +import com.android.bedstead.enterprise.workProfile +import com.android.bedstead.flags.annotations.RequireFlagsEnabled +import com.android.bedstead.harrier.BedsteadJUnit4 +import com.android.bedstead.harrier.DeviceState +import com.android.bedstead.harrier.UserType.INITIAL_USER +import com.android.bedstead.harrier.UserType.WORK_PROFILE +import com.android.bedstead.multiuser.annotations.EnsureCanAddUser +import com.android.bedstead.multiuser.annotations.EnsureHasAdditionalUser +import com.android.bedstead.multiuser.annotations.EnsureHasPrivateProfile +import com.android.bedstead.multiuser.annotations.EnsureHasSecondaryUser +import com.android.bedstead.multiuser.annotations.RequireRunNotOnSecondaryUser +import com.android.bedstead.multiuser.annotations.RequireRunOnPrimaryUser +import com.android.bedstead.multiuser.privateProfile +import com.android.bedstead.multiuser.secondaryUser +import com.android.bedstead.nene.TestApis.context +import com.android.bedstead.nene.TestApis.permissions +import com.android.bedstead.nene.TestApis.users +import com.android.bedstead.nene.types.OptionalBoolean +import com.android.bedstead.nene.userrestrictions.CommonUserRestrictions.DISALLOW_ADD_MANAGED_PROFILE +import com.android.bedstead.nene.users.UserReference +import com.android.bedstead.nene.users.UserType +import com.android.bedstead.permissions.CommonPermissions.INTERACT_ACROSS_USERS_FULL +import com.android.bedstead.permissions.CommonPermissions.MANAGE_DEFAULT_APPLICATIONS +import com.android.bedstead.permissions.CommonPermissions.MANAGE_ROLE_HOLDERS +import com.android.bedstead.permissions.annotations.EnsureDoesNotHavePermission +import com.android.bedstead.permissions.annotations.EnsureHasPermission +import com.android.compatibility.common.util.DisableAnimationRule +import com.android.compatibility.common.util.FreezeRotationRule +import com.android.compatibility.common.util.SystemUtil +import com.android.compatibility.common.util.SystemUtil.eventually +import com.android.compatibility.common.util.UiAutomatorUtils2.getUiDevice +import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject +import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull +import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit +import java.util.function.Consumer +import org.junit.After +import org.junit.Assert.assertNull +import org.junit.Assert.assertThrows +import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.ClassRule +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") +@RunWith(BedsteadJUnit4::class) +class RoleManagerMultiUserTest { + + @JvmField + @Rule + var activityRule: ActivityTestRule<WaitForResultActivity> = + ActivityTestRule(WaitForResultActivity::class.java) + + @Before + fun setUp() { + assumeTrue(RoleManagerUtil.isCddCompliantScreenSize()) + installAppForAllUsers() + + // If "none" selected in test, ensure we re-enable fallback for other test runs + permissions().withPermission(MANAGE_ROLE_HOLDERS, INTERACT_ACROSS_USERS_FULL).use { + setRoleFallbackEnabledForAllUsers() + } + } + + @After + fun tearDown() { + uninstallAppForAllUsers() + + // If "none" selected in test, ensure we re-enable fallback for other test runs + permissions().withPermission(MANAGE_ROLE_HOLDERS, INTERACT_ACROSS_USERS_FULL).use { + setRoleFallbackEnabledForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile(installInstrumentedApp = OptionalBoolean.TRUE) + @EnsureHasPrivateProfile(installInstrumentedApp = OptionalBoolean.TRUE) + @RequireRunOnPrimaryUser + @Test + @Throws(Exception::class) + fun isAvailableAsUserForProfileGroupExclusiveRole() { + val workProfileRoleManager = getRoleManagerForUser(deviceState.workProfile()) + val privateProfileRoleManager = getRoleManagerForUser(deviceState.privateProfile()) + + assertThat(roleManager.isRoleAvailable(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)).isTrue() + assertThat(workProfileRoleManager.isRoleAvailable(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isTrue() + assertThat(privateProfileRoleManager.isRoleAvailable(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isFalse() + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @Test + @Throws(Exception::class) + fun cannotGetActiveUserForNonCrossUserRole() { + assertThrows(IllegalArgumentException::class.java) { + roleManager.getActiveUserForRole(RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER) + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(MANAGE_ROLE_HOLDERS) + @EnsureDoesNotHavePermission(INTERACT_ACROSS_USERS_FULL) + @Test + @Throws(Exception::class) + fun cannotGetActiveUserForRoleWithoutInteractAcrossUserPermission() { + assertThrows(SecurityException::class.java) { + roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL) + @EnsureDoesNotHavePermission(MANAGE_ROLE_HOLDERS, MANAGE_DEFAULT_APPLICATIONS) + @Test + @Throws(Exception::class) + fun cannotGetActiveUserForRoleWithoutManageRoleAndManageDefaultApplicationsPermission() { + assertThrows(SecurityException::class.java) { + roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @Test + @Throws(Exception::class) + fun cannotSetActiveUserForNonCrossUserRole() { + assertThrows(IllegalArgumentException::class.java) { + roleManager.setActiveUserForRole( + RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER, + Process.myUserHandle(), + 0, + ) + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(MANAGE_ROLE_HOLDERS) + @EnsureDoesNotHavePermission(INTERACT_ACROSS_USERS_FULL) + @Test + @Throws(Exception::class) + fun cannotSetActiveUserForRoleWithoutInteractAcrossUserPermission() { + assertThrows(SecurityException::class.java) { + roleManager.setActiveUserForRole( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + Process.myUserHandle(), + 0, + ) + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL) + @EnsureDoesNotHavePermission(MANAGE_ROLE_HOLDERS, MANAGE_DEFAULT_APPLICATIONS) + @Test + @Throws(Exception::class) + fun cannotSetActiveUserForRoleWithoutManageRoleAndManageDefaultApplicationsPermission() { + assertThrows(SecurityException::class.java) { + roleManager.setActiveUserForRole( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + Process.myUserHandle(), + 0, + ) + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @Test + @Throws(Exception::class) + fun cannotSetActiveUserForRoleToNonExistentUser() { + val targetActiveUser = users().nonExisting().userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, targetActiveUser, 0) + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isNotEqualTo(targetActiveUser) + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasPrivateProfile(installInstrumentedApp = OptionalBoolean.TRUE) + @Test + @Throws(Exception::class) + fun cannotSetActiveUserForRoleToPrivateProfileUser() { + val targetActiveUser = deviceState.privateProfile().userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, targetActiveUser, 0) + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isNotEqualTo(targetActiveUser) + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasAdditionalUser(installInstrumentedApp = OptionalBoolean.TRUE) + @EnsureHasSecondaryUser + @RequireRunNotOnSecondaryUser + @Test + @Throws(Exception::class) + fun cannotSetActiveUserForRoleToUserNotInProfileGroup() { + val targetActiveUser = deviceState.secondaryUser().userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, targetActiveUser, 0) + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isNotEqualTo(targetActiveUser) + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @EnsureHasAdditionalUser(installInstrumentedApp = OptionalBoolean.TRUE) + @EnsureHasSecondaryUser + @RequireRunNotOnSecondaryUser + @Test + @Throws(java.lang.Exception::class) + fun ensureRoleHasActiveUser() { + val primaryUser = deviceState.initialUser() + val primaryUserId = primaryUser.userHandle().identifier + val primaryUserRoleManager = getRoleManagerForUser(primaryUser) + val secondaryUser = deviceState.secondaryUser() + val secondaryUserId = secondaryUser.userHandle().identifier + val secondaryUserRoleManager = getRoleManagerForUser(secondaryUser) + + assertWithMessage("Expected active user in profile group for user $primaryUserId") + .that(primaryUserRoleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isNotNull() + assertWithMessage("Expected active user in profile group for user $secondaryUserId") + .that( + secondaryUserRoleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + ) + .isNotNull() + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureDoesNotHavePermission(MANAGE_DEFAULT_APPLICATIONS) + @EnsureHasWorkProfile(installInstrumentedApp = OptionalBoolean.TRUE) + @Test + @Throws(Exception::class) + fun setAndGetActiveUserForRoleSetCurrentUserWithManageRoleHoldersPermission() { + assumeFalse( + "setActiveUser not supported for private profile", + users().current().type().name() == PRIVATE_PROFILE_TYPE_NAME, + ) + + val targetActiveUser = users().current().userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, targetActiveUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_DEFAULT_APPLICATIONS) + @EnsureDoesNotHavePermission(MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile(installInstrumentedApp = OptionalBoolean.TRUE) + @Test + @Throws(Exception::class) + fun setAndGetActiveUserForRoleSetCurrentUserWithManageDefaultApplicationPermission() { + assumeFalse( + "setActiveUser not supported for private profile", + users().current().type().name() == PRIVATE_PROFILE_TYPE_NAME, + ) + + val targetActiveUser = users().current().userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, targetActiveUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile(installInstrumentedApp = OptionalBoolean.TRUE) + @Test + @Throws(Exception::class) + fun setAndGetActiveUserForRoleSetCurrentUserEnsureRoleNotHeldByInactiveUser() { + assumeFalse( + "setActiveUser not supported for private profile", + users().current().type().name() == PRIVATE_PROFILE_TYPE_NAME, + ) + // initialUser needs to be not the targetUser + val targetActiveUser = users().current().userHandle() + val initialUser = + if (targetActiveUser == deviceState.initialUser().userHandle()) { + deviceState.workProfile().userHandle() + } else { + deviceState.initialUser().userHandle() + } + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) + + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + + roleManager.setActiveUserForRole( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + targetActiveUser, + 0, + ) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + // We can assume targetActiveUser is role holder since fallback is enabled + eventually { assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) } + } finally { + clearDefaultHoldersForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile(installInstrumentedApp = OptionalBoolean.TRUE) + @Test + @Throws(Exception::class) + fun setAndGetActiveUserForRoleSetWorkProfile() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + + val targetActiveUser = deviceState.workProfile().userHandle() + roleManager.setActiveUserForRole( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + targetActiveUser, + 0, + ) + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + // We can assume targetActiveUser is role holder since fallback is enabled + eventually { assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) } + } finally { + setDefaultHoldersForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(MANAGE_ROLE_HOLDERS) + @EnsureDoesNotHavePermission(INTERACT_ACROSS_USERS_FULL) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(Exception::class) + fun cannotAddRoleHolderAsUserForProfileExclusiveRoleWithoutInteractAcrossUserPermission() { + // Set other user as active + val initialUser = deviceState.workProfile().userHandle() + // setActiveUserForRole and getActiveUserForRole is used to ensure initial active users + // state and requires INTERACT_ACROSS_USERS_FULL + permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + } + + val targetActiveUser = users().current().userHandle() + val future = CallbackFuture() + assertThrows(SecurityException::class.java) { + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + targetActiveUser, + context.mainExecutor, + future, + ) + } + assertThat( + roleManager.getRoleHoldersAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + targetActiveUser, + ) + ) + .isEmpty() + + // getActiveUserForRole is used to ensure addRoleHolderAsUser didn't set active user, and + // requires INTERACT_ACROSS_USERS_FULL + permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @Test + @Throws(java.lang.Exception::class) + fun addRoleHolderAsUserSetsCurrentUserAsActive() { + // Set other user as active + val initialUser = deviceState.workProfile().userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + + val targetActiveUser = users().current().userHandle() + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + targetActiveUser, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnWorkProfile + @Test + @Throws(java.lang.Exception::class) + fun addRoleHolderAsUserSetsWorkProfileAsActive() { + // Set other user as active + val initialUser = deviceState.initialUser().userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + + val targetActiveUser = deviceState.workProfile().userHandle() + + assertThat(targetActiveUser).isNotEqualTo(initialUser) + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + targetActiveUser, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun addRoleHolderAsUserReenablesFallbackOnProfileParent() { + // Set other user as active + val initialUserReference = deviceState.initialUser() + val initialUser = initialUserReference.userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + + val profileParentRoleManager = getRoleManagerForUser(initialUserReference) + profileParentRoleManager.setRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, false) + assertThat( + profileParentRoleManager.isRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + ) + .isFalse() + + val targetActiveUser = deviceState.workProfile().userHandle() + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + targetActiveUser, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat( + profileParentRoleManager.isRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + ) + .isTrue() + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(MANAGE_DEFAULT_APPLICATIONS) + @EnsureDoesNotHavePermission(INTERACT_ACROSS_USERS_FULL) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(Exception::class) + fun cannotSetDefaultApplicationForProfileExclusiveRoleWithoutInteractAcrossUserPermission() { + // Set other user as active + val initialUser = deviceState.workProfile().userHandle() + // setActiveUserForRole and getActiveUserForRole is used to ensure initial active users + // state and requires INTERACT_ACROSS_USERS_FULL + permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + } + + val future = CallbackFuture() + assertThrows(SecurityException::class.java) { + roleManager.setDefaultApplication( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + context.mainExecutor, + future, + ) + } + assertThat(roleManager.getDefaultApplication(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)).isNull() + + // getActiveUserForRole is used to ensure setDefaultApplication didn't set active user, + // and requires INTERACT_ACROSS_USERS_FULL + permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_DEFAULT_APPLICATIONS) + @EnsureHasWorkProfile + @Test + @Throws(java.lang.Exception::class) + fun setDefaultApplicationSetsCurrentUserAsActive() { + // Set other user as active + val initialUser = deviceState.workProfile().userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + + val targetActiveUser = users().current().userHandle() + val future = CallbackFuture() + roleManager.setDefaultApplication( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + eventually { assertExpectedProfileHasRoleUsingGetDefaultApplication(targetActiveUser) } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_DEFAULT_APPLICATIONS) + @EnsureHasWorkProfile + @RequireRunOnWorkProfile + @Test + @Throws(java.lang.Exception::class) + fun setDefaultApplicationSetsWorkProfileAsActive() { + // Set other user as active + val initialUser = deviceState.initialUser().userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + + val targetActiveUser = deviceState.workProfile().userHandle() + assertThat(targetActiveUser).isNotEqualTo(initialUser) + val future = CallbackFuture() + roleManager.setDefaultApplication( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + eventually { assertExpectedProfileHasRoleUsingGetDefaultApplication(targetActiveUser) } + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasPermission( + INTERACT_ACROSS_USERS_FULL, + MANAGE_DEFAULT_APPLICATIONS, + MANAGE_ROLE_HOLDERS, + ) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun setDefaultApplicationReenablesFallbackOnProfileParent() { + // Set other user as active + val initialUserReference = deviceState.initialUser() + val initialUser = initialUserReference.userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + + val profileParentRoleManager = getRoleManagerForUser(initialUserReference) + profileParentRoleManager.setRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, false) + assertThat( + profileParentRoleManager.isRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + ) + .isFalse() + + val future = CallbackFuture() + getRoleManagerForUser(deviceState.workProfile()) + .setDefaultApplication( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat( + profileParentRoleManager.isRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + ) + .isTrue() + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureCanAddUser + @EnsureHasNoWorkProfile + @RequireRunOnPrimaryUser + @EnsureDoesNotHaveUserRestriction(DISALLOW_ADD_MANAGED_PROFILE) + @Test + @Throws(Exception::class) + fun ensureActiveUserSetToParentOnUserRemoved() { + users() + .createUser() + .parent(users().initial()) + .type(users().supportedType(UserType.MANAGED_PROFILE_TYPE_NAME)) + .createAndStart() + .use { userReference -> + val targetActiveUser = userReference.userHandle() + roleManager.setActiveUserForRole( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + targetActiveUser, + 0, + ) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + + userReference.remove() + } + + // Removal of users in roles service might take a moment + eventually { + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(users().current().userHandle()) + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListAndSetDefaultAppThenIsDefaultApp() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click() + getUiDevice().waitForIdle() + + val targetActiveUser = users().current().userHandle() + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + if (isWatch) { + waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click() + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + .click() + } + + if (isWatch) { + waitFindObject( + By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel)) + ) + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true).checked(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + } + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + + pressBack() + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListAndSetWorkDefaultAppThenIsDefaultApp() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click() + getUiDevice().waitForIdle() + + val targetActiveUser = deviceState.workProfile().userHandle() + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + if (isWatch) { + waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click() + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + .click() + } + + if (isWatch) { + waitFindObject( + By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel)) + ) + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true).checked(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + } + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + + pressBack() + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListAndSetDefaultAppThenSetNoneThenHasNoneDefaultApp() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click() + getUiDevice().waitForIdle() + + val targetActiveUser = users().current().userHandle() + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + if (isWatch) { + waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click() + getUiDevice().waitForIdle() + waitFindObject(By.clickable(true).hasDescendant(By.text(NONE_LABEL))).click() + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + .click() + getUiDevice().waitForIdle() + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(NONE_LABEL)) + ) + .click() + } + + if (isWatch) { + waitFindObject(By.clickable(true).checked(true).hasDescendant(By.text(NONE_LABEL))) + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true).checked(true)) + .hasDescendant(By.text(NONE_LABEL)) + ) + } + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(deviceState.initialUser().userHandle()) + assertNoRoleHoldersUsingGetRoleHoldersAsUser() + + pressBack() + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListAndSetWorkDefaultAppThenSetNoneThenHasNoneDefaultApp() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click() + getUiDevice().waitForIdle() + + val targetActiveUser = deviceState.workProfile().userHandle() + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + if (isWatch) { + waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click() + getUiDevice().waitForIdle() + waitFindObject(By.clickable(true).hasDescendant(By.text(NONE_LABEL))).click() + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + .click() + getUiDevice().waitForIdle() + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(NONE_LABEL)) + ) + .click() + } + + if (isWatch) { + waitFindObject(By.clickable(true).checked(true).hasDescendant(By.text(NONE_LABEL))) + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true).checked(true)) + .hasDescendant(By.text(NONE_LABEL)) + ) + } + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(deviceState.initialUser().userHandle()) + assertNoRoleHoldersUsingGetRoleHoldersAsUser() + + pressBack() + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListAndSetDefaultAppThenIsDefaultAppInList() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click() + getUiDevice().waitForIdle() + + val targetActiveUser = users().current().userHandle() + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + if (isWatch) { + waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click() + waitFindObject( + By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel)) + ) + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + .click() + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true).checked(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + } + pressBack() + + waitFindObject(By.text(targetAppLabel)) + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListAndSetWorkDefaultAppThenIsDefaultAppInList() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click() + getUiDevice().waitForIdle() + + val targetActiveUser = deviceState.workProfile().userHandle() + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + if (isWatch) { + waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click() + waitFindObject( + By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel)) + ) + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + .click() + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true).checked(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + } + pressBack() + + waitFindObject(By.text(targetAppLabel)) + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListAndSetDefaultAppThenSetNoneThenIsNoneDefaultAppInList() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click() + getUiDevice().waitForIdle() + + val targetActiveUser = users().current().userHandle() + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + if (isWatch) { + waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click() + getUiDevice().waitForIdle() + waitFindObject(By.clickable(true).hasDescendant(By.text(NONE_LABEL))).click() + waitFindObject(By.clickable(true).checked(true).hasDescendant(By.text(NONE_LABEL))) + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + .click() + getUiDevice().waitForIdle() + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(NONE_LABEL)) + ) + .click() + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true).checked(true)) + .hasDescendant(By.text(NONE_LABEL)) + ) + } + pressBack() + + waitFindObject( + By.clickable(true) + .hasDescendant(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)) + .hasDescendant(By.text(NONE_LABEL)) + ) + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(deviceState.initialUser().userHandle()) + assertNoRoleHoldersUsingGetRoleHoldersAsUser() + + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListAndSetWorkDefaultAppThenSetNoneThenIsNoneDefaultAppInList() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click() + getUiDevice().waitForIdle() + + val targetActiveUser = deviceState.workProfile().userHandle() + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + if (isWatch) { + waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click() + getUiDevice().waitForIdle() + waitFindObject(By.clickable(true).hasDescendant(By.text(NONE_LABEL))).click() + waitFindObject(By.clickable(true).checked(true).hasDescendant(By.text(NONE_LABEL))) + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + .click() + getUiDevice().waitForIdle() + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(NONE_LABEL)) + ) + .click() + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true).checked(true)) + .hasDescendant(By.text(NONE_LABEL)) + ) + } + pressBack() + + waitFindObject( + By.clickable(true) + .hasDescendant(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)) + .hasDescendant(By.text(NONE_LABEL)) + ) + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(deviceState.initialUser().userHandle()) + assertNoRoleHoldersUsingGetRoleHoldersAsUser() + + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListFromPrimaryUserAndShowsPrimaryIsDefaultAppInList() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + val targetActiveUser = deviceState.initialUser().userHandle() + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + targetActiveUser, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + waitFindObject(By.text(targetAppLabel)) + + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListFromPrimaryUserAndShowsWorkIsDefaultAppInList() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + val targetActiveUser = deviceState.workProfile().userHandle() + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + targetActiveUser, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + waitFindObject(By.text(targetAppLabel)) + + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnWorkProfile + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListFromWorkProfileAndShowsPrimaryIsDefaultAppInList() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + val targetActiveUser = deviceState.initialUser().userHandle() + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + targetActiveUser, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + waitFindObject(By.text(targetAppLabel)) + + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnWorkProfile + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListFromWorkProfileAndShowsWorkIsDefaultAppInList() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + val targetActiveUser = deviceState.workProfile().userHandle() + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + targetActiveUser, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + waitFindObject(By.text(targetAppLabel)) + + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun requestRoleAndAllowPrimaryThenIsRoleHolder() { + try { + // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-primary selected first. Request exits early if user and package + // already the role holder + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + deviceState.workProfile().userHandle(), + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + } + + requestRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + + val targetActiveUser = deviceState.initialUser().userHandle() + respondToRoleRequest(true, targetActiveUser) + + // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and + // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role + // holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + } + } finally { + // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun requestRoleAndAllowWorkThenWorkIsRoleHolder() { + try { + // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-primary selected first. Request exits early if user and package + // already the role holder + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + deviceState.workProfile().userHandle(), + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + } + + requestRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + + val targetActiveUser = deviceState.workProfile().userHandle() + respondToRoleRequest(true, targetActiveUser) + + // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and + // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role + // holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + } + } finally { + // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun requestRoleAndSelectNoneThenIsNoneRoleHolder() { + try { + // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-primary selected first. Request exits early if user and package + // already the role holder + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + deviceState.workProfile().userHandle(), + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + } + + requestRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + respondNoneToRoleRequest() + + // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and + // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role + // holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(deviceState.initialUser().userHandle()) + assertNoRoleHoldersUsingGetRoleHoldersAsUser() + } + } finally { + // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasWorkProfile + @RequireRunOnWorkProfile + @Test + @Throws(java.lang.Exception::class) + fun requestRoleFromWorkProfileAndAllowPrimaryThenIsRoleHolder() { + try { + // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-work selected first. Request exits early if user and package + // already the role holder + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + deviceState.initialUser().userHandle(), + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + } + + requestRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + + val targetActiveUser = deviceState.initialUser().userHandle() + respondToRoleRequest(true, targetActiveUser) + + // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and + // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role + // holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + } + } finally { + // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasWorkProfile + @RequireRunOnWorkProfile + @Test + @Throws(java.lang.Exception::class) + fun requestRoleFromWorkProfileAndAllowWorkThenWorkIsRoleHolder() { + try { + // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-work selected first. Request exits early if user and package + // already the role holder + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + deviceState.initialUser().userHandle(), + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + } + + requestRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + + val targetActiveUser = deviceState.workProfile().userHandle() + respondToRoleRequest(true, targetActiveUser) + + // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and + // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role + // holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + } + } finally { + // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasWorkProfile + @RequireRunOnWorkProfile + @Test + @Throws(java.lang.Exception::class) + fun requestRoleFromWorkProfileAndSelectNoneThenIsNoneRoleHolder() { + try { + // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-work selected first. Request exits early if user and package + // already the role holder + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + deviceState.initialUser().userHandle(), + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + } + + requestRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + respondNoneToRoleRequest() + + // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and + // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role + // holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(deviceState.initialUser().userHandle()) + assertNoRoleHoldersUsingGetRoleHoldersAsUser() + } + } finally { + // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasUserRestriction(value = DISALLOW_CONFIG_DEFAULT_APPS, onUser = INITIAL_USER) + @EnsureHasWorkProfile(isOrganizationOwned = false) + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListAndOpenDefaultAppWhenBYODHasUserRestrictionOnPrimaryProfile() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click() + getUiDevice().waitForIdle() + + // CollapsingToolbar title can't be found by text, so using description instead. + waitFindObject(By.desc(PROFILE_GROUP_EXCLUSIVITY_ROLE_LABEL)) + + pressBack() + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasUserRestriction(value = DISALLOW_CONFIG_DEFAULT_APPS, onUser = INITIAL_USER) + @EnsureHasWorkProfile(isOrganizationOwned = true) + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListAndCannotOpenDefaultAppWhenHasUserRestrictionOnPrimaryProfile() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click() + getUiDevice().waitForIdle() + + // CollapsingToolbar title can't be found by text, so using description instead. + assertNull( + waitFindObjectOrNull( + By.desc(PROFILE_GROUP_EXCLUSIVITY_ROLE_LABEL), + IDLE_TIMEOUT_MILLIS, + ) + ) + + pressBack() + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasUserRestriction(value = DISALLOW_CONFIG_DEFAULT_APPS, onUser = WORK_PROFILE) + @EnsureHasWorkProfile(isOrganizationOwned = true) + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppListAndCannotOpenDefaultAppWhenHasUserRestrictionOnWorkProfile() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + context.startActivity( + Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) + .addCategory(Intent.CATEGORY_DEFAULT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + waitFindObject(By.text(PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL)).click() + getUiDevice().waitForIdle() + + // CollapsingToolbar title can't be found by text, so using description instead. + assertNull( + waitFindObjectOrNull( + By.desc(PROFILE_GROUP_EXCLUSIVITY_ROLE_LABEL), + IDLE_TIMEOUT_MILLIS, + ) + ) + + pressBack() + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasUserRestriction(value = DISALLOW_CONFIG_DEFAULT_APPS, onUser = INITIAL_USER) + @EnsureHasWorkProfile(isOrganizationOwned = false) + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppDetailsAndSetDefaultAppWhenBYODHasUserRestrictionOnPrimaryProfile() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-target selected first. Request exits early if user and package + // already the role holder + val initialActiveUser = deviceState.workProfile().userHandle() + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + initialActiveUser, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + + context.startActivity( + Intent(Intent.ACTION_MANAGE_DEFAULT_APP) + .addCategory(Intent.CATEGORY_DEFAULT) + .putExtra(Intent.EXTRA_ROLE_NAME, PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + + val targetActiveUser = users().current().userHandle() + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + if (isWatch) { + waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click() + waitFindObject( + By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel)) + ) + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + .click() + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true).checked(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + } + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + + pressBack() + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasUserRestriction(value = DISALLOW_CONFIG_DEFAULT_APPS, onUser = INITIAL_USER) + @EnsureHasWorkProfile(isOrganizationOwned = true) + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppDetailsAndCannotSetDefaultAppWhenHasUserRestrictionOnPrimaryProfile() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-target selected first. Request exits early if user and package + // already the role holder + val initialActiveUser = deviceState.workProfile().userHandle() + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + initialActiveUser, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + + context.startActivity( + Intent(Intent.ACTION_MANAGE_DEFAULT_APP) + .addCategory(Intent.CATEGORY_DEFAULT) + .putExtra(Intent.EXTRA_ROLE_NAME, PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + + val targetActiveUser = users().current().userHandle() + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + if (isWatch) { + waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click() + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + .click() + } + + if (isWatch) { + assertNull( + waitFindObjectOrNull( + By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel)), + IDLE_TIMEOUT_MILLIS, + ) + ) + } else { + assertNull( + waitFindObjectOrNull( + By.clickable(true) + .hasDescendant(By.checkable(true).checked(true)) + .hasDescendant(By.text(targetAppLabel)), + IDLE_TIMEOUT_MILLIS, + ) + ) + } + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(initialActiveUser) + + pressBack() + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasUserRestriction(value = DISALLOW_CONFIG_DEFAULT_APPS, onUser = WORK_PROFILE) + @EnsureHasWorkProfile(isOrganizationOwned = true) + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun openDefaultAppDetailsAndCannotSetDefaultAppWhenHasUserRestrictionOnWorkProfile() { + try { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-target selected first. Request exits early if user and package + // already the role holder + val initialActiveUser = deviceState.workProfile().userHandle() + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + initialActiveUser, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + + context.startActivity( + Intent(Intent.ACTION_MANAGE_DEFAULT_APP) + .addCategory(Intent.CATEGORY_DEFAULT) + .putExtra(Intent.EXTRA_ROLE_NAME, PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + ) + getUiDevice().waitForIdle() + + val targetActiveUser = users().current().userHandle() + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + if (isWatch) { + waitFindObject(By.clickable(true).hasDescendant(By.text(targetAppLabel))).click() + } else { + waitFindObject( + By.clickable(true) + .hasDescendant(By.checkable(true)) + .hasDescendant(By.text(targetAppLabel)) + ) + .click() + } + + if (isWatch) { + assertNull( + waitFindObjectOrNull( + By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel)), + IDLE_TIMEOUT_MILLIS, + ) + ) + } else { + assertNull( + waitFindObjectOrNull( + By.clickable(true) + .hasDescendant(By.checkable(true).checked(true)) + .hasDescendant(By.text(targetAppLabel)), + IDLE_TIMEOUT_MILLIS, + ) + ) + } + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(initialActiveUser) + + pressBack() + pressBack() + } finally { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasUserRestriction(value = DISALLOW_CONFIG_DEFAULT_APPS, onUser = INITIAL_USER) + @EnsureHasWorkProfile(isOrganizationOwned = false) + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun requestRoleAllowedWhenBYODHasUserRestrictionOnPrimaryProfile() { + try { + // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-primary selected first. Request exits early if user and package + // already the role holder + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + deviceState.workProfile().userHandle(), + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + } + + requestRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + + val targetActiveUser = deviceState.initialUser().userHandle() + respondToRoleRequest(true, targetActiveUser) + + // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and + // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role + // holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + } + } finally { + // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasUserRestriction(value = DISALLOW_CONFIG_DEFAULT_APPS, onUser = INITIAL_USER) + @EnsureHasWorkProfile(isOrganizationOwned = true) + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun requestRoleDeniedWhenHasUserRestrictionOnPrimaryProfile() { + try { + // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-primary selected first. Request exits early if user and package + // already the role holder + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + deviceState.workProfile().userHandle(), + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + } + + requestRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + roleRequestNotShown() + } finally { + // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + } + + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasUserRestriction(value = DISALLOW_CONFIG_DEFAULT_APPS, onUser = WORK_PROFILE) + @EnsureHasWorkProfile(isOrganizationOwned = true) + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun requestRoleDeniedWhenHasUserRestrictionOnWorkProfile() { + try { + // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + // Set test default role holder. Ensures fallbacks to a default holder + setDefaultHoldersForTestForAllUsers() + setRoleVisibleForTestForAllUsers() + + // Ensure non-primary selected first. Request exits early if user and package + // already the role holder + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + deviceState.workProfile().userHandle(), + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + } + + requestRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + roleRequestNotShown() + } finally { + // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require + // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user + // role active user and role holder states + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { + clearDefaultHoldersForTestForAllUsers() + clearRoleVisibleForTestForAllUsers() + } + } + } + + private fun installAppForAllUsers() { + SystemUtil.runShellCommandOrThrow("pm install -r --user all $APP_APK_PATH") + } + + private fun uninstallAppForAllUsers() { + SystemUtil.runShellCommand("pm uninstall $APP_PACKAGE_NAME") + } + + private fun pressBack() { + getUiDevice().pressBack() + getUiDevice().waitForIdle() + } + + private fun requestRole(roleName: String) { + val intent = + Intent() + .setComponent(ComponentName(APP_PACKAGE_NAME, APP_REQUEST_ROLE_ACTIVITY_NAME)) + .putExtra(Intent.EXTRA_ROLE_NAME, roleName) + activityRule.getActivity().startActivityToWaitForResult(intent) + } + + private fun respondToRoleRequest(allow: Boolean, targetActiveUser: UserHandle) { + if (allow) { + val targetAppLabel = "$APP_LABEL@${targetActiveUser.identifier}" + waitFindObject(By.text(targetAppLabel)).click() + } + val result: Pair<Int, Intent?> = clickButtonAndWaitForResult(allow) + val expectedResult = + if (allow && targetActiveUser == users().instrumented().userHandle()) Activity.RESULT_OK + else Activity.RESULT_CANCELED + + assertThat(result.first).isEqualTo(expectedResult) + } + + private fun respondNoneToRoleRequest() { + waitFindObject(By.text(NONE_LABEL)).click() + val result: Pair<Int, Intent?> = clickButtonAndWaitForResult(true) + assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED) + } + + private fun clickButtonAndWaitForResult(positive: Boolean): Pair<Int, Intent?> { + waitFindObject(if (positive) POSITIVE_BUTTON_SELECTOR else NEGATIVE_BUTTON_SELECTOR).click() + return waitForResult() + } + + private fun roleRequestNotShown() { + val requestRoleItem = + waitFindObjectOrNull(By.textStartsWith(APP_LABEL), IDLE_TIMEOUT_MILLIS) + assertNull(requestRoleItem) + + val result: Pair<Int, Intent?> = waitForResult() + assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED) + } + + @Throws(InterruptedException::class) + private fun waitForResult(): Pair<Int, Intent?> { + return activityRule.getActivity().waitForActivityResult(TIMEOUT_MILLIS) + } + + private fun assertNoRoleHoldersUsingGetRoleHoldersAsUser() { + for (userReference in users().profileGroup(deviceState.initialUser())) { + val user = userReference.userHandle() + // Verify the non-active user does not hold the role + assertWithMessage( + "Expected user ${user.identifier} to not have a role holder for" + + " $PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME" + ) + .that(roleManager.getRoleHoldersAsUser(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, user)) + .isEmpty() + } + } + + private fun assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser( + expectedActiveUser: UserHandle + ) { + for (userReference in users().profileGroup(deviceState.initialUser())) { + val user = userReference.userHandle() + val roleHolders = + roleManager.getRoleHoldersAsUser(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, user) + if (user == expectedActiveUser) { + assertWithMessage( + "Expected user ${user.identifier} to have a role holder for " + + " $PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME" + ) + .that(roleHolders) + .isNotEmpty() + assertWithMessage( + "Expected user ${user.identifier} to have $APP_PACKAGE_NAME as role " + + "holder for $PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME" + ) + .that(roleHolders.first()) + .isEqualTo(APP_PACKAGE_NAME) + } else { + // Verify the non-active user does not hold the role + assertWithMessage( + "Expected user ${user.identifier} to not have a role holder for" + + " $PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME" + ) + .that(roleHolders) + .isEmpty() + } + } + } + + private fun assertExpectedProfileHasRoleUsingGetDefaultApplication( + expectedActiveUser: UserHandle + ) { + for (userReference in users().profileGroup(deviceState.initialUser())) { + val userRoleManager = getRoleManagerForUser(userReference) + val user = userReference.userHandle() + if (user == expectedActiveUser) { + assertWithMessage("Expected default application for user ${user.identifier}") + .that( + userRoleManager.getDefaultApplication(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + ) + .isEqualTo(APP_PACKAGE_NAME) + } else { + // Verify the non-active user does not hold the role + assertWithMessage("Expected no default application for user ${user.identifier}") + .that( + userRoleManager.getDefaultApplication(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + ) + .isNull() + } + } + } + + private fun setDefaultHoldersForTestForAllUsers() { + // Set test default role holder. Ensures fallbacks to a default holder + for (userRoleManager in + users().profileGroup(users().current()).map { getRoleManagerForUser(it) }) { + userRoleManager.setDefaultHoldersForTest( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + listOf(APP_PACKAGE_NAME), + ) + } + } + + private fun clearDefaultHoldersForTestForAllUsers() { + // Set test default role holder. Ensures fallbacks to a default holder + for (userRoleManager in + users().profileGroup(users().current()).map { getRoleManagerForUser(it) }) { + userRoleManager.setDefaultHoldersForTest( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + emptyList(), + ) + } + } + + private fun setRoleVisibleForTestForAllUsers() { + // Set test default role holder. Ensures fallbacks to a default holder + for (userRoleManager in + users().profileGroup(users().current()).map { getRoleManagerForUser(it) }) { + userRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, true) + } + } + + private fun clearRoleVisibleForTestForAllUsers() { + // Set test default role holder. Ensures fallbacks to a default holder + for (userRoleManager in + users().profileGroup(users().current()).map { getRoleManagerForUser(it) }) { + userRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, false) + } + } + + private fun setRoleFallbackEnabledForAllUsers() { + for (userReference in users().profileGroup(users().current())) { + try { + val userRoleManager = getRoleManagerForUser(userReference) + userRoleManager.setRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, true) + } catch (e: Exception) { + Log.w( + LOG_TAG, + "Encountered error setting fallback enabled for" + + " $PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME@" + + "${userReference.userHandle().identifier}", + e, + ) + } + } + } + + private fun getRoleManagerForUser(user: UserReference): RoleManager { + val userContext = context().androidContextAsUser(user) + return userContext.getSystemService(RoleManager::class.java) + } + + class CallbackFuture : CompletableFuture<Boolean?>(), Consumer<Boolean?> { + override fun accept(successful: Boolean?) { + complete(successful) + } + } + + companion object { + private val LOG_TAG = RoleManagerMultiUserTest::class.java.simpleName + + private const val TIMEOUT_MILLIS: Long = (15 * 1000).toLong() + private const val IDLE_TIMEOUT_MILLIS: Long = (2 * 1000).toLong() + private const val PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME = + RoleManager.ROLE_RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY + private const val PROFILE_GROUP_EXCLUSIVITY_ROLE_LABEL = + "Default test profile group exclusive role app" + private const val PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL = + "Test profile group exclusive role app" + private const val PRIVATE_PROFILE_TYPE_NAME = "android.os.usertype.profile.PRIVATE" + private const val APP_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestApp.apk" + private const val APP_PACKAGE_NAME = "android.app.role.cts.app" + private const val APP_LABEL = "CtsRoleTestApp" + private const val APP_REQUEST_ROLE_ACTIVITY_NAME = APP_PACKAGE_NAME + ".RequestRoleActivity" + private const val NONE_LABEL = "None" + + private val context: Context = context().instrumentedContext() + private val roleManager: RoleManager = context.getSystemService(RoleManager::class.java) + private val packageManager: PackageManager = context.packageManager + private val isWatch = packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH) + + private val NEGATIVE_BUTTON_SELECTOR = + if (isWatch) By.text("Cancel") else By.res("android:id/button2") + private val POSITIVE_BUTTON_SELECTOR = + if (isWatch) By.text("Set as default") else By.res("android:id/button1") + + @JvmField @ClassRule @Rule val deviceState = DeviceState() + + @JvmField + @ClassRule + @Rule + var disableAnimationRule: DisableAnimationRule = DisableAnimationRule() + + @JvmField @ClassRule @Rule var freezeRotationRule: FreezeRotationRule = FreezeRotationRule() + } +} diff --git a/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/WaitForResultActivity.kt b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/WaitForResultActivity.kt new file mode 100644 index 000000000..84590ce91 --- /dev/null +++ b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/WaitForResultActivity.kt @@ -0,0 +1,67 @@ +/* + * 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 android.app.rolemultiuser.cts + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.util.Pair +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit + +/** An Activity that can start another Activity and wait for its result. */ +class WaitForResultActivity : Activity() { + private var mLatch: CountDownLatch? = null + private var mResultCode = 0 + private var mData: Intent? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + if (savedInstanceState != null) { + throw RuntimeException( + ("Activity was recreated (perhaps due to a configuration change?) " + + "and this activity doesn't currently know how to gracefully handle " + + "configuration changes.") + ) + } + } + + fun startActivityToWaitForResult(intent: Intent) { + mLatch = CountDownLatch(1) + startActivityForResult(intent, REQUEST_CODE_WAIT_FOR_RESULT) + } + + @Throws(InterruptedException::class) + fun waitForActivityResult(timeoutMillis: Long): Pair<Int, Intent?> { + mLatch!!.await(timeoutMillis, TimeUnit.MILLISECONDS) + return Pair(mResultCode, mData) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + if (requestCode == REQUEST_CODE_WAIT_FOR_RESULT) { + mResultCode = resultCode + mData = data + mLatch!!.countDown() + } else { + super.onActivityResult(requestCode, resultCode, data) + } + } + + companion object { + private const val REQUEST_CODE_WAIT_FOR_RESULT = 1 + } +} diff --git a/tests/cts/safetycenter/AndroidTest.xml b/tests/cts/safetycenter/AndroidTest.xml index 6d8c3069c..ed161f0b6 100644 --- a/tests/cts/safetycenter/AndroidTest.xml +++ b/tests/cts/safetycenter/AndroidTest.xml @@ -47,6 +47,10 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS --receiver-foreground" /> </target_preparer> diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt index c344d7ebd..1320c2ff9 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterDataTest.kt @@ -492,8 +492,8 @@ class SafetyCenterDataTest { status1, listOf(issue1), listOf(entryOrGroup1), - listOf(staticEntryGroup1) - ) + listOf(staticEntryGroup1), + ), ) .addEqualityGroup( data2, @@ -501,19 +501,19 @@ class SafetyCenterDataTest { status2, listOf(issue2), listOf(entryOrGroup2), - listOf(staticEntryGroup2) - ) + listOf(staticEntryGroup2), + ), ) .addEqualityGroup( SafetyCenterData(status1, listOf(), listOf(), listOf()), - SafetyCenterData(status1, listOf(), listOf(), listOf()) + SafetyCenterData(status1, listOf(), listOf(), listOf()), ) .addEqualityGroup( SafetyCenterData( status2, listOf(issue1), listOf(entryOrGroup1), - listOf(staticEntryGroup1) + listOf(staticEntryGroup1), ) ) .addEqualityGroup( @@ -521,7 +521,7 @@ class SafetyCenterDataTest { status1, listOf(issue2), listOf(entryOrGroup1), - listOf(staticEntryGroup1) + listOf(staticEntryGroup1), ) ) .addEqualityGroup( @@ -529,7 +529,7 @@ class SafetyCenterDataTest { status1, listOf(issue1), listOf(entryOrGroup2), - listOf(staticEntryGroup1) + listOf(staticEntryGroup1), ) ) .addEqualityGroup( @@ -537,7 +537,7 @@ class SafetyCenterDataTest { status1, listOf(issue1), listOf(entryOrGroup1), - listOf(staticEntryGroup2) + listOf(staticEntryGroup2), ) ) @@ -550,7 +550,7 @@ class SafetyCenterDataTest { EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetyCenterData.CREATOR, ignoreToString = true, - createCopy = { SafetyCenterData.Builder(it).build() } + createCopy = { SafetyCenterData.Builder(it).build() }, ) .addEqualityGroup( data1, @@ -558,7 +558,7 @@ class SafetyCenterDataTest { status1, listOf(issue1), listOf(entryOrGroup1), - listOf(staticEntryGroup1) + listOf(staticEntryGroup1), ), SafetyCenterData.Builder(status1) .addIssue(issue1) @@ -570,7 +570,7 @@ class SafetyCenterDataTest { .addEntryOrGroup(entryOrGroup1) .addStaticEntryGroup(staticEntryGroup1) .setExtras(unknownExtras) - .build() + .build(), ) .addEqualityGroup( SafetyCenterData.Builder(status1) @@ -640,7 +640,7 @@ class SafetyCenterDataTest { .addStaticEntryGroup(staticEntryGroup1) .addIssue(issue1) .setExtras(filledExtrasIssuesToGroups1) - .build() + .build(), ) .addEqualityGroup( SafetyCenterData.Builder(status1) diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt index 7ae5fb347..38ed449f7 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryGroupTest.kt @@ -175,7 +175,7 @@ class SafetyCenterEntryGroupTest { fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() { EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetyCenterEntryGroup.CREATOR, - createCopy = { SafetyCenterEntryGroup.Builder(it).build() } + createCopy = { SafetyCenterEntryGroup.Builder(it).build() }, ) .addEqualityGroup( entryGroup1, @@ -183,7 +183,7 @@ class SafetyCenterEntryGroupTest { .setSummary("A group summary") .setSeverityLevel(SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK) .setEntries(listOf(entry1)) - .build() + .build(), ) .addEqualityGroup(entryGroup2) .addEqualityGroup( diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt index 116164288..2811b87f2 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterEntryTest.kt @@ -41,18 +41,18 @@ class SafetyCenterEntryTest { context, 0, Intent("Fake Different Data"), - PendingIntent.FLAG_IMMUTABLE + PendingIntent.FLAG_IMMUTABLE, ) private val iconAction1 = SafetyCenterEntry.IconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, - pendingIntent1 + pendingIntent1, ) private val iconAction2 = SafetyCenterEntry.IconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, - pendingIntent2 + pendingIntent2, ) private val entry1 = @@ -213,7 +213,7 @@ class SafetyCenterEntryTest { fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() { EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetyCenterEntry.CREATOR, - createCopy = { SafetyCenterEntry.Builder(it).build() } + createCopy = { SafetyCenterEntry.Builder(it).build() }, ) .addEqualityGroup(entry1) .addEqualityGroup( @@ -226,7 +226,7 @@ class SafetyCenterEntryTest { .setPendingIntent(pendingIntent1) .setIconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, - pendingIntent2 + pendingIntent2, ) .build(), SafetyCenterEntry.Builder("id", "a title") @@ -238,9 +238,9 @@ class SafetyCenterEntryTest { .setPendingIntent(pendingIntent1) .setIconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, - pendingIntent2 + pendingIntent2, ) - .build() + .build(), ) .addEqualityGroup(SafetyCenterEntry.Builder(entry1).setId("a different id").build()) .addEqualityGroup( @@ -274,7 +274,7 @@ class SafetyCenterEntryTest { assertThat( SafetyCenterEntry.IconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, - pendingIntent1 + pendingIntent1, ) .type ) @@ -282,7 +282,7 @@ class SafetyCenterEntryTest { assertThat( SafetyCenterEntry.IconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, - pendingIntent1 + pendingIntent1, ) .type ) @@ -294,7 +294,7 @@ class SafetyCenterEntryTest { assertThat( SafetyCenterEntry.IconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, - pendingIntent1 + pendingIntent1, ) .pendingIntent ) @@ -302,7 +302,7 @@ class SafetyCenterEntryTest { assertThat( SafetyCenterEntry.IconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, - pendingIntent2 + pendingIntent2, ) .pendingIntent ) @@ -340,26 +340,26 @@ class SafetyCenterEntryTest { iconAction1, SafetyCenterEntry.IconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, - pendingIntent1 - ) + pendingIntent1, + ), ) .addEqualityGroup( iconAction2, SafetyCenterEntry.IconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, - pendingIntent2 - ) + pendingIntent2, + ), ) .addEqualityGroup( SafetyCenterEntry.IconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_INFO, - pendingIntent1 + pendingIntent1, ) ) .addEqualityGroup( SafetyCenterEntry.IconAction( SafetyCenterEntry.IconAction.ICON_ACTION_TYPE_GEAR, - pendingIntent2 + pendingIntent2, ) ) .test() diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorDetailsTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorDetailsTest.kt index 0d97026bd..e7565bf61 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorDetailsTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterErrorDetailsTest.kt @@ -58,7 +58,7 @@ class SafetyCenterErrorDetailsTest { .addEqualityGroup(errorDetails2, SafetyCenterErrorDetails("another error message")) .addEqualityGroup( SafetyCenterErrorDetails("a different error message"), - SafetyCenterErrorDetails("a different error message") + SafetyCenterErrorDetails("a different error message"), ) .test() } diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt index be7ca343c..fd359f600 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterIssueTest.kt @@ -47,7 +47,7 @@ class SafetyCenterIssueTest { context, 0, Intent("Fake Different Data"), - PendingIntent.FLAG_IMMUTABLE + PendingIntent.FLAG_IMMUTABLE, ) private val action1 = @@ -451,7 +451,7 @@ class SafetyCenterIssueTest { .setIsInFlight(true) .setSuccessMessage("a success message") .setConfirmationDialogDetails(confirmationDialogDetails) - .build() + .build(), ) .addEqualityGroup( SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1) @@ -534,7 +534,7 @@ class SafetyCenterIssueTest { .build(), SafetyCenterIssue.Builder(issueWithTiramisuFields) .setAttributionTitle("Attribution title") - .build() + .build(), ) .addEqualityGroup( SafetyCenterIssue.Builder(issueWithTiramisuFields) @@ -549,7 +549,7 @@ class SafetyCenterIssueTest { ) .addEqualityGroup( SafetyCenterIssue.Builder(issueWithTiramisuFields).setGroupId("group_id").build(), - SafetyCenterIssue.Builder(issueWithTiramisuFields).setGroupId("group_id").build() + SafetyCenterIssue.Builder(issueWithTiramisuFields).setGroupId("group_id").build(), ) .addEqualityGroup( SafetyCenterIssue.Builder(issueWithTiramisuFields) @@ -625,7 +625,7 @@ class SafetyCenterIssueTest { ) .addEqualityGroup( ConfirmationDialogDetails("Title", "Text", "Accept", "Deny"), - ConfirmationDialogDetails("Title", "Text", "Accept", "Deny") + ConfirmationDialogDetails("Title", "Text", "Accept", "Deny"), ) .addEqualityGroup(ConfirmationDialogDetails("Other title", "Text", "Accept", "Deny")) .addEqualityGroup(ConfirmationDialogDetails("Title", "Other text", "Accept", "Deny")) @@ -643,7 +643,7 @@ class SafetyCenterIssueTest { ) = EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetyCenterIssue.CREATOR, - createCopy = createCopyFromBuilder + createCopy = createCopyFromBuilder, ) .addEqualityGroup(issue1, SafetyCenterIssue.Builder(issue1).build()) .addEqualityGroup(issueWithRequiredFieldsOnly) @@ -657,7 +657,7 @@ class SafetyCenterIssueTest { .setSubtitle("In the neighborhood") .setSeverityLevel(SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK) .setActions(listOf(action1)) - .build() + .build(), ) .addEqualityGroup(SafetyCenterIssue.Builder(issue1).setId("a different id").build()) .addEqualityGroup( @@ -685,7 +685,7 @@ class SafetyCenterIssueTest { ) = EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetyCenterIssue.Action.CREATOR, - createCopy = createCopyFromBuilder + createCopy = createCopyFromBuilder, ) .addEqualityGroup(action1) .addEqualityGroup(action2) @@ -699,7 +699,7 @@ class SafetyCenterIssueTest { .setWillResolve(true) .setIsInFlight(true) .setSuccessMessage("a success message") - .build() + .build(), ) .addEqualityGroup( SafetyCenterIssue.Action.Builder("an_id", "a label", pendingIntent1) diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt index 8fd45efb8..b1c731f08 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt @@ -216,7 +216,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterTestHelper.setData( DYNAMIC_OTHER_PACKAGE_ID, - safetySourceTestData.unspecified + safetySourceTestData.unspecified, ) } @@ -281,7 +281,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterTestHelper.setData( DYNAMIC_IN_STATELESS_ID, - safetySourceTestData.information + safetySourceTestData.information, ) } @@ -342,7 +342,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterTestHelper.setData( ISSUE_ONLY_BAREBONE_ID, - safetySourceTestData.unspecified + safetySourceTestData.unspecified, ) } @@ -359,7 +359,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterTestHelper.setData( DYNAMIC_BAREBONE_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue), ) } @@ -400,7 +400,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.informationWithIssue + safetySourceTestData.informationWithIssue, ) } @@ -421,7 +421,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) } @@ -454,7 +454,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterTestHelper.setData( DYNAMIC_ALL_OPTIONAL_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) } @@ -490,7 +490,7 @@ class SafetyCenterManagerTest { ISSUE_ONLY_ALL_OPTIONAL_ID, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalResolvingGeneralIssue - ) + ), ) } @@ -521,7 +521,7 @@ class SafetyCenterManagerTest { SafetyCenterFlags.issueCategoryAllowlists = mapOf( ISSUE_CATEGORY_DEVICE to setOf(SAMPLE_SOURCE_ID), - ISSUE_CATEGORY_GENERAL to setOf(SAMPLE_SOURCE_ID) + ISSUE_CATEGORY_GENERAL to setOf(SAMPLE_SOURCE_ID), ) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) @@ -539,7 +539,7 @@ class SafetyCenterManagerTest { mapOf( ISSUE_CATEGORY_ACCOUNT to setOf(SINGLE_SOURCE_ID, SAMPLE_SOURCE_ID), ISSUE_CATEGORY_DEVICE to setOf(SAMPLE_SOURCE_ID), - ISSUE_CATEGORY_GENERAL to setOf(SAMPLE_SOURCE_ID) + ISSUE_CATEGORY_GENERAL to setOf(SAMPLE_SOURCE_ID), ) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) @@ -560,7 +560,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.recommendationWithAccountIssue + safetySourceTestData.recommendationWithAccountIssue, ) } @@ -577,7 +577,7 @@ class SafetyCenterManagerTest { SafetyCenterFlags.issueCategoryAllowlists = mapOf( ISSUE_CATEGORY_ACCOUNT to setOf(SAMPLE_SOURCE_ID), - ISSUE_CATEGORY_DEVICE to setOf(SINGLE_SOURCE_ID) + ISSUE_CATEGORY_DEVICE to setOf(SINGLE_SOURCE_ID), ) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) @@ -585,7 +585,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.recommendationWithAccountIssue + safetySourceTestData.recommendationWithAccountIssue, ) } @@ -605,7 +605,7 @@ class SafetyCenterManagerTest { safetyCenterManager.setSafetySourceDataWithPermission( SINGLE_SOURCE_ID, safetySourceTestData.unspecified, - EVENT_SOURCE_STATE_CHANGED + EVENT_SOURCE_STATE_CHANGED, ) safetyCenterTestHelper.setEnabled(true) @@ -620,7 +620,7 @@ class SafetyCenterManagerTest { safetyCenterManager.setSafetySourceData( SINGLE_SOURCE_ID, safetySourceTestData.unspecified, - EVENT_SOURCE_STATE_CHANGED + EVENT_SOURCE_STATE_CHANGED, ) } } @@ -702,7 +702,7 @@ class SafetyCenterManagerTest { safetyCenterManager.reportSafetySourceErrorWithPermission( SINGLE_SOURCE_ID, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) listener.receiveSafetyCenterData() @@ -717,7 +717,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterManager.reportSafetySourceErrorWithPermission( SINGLE_SOURCE_ID, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) } @@ -732,7 +732,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterManager.reportSafetySourceErrorWithPermission( STATIC_BAREBONE_ID, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) } @@ -749,7 +749,7 @@ class SafetyCenterManagerTest { assertFailsWith(IllegalArgumentException::class) { safetyCenterManager.reportSafetySourceErrorWithPermission( DYNAMIC_OTHER_PACKAGE_ID, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) } @@ -769,7 +769,7 @@ class SafetyCenterManagerTest { safetyCenterManager.reportSafetySourceErrorWithPermission( SINGLE_SOURCE_ID, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) assertFailsWith(TimeoutCancellationException::class) { @@ -782,7 +782,7 @@ class SafetyCenterManagerTest { assertFailsWith(SecurityException::class) { safetyCenterManager.reportSafetySourceError( SINGLE_SOURCE_ID, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) } } @@ -791,7 +791,7 @@ class SafetyCenterManagerTest { fun safetyCenterEnabledChanged_whenImplicitReceiverHasPermission_receiverCalled() { assumeTrue( "Cannot toggle SafetyCenter using DeviceConfig", - SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig() + SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig(), ) // Implicit broadcast is only sent to system user. assumeTrue(context.getSystemService(UserManager::class.java)!!.isSystemUser) @@ -813,7 +813,7 @@ class SafetyCenterManagerTest { fun safetyCenterEnabledChanged_whenImplicitReceiverDoesntHavePermission_receiverNotCalled() { assumeTrue( "Cannot toggle SafetyCenter using DeviceConfig", - SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig() + SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig(), ) // Implicit broadcast is only sent to system user. assumeTrue(context.getSystemService(UserManager::class.java)!!.isSystemUser) @@ -829,7 +829,7 @@ class SafetyCenterManagerTest { fun safetyCenterEnabledChanged_whenSourceReceiverHasPermission_receiverCalled() { assumeTrue( "Cannot toggle SafetyCenter using DeviceConfig", - SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig() + SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig(), ) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) @@ -848,14 +848,14 @@ class SafetyCenterManagerTest { fun safetyCenterEnabledChanged_valueDoesntChange_receiverNotCalled() { assumeTrue( "Cannot toggle SafetyCenter using DeviceConfig", - SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig() + SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig(), ) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) assertFailsWith(TimeoutCancellationException::class) { SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait( true, - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } } @@ -864,7 +864,7 @@ class SafetyCenterManagerTest { fun safetyCenterEnabledChanged_whenSourceReceiverDoesntHavePermission_receiverNotCalled() { assumeTrue( "Cannot toggle SafetyCenter using DeviceConfig", - SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig() + SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig(), ) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) @@ -877,12 +877,12 @@ class SafetyCenterManagerTest { fun safetyCenterEnabledChanged_whenSourceReceiverNotInConfig_receiverNotCalled() { assumeTrue( "Cannot toggle SafetyCenter using DeviceConfig", - SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig() + SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig(), ) assertFailsWith(TimeoutCancellationException::class) { SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait( false, - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } } @@ -891,14 +891,14 @@ class SafetyCenterManagerTest { fun safetyCenterEnabledChanged_whenNoDeviceConfigFlag_receiverNotCalled() { assumeFalse( "SafetyCenter DeviceConfig flag is in use", - SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig() + SafetyCenterTestHelper.safetyCenterCanBeToggledUsingDeviceConfig(), ) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) assertFailsWith(TimeoutCancellationException::class) { SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait( false, - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } } @@ -908,7 +908,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Rescan(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue) + Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_RESCAN_BUTTON_CLICK @@ -925,7 +925,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -943,7 +943,7 @@ class SafetyCenterManagerTest { SafetySourceReceiver.runInForegroundService = true SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -961,13 +961,13 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.informationWithIssue) + Response.SetData(safetySourceTestData.informationWithIssue), ) assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - timeout = TIMEOUT_SHORT + timeout = TIMEOUT_SHORT, ) } @@ -982,7 +982,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.informationWithIssue) + Response.SetData(safetySourceTestData.informationWithIssue), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -1015,11 +1015,11 @@ class SafetyCenterManagerTest { SafetySourceReceiver.apply { setResponse( Request.Rescan(SOURCE_ID_1), - Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue) + Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue), ) setResponse( Request.Rescan(SOURCE_ID_3), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) } @@ -1047,11 +1047,11 @@ class SafetyCenterManagerTest { SafetySourceReceiver.apply { setResponse( Request.Refresh(SOURCE_ID_1), - Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue) + Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue), ) setResponse( Request.Refresh(SOURCE_ID_3), - Response.SetData(safetySourceTestData.informationWithIssue) + Response.SetData(safetySourceTestData.informationWithIssue), ) } @@ -1077,7 +1077,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Rescan(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue) + Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue), ) assertFailsWith(TimeoutCancellationException::class) { @@ -1094,13 +1094,13 @@ class SafetyCenterManagerTest { fun refreshSafetySources_whenSourceNotInConfig_sourceDoesntSendData() { SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - timeout = TIMEOUT_SHORT + timeout = TIMEOUT_SHORT, ) } } @@ -1122,7 +1122,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Rescan(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) val broadcastId1 = @@ -1143,7 +1143,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Rescan(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information, overrideBroadcastId = "invalid") + Response.SetData(safetySourceTestData.information, overrideBroadcastId = "invalid"), ) val listener = safetyCenterTestHelper.addListener() @@ -1157,7 +1157,7 @@ class SafetyCenterManagerTest { SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN @@ -1172,14 +1172,14 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN ) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue) + Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -1201,7 +1201,7 @@ class SafetyCenterManagerTest { ) SafetySourceReceiver.setResponse( Request.Rescan(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -1230,7 +1230,7 @@ class SafetyCenterManagerTest { SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_LONG) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -1249,7 +1249,7 @@ class SafetyCenterManagerTest { ) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -1269,7 +1269,7 @@ class SafetyCenterManagerTest { for (sourceId in listOf(SOURCE_ID_2, SOURCE_ID_3)) { SafetySourceReceiver.setResponse( Request.Rescan(sourceId), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) } val listener = safetyCenterTestHelper.addListener() @@ -1289,7 +1289,7 @@ class SafetyCenterManagerTest { for (sourceId in listOf(SOURCE_ID_2, SOURCE_ID_3)) { SafetySourceReceiver.setResponse( Request.Rescan(sourceId), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) } val listener = safetyCenterTestHelper.addListener() @@ -1308,7 +1308,7 @@ class SafetyCenterManagerTest { // SOURCE_ID_1 and SOURCE_ID_2 will timeout SafetySourceReceiver.setResponse( Request.Rescan(SOURCE_ID_3), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) val listener = safetyCenterTestHelper.addListener() @@ -1355,7 +1355,7 @@ class SafetyCenterManagerTest { assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - timeout = TIMEOUT_SHORT + timeout = TIMEOUT_SHORT, ) } } @@ -1377,15 +1377,15 @@ class SafetyCenterManagerTest { SafetySourceReceiver.apply { setResponse( Request.Refresh(SOURCE_ID_1), - Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue) + Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue), ) setResponse( Request.Refresh(SOURCE_ID_2), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) setResponse( Request.Refresh(SOURCE_ID_3), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) } // But sources 1 and 3 should not be refreshed in background @@ -1409,7 +1409,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue) + Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue), ) SafetyCenterFlags.backgroundRefreshDeniedSources = setOf(SINGLE_SOURCE_ID) @@ -1426,7 +1426,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Rescan(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue) + Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue), ) SafetyCenterFlags.backgroundRefreshDeniedSources = setOf(SINGLE_SOURCE_ID) @@ -1444,14 +1444,14 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) SafetyCenterFlags.backgroundRefreshDeniedSources = setOf(SINGLE_SOURCE_ID) assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PERIODIC, - timeout = TIMEOUT_SHORT + timeout = TIMEOUT_SHORT, ) } @@ -1466,7 +1466,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue) + Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -1484,21 +1484,21 @@ class SafetyCenterManagerTest { SafetySourceReceiver.apply { setResponse( Request.Refresh(SOURCE_ID_1), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) setResponse( Request.Refresh(SOURCE_ID_2), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) setResponse( Request.Refresh(SOURCE_ID_3), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) } safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - safetySourceIds = listOf(SOURCE_ID_1, SOURCE_ID_2) + safetySourceIds = listOf(SOURCE_ID_1, SOURCE_ID_2), ) val apiSafetySourceData1 = @@ -1518,7 +1518,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue) + Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue), ) assertFailsWith(TimeoutCancellationException::class) { @@ -1541,7 +1541,7 @@ class SafetyCenterManagerTest { assertFails { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - safetySourceIds = listOf(SOURCE_ID_1, SOURCE_ID_3) + safetySourceIds = listOf(SOURCE_ID_1, SOURCE_ID_3), ) } } @@ -1647,7 +1647,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val safetyCenterDataFromListener = listener.receiveSafetyCenterData() @@ -1708,7 +1708,7 @@ class SafetyCenterManagerTest { } safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( directExecutor(), - oneShotListener + oneShotListener, ) // Check that we don't deadlock when using a one-shot listener. This is because adding the @@ -1725,7 +1725,7 @@ class SafetyCenterManagerTest { val listener = SafetyCenterTestListener() safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( directExecutor(), - listener + listener, ) assertFailsWith(TimeoutCancellationException::class) { @@ -1764,7 +1764,7 @@ class SafetyCenterManagerTest { val listener = SafetyCenterTestListener() safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( fakeExecutor, - listener + listener, ) fakeExecutor.getNextTask().run() listener.receiveSafetyCenterData() @@ -1812,7 +1812,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.recommendationDismissPendingIntentIssue + safetySourceTestData.recommendationDismissPendingIntentIssue, ) val apiSafetySourceDataBeforeDismissal = safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID) @@ -1822,7 +1822,7 @@ class SafetyCenterManagerTest { ) SafetySourceReceiver.setResponse( Request.DismissIssue(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.dismissSafetyCenterIssueWithPermissionAndWait( @@ -1839,7 +1839,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() @@ -1857,7 +1857,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID) @@ -1878,7 +1878,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID) @@ -1889,7 +1889,7 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - issueTypeId = "some_other_issue_type_id" + issueTypeId = "some_other_issue_type_id", ) ) @@ -1903,7 +1903,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() safetyCenterTestHelper.setEnabled(false) @@ -1931,7 +1931,7 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - userId = USER_NULL + userId = USER_NULL, ) ) } @@ -1949,7 +1949,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val apiSafetySourceDataBeforeExecution = safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID) @@ -1959,7 +1959,7 @@ class SafetyCenterManagerTest { ) SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait( @@ -1967,8 +1967,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) val apiSafetySourceDataAfterExecution = @@ -1989,8 +1989,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) val error = listener.receiveSafetyCenterErrorDetails() @@ -2015,8 +2015,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) val error = listener.receiveSafetyCenterErrorDetails() @@ -2043,7 +2043,7 @@ class SafetyCenterManagerTest { } safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( fakeExecutor, - listener + listener, ) fakeExecutor.getNextTask().run() @@ -2052,8 +2052,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) fakeExecutor.getNextTask().run() @@ -2072,9 +2072,9 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID + CRITICAL_ISSUE_ACTION_ID, ), - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } assertFailsWith(TimeoutCancellationException::class) { @@ -2087,7 +2087,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait( @@ -2095,8 +2095,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) listener.receiveSafetyCenterData() @@ -2106,9 +2106,9 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID + CRITICAL_ISSUE_ACTION_ID, ), - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } assertFailsWith(TimeoutCancellationException::class) { @@ -2121,7 +2121,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() safetyCenterTestHelper.setEnabled(false) @@ -2132,9 +2132,9 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID + CRITICAL_ISSUE_ACTION_ID, ), - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } assertFailsWith(TimeoutCancellationException::class) { @@ -2154,12 +2154,12 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) assertFailsWith(IllegalArgumentException::class) { @@ -2168,9 +2168,9 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID + "invalid", - CRITICAL_ISSUE_ACTION_ID + CRITICAL_ISSUE_ACTION_ID, ), - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } @@ -2184,12 +2184,12 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) assertFailsWith(TimeoutCancellationException::class) { @@ -2198,9 +2198,9 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID + "invalid" + CRITICAL_ISSUE_ACTION_ID + "invalid", ), - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } @@ -2217,8 +2217,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SOURCE_ID_1, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) } } @@ -2230,14 +2230,14 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - userId = USER_NULL + userId = USER_NULL, ), SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, CRITICAL_ISSUE_ACTION_ID, - userId = USER_NULL - ) + userId = USER_NULL, + ), ) } } @@ -2255,7 +2255,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData(SOURCE_ID_1, safetySourceTestData.unspecified) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterManager.clearAllSafetySourceDataForTestsWithPermission() @@ -2271,7 +2271,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setEnabled(false) diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt index 71be3d5eb..0709bfc83 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryGroupTest.kt @@ -104,11 +104,11 @@ class SafetyCenterStaticEntryGroupTest { ) .addEqualityGroup( staticEntryGroup, - SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1, staticEntry2)) + SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1, staticEntry2)), ) .addEqualityGroup( SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1)), - SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1)) + SafetyCenterStaticEntryGroup("a title", listOf(staticEntry1)), ) .addEqualityGroup( SafetyCenterStaticEntryGroup("a different title", listOf(staticEntry1)) diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt index 045a50f75..7a5e6a737 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStaticEntryTest.kt @@ -40,7 +40,7 @@ class SafetyCenterStaticEntryTest { context, 0, Intent("Fake Different Data"), - PendingIntent.FLAG_IMMUTABLE + PendingIntent.FLAG_IMMUTABLE, ) private val title1 = "a title" @@ -101,14 +101,14 @@ class SafetyCenterStaticEntryTest { fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() { EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetyCenterStaticEntry.CREATOR, - createCopy = { SafetyCenterStaticEntry.Builder(it).build() } + createCopy = { SafetyCenterStaticEntry.Builder(it).build() }, ) .addEqualityGroup( staticEntry1, SafetyCenterStaticEntry.Builder("a title") .setSummary("a summary") .setPendingIntent(pendingIntent1) - .build() + .build(), ) .addEqualityGroup(staticEntry2) .addEqualityGroup(staticEntryMinimal, SafetyCenterStaticEntry.Builder("").build()) @@ -120,7 +120,7 @@ class SafetyCenterStaticEntryTest { SafetyCenterStaticEntry.Builder("titlee") .setSummary("sumaree") .setPendingIntent(pendingIntent1) - .build() + .build(), ) .addEqualityGroup( SafetyCenterStaticEntry.Builder(staticEntry1).setTitle("a different title").build() diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt index 4df4e5d35..561e34d3b 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterStatusTest.kt @@ -156,7 +156,7 @@ class SafetyCenterStatusTest { fun equalsHashCodeToString_usingEqualsHashCodeToStringTester() { EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetyCenterStatus.CREATOR, - createCopy = { SafetyCenterStatus.Builder(it).build() } + createCopy = { SafetyCenterStatus.Builder(it).build() }, ) .addEqualityGroup( baseStatus, @@ -164,7 +164,7 @@ class SafetyCenterStatusTest { .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION) .setRefreshStatus(SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS) .build(), - SafetyCenterStatus.Builder(baseStatus).build() + SafetyCenterStatus.Builder(baseStatus).build(), ) .addEqualityGroup( SafetyCenterStatus.Builder("same title", "same summary") @@ -172,7 +172,7 @@ class SafetyCenterStatusTest { .build(), SafetyCenterStatus.Builder("same title", "same summary") .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK) - .build() + .build(), ) .addEqualityGroup( SafetyCenterStatus.Builder(baseStatus).setTitle("that's not it").build() diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt index d882fc3cb..3beced151 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt @@ -119,7 +119,7 @@ class SafetyCenterUnsupportedTest { safetyCenterManager.setSafetySourceDataWithPermission( SINGLE_SOURCE_ID, safetySourceTestData.criticalWithResolvingGeneralIssue, - EVENT_SOURCE_STATE_CHANGED + EVENT_SOURCE_STATE_CHANGED, ) val apiSafetySourceData = @@ -134,7 +134,7 @@ class SafetyCenterUnsupportedTest { safetyCenterManager.setSafetySourceData( SINGLE_SOURCE_ID, safetySourceTestData.unspecified, - EVENT_SOURCE_STATE_CHANGED + EVENT_SOURCE_STATE_CHANGED, ) } } @@ -154,12 +154,12 @@ class SafetyCenterUnsupportedTest { val listener = SafetyCenterTestListener() safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( directExecutor(), - listener + listener, ) safetyCenterManager.reportSafetySourceErrorWithPermission( SINGLE_SOURCE_ID, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) assertFailsWith(TimeoutCancellationException::class) { @@ -172,7 +172,7 @@ class SafetyCenterUnsupportedTest { assertFailsWith(SecurityException::class) { safetyCenterManager.reportSafetySourceError( SINGLE_SOURCE_ID, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) } } @@ -186,7 +186,7 @@ class SafetyCenterUnsupportedTest { assertFailsWith(TimeoutCancellationException::class) { enabledChangedReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait( false, - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } enabledChangedReceiver.unregister() @@ -201,7 +201,7 @@ class SafetyCenterUnsupportedTest { assertFailsWith(TimeoutCancellationException::class) { SafetySourceReceiver.setSafetyCenterEnabledWithReceiverPermissionAndWait( false, - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } } @@ -215,7 +215,7 @@ class SafetyCenterUnsupportedTest { assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - timeout = TIMEOUT_SHORT + timeout = TIMEOUT_SHORT, ) } } @@ -260,7 +260,7 @@ class SafetyCenterUnsupportedTest { safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( directExecutor(), - listener + listener, ) assertFailsWith(TimeoutCancellationException::class) { @@ -285,7 +285,7 @@ class SafetyCenterUnsupportedTest { val listener = SafetyCenterTestListener() safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( directExecutor(), - listener + listener, ) safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener) @@ -300,7 +300,7 @@ class SafetyCenterUnsupportedTest { val listener = SafetyCenterTestListener() safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( directExecutor(), - listener + listener, ) assertFailsWith(SecurityException::class) { @@ -316,12 +316,12 @@ class SafetyCenterUnsupportedTest { safetyCenterManager.setSafetySourceDataWithPermission( SINGLE_SOURCE_ID, safetySourceTestData.criticalWithResolvingGeneralIssue, - EVENT_SOURCE_STATE_CHANGED + EVENT_SOURCE_STATE_CHANGED, ) val listener = SafetyCenterTestListener() safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( directExecutor(), - listener + listener, ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( @@ -348,12 +348,12 @@ class SafetyCenterUnsupportedTest { safetyCenterManager.setSafetySourceDataWithPermission( SINGLE_SOURCE_ID, safetySourceTestData.criticalWithResolvingGeneralIssue, - EVENT_SOURCE_STATE_CHANGED + EVENT_SOURCE_STATE_CHANGED, ) val listener = SafetyCenterTestListener() safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( directExecutor(), - listener + listener, ) assertFailsWith(TimeoutCancellationException::class) { @@ -362,9 +362,9 @@ class SafetyCenterUnsupportedTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID + CRITICAL_ISSUE_ACTION_ID, ), - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } assertFailsWith(TimeoutCancellationException::class) { @@ -387,7 +387,7 @@ class SafetyCenterUnsupportedTest { safetyCenterManager.setSafetySourceDataWithPermission( SINGLE_SOURCE_ID, safetySourceTestData.criticalWithResolvingGeneralIssue, - EVENT_SOURCE_STATE_CHANGED + EVENT_SOURCE_STATE_CHANGED, ) val apiSafetySourceDataBeforeClearing = safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID) diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt index 4d1cb6a8b..cba29852f 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt @@ -203,7 +203,7 @@ class SafetyEventTest { ) = EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetyEvent.CREATOR, - createCopy = createCopyFromBuilder + createCopy = createCopyFromBuilder, ) .addEqualityGroup(SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()) .addEqualityGroup( @@ -212,7 +212,7 @@ class SafetyEventTest { .build(), SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED) .setRefreshBroadcastId(REFRESH_BROADCAST_ID) - .build() + .build(), ) .addEqualityGroup( SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED) @@ -222,7 +222,7 @@ class SafetyEventTest { SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED) .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID) .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID) - .build() + .build(), ) .addEqualityGroup( SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED) @@ -232,7 +232,7 @@ class SafetyEventTest { SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED) .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID) .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID) - .build() + .build(), ) .addEqualityGroup(SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()) .addEqualityGroup(SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED).build()) diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt index ba2ab3d76..287aa15a3 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceDataTest.kt @@ -350,11 +350,11 @@ class SafetySourceDataTest { EqualsHashCodeToStringTester.ofParcelable(parcelableCreator = SafetySourceData.CREATOR) .addEqualityGroup( SafetySourceData.Builder().setStatus(firstStatus).build(), - SafetySourceData.Builder().setStatus(firstStatus).build() + SafetySourceData.Builder().setStatus(firstStatus).build(), ) .addEqualityGroup( SafetySourceData.Builder().addIssue(firstIssue).addIssue(secondIssue).build(), - SafetySourceData.Builder().addIssue(firstIssue).addIssue(secondIssue).build() + SafetySourceData.Builder().addIssue(firstIssue).addIssue(secondIssue).build(), ) .addEqualityGroup( SafetySourceData.Builder() @@ -366,7 +366,7 @@ class SafetySourceDataTest { .setStatus(firstStatus) .addIssue(firstIssue) .addIssue(secondIssue) - .build() + .build(), ) .addEqualityGroup(SafetySourceData.Builder().setStatus(secondStatus).build()) .addEqualityGroup( @@ -394,11 +394,11 @@ class SafetySourceDataTest { EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetySourceData.CREATOR, ignoreToString = true, - createCopy = { SafetySourceData.Builder(it).build() } + createCopy = { SafetySourceData.Builder(it).build() }, ) .addEqualityGroup( SafetySourceData.Builder().setStatus(firstStatus).build(), - SafetySourceData.Builder().setStatus(firstStatus).setExtras(filledExtras).build() + SafetySourceData.Builder().setStatus(firstStatus).setExtras(filledExtras).build(), ) .addEqualityGroup( SafetySourceData.Builder().addIssue(firstIssue).addIssue(secondIssue).build(), @@ -406,7 +406,7 @@ class SafetySourceDataTest { .addIssue(firstIssue) .addIssue(secondIssue) .setExtras(filledExtras) - .build() + .build(), ) .addEqualityGroup( SafetySourceData.Builder() @@ -419,11 +419,11 @@ class SafetySourceDataTest { .addIssue(firstIssue) .addIssue(secondIssue) .setExtras(filledExtras) - .build() + .build(), ) .addEqualityGroup( SafetySourceData.Builder().setStatus(secondStatus).build(), - SafetySourceData.Builder().setStatus(secondStatus).setExtras(filledExtras).build() + SafetySourceData.Builder().setStatus(secondStatus).setExtras(filledExtras).build(), ) .addEqualityGroup( SafetySourceData.Builder().addIssue(secondIssue).addIssue(firstIssue).build(), @@ -431,11 +431,11 @@ class SafetySourceDataTest { .addIssue(secondIssue) .addIssue(firstIssue) .setExtras(filledExtras) - .build() + .build(), ) .addEqualityGroup( SafetySourceData.Builder().addIssue(firstIssue).build(), - SafetySourceData.Builder().addIssue(firstIssue).setExtras(filledExtras).build() + SafetySourceData.Builder().addIssue(firstIssue).setExtras(filledExtras).build(), ) .addEqualityGroup( SafetySourceData.Builder() @@ -448,7 +448,7 @@ class SafetySourceDataTest { .addIssue(firstIssue) .addIssue(secondIssue) .setExtras(filledExtras) - .build() + .build(), ) .test() } @@ -485,7 +485,7 @@ class SafetySourceDataTest { context, /* requestCode = */ 0, Intent("Status PendingIntent $id"), - FLAG_IMMUTABLE + FLAG_IMMUTABLE, ) ) .build() @@ -496,7 +496,7 @@ class SafetySourceDataTest { "Issue summary $id", "Issue summary $id", severityLevel, - "Issue type id $id" + "Issue type id $id", ) .addAction( SafetySourceIssue.Action.Builder( @@ -506,8 +506,8 @@ class SafetySourceDataTest { context, /* requestCode = */ 0, Intent("Issue PendingIntent $id"), - FLAG_IMMUTABLE - ) + FLAG_IMMUTABLE, + ), ) .build() ) diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt index 336462491..4133f6f17 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt @@ -51,7 +51,7 @@ class SafetySourceErrorDetailsTest { SafetySourceErrorDetails(SAFETY_EVENT), SafetySourceErrorDetails( SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build() - ) + ), ) .addEqualityGroup( SafetySourceErrorDetails( diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt index 2d19a3175..a7149e4d7 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceIssueTest.kt @@ -238,7 +238,7 @@ class SafetySourceIssueTest { Action.Builder("action_id", "Action label", pendingIntent1) .setConfirmationDialogDetails(confirmationDialogDetails) .setWillResolve(false) - .build() + .build(), ) .addEqualityGroup( Action.Builder("action_id", "Action label", pendingIntent1) @@ -270,8 +270,8 @@ class SafetySourceIssueTest { context, 0, Intent("Other action PendingIntent"), - FLAG_IMMUTABLE - ) + FLAG_IMMUTABLE, + ), ) .setConfirmationDialogDetails(confirmationDialogDetails) .build() @@ -465,7 +465,7 @@ class SafetySourceIssueTest { fun notification_equalsHashCodeToString_usingEqualsHashCodeToStringTester() { EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = Notification.CREATOR, - createCopy = { Notification.Builder(it).build() } + createCopy = { Notification.Builder(it).build() }, ) .addEqualityGroup( Notification.Builder("Title", "Text").build(), @@ -477,7 +477,7 @@ class SafetySourceIssueTest { .addEqualityGroup(Notification.Builder("Title", "Text").addAction(action2).build()) .addEqualityGroup( Notification.Builder("Title", "Text").addAction(action1).addAction(action2).build(), - Notification.Builder("Title", "Text").addActions(listOf(action1, action2)).build() + Notification.Builder("Title", "Text").addActions(listOf(action1, action2)).build(), ) .test() } @@ -538,7 +538,7 @@ class SafetySourceIssueTest { ) .addEqualityGroup( ConfirmationDialogDetails("Title", "Text", "Accept", "Deny"), - ConfirmationDialogDetails("Title", "Text", "Accept", "Deny") + ConfirmationDialogDetails("Title", "Text", "Accept", "Deny"), ) .addEqualityGroup(ConfirmationDialogDetails("Other title", "Text", "Accept", "Deny")) .addEqualityGroup(ConfirmationDialogDetails("Title", "Other text", "Accept", "Deny")) @@ -555,7 +555,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -571,7 +571,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -587,7 +587,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -603,7 +603,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .addAction(action1) @@ -620,7 +620,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -637,7 +637,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -654,7 +654,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .setAttributionTitle("attribution title") @@ -672,7 +672,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -689,7 +689,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) assertFails { safetySourceIssueBuilder.setAttributionTitle("title") } @@ -703,7 +703,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -719,7 +719,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -735,7 +735,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .setIssueCategory(ISSUE_CATEGORY_DEVICE) @@ -753,7 +753,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PASSWORDS) @@ -771,7 +771,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .addAction(action2) @@ -788,7 +788,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .addAction(action2) @@ -806,7 +806,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) val actions = safetySourceIssueBuilder.build().actions @@ -824,7 +824,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .addAction(action2) @@ -843,7 +843,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -859,7 +859,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .setOnDismissPendingIntent(pendingIntentService) @@ -877,7 +877,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -894,7 +894,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .setDeduplicationId("deduplication_id") @@ -912,7 +912,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -929,7 +929,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) assertFails { safetySourceIssueBuilder.setDeduplicationId("id") } @@ -943,7 +943,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -960,7 +960,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -977,7 +977,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .setCustomNotification( @@ -1004,7 +1004,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -1021,7 +1021,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) assertFails { safetySourceIssueBuilder.setCustomNotification(null) } @@ -1036,7 +1036,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -1054,7 +1054,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_NEVER) @@ -1073,7 +1073,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -1090,7 +1090,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) val exception = @@ -1110,7 +1110,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) assertFails { safetySourceIssueBuilder.setNotificationBehavior(0) } @@ -1125,7 +1125,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -1143,7 +1143,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC) @@ -1162,7 +1162,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -1179,7 +1179,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) val exception = @@ -1199,7 +1199,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) assertFails { safetySourceIssueBuilder.setIssueActionability(0) } @@ -1213,7 +1213,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) } } @@ -1226,7 +1226,7 @@ class SafetySourceIssueTest { Generic.asNull(), "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) } } @@ -1239,7 +1239,7 @@ class SafetySourceIssueTest { "Issue title", Generic.asNull(), SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) } } @@ -1253,7 +1253,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_UNSPECIFIED, - "issue_type_id" + "issue_type_id", ) } assertThat(exception) @@ -1270,7 +1270,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", -1, - "issue_type_id" + "issue_type_id", ) } assertThat(exception) @@ -1286,7 +1286,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - Generic.asNull() + Generic.asNull(), ) } } @@ -1299,7 +1299,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) val exception = @@ -1319,7 +1319,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) @@ -1339,7 +1339,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) val exception = assertFailsWith(IllegalArgumentException::class) { @@ -1348,7 +1348,7 @@ class SafetySourceIssueTest { context, /* requestCode = */ 0, Intent("PendingIntent activity"), - FLAG_IMMUTABLE + FLAG_IMMUTABLE, ) ) } @@ -1365,7 +1365,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .addAction(action1) @@ -1385,7 +1385,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) val exception = @@ -1410,7 +1410,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .addAction(action2) @@ -1432,7 +1432,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) val exception = @@ -1452,7 +1452,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP) .build() @@ -1469,7 +1469,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC) .build() @@ -1485,7 +1485,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1505,7 +1505,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1526,7 +1526,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1553,7 +1553,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DATA) @@ -1601,7 +1601,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1622,7 +1622,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1641,7 +1641,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1655,7 +1655,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1663,7 +1663,7 @@ class SafetySourceIssueTest { .addAction(action2) .setOnDismissPendingIntent(pendingIntentService) .setAttributionTitle("attribution title") - .build() + .build(), ) .addEqualityGroup( SafetySourceIssue.Builder( @@ -1671,7 +1671,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_CRITICAL_WARNING, - "issue_type_id" + "issue_type_id", ) .setAttributionTitle("Other issue attribution title") .addAction(action1) @@ -1683,7 +1683,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1698,7 +1698,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1707,7 +1707,7 @@ class SafetySourceIssueTest { .setOnDismissPendingIntent(pendingIntentService) .setAttributionTitle("attribution title") .setDeduplicationId("deduplication_id") - .build() + .build(), ) .addEqualityGroup( SafetySourceIssue.Builder( @@ -1715,7 +1715,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1732,7 +1732,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Other issue subtitle") .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DATA) @@ -1745,7 +1745,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Other issue subtitle") .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PASSWORDS) @@ -1758,7 +1758,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Other issue subtitle") .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PERSONAL_SAFETY) @@ -1771,7 +1771,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL) .addAction(action1) @@ -1786,7 +1786,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP) .addAction(action1) @@ -1796,11 +1796,11 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP) .addAction(action1) - .build() + .build(), ) .addEqualityGroup( SafetySourceIssue.Builder( @@ -1808,7 +1808,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC) .addAction(action1) @@ -1820,7 +1820,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC) .build() @@ -1831,7 +1831,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_DELAYED) .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC) @@ -1843,7 +1843,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1864,7 +1864,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1889,7 +1889,7 @@ class SafetySourceIssueTest { ) = EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetySourceIssue.CREATOR, - createCopy = createCopyFromBuilder + createCopy = createCopyFromBuilder, ) .addEqualityGroup( SafetySourceIssue.Builder( @@ -1897,7 +1897,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -1910,14 +1910,14 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) .addAction(action1) .addAction(action2) .setOnDismissPendingIntent(pendingIntentService) - .build() + .build(), ) .addEqualityGroup( SafetySourceIssue.Builder( @@ -1925,7 +1925,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -1936,7 +1936,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -1947,7 +1947,7 @@ class SafetySourceIssueTest { "Other issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -1958,7 +1958,7 @@ class SafetySourceIssueTest { "Issue title", "Different issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -1969,7 +1969,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_CRITICAL_WARNING, - "issue_type_id" + "issue_type_id", ) .addAction(action1) .build() @@ -1980,7 +1980,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "other_issue_type_id" + "other_issue_type_id", ) .addAction(action1) .build() @@ -1991,7 +1991,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .addAction(action2) .build() @@ -2002,7 +2002,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Other issue subtitle") .setIssueCategory(ISSUE_CATEGORY_ACCOUNT) @@ -2017,7 +2017,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Other issue subtitle") .setIssueCategory(ISSUE_CATEGORY_DEVICE) @@ -2032,7 +2032,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Other issue subtitle") .setIssueCategory(ISSUE_CATEGORY_DEVICE) @@ -2047,7 +2047,7 @@ class SafetySourceIssueTest { "Issue title", "Issue summary", SEVERITY_LEVEL_INFORMATION, - "issue_type_id" + "issue_type_id", ) .setSubtitle("Other issue subtitle") .setIssueCategory(ISSUE_CATEGORY_DEVICE) @@ -2058,7 +2058,7 @@ class SafetySourceIssueTest { context, 0, Intent("Other PendingIntent service"), - FLAG_IMMUTABLE + FLAG_IMMUTABLE, ) ) .build() @@ -2069,14 +2069,14 @@ class SafetySourceIssueTest { ) = EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = Action.CREATOR, - createCopy = createCopyFromBuilder + createCopy = createCopyFromBuilder, ) .addEqualityGroup( Action.Builder("action_id", "Action label", pendingIntent1).build(), Action.Builder("action_id", "Action label", pendingIntent1).build(), Action.Builder("action_id", "Action label", pendingIntent1) .setWillResolve(false) - .build() + .build(), ) .addEqualityGroup( Action.Builder("action_id", "Action label", pendingIntent1) @@ -2102,8 +2102,8 @@ class SafetySourceIssueTest { context, 0, Intent("Other action PendingIntent"), - FLAG_IMMUTABLE - ) + FLAG_IMMUTABLE, + ), ) .build() ) diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt index 2a20cd45d..04a91b268 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceStatusTest.kt @@ -98,7 +98,7 @@ class SafetySourceStatusTest { EqualsHashCodeToStringTester.ofParcelable(parcelableCreator = IconAction.CREATOR) .addEqualityGroup( IconAction(ICON_TYPE_GEAR, pendingIntent1), - IconAction(ICON_TYPE_GEAR, pendingIntent1) + IconAction(ICON_TYPE_GEAR, pendingIntent1), ) .addEqualityGroup(IconAction(ICON_TYPE_INFO, pendingIntent1)) .addEqualityGroup(IconAction(ICON_TYPE_GEAR, pendingIntent2)) @@ -195,7 +195,7 @@ class SafetySourceStatusTest { SafetySourceStatus.Builder( Generic.asNull(), "Status summary", - SEVERITY_LEVEL_INFORMATION + SEVERITY_LEVEL_INFORMATION, ) } } @@ -229,7 +229,7 @@ class SafetySourceStatusTest { context, /* requestCode = */ 0, Intent("PendingIntent service"), - FLAG_IMMUTABLE + FLAG_IMMUTABLE, ) ) } @@ -298,13 +298,13 @@ class SafetySourceStatusTest { ) = EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetySourceStatus.CREATOR, - createCopy = createCopyFromBuilder + createCopy = createCopyFromBuilder, ) .addEqualityGroup( SafetySourceStatus.Builder( "Status title", "Status summary", - SEVERITY_LEVEL_INFORMATION + SEVERITY_LEVEL_INFORMATION, ) .setPendingIntent(pendingIntent1) .setIconAction(iconAction1) @@ -313,18 +313,18 @@ class SafetySourceStatusTest { SafetySourceStatus.Builder( "Status title", "Status summary", - SEVERITY_LEVEL_INFORMATION + SEVERITY_LEVEL_INFORMATION, ) .setPendingIntent(pendingIntent1) .setIconAction(iconAction1) .setEnabled(true) - .build() + .build(), ) .addEqualityGroup( SafetySourceStatus.Builder( "Status title", "Status summary", - SEVERITY_LEVEL_INFORMATION + SEVERITY_LEVEL_INFORMATION, ) .build() ) @@ -332,7 +332,7 @@ class SafetySourceStatusTest { SafetySourceStatus.Builder( "Other status title", "Status summary", - SEVERITY_LEVEL_INFORMATION + SEVERITY_LEVEL_INFORMATION, ) .build() ) @@ -340,7 +340,7 @@ class SafetySourceStatusTest { SafetySourceStatus.Builder( "Status title", "Other status summary", - SEVERITY_LEVEL_INFORMATION + SEVERITY_LEVEL_INFORMATION, ) .build() ) @@ -348,7 +348,7 @@ class SafetySourceStatusTest { SafetySourceStatus.Builder( "Status title", "Status summary", - SEVERITY_LEVEL_CRITICAL_WARNING + SEVERITY_LEVEL_CRITICAL_WARNING, ) .build() ) @@ -356,7 +356,7 @@ class SafetySourceStatusTest { SafetySourceStatus.Builder( "Status title", "Status summary", - SEVERITY_LEVEL_CRITICAL_WARNING + SEVERITY_LEVEL_CRITICAL_WARNING, ) .setPendingIntent(pendingIntent2) .build() @@ -365,7 +365,7 @@ class SafetySourceStatusTest { SafetySourceStatus.Builder( "Status title", "Status summary", - SEVERITY_LEVEL_CRITICAL_WARNING + SEVERITY_LEVEL_CRITICAL_WARNING, ) .setIconAction(iconAction2) .build() @@ -374,7 +374,7 @@ class SafetySourceStatusTest { SafetySourceStatus.Builder( "Status title", "Status summary", - SEVERITY_LEVEL_UNSPECIFIED + SEVERITY_LEVEL_UNSPECIFIED, ) .setEnabled(false) .build() diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt index 68dcd4a11..c3b6ef1b3 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetyCenterConfigTest.kt @@ -36,7 +36,7 @@ class SafetyCenterConfigTest { assertThat(BASE.safetySourcesGroups) .containsExactly( SafetySourcesGroupTest.STATELESS_INFERRED, - SafetySourcesGroupTest.HIDDEN_INFERRED + SafetySourcesGroupTest.HIDDEN_INFERRED, ) .inOrder() } @@ -65,7 +65,7 @@ class SafetyCenterConfigTest { assertThat(sourceGroups) .containsExactly( SafetySourcesGroupTest.STATELESS_INFERRED, - SafetySourcesGroupTest.HIDDEN_INFERRED + SafetySourcesGroupTest.HIDDEN_INFERRED, ) .inOrder() } @@ -99,14 +99,14 @@ class SafetyCenterConfigTest { ) = EqualsHashCodeToStringTester.ofParcelable( parcelableCreator = SafetyCenterConfig.CREATOR, - createCopy = createCopyFromBuilder + createCopy = createCopyFromBuilder, ) .addEqualityGroup( BASE, SafetyCenterConfig.Builder() .addSafetySourcesGroup(SafetySourcesGroupTest.STATELESS_INFERRED) .addSafetySourcesGroup(SafetySourcesGroupTest.HIDDEN_INFERRED) - .build() + .build(), ) .addEqualityGroup( SafetyCenterConfig.Builder() diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt index 4b6f0f6f9..210a5b5e7 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt @@ -368,7 +368,7 @@ class SafetySourceTest { { SafetySource.Builder(it).build() } } else { null - } + }, ) .addEqualityGroup(DYNAMIC_BAREBONE) .addEqualityGroup( @@ -396,7 +396,7 @@ class SafetySourceTest { setTitleForPrivateProfileResId(REFERENCE_RES_ID) } } - .build() + .build(), ) .addEqualityGroup(DYNAMIC_HIDDEN) .addEqualityGroup(DYNAMIC_HIDDEN_WITH_SEARCH) diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt index f741369eb..06aad5d40 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourcesGroupTest.kt @@ -155,7 +155,7 @@ class SafetySourcesGroupTest { .containsExactly( SafetySourceTest.DYNAMIC_BAREBONE, SafetySourceTest.STATIC_BAREBONE, - SafetySourceTest.ISSUE_ONLY_BAREBONE + SafetySourceTest.ISSUE_ONLY_BAREBONE, ) .inOrder() assertThat(STATELESS_INFERRED.safetySources) @@ -169,7 +169,7 @@ class SafetySourcesGroupTest { .containsExactly( SafetySourceTest.DYNAMIC_BAREBONE, SafetySourceTest.STATIC_BAREBONE, - SafetySourceTest.ISSUE_ONLY_BAREBONE + SafetySourceTest.ISSUE_ONLY_BAREBONE, ) assertThat(STATELESS_BAREBONE.safetySources) .containsExactly(SafetySourceTest.STATIC_BAREBONE) @@ -177,7 +177,7 @@ class SafetySourcesGroupTest { .containsExactly( SafetySourceTest.DYNAMIC_BAREBONE, SafetySourceTest.STATIC_BAREBONE, - SafetySourceTest.ISSUE_ONLY_BAREBONE + SafetySourceTest.ISSUE_ONLY_BAREBONE, ) assertThat(HIDDEN_BAREBONE.safetySources) .containsExactly(SafetySourceTest.ISSUE_ONLY_BAREBONE) @@ -325,7 +325,7 @@ class SafetySourcesGroupTest { { SafetySourcesGroup.Builder(it).build() } } else { null - } + }, ) .addEqualityGroup(STATEFUL_INFERRED_WITH_SUMMARY) .addEqualityGroup(STATEFUL_INFERRED_WITH_ICON) @@ -340,7 +340,7 @@ class SafetySourcesGroupTest { .addSafetySource(SafetySourceTest.DYNAMIC_BAREBONE) .addSafetySource(SafetySourceTest.STATIC_BAREBONE) .addSafetySource(SafetySourceTest.ISSUE_ONLY_BAREBONE) - .build() + .build(), ) .apply { if (SdkLevel.isAtLeastU()) add(STATEFUL_ALL_OPTIONAL) } .toTypedArray() diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt index 7c9e2cffc..34f5c1f69 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/XmlConfigTest.kt @@ -88,7 +88,7 @@ class XmlConfigTest { private fun parseXmlConfig() = SafetyCenterConfigParser.parseXmlResource( safetyCenterResourcesApk.safetyCenterConfig!!, - safetyCenterResourcesApk.resources + safetyCenterResourcesApk.resources, ) companion object { diff --git a/tests/functional/safetycenter/multiusers/Android.bp b/tests/functional/safetycenter/multiusers/Android.bp index 30024221b..745e763f0 100644 --- a/tests/functional/safetycenter/multiusers/Android.bp +++ b/tests/functional/safetycenter/multiusers/Android.bp @@ -36,6 +36,7 @@ android_test { "Harrier", "Nene", "TestApp", + "bedstead-enterprise", "com.android.permission.flags-aconfig-java-export", ], test_suites: [ diff --git a/tests/functional/safetycenter/multiusers/AndroidTest.xml b/tests/functional/safetycenter/multiusers/AndroidTest.xml index 20032357a..bfb7fdbf2 100644 --- a/tests/functional/safetycenter/multiusers/AndroidTest.xml +++ b/tests/functional/safetycenter/multiusers/AndroidTest.xml @@ -47,6 +47,10 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS --receiver-foreground" /> </target_preparer> diff --git a/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt b/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt index ff5dcc1f6..041cc652f 100644 --- a/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt +++ b/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt @@ -41,16 +41,20 @@ import android.safetycenter.SafetyEvent import android.safetycenter.SafetySourceData import androidx.test.core.app.ApplicationProvider import androidx.test.filters.LargeTest -import com.android.bedstead.harrier.BedsteadJUnit4 -import com.android.bedstead.harrier.DeviceState -import com.android.bedstead.harrier.annotations.EnsureHasAdditionalUser -import com.android.bedstead.harrier.annotations.EnsureHasCloneProfile -import com.android.bedstead.enterprise.annotations.EnsureHasNoWorkProfile -import com.android.bedstead.harrier.annotations.EnsureHasPrivateProfile -import com.android.bedstead.harrier.annotations.EnsureHasNoPrivateProfile -import com.android.bedstead.enterprise.annotations.EnsureHasWorkProfile import com.android.bedstead.enterprise.annotations.EnsureHasDeviceOwner import com.android.bedstead.enterprise.annotations.EnsureHasNoDeviceOwner +import com.android.bedstead.enterprise.annotations.EnsureHasNoWorkProfile +import com.android.bedstead.enterprise.annotations.EnsureHasWorkProfile +import com.android.bedstead.enterprise.workProfile +import com.android.bedstead.harrier.BedsteadJUnit4 +import com.android.bedstead.harrier.DeviceState +import com.android.bedstead.multiuser.additionalUser +import com.android.bedstead.multiuser.annotations.EnsureHasAdditionalUser +import com.android.bedstead.multiuser.annotations.EnsureHasCloneProfile +import com.android.bedstead.multiuser.annotations.EnsureHasNoPrivateProfile +import com.android.bedstead.multiuser.annotations.EnsureHasPrivateProfile +import com.android.bedstead.multiuser.cloneProfile +import com.android.bedstead.multiuser.privateProfile import com.android.bedstead.nene.TestApis import com.android.bedstead.nene.types.OptionalBoolean.TRUE import com.android.compatibility.common.util.DisableAnimationRule @@ -132,30 +136,30 @@ class SafetyCenterMultiUsersTest { listOf( safetyCenterTestData.safetyCenterIssueCritical( DYNAMIC_BAREBONE_ID, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueCritical( ISSUE_ONLY_BAREBONE_ID, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueRecommendation( DYNAMIC_DISABLED_ID, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueRecommendation( ISSUE_ONLY_ALL_OPTIONAL_ID, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_IN_STATELESS_ID, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_IN_STATELESS_ID, - groupId = MIXED_STATELESS_GROUP_ID - ) + groupId = MIXED_STATELESS_GROUP_ID, + ), ) private val dynamicBareboneDefault: SafetyCenterEntry @@ -181,7 +185,7 @@ class SafetyCenterMultiUsersTest { .safetyCenterEntryDefaultBuilder( DYNAMIC_DISABLED_ID, userId = deviceState.workProfile().id(), - title = "Paste" + title = "Paste", ) .setPendingIntent(null) .setEnabled(false) @@ -196,11 +200,9 @@ class SafetyCenterMultiUsersTest { DYNAMIC_DISABLED_ID, deviceState.workProfile().id(), title = "Ok title for Work", - pendingIntent = null - ) - .setSummary( - safetyCenterResourcesApk.getStringByName("work_profile_paused"), + pendingIntent = null, ) + .setSummary(safetyCenterResourcesApk.getStringByName("work_profile_paused")) .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED) .setEnabled(false) .build() @@ -212,7 +214,7 @@ class SafetyCenterMultiUsersTest { get() = safetyCenterTestData.safetyCenterEntryUnspecified( DYNAMIC_HIDDEN_ID, - pendingIntent = null + pendingIntent = null, ) private val dynamicHiddenForWorkUpdated: SafetyCenterEntry @@ -225,11 +227,9 @@ class SafetyCenterMultiUsersTest { DYNAMIC_HIDDEN_ID, deviceState.workProfile().id(), title = "Ok title for Work", - pendingIntent = null - ) - .setSummary( - safetyCenterResourcesApk.getStringByName("work_profile_paused"), + pendingIntent = null, ) + .setSummary(safetyCenterResourcesApk.getStringByName("work_profile_paused")) .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED) .setEnabled(false) .build() @@ -262,12 +262,12 @@ class SafetyCenterMultiUsersTest { .safetyCenterEntryDefaultStaticBuilder( STATIC_ALL_OPTIONAL_ID, userId = deviceState.workProfile().id(), - title = "Paste" + title = "Paste", ) .setPendingIntent( createTestActivityRedirectPendingIntentForUser( deviceState.workProfile().userHandle(), - explicit = false + explicit = false, ) ) @@ -287,12 +287,12 @@ class SafetyCenterMultiUsersTest { .safetyCenterEntryDefaultStaticBuilder( STATIC_ALL_OPTIONAL_ID, userId = deviceState.privateProfile().id(), - title = "Unknown" + title = "Unknown", ) .setPendingIntent( createTestActivityRedirectPendingIntentForUser( deviceState.privateProfile().userHandle(), - explicit = false + explicit = false, ) ) @@ -320,20 +320,20 @@ class SafetyCenterMultiUsersTest { .setPendingIntent( createTestActivityRedirectPendingIntentForUser( deviceState.workProfile().userHandle(), - explicit + explicit, ) ) private fun staticEntryForPrivateBuilder( title: CharSequence = "Unknown", - explicit: Boolean = true + explicit: Boolean = true, ) = SafetyCenterStaticEntry.Builder(title) .setSummary("OK") .setPendingIntent( createTestActivityRedirectPendingIntentForUser( deviceState.privateProfile().userHandle(), - explicit + explicit, ) ) @@ -374,18 +374,20 @@ class SafetyCenterMultiUsersTest { safetyCenterTestData.safetyCenterStatusUnknown, emptyList(), listOf( - SafetyCenterEntryOrGroup( + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, safetyCenterTestData.safetyCenterEntryDefault( SINGLE_SOURCE_ALL_PROFILE_ID, deviceState.additionalUser().id(), pendingIntent = createTestActivityRedirectPendingIntentForUser( deviceState.additionalUser().userHandle() - ) - ) + ), + ), + "No info yet", ) ), - emptyList() + emptyList(), ) @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context) @@ -449,7 +451,7 @@ class SafetyCenterMultiUsersTest { getSafetyCenterManagerForUser(deviceState.workProfile().userHandle()) managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForWork + dataForWork, ) setQuietMode(true) @@ -470,7 +472,7 @@ class SafetyCenterMultiUsersTest { val dataForAdditionalUser = safetySourceTestData.information additionalUserSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForAdditionalUser + dataForAdditionalUser, ) checkState( additionalUserSafetyCenterManager.getSafetySourceDataWithInteractAcrossUsersPermission( @@ -510,7 +512,7 @@ class SafetyCenterMultiUsersTest { val dataForWork = safetySourceTestData.informationWithIssueForWork managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForWork + dataForWork, ) TestApis.packages().find(context.packageName).uninstall(deviceState.workProfile()) @@ -531,7 +533,7 @@ class SafetyCenterMultiUsersTest { val dataForWork = safetySourceTestData.informationWithIssueForWork managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForWork + dataForWork, ) deviceState.workProfile().remove() @@ -552,7 +554,7 @@ class SafetyCenterMultiUsersTest { val dataForWork = safetySourceTestData.informationWithIssueForWork managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForWork + dataForWork, ) setQuietMode(true) @@ -593,14 +595,14 @@ class SafetyCenterMultiUsersTest { staticGroupBuilder .setEntries(listOf(staticBarebone, staticAllOptional)) .build() - ) + ), ), listOf( SafetyCenterStaticEntryGroup( "OK", - listOf(createStaticEntry(), createStaticEntry(explicit = false)) + listOf(createStaticEntry(), createStaticEntry(explicit = false)), ) - ) + ), ) assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig) } @@ -628,7 +630,7 @@ class SafetyCenterMultiUsersTest { listOf( dynamicBareboneDefault, dynamicDisabledDefault, - dynamicDisabledForWorkDefault + dynamicDisabledForWorkDefault, ) ) .setSeverityUnspecifiedIconType( @@ -642,7 +644,7 @@ class SafetyCenterMultiUsersTest { listOf(staticBarebone, staticAllOptional, staticAllOptionalForWork) ) .build() - ) + ), ), listOf( SafetyCenterStaticEntryGroup( @@ -651,10 +653,10 @@ class SafetyCenterMultiUsersTest { createStaticEntry(), createStaticEntryForWork(), createStaticEntry(explicit = false), - createStaticEntryForWork(explicit = false) - ) + createStaticEntryForWork(explicit = false), + ), ) - ) + ), ) assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig) } @@ -682,7 +684,7 @@ class SafetyCenterMultiUsersTest { dynamicBareboneUpdated, dynamicDisabledUpdated, dynamicDisabledForWorkDefault, - dynamicHiddenUpdated + dynamicHiddenUpdated, ) ) .setSeverityUnspecifiedIconType( @@ -696,7 +698,7 @@ class SafetyCenterMultiUsersTest { listOf(staticBarebone, staticAllOptional, staticAllOptionalForWork) ) .build() - ) + ), ), listOf( SafetyCenterStaticEntryGroup( @@ -705,10 +707,10 @@ class SafetyCenterMultiUsersTest { staticEntryUpdated, createStaticEntryForWork(), createStaticEntry(explicit = false), - createStaticEntryForWork(explicit = false) - ) + createStaticEntryForWork(explicit = false), + ), ) - ) + ), ) assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig) } @@ -730,56 +732,56 @@ class SafetyCenterMultiUsersTest { listOf( safetyCenterTestData.safetyCenterIssueCritical( DYNAMIC_BAREBONE_ID, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueCritical( ISSUE_ONLY_BAREBONE_ID, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueRecommendation( DYNAMIC_DISABLED_ID, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueRecommendation( ISSUE_ONLY_ALL_OPTIONAL_ID, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_IN_STATELESS_ID, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_IN_STATELESS_ID, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_DISABLED_ID, managedUserId, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_HIDDEN_ID, managedUserId, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_ALL_OPTIONAL_ID, managedUserId, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_IN_STATELESS_ID, managedUserId, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_IN_STATELESS_ID, managedUserId, - groupId = MIXED_STATELESS_GROUP_ID - ) + groupId = MIXED_STATELESS_GROUP_ID, + ), ), listOf( SafetyCenterEntryOrGroup( @@ -792,7 +794,7 @@ class SafetyCenterMultiUsersTest { dynamicDisabledUpdated, dynamicDisabledForWorkUpdated, dynamicHiddenUpdated, - dynamicHiddenForWorkUpdated + dynamicHiddenForWorkUpdated, ) ) .setSeverityUnspecifiedIconType( @@ -806,7 +808,7 @@ class SafetyCenterMultiUsersTest { listOf(staticBarebone, staticAllOptional, staticAllOptionalForWork) ) .build() - ) + ), ), listOf( SafetyCenterStaticEntryGroup( @@ -815,10 +817,10 @@ class SafetyCenterMultiUsersTest { staticEntryUpdated, staticEntryForWorkUpdated, createStaticEntry(explicit = false), - createStaticEntryForWork(explicit = false) - ) + createStaticEntryForWork(explicit = false), + ), ) - ) + ), ) assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig) } @@ -842,56 +844,56 @@ class SafetyCenterMultiUsersTest { listOf( safetyCenterTestData.safetyCenterIssueCritical( DYNAMIC_BAREBONE_ID, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueCritical( ISSUE_ONLY_BAREBONE_ID, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueRecommendation( DYNAMIC_DISABLED_ID, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueRecommendation( ISSUE_ONLY_ALL_OPTIONAL_ID, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_IN_STATELESS_ID, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_IN_STATELESS_ID, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_DISABLED_ID, managedUserId, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_HIDDEN_ID, managedUserId, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_ALL_OPTIONAL_ID, managedUserId, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_IN_STATELESS_ID, managedUserId, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_IN_STATELESS_ID, managedUserId, - groupId = MIXED_STATELESS_GROUP_ID - ) + groupId = MIXED_STATELESS_GROUP_ID, + ), ), listOf( SafetyCenterEntryOrGroup( @@ -904,7 +906,7 @@ class SafetyCenterMultiUsersTest { dynamicDisabledUpdated, dynamicDisabledForWorkUpdated, dynamicHiddenUpdated, - dynamicHiddenForWorkUpdated + dynamicHiddenForWorkUpdated, ) ) .setSeverityUnspecifiedIconType( @@ -918,7 +920,7 @@ class SafetyCenterMultiUsersTest { listOf(staticBarebone, staticAllOptional, staticAllOptionalForWork) ) .build() - ) + ), ), listOf( SafetyCenterStaticEntryGroup( @@ -927,10 +929,10 @@ class SafetyCenterMultiUsersTest { staticEntryUpdated, staticEntryForWorkUpdated, createStaticEntry(explicit = false), - createStaticEntryForWork(explicit = false) - ) + createStaticEntryForWork(explicit = false), + ), ) - ) + ), ) assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig) } @@ -956,82 +958,82 @@ class SafetyCenterMultiUsersTest { listOf( safetyCenterTestData.safetyCenterIssueCritical( DYNAMIC_BAREBONE_ID, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueCritical( ISSUE_ONLY_BAREBONE_ID, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueRecommendation( DYNAMIC_DISABLED_ID, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueRecommendation( ISSUE_ONLY_ALL_OPTIONAL_ID, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_IN_STATELESS_ID, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_IN_STATELESS_ID, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_DISABLED_ID, managedUserId, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_HIDDEN_ID, managedUserId, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_ALL_OPTIONAL_ID, managedUserId, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_IN_STATELESS_ID, managedUserId, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_IN_STATELESS_ID, managedUserId, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_DISABLED_ID, privateProfileId, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_HIDDEN_ID, privateProfileId, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_ALL_OPTIONAL_ID, privateProfileId, attributionTitle = null, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_IN_STATELESS_ID, privateProfileId, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_IN_STATELESS_ID, privateProfileId, - groupId = MIXED_STATELESS_GROUP_ID - ) + groupId = MIXED_STATELESS_GROUP_ID, + ), ), listOf( SafetyCenterEntryOrGroup( @@ -1046,7 +1048,7 @@ class SafetyCenterMultiUsersTest { dynamicDisabledForPrivateUpdated, dynamicHiddenUpdated, dynamicHiddenForWorkUpdated, - dynamicHiddenForPrivateUpdated + dynamicHiddenForPrivateUpdated, ) ) .setSeverityUnspecifiedIconType( @@ -1061,11 +1063,11 @@ class SafetyCenterMultiUsersTest { staticBarebone, staticAllOptional, staticAllOptionalForWork, - staticAllOptionalForPrivate + staticAllOptionalForPrivate, ) ) .build() - ) + ), ), listOf( SafetyCenterStaticEntryGroup( @@ -1076,10 +1078,10 @@ class SafetyCenterMultiUsersTest { staticEntryForPrivateUpdated, createStaticEntry(explicit = false), createStaticEntryForWork(explicit = false), - createStaticEntryForPrivate(explicit = false) - ) + createStaticEntryForPrivate(explicit = false), + ), ) - ) + ), ) assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig) } @@ -1124,11 +1126,11 @@ class SafetyCenterMultiUsersTest { listOf( staticBarebone, staticAllOptional, - staticAllOptionalForWorkPaused + staticAllOptionalForWorkPaused, ) ) .build() - ) + ), ), listOf( SafetyCenterStaticEntryGroup( @@ -1137,10 +1139,10 @@ class SafetyCenterMultiUsersTest { staticEntryUpdated, staticEntryForWorkPausedUpdated, createStaticEntry(explicit = false), - createStaticEntryForWorkPaused() - ) + createStaticEntryForWorkPaused(), + ), ) - ) + ), ) assertThat(apiSafetyCenterData.withoutExtras()).isEqualTo(safetyCenterDataFromComplexConfig) } @@ -1157,7 +1159,7 @@ class SafetyCenterMultiUsersTest { getSafetyCenterManagerForUser(deviceState.workProfile().userHandle()) managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForPrimaryUserWorkProfile + dataForPrimaryUserWorkProfile, ) val additionalUserSafetyCenterManager = @@ -1199,8 +1201,8 @@ class SafetyCenterMultiUsersTest { pendingIntent = createTestActivityRedirectPendingIntentForUser( deviceState.workProfile().userHandle() - ) - ) + ), + ), ) ) .setSeverityUnspecifiedIconType( @@ -1209,7 +1211,7 @@ class SafetyCenterMultiUsersTest { .build() ) ), - emptyList() + emptyList(), ) checkState( safetyCenterManager.getSafetyCenterDataWithPermission() == @@ -1227,11 +1229,13 @@ class SafetyCenterMultiUsersTest { safetyCenterTestData.safetyCenterStatusUnknown, emptyList(), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ALL_PROFILE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ALL_PROFILE_ID), + "No info yet", ) ), - emptyList() + emptyList(), ) assertThat(safetyCenterManager.getSafetyCenterDataWithPermission()) .isEqualTo(safetyCenterDataForPrimaryUser) @@ -1271,8 +1275,8 @@ class SafetyCenterMultiUsersTest { pendingIntent = createTestActivityRedirectPendingIntentForUser( deviceState.privateProfile().userHandle() - ) - ) + ), + ), ) ) .setSeverityUnspecifiedIconType( @@ -1281,7 +1285,7 @@ class SafetyCenterMultiUsersTest { .build() ) ), - emptyList() + emptyList(), ) assertThat(safetyCenterManager.getSafetyCenterDataWithPermission()) @@ -1298,11 +1302,13 @@ class SafetyCenterMultiUsersTest { safetyCenterTestData.safetyCenterStatusUnknown, emptyList(), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ALL_PROFILE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ALL_PROFILE_ID), + "No info yet", ) ), - emptyList() + emptyList(), ) assertThat(safetyCenterManager.getSafetyCenterDataWithPermission()) .isEqualTo(safetyCenterDataForPrimaryUser) @@ -1345,7 +1351,7 @@ class SafetyCenterMultiUsersTest { assertFailsWith(IllegalArgumentException::class) { managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( ISSUE_ONLY_ALL_OPTIONAL_ID, - dataForWork + dataForWork, ) } } @@ -1362,7 +1368,7 @@ class SafetyCenterMultiUsersTest { managedSafetyCenterManager.setSafetySourceData( SINGLE_SOURCE_ALL_PROFILE_ID, dataForWork, - EVENT_SOURCE_STATE_CHANGED + EVENT_SOURCE_STATE_CHANGED, ) } } @@ -1378,7 +1384,7 @@ class SafetyCenterMultiUsersTest { managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForWork + dataForWork, ) val safetySourceData = @@ -1399,7 +1405,7 @@ class SafetyCenterMultiUsersTest { managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForWork + dataForWork, ) val safetySourceData = @@ -1419,7 +1425,7 @@ class SafetyCenterMultiUsersTest { clonedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForClone + dataForClone, ) val safetySourceData = @@ -1440,7 +1446,7 @@ class SafetyCenterMultiUsersTest { managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForWork + dataForWork, ) val safetySourceData = @@ -1464,7 +1470,7 @@ class SafetyCenterMultiUsersTest { SafetySourceTestData.issuesOnly(safetySourceTestData.criticalResolvingGeneralIssue) managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( ISSUE_ONLY_ALL_PROFILE_SOURCE_ID, - dataForWorkProfile + dataForWorkProfile, ) val apiSafetySourceData = @@ -1488,7 +1494,7 @@ class SafetyCenterMultiUsersTest { assertFailsWith(IllegalArgumentException::class) { managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ID, - dataForWork + dataForWork, ) } } @@ -1505,7 +1511,7 @@ class SafetyCenterMultiUsersTest { getSafetyCenterManagerForUser(deviceState.workProfile().userHandle()) managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForWork + dataForWork, ) val apiSafetySourceData = @@ -1532,14 +1538,14 @@ class SafetyCenterMultiUsersTest { managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ALL_PROFILE_ID, - dataForWork + dataForWork, ) TestNotificationListener.waitForNotificationsMatching( NotificationCharacteristics( title = "Information issue title", text = "Information issue summary", - actions = listOf("Review") + actions = listOf("Review"), ) ) } @@ -1555,7 +1561,7 @@ class SafetyCenterMultiUsersTest { getSafetyCenterManagerForUser(deviceState.additionalUser().userHandle()) additionalUserSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ID, - dataForPrimaryUser + dataForPrimaryUser, ) val apiSafetySourceData = @@ -1577,7 +1583,7 @@ class SafetyCenterMultiUsersTest { getSafetyCenterManagerForUser(deviceState.additionalUser().userHandle()) additionalUserSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ID, - dataForAdditionalUser + dataForAdditionalUser, ) val apiSafetySourceDataForPrimaryUser = @@ -1600,7 +1606,7 @@ class SafetyCenterMultiUsersTest { getSafetyCenterManagerForUser(deviceState.additionalUser().userHandle()) additionalUserSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( SINGLE_SOURCE_ID, - dataForAdditionalUser + dataForAdditionalUser, ) val apiSafetySourceDataForPrimaryUser = @@ -1627,12 +1633,12 @@ class SafetyCenterMultiUsersTest { private fun createTestActivityRedirectPendingIntentForUser( user: UserHandle, - explicit: Boolean = true + explicit: Boolean = true, ): PendingIntent { return callWithShellPermissionIdentity(INTERACT_ACROSS_USERS) { SafetySourceTestData.createRedirectPendingIntent( getContextForUser(user), - SafetySourceTestData.createTestActivityIntent(getContextForUser(user), explicit) + SafetySourceTestData.createTestActivityIntent(getContextForUser(user), explicit), ) } } @@ -1647,7 +1653,7 @@ class SafetyCenterMultiUsersTest { private fun SafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( id: String, dataToSet: SafetySourceData, - safetyEvent: SafetyEvent = EVENT_SOURCE_STATE_CHANGED + safetyEvent: SafetyEvent = EVENT_SOURCE_STATE_CHANGED, ) = callWithShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL) { setSafetySourceDataWithPermission(id, dataToSet, safetyEvent) @@ -1691,28 +1697,28 @@ class SafetyCenterMultiUsersTest { private fun updatePrimaryProfileSources() { safetyCenterTestHelper.setData( DYNAMIC_BAREBONE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( DYNAMIC_DISABLED_ID, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(DYNAMIC_HIDDEN_ID, safetySourceTestData.unspecified) safetyCenterTestHelper.setData( ISSUE_ONLY_BAREBONE_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.criticalResolvingGeneralIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.criticalResolvingGeneralIssue), ) safetyCenterTestHelper.setData( ISSUE_ONLY_ALL_OPTIONAL_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue), ) safetyCenterTestHelper.setData( DYNAMIC_IN_STATELESS_ID, - safetySourceTestData.unspecifiedWithIssue + safetySourceTestData.unspecifiedWithIssue, ) safetyCenterTestHelper.setData( ISSUE_ONLY_IN_STATELESS_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue), ) } @@ -1721,23 +1727,23 @@ class SafetyCenterMultiUsersTest { getSafetyCenterManagerForUser(deviceState.workProfile().userHandle()) managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( DYNAMIC_DISABLED_ID, - safetySourceTestData.informationWithIssueForWork + safetySourceTestData.informationWithIssueForWork, ) managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( DYNAMIC_HIDDEN_ID, - safetySourceTestData.informationWithIssueForWork + safetySourceTestData.informationWithIssueForWork, ) managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( ISSUE_ONLY_ALL_OPTIONAL_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue), ) managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( DYNAMIC_IN_STATELESS_ID, - safetySourceTestData.unspecifiedWithIssueForWork + safetySourceTestData.unspecifiedWithIssueForWork, ) managedSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( ISSUE_ONLY_IN_STATELESS_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue), ) } @@ -1746,23 +1752,23 @@ class SafetyCenterMultiUsersTest { getSafetyCenterManagerForUser(deviceState.privateProfile().userHandle()) privateSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( DYNAMIC_DISABLED_ID, - safetySourceTestData.informationWithIssueForPrivate + safetySourceTestData.informationWithIssueForPrivate, ) privateSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( DYNAMIC_HIDDEN_ID, - safetySourceTestData.informationWithIssueForPrivate + safetySourceTestData.informationWithIssueForPrivate, ) privateSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( ISSUE_ONLY_ALL_OPTIONAL_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue), ) privateSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( DYNAMIC_IN_STATELESS_ID, - safetySourceTestData.unspecifiedWithIssueForPrivate + safetySourceTestData.unspecifiedWithIssueForPrivate, ) privateSafetyCenterManager.setSafetySourceDataWithInteractAcrossUsersPermission( ISSUE_ONLY_IN_STATELESS_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue), ) } } diff --git a/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml b/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml index a1826653f..ee79dcd2a 100644 --- a/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml +++ b/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml @@ -47,6 +47,10 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS --receiver-foreground" /> </target_preparer> diff --git a/tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt b/tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt index 73f435615..09a32f058 100644 --- a/tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt +++ b/tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt @@ -60,6 +60,7 @@ import com.android.safetycenter.testing.UiTestHelper.RESCAN_BUTTON_LABEL import com.android.safetycenter.testing.UiTestHelper.clickConfirmDismissal import com.android.safetycenter.testing.UiTestHelper.clickDismissIssueCard import com.android.safetycenter.testing.UiTestHelper.clickMoreIssuesCard +import com.android.safetycenter.testing.UiTestHelper.clickOpenSubpage import com.android.safetycenter.testing.UiTestHelper.resetRotation import com.android.safetycenter.testing.UiTestHelper.rotate import com.android.safetycenter.testing.UiTestHelper.setAnimationsEnabled @@ -73,7 +74,9 @@ import com.android.safetycenter.testing.UiTestHelper.waitPageTitleDisplayed import com.android.safetycenter.testing.UiTestHelper.waitSourceDataDisplayed import com.android.safetycenter.testing.UiTestHelper.waitSourceIssueDisplayed import com.android.safetycenter.testing.UiTestHelper.waitSourceIssueNotDisplayed +import java.util.regex.Pattern import org.junit.After +import org.junit.Assume.assumeFalse import org.junit.Assume.assumeTrue import org.junit.Rule import org.junit.Test @@ -99,13 +102,13 @@ class SafetyCenterActivityTest { } @Test - fun launchActivity_allowingSettingsTrampoline() { + fun launchActivity_allowingSettingsTrampoline_showsSafetyCenter() { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) val dataToDisplay = safetySourceTestData.criticalWithResolvingGeneralIssue safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToDisplay) context.launchSafetyCenterActivity(preventTrampolineToSettings = false) { - waitSourceDataDisplayed(dataToDisplay) + waitSourceIssueDisplayed(dataToDisplay.issues[0]) } } @@ -120,7 +123,7 @@ class SafetyCenterActivityTest { context.getString(safetyCenterTestConfigs.staticSource1.summaryResId), context.getString(safetyCenterTestConfigs.staticSourceGroup2.titleResId), context.getString(safetyCenterTestConfigs.staticSource2.titleResId), - context.getString(safetyCenterTestConfigs.staticSource2.summaryResId) + context.getString(safetyCenterTestConfigs.staticSource2.summaryResId), ) } } @@ -131,7 +134,13 @@ class SafetyCenterActivityTest { val dataToDisplay = safetySourceTestData.criticalWithResolvingGeneralIssue safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToDisplay) - context.launchSafetyCenterActivity { waitSourceDataDisplayed(dataToDisplay) } + context.launchSafetyCenterActivity { + if (SafetyCenterFlags.showSubpages) { + waitSourceIssueDisplayed(dataToDisplay.issues[0]) + } else { + waitSourceDataDisplayed(dataToDisplay) + } + } } @Test @@ -144,8 +153,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_1_TITLE, entrySummary = SAFETY_SOURCE_1_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_2, @@ -153,8 +162,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_2_TITLE, entrySummary = SAFETY_SOURCE_2_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_3, @@ -162,8 +171,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_3_TITLE, entrySummary = SAFETY_SOURCE_3_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_4, @@ -171,8 +180,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_4_TITLE, entrySummary = SAFETY_SOURCE_4_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_5, @@ -180,8 +189,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_5_TITLE, entrySummary = SAFETY_SOURCE_5_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) } @@ -190,7 +199,7 @@ class SafetyCenterActivityTest { context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.titleResId), context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.summaryResId), context.getString(safetyCenterTestConfigs.dynamicSourceGroup3.titleResId), - context.getString(safetyCenterTestConfigs.dynamicSourceGroup3.summaryResId) + context.getString(safetyCenterTestConfigs.dynamicSourceGroup3.summaryResId), ) waitAllTextNotDisplayed( SAFETY_SOURCE_1_TITLE, @@ -200,7 +209,7 @@ class SafetyCenterActivityTest { SAFETY_SOURCE_4_TITLE, SAFETY_SOURCE_4_SUMMARY, SAFETY_SOURCE_5_TITLE, - SAFETY_SOURCE_5_SUMMARY + SAFETY_SOURCE_5_SUMMARY, ) } } @@ -215,8 +224,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_1_TITLE, entrySummary = SAFETY_SOURCE_1_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_2, @@ -224,8 +233,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_RECOMMENDATION, entryTitle = SAFETY_SOURCE_2_TITLE, entrySummary = SAFETY_SOURCE_2_SUMMARY, - withIssue = true - ) + withIssue = true, + ), ) setData( SOURCE_ID_3, @@ -233,8 +242,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_3_TITLE, entrySummary = SAFETY_SOURCE_3_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_4, @@ -242,8 +251,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_RECOMMENDATION, entryTitle = SAFETY_SOURCE_4_TITLE, entrySummary = SAFETY_SOURCE_4_SUMMARY, - withIssue = true - ) + withIssue = true, + ), ) setData( SOURCE_ID_5, @@ -251,8 +260,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_CRITICAL_WARNING, entryTitle = SAFETY_SOURCE_5_TITLE, entrySummary = SAFETY_SOURCE_5_SUMMARY, - withIssue = true - ) + withIssue = true, + ), ) } @@ -261,7 +270,7 @@ class SafetyCenterActivityTest { context.getString(safetyCenterTestConfigs.dynamicSourceGroup1.titleResId), SAFETY_SOURCE_2_SUMMARY, context.getString(safetyCenterTestConfigs.dynamicSourceGroup3.titleResId), - SAFETY_SOURCE_5_SUMMARY + SAFETY_SOURCE_5_SUMMARY, ) waitAllTextNotDisplayed( SAFETY_SOURCE_1_TITLE, @@ -269,13 +278,15 @@ class SafetyCenterActivityTest { SAFETY_SOURCE_1_SUMMARY, SAFETY_SOURCE_4_TITLE, SAFETY_SOURCE_5_TITLE, - SAFETY_SOURCE_4_SUMMARY + SAFETY_SOURCE_4_SUMMARY, ) } } @Test fun launchActivity_displaysGroupsOfSingleSourceAsEntity() { + // Single source groups are displayed in the subpage when subpages enabled + assumeFalse(SafetyCenterFlags.showSubpages) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig) context.launchSafetyCenterActivity { @@ -297,7 +308,11 @@ class SafetyCenterActivityTest { val dataToDisplay = safetySourceTestData.recommendationWithGeneralIssue safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, dataToDisplay) - waitSourceDataDisplayed(dataToDisplay) + if (SafetyCenterFlags.showSubpages) { + waitSourceIssueDisplayed(dataToDisplay.issues[0]) + } else { + waitSourceDataDisplayed(dataToDisplay) + } } } @@ -338,6 +353,8 @@ class SafetyCenterActivityTest { @Test fun entryListWithEntryGroup_informationState_hasContentDescription() { + // No custom content descriptions when using subpages + assumeFalse(SafetyCenterFlags.showSubpages) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData(SOURCE_ID_1, safetySourceTestData.information) safetyCenterTestHelper.setData(SOURCE_ID_2, safetySourceTestData.information) @@ -355,10 +372,12 @@ class SafetyCenterActivityTest { @Test fun entryListWithEntryGroup_recommendationState_hasActionsNeededContentDescription() { + // No custom content descriptions when using subpages + assumeFalse(SafetyCenterFlags.showSubpages) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_2, safetySourceTestData.information) safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.information) @@ -394,6 +413,8 @@ class SafetyCenterActivityTest { @Test fun entryListWithEntryGroup_unclickableDisabledEntry_hasContentDescription() { + // No custom content descriptions when using subpages + assumeFalse(SafetyCenterFlags.showSubpages) safetyCenterTestHelper.setConfig( safetyCenterTestConfigs.multipleSourcesConfigWithSourceWithInvalidIntent ) @@ -412,7 +433,7 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.unspecifiedDisabledWithTestActivityRedirect + safetySourceTestData.unspecifiedDisabledWithTestActivityRedirect, ) context.launchSafetyCenterActivity { @@ -424,10 +445,12 @@ class SafetyCenterActivityTest { @Test fun entryListWithEntryGroup_clickableDisabledEntry_hasContentDescription() { + // No custom content descriptions when using subpages + assumeFalse(SafetyCenterFlags.showSubpages) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.unspecifiedDisabledWithTestActivityRedirect + safetySourceTestData.unspecifiedDisabledWithTestActivityRedirect, ) context.launchSafetyCenterActivity { @@ -442,6 +465,8 @@ class SafetyCenterActivityTest { @Test fun entryListWithSingleSource_informationState_hasContentDescription() { + // No custom content descriptions when using subpages + assumeFalse(SafetyCenterFlags.showSubpages) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information) @@ -456,6 +481,12 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) context.launchSafetyCenterActivity { + if (SafetyCenterFlags.showSubpages) { + clickOpenSubpage( + context, + safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first(), + ) + } waitDisplayed(By.text("OK")) { it.click() } waitButtonDisplayed("Exit test activity") { it.click() } waitDisplayed(By.text("OK")) @@ -467,6 +498,13 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.implicitIntentSingleSourceConfig) context.launchSafetyCenterActivity { + if (SafetyCenterFlags.showSubpages) { + clickOpenSubpage( + context, + safetyCenterTestConfigs.implicitIntentSingleSourceConfig.safetySourcesGroups + .first(), + ) + } waitDisplayed(By.text("OK")) { it.click() } waitButtonDisplayed("Exit test activity") { it.click() } } @@ -478,6 +516,12 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information) context.launchSafetyCenterActivity { + if (SafetyCenterFlags.showSubpages) { + clickOpenSubpage( + context, + safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first(), + ) + } waitDisplayed(By.text("Ok title")) { it.click() } waitButtonDisplayed("Exit test activity") { it.click() } waitDisplayed(By.text("Ok title")) @@ -489,10 +533,16 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.informationWithIconAction + safetySourceTestData.informationWithIconAction, ) context.launchSafetyCenterActivity { + if (SafetyCenterFlags.showSubpages) { + clickOpenSubpage( + context, + safetyCenterTestConfigs.singleSourceConfig.safetySourcesGroups.first(), + ) + } waitDisplayed(By.desc("Information")) { it.click() } waitButtonDisplayed("Exit test activity") { it.click() } waitDisplayed(By.text("Ok title")) @@ -523,7 +573,7 @@ class SafetyCenterActivityTest { val issue = safetySourceTestData.recommendationGeneralIssue safetyCenterTestHelper.setData( ISSUE_ONLY_ALL_OPTIONAL_ID, - SafetySourceTestData.issuesOnly(issue) + SafetySourceTestData.issuesOnly(issue), ) context.launchSafetyCenterActivity { waitDisplayed(By.desc("Alert. ${issue.title}")) } @@ -553,7 +603,6 @@ class SafetyCenterActivityTest { clickDismissIssueCard() waitSourceIssueNotDisplayed(safetySourceTestData.informationIssue) - waitSourceDataDisplayed(safetySourceTestData.information) waitButtonDisplayed(RESCAN_BUTTON_LABEL) } } @@ -563,7 +612,7 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) context.launchSafetyCenterActivity { @@ -581,21 +630,21 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) context.launchSafetyCenterActivity { clickDismissIssueCard() waitAllTextDisplayed( "Dismiss this alert?", - "Review your security and privacy settings any time to add more protection" + "Review your security and privacy settings any time to add more protection", ) getUiDevice().rotate() waitAllTextDisplayed( "Dismiss this alert?", - "Review your security and privacy settings any time to add more protection" + "Review your security and privacy settings any time to add more protection", ) clickConfirmDismissal() @@ -609,7 +658,7 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) context.launchSafetyCenterActivity { @@ -626,7 +675,7 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) context.launchSafetyCenterActivity { @@ -650,13 +699,13 @@ class SafetyCenterActivityTest { // Set the initial data for the source safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage + safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage, ) // Clear the data when action is triggered to simulate resolution. SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.ClearData + Response.ClearData, ) context.launchSafetyCenterActivity(withReceiverPermission = true) { @@ -680,13 +729,13 @@ class SafetyCenterActivityTest { // Set the initial data for the source safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage + safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage, ) // Clear the data when action is triggered to simulate resolution. SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.ClearData + Response.ClearData, ) context.launchSafetyCenterActivity(withReceiverPermission = true) { @@ -708,13 +757,13 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssueWithConfirmation + safetySourceTestData.criticalWithResolvingGeneralIssueWithConfirmation, ) // Clear the data when action is triggered to simulate resolution. SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.ClearData + Response.ClearData, ) context.launchSafetyCenterActivity(withReceiverPermission = true) { @@ -734,13 +783,13 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssueWithConfirmation + safetySourceTestData.criticalWithResolvingGeneralIssueWithConfirmation, ) // Clear the data when action is triggered to simulate resolution. SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.ClearData + Response.ClearData, ) context.launchSafetyCenterActivity(withReceiverPermission = true) { @@ -764,7 +813,7 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssueWithConfirmation + safetySourceTestData.criticalWithResolvingGeneralIssueWithConfirmation, ) context.launchSafetyCenterActivity(withReceiverPermission = true) { @@ -786,13 +835,13 @@ class SafetyCenterActivityTest { // Set the initial data for the source safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) // Clear the data when action is triggered to simulate resolution. SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.ClearData + Response.ClearData, ) context.launchSafetyCenterActivity(withReceiverPermission = true) { @@ -909,11 +958,11 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue) @@ -923,7 +972,7 @@ class SafetyCenterActivityTest { waitExpandedIssuesDisplayed( safetySourceTestData.criticalResolvingGeneralIssue, safetySourceTestData.recommendationGeneralIssue, - safetySourceTestData.informationIssue + safetySourceTestData.informationIssue, ) } } @@ -933,11 +982,11 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue) @@ -948,7 +997,7 @@ class SafetyCenterActivityTest { waitCollapsedIssuesDisplayed( safetySourceTestData.criticalResolvingGeneralIssue, safetySourceTestData.recommendationGeneralIssue, - safetySourceTestData.informationIssue + safetySourceTestData.informationIssue, ) } } @@ -958,11 +1007,11 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.criticalWithRedirectingIssue + safetySourceTestData.criticalWithRedirectingIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue) @@ -973,7 +1022,7 @@ class SafetyCenterActivityTest { waitCollapsedIssuesDisplayed( safetySourceTestData.criticalRedirectingIssue, safetySourceTestData.criticalResolvingGeneralIssue, - safetySourceTestData.informationIssue + safetySourceTestData.informationIssue, ) } } @@ -983,11 +1032,11 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue) @@ -1007,11 +1056,11 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue) @@ -1022,7 +1071,7 @@ class SafetyCenterActivityTest { waitCollapsedIssuesDisplayed( safetySourceTestData.criticalResolvingGeneralIssue, safetySourceTestData.recommendationGeneralIssue, - safetySourceTestData.informationIssue + safetySourceTestData.informationIssue, ) } } @@ -1032,7 +1081,7 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) context.launchSafetyCenterActivity { @@ -1046,11 +1095,11 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue) @@ -1058,7 +1107,7 @@ class SafetyCenterActivityTest { waitCollapsedIssuesDisplayed( safetySourceTestData.criticalResolvingGeneralIssue, safetySourceTestData.recommendationGeneralIssue, - safetySourceTestData.informationIssue + safetySourceTestData.informationIssue, ) } } @@ -1068,11 +1117,11 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue) @@ -1084,7 +1133,7 @@ class SafetyCenterActivityTest { waitExpandedIssuesDisplayed( safetySourceTestData.criticalResolvingGeneralIssue, safetySourceTestData.recommendationGeneralIssue, - safetySourceTestData.informationIssue + safetySourceTestData.informationIssue, ) } } @@ -1094,11 +1143,11 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue) @@ -1118,7 +1167,7 @@ class SafetyCenterActivityTest { waitExpandedIssuesDisplayed( safetySourceTestData.criticalResolvingGeneralIssue, safetySourceTestData.recommendationGeneralIssue, - safetySourceTestData.informationIssue + safetySourceTestData.informationIssue, ) } } @@ -1128,11 +1177,11 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue) @@ -1152,11 +1201,11 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_3, safetySourceTestData.informationWithIssue) @@ -1173,7 +1222,7 @@ class SafetyCenterActivityTest { } @Test - fun collapsedEntryGroup_expandsWhenClicked() { + fun entryGroup_showsEntriesWhenClicked() { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig) with(safetyCenterTestHelper) { setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig) @@ -1183,8 +1232,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_1_TITLE, entrySummary = SAFETY_SOURCE_1_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_2, @@ -1192,8 +1241,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_2_TITLE, entrySummary = SAFETY_SOURCE_2_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_3, @@ -1201,8 +1250,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_3_TITLE, entrySummary = SAFETY_SOURCE_3_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_4, @@ -1210,8 +1259,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_4_TITLE, entrySummary = SAFETY_SOURCE_4_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_5, @@ -1219,8 +1268,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_5_TITLE, entrySummary = SAFETY_SOURCE_5_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) } @@ -1238,13 +1287,14 @@ class SafetyCenterActivityTest { SAFETY_SOURCE_1_TITLE, SAFETY_SOURCE_1_SUMMARY, SAFETY_SOURCE_2_TITLE, - SAFETY_SOURCE_2_SUMMARY + SAFETY_SOURCE_2_SUMMARY, ) } } @Test fun expandedEntryGroup_collapsesWhenClicked() { + assumeFalse(SafetyCenterFlags.showSubpages) // No collapsible groups when using subpages with(safetyCenterTestHelper) { setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig) setData( @@ -1253,8 +1303,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_1_TITLE, entrySummary = SAFETY_SOURCE_1_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_2, @@ -1262,8 +1312,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_2_TITLE, entrySummary = SAFETY_SOURCE_2_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_3, @@ -1271,8 +1321,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_3_TITLE, entrySummary = SAFETY_SOURCE_3_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_4, @@ -1280,8 +1330,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_4_TITLE, entrySummary = SAFETY_SOURCE_4_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_5, @@ -1289,8 +1339,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_5_TITLE, entrySummary = SAFETY_SOURCE_5_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) } @@ -1332,13 +1382,14 @@ class SafetyCenterActivityTest { ) waitAllTextDisplayed( context.getString(safetyCenterTestConfigs.dynamicSource1.titleResId), - context.getString(safetyCenterTestConfigs.dynamicSource2.titleResId) + context.getString(safetyCenterTestConfigs.dynamicSource2.titleResId), ) } } @Test fun expandedEntryGroup_otherGroupRemainsCollapsed() { + assumeFalse(SafetyCenterFlags.showSubpages) // No collapsible groups when using subpages safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig) with(safetyCenterTestHelper) { setConfig(safetyCenterTestConfigs.multipleSourceGroupsConfig) @@ -1348,8 +1399,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_1_TITLE, entrySummary = SAFETY_SOURCE_1_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_2, @@ -1357,8 +1408,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_2_TITLE, entrySummary = SAFETY_SOURCE_2_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_3, @@ -1366,8 +1417,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_3_TITLE, entrySummary = SAFETY_SOURCE_3_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_4, @@ -1375,8 +1426,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_4_TITLE, entrySummary = SAFETY_SOURCE_4_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) setData( SOURCE_ID_5, @@ -1384,8 +1435,8 @@ class SafetyCenterActivityTest { severityLevel = SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_5_TITLE, entrySummary = SAFETY_SOURCE_5_SUMMARY, - withIssue = false - ) + withIssue = false, + ), ) } @@ -1425,7 +1476,7 @@ class SafetyCenterActivityTest { context.launchSafetyCenterActivity { waitAllTextDisplayed( context.getString(lastGroup.titleResId), - context.getString(lastGroup.summaryResId) + context.getString(lastGroup.summaryResId), ) waitDisplayed(By.text(context.getString(firstGroup.titleResId))) { it.click() } @@ -1444,6 +1495,13 @@ class SafetyCenterActivityTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.implicitIntentSingleSourceConfig) context.launchSafetyCenterActivity { + if (SafetyCenterFlags.showSubpages) { + clickOpenSubpage( + context, + safetyCenterTestConfigs.implicitIntentSingleSourceConfig.safetySourcesGroups + .first(), + ) + } waitDisplayed(By.text("OK")) { it.click() } waitDisplayed(By.text("is_from_settings_homepage false")) waitButtonDisplayed("Exit test activity") { it.click() } @@ -1477,9 +1535,10 @@ class SafetyCenterActivityTest { ) safetyCenterTestHelper.setEnabled(false) + val containsPrivacyPattern = Pattern.compile(".*[Pp]rivacy|[Pp]ermission.*") // NOTYPO context.launchSafetyCenterActivity(intentAction = PRIVACY_CONTROLS_ACTION) { waitDisplayed(By.pkg(context.getSettingsPackageName())) - waitPageTitleDisplayed("Privacy") + waitDisplayed(By.text(containsPrivacyPattern)) } } diff --git a/tests/functional/safetycenter/singleuser/AndroidTest.xml b/tests/functional/safetycenter/singleuser/AndroidTest.xml index 3aa173508..f778ca93e 100644 --- a/tests/functional/safetycenter/singleuser/AndroidTest.xml +++ b/tests/functional/safetycenter/singleuser/AndroidTest.xml @@ -47,6 +47,10 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS --receiver-foreground" /> </target_preparer> diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt index cb3935ec5..f5d230deb 100644 --- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt +++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt @@ -75,6 +75,7 @@ import com.android.safetycenter.internaldata.SafetyCenterIds import com.android.safetycenter.resources.SafetyCenterResourcesApk import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG import com.android.safetycenter.testing.Coroutines.TIMEOUT_SHORT +import com.android.safetycenter.testing.Coroutines.assertWithTimeout import com.android.safetycenter.testing.Coroutines.waitForWithTimeout import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.dismissSafetyCenterIssueWithPermission import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.getSafetyCenterConfigWithPermission @@ -104,6 +105,7 @@ import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.MIXED_ import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.MIXED_STATELESS_GROUP_ID import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.MULTIPLE_SOURCES_GROUP_ID_1 import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.MULTIPLE_SOURCES_GROUP_ID_2 +import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_GROUP_ID import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_1 import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_2 @@ -160,7 +162,7 @@ class SafetyCenterManagerTest { get() = SafetyCenterStatus.Builder( safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"), - safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary") + safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary"), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK) .build() @@ -169,7 +171,7 @@ class SafetyCenterManagerTest { get() = SafetyCenterStatus.Builder( safetyCenterResourcesApk.getStringByName("scanning_title"), - safetyCenterResourcesApk.getStringByName("loading_summary") + safetyCenterResourcesApk.getStringByName("loading_summary"), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_UNKNOWN) .setRefreshStatus(REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS) @@ -179,7 +181,7 @@ class SafetyCenterManagerTest { get() = SafetyCenterStatus.Builder( safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK) .build() @@ -190,7 +192,7 @@ class SafetyCenterManagerTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_ok_review_title" ), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK) .build() @@ -203,7 +205,7 @@ class SafetyCenterManagerTest { ), safetyCenterResourcesApk.getStringByName( "overall_severity_level_ok_review_summary" - ) + ), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK) .build() @@ -214,7 +216,7 @@ class SafetyCenterManagerTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_safety_recommendation_title" ), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION) .build() @@ -225,7 +227,7 @@ class SafetyCenterManagerTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_account_recommendation_title" ), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION) .build() @@ -236,7 +238,7 @@ class SafetyCenterManagerTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_device_recommendation_title" ), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_RECOMMENDATION) .build() @@ -247,7 +249,7 @@ class SafetyCenterManagerTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_critical_safety_warning_title" ), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING) .build() @@ -258,7 +260,7 @@ class SafetyCenterManagerTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_critical_safety_warning_title" ), - safetyCenterTestData.getAlertString(2) + safetyCenterTestData.getAlertString(2), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING) .build() @@ -269,7 +271,7 @@ class SafetyCenterManagerTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_critical_account_warning_title" ), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING) .build() @@ -280,7 +282,7 @@ class SafetyCenterManagerTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_critical_account_warning_title" ), - safetyCenterTestData.getAlertString(2) + safetyCenterTestData.getAlertString(2), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING) .build() @@ -291,7 +293,7 @@ class SafetyCenterManagerTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_critical_device_warning_title" ), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING) .build() @@ -302,21 +304,23 @@ class SafetyCenterManagerTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_critical_device_warning_title" ), - safetyCenterTestData.getAlertString(2) + safetyCenterTestData.getAlertString(2), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING) .build() private val safetyCenterEntryOrGroupRecommendation: SafetyCenterEntryOrGroup get() = - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID), ) private val safetyCenterEntryOrGroupCritical: SafetyCenterEntryOrGroup get() = - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryCritical(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryCritical(SINGLE_SOURCE_ID), ) private val safetyCenterEntryGroupMixedFromComplexConfig: SafetyCenterEntryOrGroup @@ -330,7 +334,7 @@ class SafetyCenterManagerTest { safetyCenterTestData.safetyCenterEntryDefault(DYNAMIC_IN_STATEFUL_ID), SafetyCenterEntry.Builder( SafetyCenterTestData.entryId(STATIC_IN_STATEFUL_ID), - "OK" + "OK", ) .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED) .setSummary("OK") @@ -342,7 +346,7 @@ class SafetyCenterManagerTest { .setSeverityUnspecifiedIconType( SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON ) - .build() + .build(), ) ) .setSeverityUnspecifiedIconType( @@ -370,8 +374,8 @@ class SafetyCenterManagerTest { explicit = false ) ) - .build() - ) + .build(), + ), ) private val safetyCenterStaticEntryGroupMixedFromComplexConfig: SafetyCenterStaticEntryGroup @@ -392,8 +396,8 @@ class SafetyCenterManagerTest { explicit = false ) ) - .build() - ) + .build(), + ), ) private val safetyCenterStaticEntryGroupMixedUpdatedFromComplexConfig: @@ -415,8 +419,8 @@ class SafetyCenterManagerTest { explicit = false ) ) - .build() - ) + .build(), + ), ) private val safetyCenterDataFromConfigScanning: SafetyCenterData @@ -425,11 +429,13 @@ class SafetyCenterManagerTest { safetyCenterStatusUnknownScanning, emptyList(), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ID), + "No info yet", ) ), - emptyList() + emptyList(), ) private val safetyCenterDataFromConfig: SafetyCenterData @@ -438,11 +444,13 @@ class SafetyCenterManagerTest { safetyCenterTestData.safetyCenterStatusUnknown, emptyList(), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryDefault(SINGLE_SOURCE_ID), + "No info yet", ) ), - emptyList() + emptyList(), ) private val safetyCenterDataUnspecified: SafetyCenterData @@ -451,11 +459,12 @@ class SafetyCenterManagerTest { safetyCenterStatusOk, emptyList(), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryUnspecified(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryUnspecified(SINGLE_SOURCE_ID), ) ), - emptyList() + emptyList(), ) private val safetyCenterDataOk: SafetyCenterData @@ -464,11 +473,12 @@ class SafetyCenterManagerTest { safetyCenterStatusOk, emptyList(), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryOk(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryOk(SINGLE_SOURCE_ID), ) ), - emptyList() + emptyList(), ) private val safetyCenterDataOkWithIconAction: SafetyCenterData @@ -477,17 +487,18 @@ class SafetyCenterManagerTest { safetyCenterStatusOk, emptyList(), listOf( - SafetyCenterEntryOrGroup( + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, safetyCenterTestData .safetyCenterEntryOkBuilder(SINGLE_SOURCE_ID) .setIconAction( ICON_ACTION_TYPE_INFO, - safetySourceTestData.createTestActivityRedirectPendingIntent() + safetySourceTestData.createTestActivityRedirectPendingIntent(), ) - .build() + .build(), ) ), - emptyList() + emptyList(), ) private val safetyCenterDataUnknownScanningWithError: SafetyCenterData @@ -496,11 +507,13 @@ class SafetyCenterManagerTest { safetyCenterStatusUnknownScanning, emptyList(), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryError(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryError(SINGLE_SOURCE_ID), + "Couldn’t check setting", ) ), - emptyList() + emptyList(), ) private val safetyCenterDataUnknownReviewError: SafetyCenterData @@ -509,11 +522,13 @@ class SafetyCenterManagerTest { safetyCenterTestData.safetyCenterStatusUnknown, emptyList(), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryError(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryError(SINGLE_SOURCE_ID), + "Couldn’t check setting", ) ), - emptyList() + emptyList(), ) private val safetyCenterDataOkOneAlert: SafetyCenterData @@ -522,20 +537,40 @@ class SafetyCenterManagerTest { safetyCenterStatusOkOneAlert, listOf(safetyCenterTestData.safetyCenterIssueInformation(SINGLE_SOURCE_ID)), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryOk(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryOk(SINGLE_SOURCE_ID), + "Ok summary", // When an issue is present, entry summary is used ) ), - emptyList() + emptyList(), ) + private val safetyCenterDataOkOneDismissedAlert: SafetyCenterData + get() = + SafetyCenterData( + safetyCenterStatusOk, + emptyList(), + listOf( + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryOk(SINGLE_SOURCE_ID), + "Ok summary", // When an issue is present, entry summary is used + ) + ), + emptyList(), + ) + .withDismissedIssuesIfAtLeastU( + listOf(safetyCenterTestData.safetyCenterIssueInformation(SINGLE_SOURCE_ID)) + ) + private val safetyCenterDataOkReviewCriticalEntry: SafetyCenterData get() = SafetyCenterData( safetyCenterStatusOkReview, emptyList(), listOf(safetyCenterEntryOrGroupCritical), - emptyList() + emptyList(), ) private val safetyCenterDataOkReviewRecommendationEntry: SafetyCenterData @@ -544,7 +579,7 @@ class SafetyCenterManagerTest { safetyCenterStatusOkReview, emptyList(), listOf(safetyCenterEntryOrGroupRecommendation), - emptyList() + emptyList(), ) private val safetyCenterDataOkReviewOneAlert: SafetyCenterData @@ -553,7 +588,7 @@ class SafetyCenterManagerTest { safetyCenterStatusOkReviewOneAlert, listOf(safetyCenterTestData.safetyCenterIssueInformation(SINGLE_SOURCE_ID)), listOf(safetyCenterEntryOrGroupCritical), - emptyList() + emptyList(), ) private val safetyCenterDataGeneralRecommendationOneAlert: SafetyCenterData @@ -562,11 +597,12 @@ class SafetyCenterManagerTest { safetyCenterStatusGeneralRecommendationOneAlert, listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID)), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID), ) ), - emptyList() + emptyList(), ) private val safetyCenterDataGeneralRecommendationAlertWithConfirmation: SafetyCenterData @@ -576,15 +612,16 @@ class SafetyCenterManagerTest { listOf( safetyCenterTestData.safetyCenterIssueRecommendation( SINGLE_SOURCE_ID, - confirmationDialog = true + confirmationDialog = true, ) ), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID), ) ), - emptyList() + emptyList(), ) private val safetyCenterDataAccountRecommendationOneAlert: SafetyCenterData @@ -593,11 +630,12 @@ class SafetyCenterManagerTest { safetyCenterStatusAccountRecommendationOneAlert, listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID)), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID), ) ), - emptyList() + emptyList(), ) private val safetyCenterDataDeviceRecommendationOneAlert: SafetyCenterData @@ -606,11 +644,12 @@ class SafetyCenterManagerTest { safetyCenterStatusDeviceRecommendationOneAlert, listOf(safetyCenterTestData.safetyCenterIssueRecommendation(SINGLE_SOURCE_ID)), listOf( - SafetyCenterEntryOrGroup( - safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID) + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, + safetyCenterTestData.safetyCenterEntryRecommendation(SINGLE_SOURCE_ID), ) ), - emptyList() + emptyList(), ) private val safetyCenterDataGeneralCriticalOneAlert: SafetyCenterData @@ -619,7 +658,7 @@ class SafetyCenterManagerTest { safetyCenterStatusGeneralCriticalOneAlert, listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID)), listOf(safetyCenterEntryOrGroupCritical), - emptyList() + emptyList(), ) private val safetyCenterDataAccountCriticalOneAlert: SafetyCenterData @@ -628,7 +667,7 @@ class SafetyCenterManagerTest { safetyCenterStatusAccountCriticalOneAlert, listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID)), listOf(safetyCenterEntryOrGroupCritical), - emptyList() + emptyList(), ) private val safetyCenterDataDeviceCriticalOneAlert: SafetyCenterData @@ -637,7 +676,7 @@ class SafetyCenterManagerTest { safetyCenterStatusDeviceCriticalOneAlert, listOf(safetyCenterTestData.safetyCenterIssueCritical(SINGLE_SOURCE_ID)), listOf(safetyCenterEntryOrGroupCritical), - emptyList() + emptyList(), ) private val safetyCenterDataCriticalOneAlertInFlight: SafetyCenterData @@ -647,11 +686,11 @@ class SafetyCenterManagerTest { listOf( safetyCenterTestData.safetyCenterIssueCritical( SINGLE_SOURCE_ID, - isActionInFlight = true + isActionInFlight = true, ) ), listOf(safetyCenterEntryOrGroupCritical), - emptyList() + emptyList(), ) private val safetyCenterDataOkReviewOneDismissedAlertInFlight: SafetyCenterData @@ -660,13 +699,13 @@ class SafetyCenterManagerTest { safetyCenterStatusOkReview, emptyList(), listOf(safetyCenterEntryOrGroupCritical), - emptyList() + emptyList(), ) .withDismissedIssuesIfAtLeastU( listOf( safetyCenterTestData.safetyCenterIssueCritical( SINGLE_SOURCE_ID, - isActionInFlight = true + isActionInFlight = true, ) ) ) @@ -702,17 +741,17 @@ class SafetyCenterManagerTest { .safetyCenterEntryDefaultBuilder(DYNAMIC_OTHER_PACKAGE_ID) .setPendingIntent(null) .setEnabled(false) - .build() + .build(), ) ) .build() ), - safetyCenterEntryGroupMixedFromComplexConfig + safetyCenterEntryGroupMixedFromComplexConfig, ), listOf( safetyCenterStaticEntryGroupFromComplexConfig, - safetyCenterStaticEntryGroupMixedFromComplexConfig - ) + safetyCenterStaticEntryGroupMixedFromComplexConfig, + ), ) private val safetyCenterDataFromComplexConfigUpdated: SafetyCenterData @@ -722,28 +761,28 @@ class SafetyCenterManagerTest { listOf( safetyCenterTestData.safetyCenterIssueCritical( DYNAMIC_BAREBONE_ID, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueCritical( ISSUE_ONLY_BAREBONE_ID, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueRecommendation( DYNAMIC_DISABLED_ID, - groupId = DYNAMIC_GROUP_ID + groupId = DYNAMIC_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueRecommendation( ISSUE_ONLY_ALL_OPTIONAL_ID, - groupId = ISSUE_ONLY_GROUP_ID + groupId = ISSUE_ONLY_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( DYNAMIC_IN_STATELESS_ID, - groupId = MIXED_STATELESS_GROUP_ID + groupId = MIXED_STATELESS_GROUP_ID, ), safetyCenterTestData.safetyCenterIssueInformation( ISSUE_ONLY_IN_STATELESS_ID, - groupId = MIXED_STATELESS_GROUP_ID - ) + groupId = MIXED_STATELESS_GROUP_ID, + ), ), listOf( SafetyCenterEntryOrGroup( @@ -765,7 +804,7 @@ class SafetyCenterManagerTest { ), safetyCenterTestData.safetyCenterEntryUnspecified( DYNAMIC_HIDDEN_ID, - pendingIntent = null + pendingIntent = null, ), safetyCenterTestData.safetyCenterEntryOk( DYNAMIC_HIDDEN_WITH_SEARCH_ID @@ -774,17 +813,17 @@ class SafetyCenterManagerTest { .safetyCenterEntryDefaultBuilder(DYNAMIC_OTHER_PACKAGE_ID) .setPendingIntent(null) .setEnabled(false) - .build() + .build(), ) ) .build() ), - safetyCenterEntryGroupMixedFromComplexConfig + safetyCenterEntryGroupMixedFromComplexConfig, ), listOf( safetyCenterStaticEntryGroupFromComplexConfig, - safetyCenterStaticEntryGroupMixedUpdatedFromComplexConfig - ) + safetyCenterStaticEntryGroupMixedUpdatedFromComplexConfig, + ), ) @get:Rule(order = 1) val flagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() @@ -838,7 +877,7 @@ class SafetyCenterManagerTest { SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_LONG) SafetySourceReceiver.setResponse( Request.Rescan(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_RESCAN_BUTTON_CLICK @@ -869,7 +908,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Rescan(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information) val listener = safetyCenterTestHelper.addListener() @@ -894,7 +933,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) val listener = safetyCenterTestHelper.addListener() @@ -918,7 +957,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information) val listener = safetyCenterTestHelper.addListener() @@ -944,7 +983,7 @@ class SafetyCenterManagerTest { SafetyCenterFlags.overrideRefreshOnPageOpenSources = setOf(SINGLE_SOURCE_ID) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.informationWithIssue) + Response.SetData(safetySourceTestData.informationWithIssue), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -962,13 +1001,13 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.information) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.informationWithIssue) + Response.SetData(safetySourceTestData.informationWithIssue), ) assertFailsWith(TimeoutCancellationException::class) { safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( REFRESH_REASON_PAGE_OPEN, - timeout = TIMEOUT_SHORT + timeout = TIMEOUT_SHORT, ) } val apiSafetySourceDataBeforeSettingFlag = @@ -990,7 +1029,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.noPageOpenConfig) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -1020,10 +1059,16 @@ class SafetyCenterManagerTest { val expectedExplicitPendingIntent = SafetySourceTestData.createRedirectPendingIntent( context, - Intent(ACTION_TEST_ACTIVITY).setPackage(context.packageName) + Intent(ACTION_TEST_ACTIVITY).setPackage(context.packageName), ) val defaultEntryPendingIntent = apiSafetyCenterData.entriesOrGroups.firstOrNull()?.entry?.pendingIntent + ?: apiSafetyCenterData.entriesOrGroups + .firstOrNull() + ?.entryGroup + ?.entries + ?.firstOrNull() + ?.pendingIntent val defaultEntryIntentFilterEqualsToExplicitIntent = callWithShellPermissionIdentity("android.permission.GET_INTENT_SENDER_INTENT") { expectedExplicitPendingIntent.intentFilterEquals(defaultEntryPendingIntent) @@ -1040,10 +1085,16 @@ class SafetyCenterManagerTest { val expectedImplicitPendingIntent = SafetySourceTestData.createRedirectPendingIntent( context, - Intent(ACTION_TEST_ACTIVITY_EXPORTED) + Intent(ACTION_TEST_ACTIVITY_EXPORTED), ) val defaultEntryPendingIntent = apiSafetyCenterData.entriesOrGroups.firstOrNull()?.entry?.pendingIntent + ?: apiSafetyCenterData.entriesOrGroups + .firstOrNull() + ?.entryGroup + ?.entries + ?.firstOrNull() + ?.pendingIntent val defaultEntryIntentFilterEqualsToImplicitIntent = callWithShellPermissionIdentity("android.permission.GET_INTENT_SENDER_INTENT") { expectedImplicitPendingIntent.intentFilterEquals(defaultEntryPendingIntent) @@ -1060,7 +1111,7 @@ class SafetyCenterManagerTest { val expectedImplicitPendingIntent = SafetySourceTestData.createRedirectPendingIntent( context, - Intent(ACTION_TEST_ACTIVITY_EXPORTED) + Intent(ACTION_TEST_ACTIVITY_EXPORTED), ) val staticEntryPendingIntent = apiSafetyCenterData.staticEntryGroups @@ -1086,7 +1137,7 @@ class SafetyCenterManagerTest { val expectedExplicitPendingIntent = SafetySourceTestData.createRedirectPendingIntent( context, - Intent(ACTION_TEST_ACTIVITY).setPackage(context.packageName) + Intent(ACTION_TEST_ACTIVITY).setPackage(context.packageName), ) val staticEntryPendingIntent = apiSafetyCenterData.staticEntryGroups @@ -1146,7 +1197,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.informationWithIconAction + safetySourceTestData.informationWithIconAction, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1160,7 +1211,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.informationWithIssueWithAttributionTitle + safetySourceTestData.informationWithIssueWithAttributionTitle, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1189,7 +1240,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceNoGroupTitleConfig) safetyCenterTestHelper.setData( ISSUE_ONLY_ALL_OPTIONAL_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue), ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1200,11 +1251,11 @@ class SafetyCenterManagerTest { listOf( safetyCenterTestData.safetyCenterIssueRecommendation( ISSUE_ONLY_ALL_OPTIONAL_ID, - attributionTitle = null + attributionTitle = null, ) ), emptyList(), - emptyList() + emptyList(), ) assertThat(apiSafetyCenterData).isEqualTo(expectedSafetyCenterData) } @@ -1227,7 +1278,7 @@ class SafetyCenterManagerTest { val previousApiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1241,7 +1292,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterManager.reportSafetySourceErrorWithPermission( SINGLE_SOURCE_ID, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1264,7 +1315,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithInformationIssue + safetySourceTestData.criticalWithInformationIssue, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1277,7 +1328,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1291,7 +1342,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.recommendationWithIssueWithActionConfirmation + safetySourceTestData.recommendationWithIssueWithActionConfirmation, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1305,7 +1356,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.recommendationWithAccountIssue + safetySourceTestData.recommendationWithAccountIssue, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1318,7 +1369,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.recommendationWithDeviceIssue + safetySourceTestData.recommendationWithDeviceIssue, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1331,7 +1382,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1344,7 +1395,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingAccountIssue + safetySourceTestData.criticalWithResolvingAccountIssue, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1357,7 +1408,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingDeviceIssue + safetySourceTestData.criticalWithResolvingDeviceIssue, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1376,7 +1427,7 @@ class SafetyCenterManagerTest { .defaultRecommendationIssueBuilder() .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DATA) .build() - ) + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1385,7 +1436,7 @@ class SafetyCenterManagerTest { .isEqualTo( safetyCenterTestData.safetyCenterStatusOneAlert( "overall_severity_level_data_recommendation_title", - OVERALL_SEVERITY_LEVEL_RECOMMENDATION + OVERALL_SEVERITY_LEVEL_RECOMMENDATION, ) ) } @@ -1401,7 +1452,7 @@ class SafetyCenterManagerTest { .defaultCriticalResolvingIssueBuilder() .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DATA) .build() - ) + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1410,7 +1461,7 @@ class SafetyCenterManagerTest { .isEqualTo( safetyCenterTestData.safetyCenterStatusOneAlert( "overall_severity_level_critical_data_warning_title", - OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING + OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING, ) ) } @@ -1426,7 +1477,7 @@ class SafetyCenterManagerTest { .defaultRecommendationIssueBuilder() .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PASSWORDS) .build() - ) + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1435,7 +1486,7 @@ class SafetyCenterManagerTest { .isEqualTo( safetyCenterTestData.safetyCenterStatusOneAlert( "overall_severity_level_passwords_recommendation_title", - OVERALL_SEVERITY_LEVEL_RECOMMENDATION + OVERALL_SEVERITY_LEVEL_RECOMMENDATION, ) ) } @@ -1451,7 +1502,7 @@ class SafetyCenterManagerTest { .defaultCriticalResolvingIssueBuilder() .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PASSWORDS) .build() - ) + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1460,7 +1511,7 @@ class SafetyCenterManagerTest { .isEqualTo( safetyCenterTestData.safetyCenterStatusOneAlert( "overall_severity_level_critical_passwords_warning_title", - OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING + OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING, ) ) } @@ -1476,7 +1527,7 @@ class SafetyCenterManagerTest { .defaultRecommendationIssueBuilder() .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PERSONAL_SAFETY) .build() - ) + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1485,7 +1536,7 @@ class SafetyCenterManagerTest { .isEqualTo( safetyCenterTestData.safetyCenterStatusOneAlert( "overall_severity_level_personal_recommendation_title", - OVERALL_SEVERITY_LEVEL_RECOMMENDATION + OVERALL_SEVERITY_LEVEL_RECOMMENDATION, ) ) } @@ -1501,7 +1552,7 @@ class SafetyCenterManagerTest { .defaultCriticalResolvingIssueBuilder() .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_PERSONAL_SAFETY) .build() - ) + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1510,7 +1561,7 @@ class SafetyCenterManagerTest { .isEqualTo( safetyCenterTestData.safetyCenterStatusOneAlert( "overall_severity_level_critical_personal_warning_title", - OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING + OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING, ) ) } @@ -1526,7 +1577,7 @@ class SafetyCenterManagerTest { .defaultInformationIssueBuilder() .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP) .build() - ) + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1562,7 +1613,7 @@ class SafetyCenterManagerTest { .defaultInformationIssueBuilder("id_5") .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_TIP) .build(), - ) + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1582,7 +1633,7 @@ class SafetyCenterManagerTest { .defaultInformationIssueBuilder() .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC) .build() - ) + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1618,7 +1669,7 @@ class SafetyCenterManagerTest { .defaultInformationIssueBuilder("id_5") .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL) .build(), - ) + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1637,8 +1688,8 @@ class SafetyCenterManagerTest { safetySourceTestData .defaultInformationIssueBuilder() .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL) - .build(), - ) + .build() + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1648,7 +1699,7 @@ class SafetyCenterManagerTest { safetyCenterTestData.safetyCenterStatusNAlerts( "overall_severity_level_ok_title", OVERALL_SEVERITY_LEVEL_OK, - numAlerts = 1 + numAlerts = 1, ) ) } @@ -1676,7 +1727,7 @@ class SafetyCenterManagerTest { .defaultInformationIssueBuilder("id_4") .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_AUTOMATIC) .build(), - ) + ), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1686,7 +1737,7 @@ class SafetyCenterManagerTest { safetyCenterTestData.safetyCenterStatusNAlerts( "overall_severity_level_ok_title", OVERALL_SEVERITY_LEVEL_OK, - numAlerts = 2 + numAlerts = 2, ) ) } @@ -1701,7 +1752,7 @@ class SafetyCenterManagerTest { assertThat( SafetyCenterBundles.getStaticEntryId( apiSafetyCenterData, - apiSafetyCenterData.staticEntryGroups[0].staticEntries[0] + apiSafetyCenterData.staticEntryGroups[0].staticEntries[0], ) ) .isEqualTo( @@ -1713,7 +1764,7 @@ class SafetyCenterManagerTest { assertThat( SafetyCenterBundles.getStaticEntryId( apiSafetyCenterData, - apiSafetyCenterData.staticEntryGroups[1].staticEntries[0] + apiSafetyCenterData.staticEntryGroups[1].staticEntries[0], ) ) .isEqualTo( @@ -1729,7 +1780,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingDeviceIssueAndRecommendationIssue + safetySourceTestData.criticalWithResolvingDeviceIssueAndRecommendationIssue, ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1742,11 +1793,11 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.recommendationWithAccountIssue + safetySourceTestData.recommendationWithAccountIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_3, - safetySourceTestData.criticalWithResolvingDeviceIssue + safetySourceTestData.criticalWithResolvingDeviceIssue, ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1759,11 +1810,11 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_3, - safetySourceTestData.criticalWithResolvingDeviceIssue + safetySourceTestData.criticalWithResolvingDeviceIssue, ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -1782,14 +1833,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues @@ -1798,7 +1849,7 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_1, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ) ) } @@ -1814,14 +1865,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 and source group MULTIPLE_SOURCES_GROUP_ID_2 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1844,14 +1895,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 and source group MULTIPLE_SOURCES_GROUP_ID_1 safetyCenterTestHelper.setData( SOURCE_ID_2, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1874,14 +1925,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_3 and source group MULTIPLE_SOURCES_GROUP_ID_2 safetyCenterTestHelper.setData( SOURCE_ID_6, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("same") - ) + ), ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -1902,14 +1953,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("different") - ) + ), ) val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues @@ -1918,12 +1969,12 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_1, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ), safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_5, - groupId = MULTIPLE_SOURCES_GROUP_ID_2 - ) + groupId = MULTIPLE_SOURCES_GROUP_ID_2, + ), ) .inOrder() } @@ -1939,14 +1990,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_3 safetyCenterTestHelper.setData( SOURCE_ID_6, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues @@ -1955,12 +2006,12 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_1, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ), safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_6, - groupId = MULTIPLE_SOURCES_GROUP_ID_2 - ) + groupId = MULTIPLE_SOURCES_GROUP_ID_2, + ), ) .inOrder() } @@ -1976,21 +2027,21 @@ class SafetyCenterManagerTest { SOURCE_ID_4, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_3 safetyCenterTestHelper.setData( SOURCE_ID_6, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_3 safetyCenterTestHelper.setData( SOURCE_ID_7, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues @@ -1999,7 +2050,7 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_4, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ) ) } @@ -2015,14 +2066,14 @@ class SafetyCenterManagerTest { SOURCE_ID_2, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues @@ -2031,7 +2082,7 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_5, - groupId = MULTIPLE_SOURCES_GROUP_ID_2 + groupId = MULTIPLE_SOURCES_GROUP_ID_2, ) ) } @@ -2047,49 +2098,49 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("A") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_2, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("A") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_2 safetyCenterTestHelper.setData( SOURCE_ID_3, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("B") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_3 safetyCenterTestHelper.setData( SOURCE_ID_4, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("B") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("A") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_3 safetyCenterTestHelper.setData( SOURCE_ID_6, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("B") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_3 safetyCenterTestHelper.setData( SOURCE_ID_7, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("B") - ) + ), ) val apiSafetyCenterIssues = safetyCenterManager.getSafetyCenterDataWithPermission().issues @@ -2098,16 +2149,16 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_5, - groupId = MULTIPLE_SOURCES_GROUP_ID_2 + groupId = MULTIPLE_SOURCES_GROUP_ID_2, ), safetyCenterTestData.safetyCenterIssueRecommendation( SOURCE_ID_3, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ), safetyCenterTestData.safetyCenterIssueRecommendation( SOURCE_ID_4, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 - ) + groupId = MULTIPLE_SOURCES_GROUP_ID_1, + ), ) .inOrder() } @@ -2123,14 +2174,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("same") - ) + ), ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID) @@ -2148,7 +2199,7 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_1, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ) ) } @@ -2164,14 +2215,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("same") - ) + ), ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(SOURCE_ID_5, RECOMMENDATION_ISSUE_ID) @@ -2185,7 +2236,7 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_1, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ) ) assertThat(apiSafetyCenterDismissedIssues).isEmpty() @@ -2202,14 +2253,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("same") - ) + ), ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID) @@ -2224,7 +2275,7 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_1, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ) ) } @@ -2240,14 +2291,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(SOURCE_ID_5, CRITICAL_ISSUE_ID) @@ -2262,7 +2313,7 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_1, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ) ) } @@ -2282,14 +2333,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID) @@ -2303,21 +2354,17 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_5, - groupId = MULTIPLE_SOURCES_GROUP_ID_2 + groupId = MULTIPLE_SOURCES_GROUP_ID_2, ) ) - waitForWithTimeout(timeout = RESURFACE_TIMEOUT, checkPeriod = RESURFACE_CHECK) { - val hasResurfaced = - safetyCenterManager - .getSafetyCenterDataWithPermission() - .issues - .contains( - safetyCenterTestData.safetyCenterIssueCritical( - SOURCE_ID_5, - groupId = MULTIPLE_SOURCES_GROUP_ID_2 - ) + assertWithTimeout(timeout = RESURFACE_TIMEOUT, checkPeriod = RESURFACE_CHECK) { + assertThat(safetyCenterManager.getSafetyCenterDataWithPermission().issues) + .contains( + safetyCenterTestData.safetyCenterIssueCritical( + SOURCE_ID_5, + groupId = MULTIPLE_SOURCES_GROUP_ID_2, ) - hasResurfaced + ) } } @@ -2329,13 +2376,13 @@ class SafetyCenterManagerTest { mapOf( SEVERITY_LEVEL_INFORMATION to 0L, SEVERITY_LEVEL_RECOMMENDATION to 99L, - SEVERITY_LEVEL_CRITICAL_WARNING to 0L + SEVERITY_LEVEL_CRITICAL_WARNING to 0L, ) SafetyCenterFlags.resurfaceIssueDelays = mapOf( SEVERITY_LEVEL_INFORMATION to Duration.ZERO, SEVERITY_LEVEL_RECOMMENDATION to RESURFACE_DELAY, - SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO + SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO, ) safetyCenterTestHelper.setConfig( safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig @@ -2345,14 +2392,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("same") - ) + ), ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID) @@ -2366,7 +2413,7 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueRecommendation( SOURCE_ID_5, - groupId = MULTIPLE_SOURCES_GROUP_ID_2 + groupId = MULTIPLE_SOURCES_GROUP_ID_2, ) ) waitForWithTimeout(timeout = RESURFACE_TIMEOUT, checkPeriod = RESURFACE_CHECK) { @@ -2377,7 +2424,7 @@ class SafetyCenterManagerTest { .contains( safetyCenterTestData.safetyCenterIssueRecommendation( SOURCE_ID_5, - groupId = MULTIPLE_SOURCES_GROUP_ID_2 + groupId = MULTIPLE_SOURCES_GROUP_ID_2, ) ) hasResurfaced @@ -2391,13 +2438,13 @@ class SafetyCenterManagerTest { mapOf( SEVERITY_LEVEL_INFORMATION to 0L, SEVERITY_LEVEL_RECOMMENDATION to 99L, - SEVERITY_LEVEL_CRITICAL_WARNING to 99L + SEVERITY_LEVEL_CRITICAL_WARNING to 99L, ) SafetyCenterFlags.resurfaceIssueDelays = mapOf( SEVERITY_LEVEL_INFORMATION to Duration.ZERO, SEVERITY_LEVEL_RECOMMENDATION to RESURFACE_DELAY, - SEVERITY_LEVEL_CRITICAL_WARNING to RESURFACE_DELAY.multipliedBy(100) + SEVERITY_LEVEL_CRITICAL_WARNING to RESURFACE_DELAY.multipliedBy(100), ) safetyCenterTestHelper.setConfig( safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig @@ -2407,14 +2454,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("same") - ) + ), ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID) @@ -2427,7 +2474,7 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_1, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ) ) assertFailsWith(TimeoutCancellationException::class) { @@ -2439,7 +2486,7 @@ class SafetyCenterManagerTest { .contains( safetyCenterTestData.safetyCenterIssueRecommendation( SOURCE_ID_5, - groupId = MULTIPLE_SOURCES_GROUP_ID_2 + groupId = MULTIPLE_SOURCES_GROUP_ID_2, ) ) hasResurfaced @@ -2454,13 +2501,13 @@ class SafetyCenterManagerTest { mapOf( SEVERITY_LEVEL_INFORMATION to 0L, SEVERITY_LEVEL_RECOMMENDATION to 99L, - SEVERITY_LEVEL_CRITICAL_WARNING to 99L + SEVERITY_LEVEL_CRITICAL_WARNING to 99L, ) SafetyCenterFlags.resurfaceIssueDelays = mapOf( SEVERITY_LEVEL_INFORMATION to Duration.ZERO, SEVERITY_LEVEL_RECOMMENDATION to RESURFACE_DELAY.multipliedBy(100), - SEVERITY_LEVEL_CRITICAL_WARNING to RESURFACE_DELAY + SEVERITY_LEVEL_CRITICAL_WARNING to RESURFACE_DELAY, ) safetyCenterTestHelper.setConfig( safetyCenterTestConfigs.multipleSourcesWithDeduplicationInfoConfig @@ -2470,14 +2517,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("same") - ) + ), ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(SOURCE_ID_1, CRITICAL_ISSUE_ID) @@ -2490,7 +2537,7 @@ class SafetyCenterManagerTest { .containsExactly( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_1, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ) ) waitForWithTimeout(timeout = RESURFACE_TIMEOUT, checkPeriod = RESURFACE_CHECK) { @@ -2501,7 +2548,7 @@ class SafetyCenterManagerTest { .contains( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_1, - groupId = MULTIPLE_SOURCES_GROUP_ID_1 + groupId = MULTIPLE_SOURCES_GROUP_ID_1, ) ) hasResurfaced @@ -2520,14 +2567,14 @@ class SafetyCenterManagerTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) // Belongs to DEDUPLICATION_GROUP_1 safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) val listener = safetyCenterTestHelper.addListener() @@ -2545,7 +2592,7 @@ class SafetyCenterManagerTest { .contains( safetyCenterTestData.safetyCenterIssueCritical( SOURCE_ID_5, - groupId = MULTIPLE_SOURCES_GROUP_ID_2 + groupId = MULTIPLE_SOURCES_GROUP_ID_2, ) ) hasResurfaced @@ -2571,7 +2618,7 @@ class SafetyCenterManagerTest { .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE) .build() ) - .build() + .build(), ) val apiSafetyCenterStatus = safetyCenterManager.getSafetyCenterDataWithPermission().status @@ -2584,32 +2631,32 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.complexConfig) safetyCenterTestHelper.setData( DYNAMIC_BAREBONE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterTestHelper.setData( DYNAMIC_DISABLED_ID, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(DYNAMIC_HIDDEN_ID, safetySourceTestData.unspecified) safetyCenterTestHelper.setData( DYNAMIC_HIDDEN_WITH_SEARCH_ID, - safetySourceTestData.information + safetySourceTestData.information, ) safetyCenterTestHelper.setData( ISSUE_ONLY_BAREBONE_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.criticalResolvingGeneralIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.criticalResolvingGeneralIssue), ) safetyCenterTestHelper.setData( ISSUE_ONLY_ALL_OPTIONAL_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue), ) safetyCenterTestHelper.setData( DYNAMIC_IN_STATELESS_ID, - safetySourceTestData.unspecifiedWithIssue + safetySourceTestData.unspecifiedWithIssue, ) safetyCenterTestHelper.setData( ISSUE_ONLY_IN_STATELESS_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue), ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -2623,50 +2670,50 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig) safetyCenterManager.reportSafetySourceErrorWithPermission( SOURCE_ID_1, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) safetyCenterTestHelper.setData( SOURCE_ID_2, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified" - ) + entrySummary = "unspecified", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_3, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, - entrySummary = "information without issues" - ) + entrySummary = "information without issues", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_4, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, entrySummary = "information with issue", - withIssue = true - ) + withIssue = true, + ), ) safetyCenterTestHelper.setData( SOURCE_ID_5, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_RECOMMENDATION, - entrySummary = "recommendation" - ) + entrySummary = "recommendation", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_6, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_CRITICAL_WARNING, - entrySummary = "critical 1" - ) + entrySummary = "critical 1", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_7, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_CRITICAL_WARNING, - entrySummary = "critical 2" - ) + entrySummary = "critical 2", + ), ) // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry @@ -2682,43 +2729,43 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig) safetyCenterManager.reportSafetySourceErrorWithPermission( SOURCE_ID_1, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) safetyCenterTestHelper.setData( SOURCE_ID_2, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified" - ) + entrySummary = "unspecified", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_3, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, - entrySummary = "information without issues" - ) + entrySummary = "information without issues", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_4, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, entrySummary = "information with issue", - withIssue = true - ) + withIssue = true, + ), ) safetyCenterTestHelper.setData( SOURCE_ID_5, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_RECOMMENDATION, - entrySummary = "recommendation 1" - ) + entrySummary = "recommendation 1", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_6, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_RECOMMENDATION, - entrySummary = "recommendation 2" - ) + entrySummary = "recommendation 2", + ), ) // SOURCE_ID_7 leave as an UNKNOWN dynamic entry // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry @@ -2737,52 +2784,52 @@ class SafetyCenterManagerTest { SOURCE_ID_1, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 1" - ) + entrySummary = "unspecified 1", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_2, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 2" - ) + entrySummary = "unspecified 2", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_3, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, - entrySummary = "information without issues 1" - ) + entrySummary = "information without issues 1", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_4, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, entrySummary = "information with issue 1", - withIssue = true - ) + withIssue = true, + ), ) safetyCenterTestHelper.setData( SOURCE_ID_5, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, entrySummary = "information with issue 2", - withIssue = true - ) + withIssue = true, + ), ) safetyCenterTestHelper.setData( SOURCE_ID_6, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, - entrySummary = "information without issues 2" - ) + entrySummary = "information without issues 2", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_7, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 3" - ) + entrySummary = "unspecified 3", + ), ) // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry @@ -2800,50 +2847,50 @@ class SafetyCenterManagerTest { SOURCE_ID_1, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 1" - ) + entrySummary = "unspecified 1", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_2, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 2" - ) + entrySummary = "unspecified 2", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_3, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, - entrySummary = "information without issues 1" - ) + entrySummary = "information without issues 1", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_4, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, - entrySummary = "information without issues 2" - ) + entrySummary = "information without issues 2", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_5, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 3" - ) + entrySummary = "unspecified 3", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_6, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, - entrySummary = "information without issues 3" - ) + entrySummary = "information without issues 3", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_7, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 4" - ) + entrySummary = "unspecified 4", + ), ) // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry @@ -2861,51 +2908,51 @@ class SafetyCenterManagerTest { SOURCE_ID_1, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 1" - ) + entrySummary = "unspecified 1", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_2, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 2" - ) + entrySummary = "unspecified 2", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_3, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 3" - ) + entrySummary = "unspecified 3", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_4, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 4" - ) + entrySummary = "unspecified 4", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_5, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, entrySummary = "unspecified with issue", - withIssue = true - ) + withIssue = true, + ), ) safetyCenterTestHelper.setData( SOURCE_ID_6, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 6" - ) + entrySummary = "unspecified 6", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_7, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified 7" - ) + entrySummary = "unspecified 7", + ), ) // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry @@ -2921,34 +2968,34 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig) safetyCenterManager.reportSafetySourceErrorWithPermission( SOURCE_ID_1, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) safetyCenterManager.reportSafetySourceErrorWithPermission( SOURCE_ID_2, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) safetyCenterTestHelper.setData( SOURCE_ID_3, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, entrySummary = "information with issue", - withIssue = true - ) + withIssue = true, + ), ) safetyCenterTestHelper.setData( SOURCE_ID_4, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified" - ) + entrySummary = "unspecified", + ), ) // SOURCE_ID_5 leave as an UNKNOWN dynamic entry safetyCenterTestHelper.setData( SOURCE_ID_6, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, - entrySummary = "information" - ) + entrySummary = "information", + ), ) // SOURCE_ID_7 leave as an UNKNOWN dynamic entry // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry @@ -2965,7 +3012,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.summaryTestConfig) safetyCenterManager.reportSafetySourceErrorWithPermission( SOURCE_ID_1, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) // SOURCE_ID_2 leave as an UNKNOWN dynamic entry safetyCenterTestHelper.setData( @@ -2973,15 +3020,15 @@ class SafetyCenterManagerTest { safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, entrySummary = "information with issue", - withIssue = true - ) + withIssue = true, + ), ) safetyCenterTestHelper.setData( SOURCE_ID_4, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified" - ) + entrySummary = "unspecified", + ), ) // SOURCE_ID_5 leave as an UNKNOWN dynamic entry // SOURCE_ID_6 leave as an UNKNOWN dynamic entry @@ -2989,8 +3036,8 @@ class SafetyCenterManagerTest { SOURCE_ID_7, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, - entrySummary = "information" - ) + entrySummary = "information", + ), ) // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry @@ -3011,22 +3058,22 @@ class SafetyCenterManagerTest { safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, entrySummary = "information with issue", - withIssue = true - ) + withIssue = true, + ), ) safetyCenterTestHelper.setData( SOURCE_ID_4, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, - entrySummary = "unspecified" - ) + entrySummary = "unspecified", + ), ) safetyCenterTestHelper.setData( SOURCE_ID_5, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_INFORMATION, - entrySummary = "information" - ) + entrySummary = "information", + ), ) // SOURCE_ID_6 leave as an UNKNOWN dynamic entry safetyCenterTestHelper.setData( @@ -3034,8 +3081,8 @@ class SafetyCenterManagerTest { safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SEVERITY_LEVEL_UNSPECIFIED, entrySummary = "unspecified with issue", - withIssue = true - ) + withIssue = true, + ), ) // STATIC_IN_STATEFUL_ID behaves like an UNSPECIFIED dynamic entry @@ -3083,7 +3130,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData( DYNAMIC_DISABLED_ID, - safetySourceTestData.informationWithIssue + safetySourceTestData.informationWithIssue, ) val informationWithIssueGroup = @@ -3115,15 +3162,17 @@ class SafetyCenterManagerTest { safetyCenterTestData.safetyCenterStatusUnknown, emptyList(), listOf( - SafetyCenterEntryOrGroup( + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, safetyCenterTestData .safetyCenterEntryDefaultBuilder(SINGLE_SOURCE_ID) .setPendingIntent(null) .setEnabled(false) - .build() + .build(), + "No info yet", ) ), - emptyList() + emptyList(), ) assertThat(safetyCenterData).isEqualTo(expectedSafetyCenterData) } @@ -3133,7 +3182,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceInvalidIntentConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.informationWithNullIntent + safetySourceTestData.informationWithNullIntent, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -3143,16 +3192,17 @@ class SafetyCenterManagerTest { safetyCenterStatusOk, emptyList(), listOf( - SafetyCenterEntryOrGroup( + safetyCenterTestData.singletonSafetyCenterEntryOrGroup( + SINGLE_SOURCE_GROUP_ID, safetyCenterTestData .safetyCenterEntryOkBuilder(SINGLE_SOURCE_ID) .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED) .setPendingIntent(null) .setEnabled(false) - .build() + .build(), ) ), - emptyList() + emptyList(), ) assertThat(apiSafetyCenterData).isEqualTo(expectedSafetyCenterData) } @@ -3165,7 +3215,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData(SOURCE_ID_2, safetySourceTestData.information) safetyCenterTestHelper.setData( ISSUE_ONLY_ALL_OPTIONAL_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue), ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -3184,7 +3234,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData(SOURCE_ID_2, safetySourceTestData.information) safetyCenterTestHelper.setData( ISSUE_ONLY_ALL_OPTIONAL_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue), ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -3200,12 +3250,12 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.entryGroupWithIssueOnlyConfig) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) safetyCenterTestHelper.setData(SOURCE_ID_2, safetySourceTestData.information) safetyCenterTestHelper.setData( ISSUE_ONLY_ALL_OPTIONAL_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue), ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -3223,7 +3273,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData(SOURCE_ID_2, safetySourceTestData.information) safetyCenterTestHelper.setData( ISSUE_ONLY_ALL_OPTIONAL_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue), ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(ISSUE_ONLY_ALL_OPTIONAL_ID, RECOMMENDATION_ISSUE_ID) @@ -3245,7 +3295,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData(SOURCE_ID_2, safetySourceTestData.information) safetyCenterTestHelper.setData( ISSUE_ONLY_ALL_OPTIONAL_ID, - SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue) + SafetySourceTestData.issuesOnly(safetySourceTestData.recommendationGeneralIssue), ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() @@ -3287,7 +3337,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val safetyCenterDataFromListener = listener.receiveSafetyCenterData() @@ -3313,7 +3363,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() @@ -3334,7 +3384,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID) @@ -3350,7 +3400,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val safetyCenterDataAfterSourcePushesDismissedIssueAgain = @@ -3364,14 +3414,14 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - issueTypeId = "some_other_issue_type_id" + issueTypeId = "some_other_issue_type_id", ) ) @@ -3388,11 +3438,11 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.recommendationDismissPendingIntentIssue + safetySourceTestData.recommendationDismissPendingIntentIssue, ) SafetySourceReceiver.setResponse( Request.DismissIssue(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) val listener = safetyCenterTestHelper.addListener() @@ -3446,15 +3496,11 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, INFORMATION_ISSUE_ID) ) - val expectedSafetyCenterData = - safetyCenterDataOk.withDismissedIssuesIfAtLeastU( - listOf(safetyCenterTestData.safetyCenterIssueInformation(SINGLE_SOURCE_ID)) - ) assertFailsWith(TimeoutCancellationException::class) { waitForWithTimeout(timeout = TIMEOUT_SHORT) { val hasResurfaced = safetyCenterManager.getSafetyCenterDataWithPermission() != - expectedSafetyCenterData + safetyCenterDataOkOneDismissedAlert hasResurfaced } } @@ -3466,13 +3512,13 @@ class SafetyCenterManagerTest { mapOf( SEVERITY_LEVEL_INFORMATION to 0L, SEVERITY_LEVEL_RECOMMENDATION to 99L, - SEVERITY_LEVEL_CRITICAL_WARNING to 99L + SEVERITY_LEVEL_CRITICAL_WARNING to 99L, ) SafetyCenterFlags.resurfaceIssueDelays = mapOf( SEVERITY_LEVEL_INFORMATION to Duration.ZERO, SEVERITY_LEVEL_RECOMMENDATION to Duration.ZERO, - SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO + SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO, ) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue) @@ -3483,15 +3529,11 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, INFORMATION_ISSUE_ID) ) - val expectedSafetyCenterData = - safetyCenterDataOk.withDismissedIssuesIfAtLeastU( - listOf(safetyCenterTestData.safetyCenterIssueInformation(SINGLE_SOURCE_ID)) - ) assertFailsWith(TimeoutCancellationException::class) { waitForWithTimeout(timeout = TIMEOUT_SHORT) { val hasResurfaced = safetyCenterManager.getSafetyCenterDataWithPermission() != - expectedSafetyCenterData + safetyCenterDataOkOneDismissedAlert hasResurfaced } } @@ -3503,18 +3545,18 @@ class SafetyCenterManagerTest { mapOf( SEVERITY_LEVEL_INFORMATION to 0L, SEVERITY_LEVEL_RECOMMENDATION to 0L, - SEVERITY_LEVEL_CRITICAL_WARNING to 2L + SEVERITY_LEVEL_CRITICAL_WARNING to 2L, ) SafetyCenterFlags.resurfaceIssueDelays = mapOf( SEVERITY_LEVEL_INFORMATION to RESURFACE_DELAY, SEVERITY_LEVEL_RECOMMENDATION to RESURFACE_DELAY, - SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO + SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO, ) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingDeviceIssue + safetySourceTestData.criticalWithResolvingDeviceIssue, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() checkState(apiSafetyCenterData == safetyCenterDataDeviceCriticalOneAlert) @@ -3559,18 +3601,18 @@ class SafetyCenterManagerTest { mapOf( SEVERITY_LEVEL_INFORMATION to 0L, SEVERITY_LEVEL_RECOMMENDATION to 99L, - SEVERITY_LEVEL_CRITICAL_WARNING to 0L + SEVERITY_LEVEL_CRITICAL_WARNING to 0L, ) SafetyCenterFlags.resurfaceIssueDelays = mapOf( SEVERITY_LEVEL_INFORMATION to Duration.ZERO, SEVERITY_LEVEL_RECOMMENDATION to RESURFACE_DELAY, - SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO + SEVERITY_LEVEL_CRITICAL_WARNING to Duration.ZERO, ) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.recommendationWithDeviceIssue + safetySourceTestData.recommendationWithDeviceIssue, ) val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission() checkState(apiSafetyCenterData == safetyCenterDataDeviceRecommendationOneAlert) @@ -3598,12 +3640,12 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait( @@ -3611,8 +3653,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) val safetyCenterDataFromListenerDuringResolveAction = listener.receiveSafetyCenterData() @@ -3627,7 +3669,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() SafetySourceReceiver.setResponse(Request.ResolveAction(SINGLE_SOURCE_ID), Response.Error) @@ -3637,8 +3679,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) val safetyCenterDataFromListenerDuringResolveAction = listener.receiveSafetyCenterData() @@ -3662,7 +3704,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() @@ -3671,8 +3713,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) val safetyCenterDataFromListenerDuringResolveAction = listener.receiveSafetyCenterData() @@ -3696,7 +3738,7 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait( @@ -3704,8 +3746,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) listener.receiveSafetyCenterData() listener.receiveSafetyCenterData() @@ -3713,7 +3755,7 @@ class SafetyCenterManagerTest { SafetyCenterFlags.resolveActionTimeout = TIMEOUT_LONG SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait( @@ -3721,8 +3763,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) val safetyCenterDataFromListenerDuringResolveAction = listener.receiveSafetyCenterData() @@ -3737,11 +3779,11 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) val issueId = SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID) val listener = safetyCenterTestHelper.addListener() @@ -3754,8 +3796,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) if (SdkLevel.isAtLeastU()) { @@ -3775,12 +3817,12 @@ class SafetyCenterManagerTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) val listener = safetyCenterTestHelper.addListener() SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) assertFailsWith(IllegalArgumentException::class) { safetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait( @@ -3788,9 +3830,9 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID + "invalid", - CRITICAL_ISSUE_ACTION_ID + CRITICAL_ISSUE_ACTION_ID, ), - TIMEOUT_SHORT + TIMEOUT_SHORT, ) } @@ -3799,8 +3841,8 @@ class SafetyCenterManagerTest { SafetyCenterTestData.issueActionId( SINGLE_SOURCE_ID, CRITICAL_ISSUE_ID, - CRITICAL_ISSUE_ACTION_ID - ) + CRITICAL_ISSUE_ACTION_ID, + ), ) val safetyCenterDataFromListenerDuringResolveAction = listener.receiveSafetyCenterData() @@ -3891,7 +3933,7 @@ class SafetyCenterManagerTest { safetyCenterManager.reportSafetySourceErrorWithPermission( SINGLE_SOURCE_ID, - SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED) + SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED), ) val lastUpdated = dumpLastUpdated() @@ -3941,9 +3983,9 @@ class SafetyCenterManagerTest { companion object { private val RESURFACE_DELAY = Duration.ofMillis(500) - // Wait 3 times the RESURFACE_DELAY before asserting whether an issue has or has not + // Wait 5 times the RESURFACE_DELAY before asserting whether an issue has or has not // resurfaced. Use a constant additive error buffer if we increase the delay considerably. - private val RESURFACE_TIMEOUT = RESURFACE_DELAY.multipliedBy(3) + private val RESURFACE_TIMEOUT = RESURFACE_DELAY.multipliedBy(5) // Check more than once during a RESURFACE_DELAY before asserting whether an issue has or // has not resurfaced. Use a different check logic (focused at the expected resurface time) diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt index 1678ccced..ce75b00f5 100644 --- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt +++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterNotificationTest.kt @@ -116,7 +116,7 @@ class SafetyCenterNotificationTest { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.recommendationWithAccountIssue + safetySourceTestData.recommendationWithAccountIssue, ) TestNotificationListener.waitForZeroNotifications() @@ -128,7 +128,7 @@ class SafetyCenterNotificationTest { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.recommendationWithAccountIssue + safetySourceTestData.recommendationWithAccountIssue, ) TestNotificationListener.waitForZeroNotifications() @@ -140,7 +140,7 @@ class SafetyCenterNotificationTest { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.recommendationWithAccountIssue + safetySourceTestData.recommendationWithAccountIssue, ) TestNotificationListener.waitForZeroNotifications() @@ -401,7 +401,7 @@ class SafetyCenterNotificationTest { SafetySourceIssue.Action.Builder( "default_action", "Default action", - safetySourceTestData.createTestActivityRedirectPendingIntent() + safetySourceTestData.createTestActivityRedirectPendingIntent(), ) .build() ) @@ -440,7 +440,7 @@ class SafetyCenterNotificationTest { SafetySourceIssue.Action.Builder( "default_action", "Default action", - safetySourceTestData.createTestActivityRedirectPendingIntent() + safetySourceTestData.createTestActivityRedirectPendingIntent(), ) .build() ) @@ -497,7 +497,7 @@ class SafetyCenterNotificationTest { "New action", safetySourceTestData.createTestActivityRedirectPendingIntent( identifier = "new_action" - ) + ), ) .build() ) @@ -697,13 +697,13 @@ class SafetyCenterNotificationTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("same") - ) + ), ) safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) TestNotificationListener.waitForNotificationsMatching( @@ -728,7 +728,7 @@ class SafetyCenterNotificationTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("same") - ) + ), ) val notificationWithChannel = @@ -745,7 +745,7 @@ class SafetyCenterNotificationTest { SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) TestNotificationListener.waitForNotificationsMatching( @@ -762,7 +762,7 @@ class SafetyCenterNotificationTest { fun setSafetySourceData_withInformationIssue_lowImportanceBlockableNotification() { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.informationWithIssue + safetySourceTestData.informationWithIssue, ) TestNotificationListener.waitForNotificationsMatching( @@ -781,7 +781,7 @@ class SafetyCenterNotificationTest { fun setSafetySourceData_withRecommendationIssue_defaultImportanceUnblockableNotification() { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.recommendationWithAccountIssue + safetySourceTestData.recommendationWithAccountIssue, ) TestNotificationListener.waitForNotificationsMatching( @@ -800,7 +800,7 @@ class SafetyCenterNotificationTest { fun setSafetySourceData_withCriticalIssue_highImportanceUnblockableNotification() { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.criticalWithResolvingDeviceIssue(sourceId = uniqueSafetySourceId) + safetySourceTestData.criticalWithResolvingDeviceIssue(sourceId = uniqueSafetySourceId), ) TestNotificationListener.waitForNotificationsMatching( @@ -819,7 +819,7 @@ class SafetyCenterNotificationTest { fun dismissSafetyCenterIssue_dismissesNotification() { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.recommendationWithAccountIssue + safetySourceTestData.recommendationWithAccountIssue, ) TestNotificationListener.waitForSingleNotificationMatching( @@ -832,7 +832,7 @@ class SafetyCenterNotificationTest { safetyCenterManager.dismissSafetyCenterIssueWithPermission( SafetyCenterTestData.issueId( uniqueSafetySourceId, - SafetySourceTestData.RECOMMENDATION_ISSUE_ID + SafetySourceTestData.RECOMMENDATION_ISSUE_ID, ) ) @@ -843,7 +843,7 @@ class SafetyCenterNotificationTest { fun dismissingNotification_doesNotUpdateSafetyCenterData() { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.criticalWithResolvingGeneralIssue(sourceId = uniqueSafetySourceId) + safetySourceTestData.criticalWithResolvingGeneralIssue(sourceId = uniqueSafetySourceId), ) // Add the listener after setting the initial data so that we don't need to consume/receive // an update for that @@ -876,13 +876,13 @@ class SafetyCenterNotificationTest { SOURCE_ID_1, SafetySourceTestData.issuesOnly( safetySourceTestData.criticalIssueWithDeduplicationId("same") - ) + ), ) safetyCenterTestHelper.setData( SOURCE_ID_5, SafetySourceTestData.issuesOnly( safetySourceTestData.recommendationIssueWithDeduplicationId("same") - ) + ), ) val notificationWithChannel = @@ -926,7 +926,7 @@ class SafetyCenterNotificationTest { fun sendActionPendingIntent_successful_updatesListener() { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.criticalWithResolvingGeneralIssue(sourceId = uniqueSafetySourceId) + safetySourceTestData.criticalWithResolvingGeneralIssue(sourceId = uniqueSafetySourceId), ) val notificationWithChannel = TestNotificationListener.waitForSingleNotificationMatching( @@ -940,7 +940,7 @@ class SafetyCenterNotificationTest { checkNotNull(action) { "Notification action unexpectedly null" } SafetySourceReceiver.setResponse( Request.ResolveAction(uniqueSafetySourceId), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) val listener = safetyCenterTestHelper.addListener() @@ -958,7 +958,7 @@ class SafetyCenterNotificationTest { fun sendActionPendingIntent_successfulNoSuccessMessage_removesNotification() { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.criticalWithResolvingGeneralIssue(sourceId = uniqueSafetySourceId) + safetySourceTestData.criticalWithResolvingGeneralIssue(sourceId = uniqueSafetySourceId), ) val notificationWithChannel = TestNotificationListener.waitForSingleNotificationMatching( @@ -972,7 +972,7 @@ class SafetyCenterNotificationTest { checkNotNull(action) { "Notification action unexpectedly null" } SafetySourceReceiver.setResponse( Request.ResolveAction(uniqueSafetySourceId), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) sendActionPendingIntentAndWaitWithPermission(action) @@ -986,7 +986,7 @@ class SafetyCenterNotificationTest { uniqueSafetySourceId, safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage( sourceId = uniqueSafetySourceId - ) + ), ) val notificationWithChannel = TestNotificationListener.waitForSingleNotificationMatching( @@ -1000,7 +1000,7 @@ class SafetyCenterNotificationTest { checkNotNull(action) { "Notification action unexpectedly null" } SafetySourceReceiver.setResponse( Request.ResolveAction(uniqueSafetySourceId), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) sendActionPendingIntentAndWaitWithPermission(action) @@ -1017,7 +1017,7 @@ class SafetyCenterNotificationTest { uniqueSafetySourceId, safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage( sourceId = uniqueSafetySourceId - ) + ), ) val notificationWithChannel = TestNotificationListener.waitForSingleNotificationMatching( @@ -1031,7 +1031,7 @@ class SafetyCenterNotificationTest { checkNotNull(action) { "Notification action unexpectedly null" } SafetySourceReceiver.setResponse( Request.ResolveAction(uniqueSafetySourceId), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) sendActionPendingIntentAndWaitWithPermission(action) @@ -1049,7 +1049,7 @@ class SafetyCenterNotificationTest { uniqueSafetySourceId, safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage( sourceId = uniqueSafetySourceId - ) + ), ) val notificationWithChannel = TestNotificationListener.waitForSingleNotificationMatching( @@ -1063,7 +1063,7 @@ class SafetyCenterNotificationTest { checkNotNull(action) { "Notification action unexpectedly null" } SafetySourceReceiver.setResponse( Request.ResolveAction(uniqueSafetySourceId), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) SafetyCenterFlags.notificationsEnabled = false @@ -1078,7 +1078,7 @@ class SafetyCenterNotificationTest { uniqueSafetySourceId, safetySourceTestData.criticalWithResolvingIssueWithSuccessMessage( sourceId = uniqueSafetySourceId - ) + ), ) val notificationWithChannel = TestNotificationListener.waitForSingleNotificationMatching( @@ -1095,8 +1095,8 @@ class SafetyCenterNotificationTest { Response.SetData( safetySourceTestData.information, overrideSafetyEvent = - SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build() - ) + SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build(), + ), ) sendActionPendingIntentAndWaitWithPermission(action) @@ -1118,8 +1118,8 @@ class SafetyCenterNotificationTest { "Solve now!", safetySourceTestData.resolvingActionPendingIntent( sourceId = uniqueSafetySourceId, - sourceIssueActionId = "notification_action_id" - ) + sourceIssueActionId = "notification_action_id", + ), ) .setWillResolve(true) .setSuccessMessage("Solved via notification action :)") @@ -1140,8 +1140,8 @@ class SafetyCenterNotificationTest { "Default action", safetySourceTestData.resolvingActionPendingIntent( sourceId = uniqueSafetySourceId, - sourceIssueActionId = "issue_action_id" - ) + sourceIssueActionId = "issue_action_id", + ), ) .setWillResolve(true) .setSuccessMessage("Solved via issue action :(") @@ -1168,7 +1168,7 @@ class SafetyCenterNotificationTest { checkNotNull(action) { "Notification action unexpectedly null" } SafetySourceReceiver.setResponse( Request.ResolveAction(uniqueSafetySourceId), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) sendActionPendingIntentAndWaitWithPermission(action) @@ -1185,7 +1185,7 @@ class SafetyCenterNotificationTest { // to resolve that action successfully. safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.criticalWithResolvingGeneralIssue(sourceId = uniqueSafetySourceId) + safetySourceTestData.criticalWithResolvingGeneralIssue(sourceId = uniqueSafetySourceId), ) val notificationWithChannel = TestNotificationListener.waitForSingleNotificationMatching( @@ -1199,7 +1199,7 @@ class SafetyCenterNotificationTest { checkNotNull(action) { "Notification action unexpectedly null" } SafetySourceReceiver.setResponse( Request.ResolveAction(uniqueSafetySourceId), - Response.Error + Response.Error, ) val listener = safetyCenterTestHelper.addListener() @@ -1224,7 +1224,7 @@ class SafetyCenterNotificationTest { fun sendContentPendingIntent_singleIssue_opensSafetyCenterWithIssueVisible() { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.recommendationWithDeviceIssue + safetySourceTestData.recommendationWithDeviceIssue, ) val notificationWithChannel = TestNotificationListener.waitForSingleNotificationMatching( @@ -1245,11 +1245,11 @@ class SafetyCenterNotificationTest { setFlagsForImmediateNotifications(SOURCE_ID_1) safetyCenterTestHelper.setData( SOURCE_ID_1, - safetySourceTestData.recommendationWithDeviceIssue + safetySourceTestData.recommendationWithDeviceIssue, ) safetyCenterTestHelper.setData( SOURCE_ID_2, - safetySourceTestData.criticalWithResolvingGeneralIssue(sourceId = SOURCE_ID_2) + safetySourceTestData.criticalWithResolvingGeneralIssue(sourceId = SOURCE_ID_2), ) val notificationWithChannel = TestNotificationListener.waitForSingleNotificationMatching( @@ -1269,7 +1269,7 @@ class SafetyCenterNotificationTest { fun whenGreenIssue_notificationHasAutoCancel() { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.informationWithIssue + safetySourceTestData.informationWithIssue, ) val notificationWithChannel = TestNotificationListener.waitForSingleNotificationMatching( @@ -1286,7 +1286,7 @@ class SafetyCenterNotificationTest { fun whenNotGreenIssue_notificationDoesntHaveAutoCancel() { safetyCenterTestHelper.setData( uniqueSafetySourceId, - safetySourceTestData.recommendationWithDeviceIssue + safetySourceTestData.recommendationWithDeviceIssue, ) val notificationWithChannel = TestNotificationListener.waitForSingleNotificationMatching( @@ -1305,7 +1305,7 @@ class SafetyCenterNotificationTest { fun sendActionPendingIntentAndWaitWithPermission( action: Notification.Action, - timeout: Duration = Coroutines.TIMEOUT_LONG + timeout: Duration = Coroutines.TIMEOUT_LONG, ) { callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) { PendingIntentSender.send(action.actionIntent) @@ -1328,13 +1328,13 @@ class SafetyCenterNotificationTest { fun sendContentPendingIntent( statusBarNotificationWithChannel: StatusBarNotificationWithChannel, - andExecuteBlock: () -> Unit = {} + andExecuteBlock: () -> Unit = {}, ) { val contentIntent = statusBarNotificationWithChannel.statusBarNotification.notification.contentIntent executeBlockAndExit( launchActivity = { PendingIntentSender.send(contentIntent) }, - block = andExecuteBlock + block = andExecuteBlock, ) } } diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetySourceDataFixesTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetySourceDataFixesTest.kt index 4ba293eb9..5cafe3d48 100644 --- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetySourceDataFixesTest.kt +++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetySourceDataFixesTest.kt @@ -105,7 +105,7 @@ class SafetySourceDataFixesTest { .addAction( safetySourceTestData.action( id = targetActionId, - pendingIntent = originalPendingIntent + pendingIntent = originalPendingIntent, ) ) .build() @@ -126,6 +126,7 @@ class SafetySourceDataFixesTest { ) assertThat(intentsFilterEqual(overriddenPendingIntent, expectedPendingIntent)).isTrue() } + @Test @SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE) fun defaultActionOverride_notification_overridesMatchingActions() { @@ -143,7 +144,7 @@ class SafetySourceDataFixesTest { notification( safetySourceTestData.action( id = targetActionId, - pendingIntent = originalPendingIntent + pendingIntent = originalPendingIntent, ) ) ) @@ -183,7 +184,7 @@ class SafetySourceDataFixesTest { .addAction( safetySourceTestData.action( id = targetActionId, - pendingIntent = originalPendingIntent + pendingIntent = originalPendingIntent, ) ) .build() @@ -192,7 +193,7 @@ class SafetySourceDataFixesTest { safetyCenterTestHelper.setData( SOURCE_ID_2, // Different source ID - dataWithoutActionToOverride + dataWithoutActionToOverride, ) val actualPendingIntent = @@ -219,7 +220,7 @@ class SafetySourceDataFixesTest { .addAction( safetySourceTestData.action( id = "DifferentActionId", - pendingIntent = originalPendingIntent + pendingIntent = originalPendingIntent, ) ) .build() @@ -253,7 +254,7 @@ class SafetySourceDataFixesTest { .addAction( safetySourceTestData.action( id = targetActionId, - pendingIntent = originalPendingIntent + pendingIntent = originalPendingIntent, ) ) .build() @@ -289,7 +290,7 @@ class SafetySourceDataFixesTest { private fun intentsFilterEqual( actualPendingIntent: PendingIntent, - expectedPendingIntent: PendingIntent? + expectedPendingIntent: PendingIntent?, ) = callWithShellPermissionIdentity("android.permission.GET_INTENT_SENDER_INTENT") { actualPendingIntent.intentFilterEquals(expectedPendingIntent) diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.kt index 73d6a0737..1d971194e 100644 --- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.kt +++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterQsActivityTest.kt @@ -46,12 +46,12 @@ class SafetyCenterQsActivityTest { private val safetyCenterTestHelper = SafetyCenterTestHelper(context) private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context) + @get:Rule(order = 0) val freezeRotationRule = FreezeRotationRule() @get:Rule(order = 1) val supportsSafetyCenterRule = SupportsSafetyCenterRule(context) @get:Rule(order = 2) val enableCameraRule = EnableSensorRule(context, CAMERA) @get:Rule(order = 3) val enableMicrophoneRule = EnableSensorRule(context, MICROPHONE) @get:Rule(order = 4) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper) @get:Rule(order = 5) val disableAnimationRule = DisableAnimationRule() - @get:Rule(order = 6) val freezeRotationRule = FreezeRotationRule() @Before fun setTestConfigBeforeTest() { diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterStatusCardTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterStatusCardTest.kt index f76a52256..6f147dfbf 100644 --- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterStatusCardTest.kt +++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/ui/SafetyCenterStatusCardTest.kt @@ -69,7 +69,7 @@ class SafetyCenterStatusCardTest { context.launchSafetyCenterActivity { waitAllTextDisplayed( safetyCenterResourcesApk.getStringByName("scanning_title"), - safetyCenterResourcesApk.getStringByName("loading_summary") + safetyCenterResourcesApk.getStringByName("loading_summary"), ) } } @@ -79,13 +79,13 @@ class SafetyCenterStatusCardTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.informationWithIconAction + safetySourceTestData.informationWithIconAction, ) context.launchSafetyCenterActivity { waitAllTextDisplayed( safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"), - safetyCenterResourcesApk.getStringByName("loading_summary") + safetyCenterResourcesApk.getStringByName("loading_summary"), ) } } @@ -98,7 +98,7 @@ class SafetyCenterStatusCardTest { context.launchSafetyCenterActivity(withReceiverPermission = true) { waitAllTextDisplayed( safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_review_title"), - safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_review_summary") + safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_review_summary"), ) waitButtonDisplayed(RESCAN_BUTTON_LABEL) } @@ -110,13 +110,13 @@ class SafetyCenterStatusCardTest { preSetDataOnT(SINGLE_SOURCE_ID, safetySourceTestData.information) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) context.launchSafetyCenterActivity(withReceiverPermission = true) { waitAllTextDisplayed( safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"), - safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary") + safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary"), ) waitButtonDisplayed(RESCAN_BUTTON_LABEL) } @@ -128,7 +128,7 @@ class SafetyCenterStatusCardTest { preSetDataOnT(SINGLE_SOURCE_ID, safetySourceTestData.information) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) context.launchSafetyCenterActivity(withReceiverPermission = true) { @@ -143,13 +143,13 @@ class SafetyCenterStatusCardTest { preSetDataOnT(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.informationWithIssue) + Response.SetData(safetySourceTestData.informationWithIssue), ) context.launchSafetyCenterActivity(withReceiverPermission = true) { waitAllTextDisplayed( safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) waitButtonNotDisplayed(RESCAN_BUTTON_LABEL) } @@ -160,11 +160,11 @@ class SafetyCenterStatusCardTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.recommendationWithGeneralIssue + safetySourceTestData.recommendationWithGeneralIssue, ) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.recommendationWithGeneralIssue) + Response.SetData(safetySourceTestData.recommendationWithGeneralIssue), ) context.launchSafetyCenterActivity(withReceiverPermission = true) { @@ -172,7 +172,7 @@ class SafetyCenterStatusCardTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_safety_recommendation_title" ), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) waitButtonNotDisplayed(RESCAN_BUTTON_LABEL) } @@ -183,11 +183,11 @@ class SafetyCenterStatusCardTest { safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) safetyCenterTestHelper.setData( SINGLE_SOURCE_ID, - safetySourceTestData.criticalWithResolvingGeneralIssue + safetySourceTestData.criticalWithResolvingGeneralIssue, ) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue) + Response.SetData(safetySourceTestData.criticalWithResolvingGeneralIssue), ) context.launchSafetyCenterActivity(withReceiverPermission = true) { @@ -195,7 +195,7 @@ class SafetyCenterStatusCardTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_critical_safety_warning_title" ), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) waitButtonNotDisplayed(RESCAN_BUTTON_LABEL) } @@ -207,20 +207,20 @@ class SafetyCenterStatusCardTest { preSetDataOnT(SINGLE_SOURCE_ID, safetySourceTestData.information) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) context.launchSafetyCenterActivity(withReceiverPermission = true) { waitAllTextDisplayed( safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"), - safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary") + safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary"), ) waitButtonDisplayed(RESCAN_BUTTON_LABEL) { it.click() } waitAllTextDisplayed( safetyCenterResourcesApk.getStringByName("scanning_title"), - safetyCenterResourcesApk.getStringByName("loading_summary") + safetyCenterResourcesApk.getStringByName("loading_summary"), ) } } @@ -231,17 +231,17 @@ class SafetyCenterStatusCardTest { preSetDataOnT(SINGLE_SOURCE_ID, safetySourceTestData.information) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.information) + Response.SetData(safetySourceTestData.information), ) SafetySourceReceiver.setResponse( Request.Rescan(SINGLE_SOURCE_ID), - Response.SetData(safetySourceTestData.recommendationWithGeneralIssue) + Response.SetData(safetySourceTestData.recommendationWithGeneralIssue), ) context.launchSafetyCenterActivity(withReceiverPermission = true) { waitAllTextDisplayed( safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"), - safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary") + safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_summary"), ) waitButtonDisplayed(RESCAN_BUTTON_LABEL) { it.click() } @@ -250,7 +250,7 @@ class SafetyCenterStatusCardTest { safetyCenterResourcesApk.getStringByName( "overall_severity_level_safety_recommendation_title" ), - safetyCenterTestData.getAlertString(1) + safetyCenterTestData.getAlertString(1), ) } } diff --git a/tests/functional/safetycenter/subpages/AndroidTest.xml b/tests/functional/safetycenter/subpages/AndroidTest.xml index c3245e9d7..ac493841f 100644 --- a/tests/functional/safetycenter/subpages/AndroidTest.xml +++ b/tests/functional/safetycenter/subpages/AndroidTest.xml @@ -47,6 +47,10 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS --receiver-foreground" /> </target_preparer> diff --git a/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt b/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt index 7ad83b949..c3e104504 100644 --- a/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt +++ b/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/PrivacySubpageTest.kt @@ -47,9 +47,9 @@ import com.android.safetycenter.testing.UiTestHelper.waitAllTextDisplayed import com.android.safetycenter.testing.UiTestHelper.waitAllTextNotDisplayed import com.android.safetycenter.testing.UiTestHelper.waitButtonDisplayed import com.android.safetycenter.testing.UiTestHelper.waitDisplayed -import com.android.safetycenter.testing.UiTestHelper.waitPageTitleDisplayed import com.android.safetycenter.testing.UiTestHelper.waitSourceIssueDisplayed import com.android.safetycenter.testing.UiTestHelper.waitSourceIssueNotDisplayed +import java.util.regex.Pattern import org.junit.After import org.junit.Before import org.junit.Rule @@ -98,7 +98,7 @@ class PrivacySubpageTest { context.getString(firstSource.summaryResId), "Controls", context.getString(lastSource.titleResId), - context.getString(lastSource.summaryResId) + context.getString(lastSource.summaryResId), ) } } @@ -117,7 +117,7 @@ class PrivacySubpageTest { waitButtonDisplayed("Exit test activity") { it.click() } waitAllTextDisplayed( context.getString(source.titleResId), - context.getString(source.summaryResId) + context.getString(source.summaryResId), ) } } @@ -156,16 +156,16 @@ class PrivacySubpageTest { context.launchSafetyCenterActivity(extras) { waitAllText( displayed = sensorPrivacyManager.supportsSensorToggle(CAMERA), - text = "Camera access" + text = "Camera access", ) waitAllText( displayed = sensorPrivacyManager.supportsSensorToggle(MICROPHONE), - text = "Microphone access" + text = "Microphone access", ) waitAllTextDisplayed("Show clipboard access") waitAllText( displayed = getPermissionControllerBool("config_display_show_password_toggle"), - text = "Show passwords" + text = "Show passwords", ) waitAllTextDisplayed("Location access") } @@ -179,16 +179,14 @@ class PrivacySubpageTest { val source: SafetySource = sourcesGroup.safetySources.first() val extras = Bundle() extras.putString(EXTRA_SAFETY_SOURCES_GROUP_ID, sourcesGroup.id) + val containsLocationPattern = Pattern.compile(".*[Ll]ocation.*") // NOTYPO context.launchSafetyCenterActivity(extras) { - openPageAndExit("Location access") { - waitPageTitleDisplayed("Location") - waitAllTextDisplayed("Use location") - } + openPageAndExit("Location access") { waitDisplayed(By.text(containsLocationPattern)) } waitAllTextDisplayed( context.getString(source.titleResId), - context.getString(source.summaryResId) + context.getString(source.summaryResId), ) } } @@ -225,7 +223,7 @@ class PrivacySubpageTest { permissionControllerContext.resources.getIdentifier( resourceName, "bool", - "com.android.permissioncontroller" + "com.android.permissioncontroller", ) return permissionControllerContext.resources.getBoolean(resourceId) } diff --git a/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt b/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt index 236beb34e..5c770cc92 100644 --- a/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt +++ b/tests/functional/safetycenter/subpages/src/android/safetycenter/functional/ui/SafetyCenterSubpagesTest.kt @@ -160,7 +160,7 @@ class SafetyCenterSubpagesTest { context.getString(firstGroup.titleResId), context.getString(firstGroup.summaryResId), context.getString(lastGroup.titleResId), - context.getString(lastGroup.summaryResId) + context.getString(lastGroup.summaryResId), ) openPageAndExit(context.getString(lastGroup.titleResId)) { @@ -191,7 +191,7 @@ class SafetyCenterSubpagesTest { waitAllTextDisplayed( context.getString(firstGroup.titleResId), context.getString(firstGroup.summaryResId), - context.getString(lastGroup.titleResId) + context.getString(lastGroup.titleResId), ) waitDisplayed(By.text(context.getString(lastGroup.summaryResId))) { it.click() } @@ -232,24 +232,24 @@ class SafetyCenterSubpagesTest { safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SafetySourceData.SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_1_TITLE, - entrySummary = SAFETY_SOURCE_1_SUMMARY - ) + entrySummary = SAFETY_SOURCE_1_SUMMARY, + ), ) setData( SOURCE_ID_2, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SafetySourceData.SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_2_TITLE, - entrySummary = SAFETY_SOURCE_2_SUMMARY - ) + entrySummary = SAFETY_SOURCE_2_SUMMARY, + ), ) setData( SOURCE_ID_3, safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SafetySourceData.SEVERITY_LEVEL_INFORMATION, entryTitle = SAFETY_SOURCE_3_TITLE, - entrySummary = SAFETY_SOURCE_3_SUMMARY - ) + entrySummary = SAFETY_SOURCE_3_SUMMARY, + ), ) } val firstGroup = safetyCenterTestConfigs.multipleSourcesConfig.safetySourcesGroups[0] @@ -263,7 +263,7 @@ class SafetyCenterSubpagesTest { SAFETY_SOURCE_1_TITLE, SAFETY_SOURCE_1_SUMMARY, SAFETY_SOURCE_2_TITLE, - SAFETY_SOURCE_2_SUMMARY + SAFETY_SOURCE_2_SUMMARY, ) } @@ -287,7 +287,7 @@ class SafetyCenterSubpagesTest { waitButtonDisplayed("Exit test activity") { it.click() } waitAllTextDisplayed( context.getString(source.titleResId), - context.getString(source.summaryResId) + context.getString(source.summaryResId), ) } } @@ -370,7 +370,7 @@ class SafetyCenterSubpagesTest { openPageAndExit(context.getString(sourcesGroup.titleResId)) { waitAllTextDisplayed( context.getString(source.titleResId), - context.getString(source.summaryResId) + context.getString(source.summaryResId), ) } @@ -380,15 +380,15 @@ class SafetyCenterSubpagesTest { safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION, entryTitle = "Updated title", - entrySummary = "Updated summary" + entrySummary = "Updated summary", ) - ) + ), ) openPageAndExit(context.getString(sourcesGroup.titleResId)) { waitAllTextNotDisplayed( context.getString(source.titleResId), - context.getString(source.summaryResId) + context.getString(source.summaryResId), ) waitAllTextDisplayed("Updated title", "Updated summary") } @@ -405,7 +405,7 @@ class SafetyCenterSubpagesTest { openPageAndExit(context.getString(sourcesGroup.titleResId)) { waitAllTextDisplayed( context.getString(source.titleResId), - context.getString(source.summaryResId) + context.getString(source.summaryResId), ) SafetySourceReceiver.setResponse( @@ -414,15 +414,15 @@ class SafetyCenterSubpagesTest { safetySourceTestData.buildSafetySourceDataWithSummary( severityLevel = SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION, entryTitle = "Updated title", - entrySummary = "Updated summary" + entrySummary = "Updated summary", ) - ) + ), ) UiAutomatorUtils2.getUiDevice().rotate() waitAllTextDisplayed( context.getString(source.titleResId), - context.getString(source.summaryResId) + context.getString(source.summaryResId), ) waitAllTextNotDisplayed("Updated title", "Updated summary") } @@ -489,7 +489,7 @@ class SafetyCenterSubpagesTest { // Clear the data when action is triggered to simulate resolution. SafetySourceReceiver.setResponse( Request.ResolveAction(SINGLE_SOURCE_ID), - Response.ClearData + Response.ClearData, ) context.launchSafetyCenterActivity(withReceiverPermission = true) { @@ -921,7 +921,7 @@ class SafetyCenterSubpagesTest { waitPageTitleDisplayed(context.getString(sourcesGroup.titleResId)) waitAllTextDisplayed( context.getString(source.titleResId), - context.getString(source.summaryResId) + context.getString(source.summaryResId), ) } } @@ -952,7 +952,7 @@ class SafetyCenterSubpagesTest { waitAllTextDisplayed( context.getString(source.titleResId), context.getString(source.summaryResId), - safetyCenterResourcesApk.getStringByName("test_single_source_group_id_footer") + safetyCenterResourcesApk.getStringByName("test_single_source_group_id_footer"), ) } } @@ -975,7 +975,7 @@ class SafetyCenterSubpagesTest { private fun checkOnDismissedIssue( sourcesGroup: SafetySourcesGroup, issue: SafetySourceIssue, - block: () -> Unit + block: () -> Unit, ) { val safetyCenterIssueId = SafetyCenterTestData.issueId(SINGLE_SOURCE_ID, issue.id) safetyCenterTestHelper.dismissSafetyCenterIssue(safetyCenterIssueId) diff --git a/tests/hostside/safetycenter/AndroidTest.xml b/tests/hostside/safetycenter/AndroidTest.xml index a28b70c3c..41f0bcc40 100644 --- a/tests/hostside/safetycenter/AndroidTest.xml +++ b/tests/hostside/safetycenter/AndroidTest.xml @@ -32,6 +32,10 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS --receiver-foreground" /> </target_preparer> diff --git a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterNotificationLoggingHelperTests.kt b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterNotificationLoggingHelperTests.kt index 60e6e41ec..c56c913b6 100644 --- a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterNotificationLoggingHelperTests.kt +++ b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterNotificationLoggingHelperTests.kt @@ -69,6 +69,12 @@ class SafetyCenterNotificationLoggingHelperTests { @Test fun sendNotification() { safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, newTestDataWithNotifiableIssue()) + TestNotificationListener.waitForSingleNotificationMatching( + NotificationCharacteristics( + actions = listOf("See issue"), + safetySourceId = SINGLE_SOURCE_ID, + ) + ) } @Test @@ -104,7 +110,7 @@ class SafetyCenterNotificationLoggingHelperTests { statusBarNotificationWithChannel.statusBarNotification.notification.contentIntent SafetyCenterActivityLauncher.executeBlockAndExit( launchActivity = { PendingIntentSender.send(contentIntent) }, - block = {} // No action required + block = {}, // No action required ) } } diff --git a/tests/utils/safetycenter/AndroidManifest.xml b/tests/utils/safetycenter/AndroidManifest.xml index f0a4fcbb6..ce3724318 100644 --- a/tests/utils/safetycenter/AndroidManifest.xml +++ b/tests/utils/safetycenter/AndroidManifest.xml @@ -39,7 +39,6 @@ android:exported="false"/> <activity android:name=".TestActivity" - android:theme="@style/OptOutEdgeToEdgeEnforcement" android:exported="false"> <intent-filter android:priority="-1"> <action android:name="com.android.safetycenter.testing.action.TEST_ACTIVITY"/> diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt index a7009b19e..47f5165e2 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt @@ -22,6 +22,7 @@ import java.time.Duration import kotlinx.coroutines.DEBUG_PROPERTY_NAME import kotlinx.coroutines.DEBUG_PROPERTY_VALUE_AUTO import kotlinx.coroutines.DEBUG_PROPERTY_VALUE_ON +import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeout @@ -56,23 +57,37 @@ object Coroutines { /** Shorthand for [runBlocking] combined with [withTimeoutOrNull] */ fun <T> runBlockingWithTimeoutOrNull( timeout: Duration = TIMEOUT_LONG, - block: suspend () -> T + block: suspend () -> T, ): T? = runBlocking { withTimeoutOrNull(timeout.toMillis()) { block() } } /** Check a condition using coroutines with a timeout. */ fun waitForWithTimeout( timeout: Duration = TIMEOUT_LONG, checkPeriod: Duration = CHECK_PERIOD, - condition: () -> Boolean + condition: () -> Boolean, ) { runBlockingWithTimeout(timeout) { waitFor(checkPeriod, condition) } } + /** Check an assertion passes, with a timeout if it does not. */ + fun assertWithTimeout( + timeout: Duration = TIMEOUT_LONG, + checkPeriod: Duration = CHECK_PERIOD, + assertion: () -> Unit, + ) { + try { + runBlockingWithTimeout(timeout) { assertThatWaiting(checkPeriod, assertion) } + } catch (ex: TimeoutCancellationException) { + // Rerun the assertion to generate a meaningful error message that isn't just "timeout" + assertion() + } + } + /** Retries a [fallibleAction] until no errors are thrown or a timeout occurs. */ fun waitForSuccessWithTimeout( timeout: Duration = TIMEOUT_LONG, checkPeriod: Duration = CHECK_PERIOD, - fallibleAction: () -> Unit + fallibleAction: () -> Unit, ) { waitForWithTimeout(timeout, checkPeriod) { try { @@ -105,6 +120,21 @@ object Coroutines { } } + /** Check an assertion passes using coroutines. */ + private suspend fun assertThatWaiting( + checkPeriod: Duration = CHECK_PERIOD, + assertion: () -> Unit, + ) { + while (true) { + try { + assertion() + break + } catch (ex: AssertionError) { + delay(checkPeriod.toMillis()) + } + } + } + private const val TAG: String = "Coroutines" /** A medium period, to be used for conditions that are expected to change. */ diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/EnableSensorRule.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/EnableSensorRule.kt index 1ed0ecbc3..7303d631b 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/EnableSensorRule.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/EnableSensorRule.kt @@ -42,7 +42,7 @@ class EnableSensorRule(context: Context, val sensor: Int) : TestRule { override fun evaluate() { assumeTrue( "Test device does not support toggling sensor $sensor", - supportsSensorToggle() + supportsSensorToggle(), ) val oldSensorPrivacy = isSensorPrivacyEnabled() setSensorPrivacy(false) diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/EqualsHashCodeToStringTester.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/EqualsHashCodeToStringTester.kt index 2dedfc853..77577d504 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/EqualsHashCodeToStringTester.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/EqualsHashCodeToStringTester.kt @@ -45,7 +45,7 @@ private constructor( private val ignoreHashCode: Boolean = false, private val ignoreToString: Boolean = false, private val parcelRoundTripEqualsEquivalence: Equivalence<T>? = null, - private val createCopy: ((T) -> T)? = null + private val createCopy: ((T) -> T)? = null, ) { private val equalsTester = EqualsTester() @@ -85,13 +85,13 @@ private constructor( parcelableCreator: Parcelable.Creator<T>, ignoreHashCode: Boolean = false, ignoreToString: Boolean = false, - createCopy: ((T) -> T)? = null + createCopy: ((T) -> T)? = null, ): EqualsHashCodeToStringTester<T> = EqualsHashCodeToStringTester( ignoreHashCode, ignoreToString, parcelRoundTripEqualsEquivalence(parcelableCreator), - createCopy + createCopy, ) /** @@ -103,13 +103,13 @@ private constructor( fun <T> of( ignoreHashCode: Boolean = false, ignoreToString: Boolean = false, - createCopy: ((T) -> T)? = null + createCopy: ((T) -> T)? = null, ): EqualsHashCodeToStringTester<T> = EqualsHashCodeToStringTester( ignoreHashCode, ignoreToString, parcelRoundTripEqualsEquivalence = null, - createCopy + createCopy, ) /** diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/NotificationCharacteristics.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/NotificationCharacteristics.kt index 81b752bca..11827a5f4 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/NotificationCharacteristics.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/NotificationCharacteristics.kt @@ -38,7 +38,7 @@ data class NotificationCharacteristics( private fun importanceMatches( statusBarNotificationWithChannel: StatusBarNotificationWithChannel, - characteristicImportance: Int + characteristicImportance: Int, ): Boolean { return characteristicImportance == IMPORTANCE_ANY || statusBarNotificationWithChannel.channel.importance == characteristicImportance @@ -46,7 +46,7 @@ data class NotificationCharacteristics( private fun blockableMatches( statusBarNotificationWithChannel: StatusBarNotificationWithChannel, - characteristicBlockable: Boolean? + characteristicBlockable: Boolean?, ): Boolean { return characteristicBlockable == null || statusBarNotificationWithChannel.channel.isBlockable == characteristicBlockable @@ -54,7 +54,7 @@ data class NotificationCharacteristics( fun safetySourceIdMatches( statusBarNotification: StatusBarNotification, - safetySourceId: String? + safetySourceId: String?, ): Boolean { return safetySourceId == null || SafetyCenterIds.issueKeyFromString(statusBarNotification.tag).safetySourceId == @@ -63,7 +63,7 @@ data class NotificationCharacteristics( private fun isMatch( statusBarNotificationWithChannel: StatusBarNotificationWithChannel, - characteristic: NotificationCharacteristics + characteristic: NotificationCharacteristics, ): Boolean { val notif = statusBarNotificationWithChannel.statusBarNotification.notification val extras = notif.extras @@ -75,13 +75,13 @@ data class NotificationCharacteristics( blockableMatches(statusBarNotificationWithChannel, characteristic.blockable) && safetySourceIdMatches( statusBarNotificationWithChannel.statusBarNotification, - characteristic.safetySourceId + characteristic.safetySourceId, ) } fun areMatching( statusBarNotifications: List<StatusBarNotificationWithChannel>, - characteristics: List<NotificationCharacteristics> + characteristics: List<NotificationCharacteristics>, ): Boolean { if (statusBarNotifications.size != characteristics.size) { return false diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt index 40515fa33..62f324d89 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterActivityLauncher.kt @@ -48,13 +48,13 @@ object SafetyCenterActivityLauncher { intentAction: String = ACTION_SAFETY_CENTER, withReceiverPermission: Boolean = false, preventTrampolineToSettings: Boolean = true, - block: () -> Unit + block: () -> Unit, ) { val launchSafetyCenterIntent = createIntent( intentAction, intentExtras, - preventTrampolineToSettings = preventTrampolineToSettings + preventTrampolineToSettings = preventTrampolineToSettings, ) if (withReceiverPermission) { callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) { @@ -83,7 +83,7 @@ object SafetyCenterActivityLauncher { private fun createIntent( intentAction: String, intentExtras: Bundle?, - preventTrampolineToSettings: Boolean = false + preventTrampolineToSettings: Boolean = false, ): Intent { val launchIntent = Intent(intentAction).addFlags(FLAG_ACTIVITY_NEW_TASK).addFlags(FLAG_ACTIVITY_CLEAR_TASK) diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterApisWithShellPermissions.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterApisWithShellPermissions.kt index 961d03c47..b5f732bad 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterApisWithShellPermissions.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterApisWithShellPermissions.kt @@ -52,7 +52,7 @@ object SafetyCenterApisWithShellPermissions { fun SafetyCenterManager.setSafetySourceDataWithPermission( safetySourceId: String, safetySourceData: SafetySourceData?, - safetyEvent: SafetyEvent + safetyEvent: SafetyEvent, ) { callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) { setSafetySourceData(safetySourceId, safetySourceData, safetyEvent) @@ -72,7 +72,7 @@ object SafetyCenterApisWithShellPermissions { */ fun SafetyCenterManager.reportSafetySourceErrorWithPermission( safetySourceId: String, - safetySourceErrorDetails: SafetySourceErrorDetails + safetySourceErrorDetails: SafetySourceErrorDetails, ) { callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) { reportSafetySourceError(safetySourceId, safetySourceErrorDetails) @@ -85,7 +85,7 @@ object SafetyCenterApisWithShellPermissions { */ fun SafetyCenterManager.refreshSafetySourcesWithPermission( refreshReason: Int, - safetySourceIds: List<String>? = null + safetySourceIds: List<String>? = null, ) { callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) { if (safetySourceIds != null) { @@ -116,7 +116,7 @@ object SafetyCenterApisWithShellPermissions { */ fun SafetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( executor: Executor, - listener: OnSafetyCenterDataChangedListener + listener: OnSafetyCenterDataChangedListener, ) { callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) { addOnSafetyCenterDataChangedListener(executor, listener) @@ -151,7 +151,7 @@ object SafetyCenterApisWithShellPermissions { */ fun SafetyCenterManager.executeSafetyCenterIssueActionWithPermission( safetyCenterIssueId: String, - safetyCenterIssueActionId: String + safetyCenterIssueActionId: String, ) { callWithShellPermissionIdentity(MANAGE_SAFETY_CENTER) { executeSafetyCenterIssueAction(safetyCenterIssueId, safetyCenterIssueActionId) diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt index f8926caac..e454b6e25 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterEnabledChangedReceiver.kt @@ -54,16 +54,14 @@ class SafetyCenterEnabledChangedReceiver(private val context: Context) : Broadca fun setSafetyCenterEnabledWithReceiverPermissionAndWait( value: Boolean, - timeout: Duration = TIMEOUT_LONG + timeout: Duration = TIMEOUT_LONG, ): Boolean = callWithShellPermissionIdentity(READ_SAFETY_CENTER_STATUS) { SafetyCenterFlags.isEnabled = value receiveSafetyCenterEnabledChanged(timeout) } - fun setSafetyCenterEnabledWithoutReceiverPermissionAndWait( - value: Boolean, - ) { + fun setSafetyCenterEnabledWithoutReceiverPermissionAndWait(value: Boolean) { SafetyCenterFlags.isEnabled = value WaitForBroadcasts.waitForBroadcasts() receiveSafetyCenterEnabledChanged(TIMEOUT_SHORT) diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt index 912ea44ad..7efbba7a0 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt @@ -17,6 +17,7 @@ package com.android.safetycenter.testing import android.Manifest.permission.READ_DEVICE_CONFIG +import android.Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG import android.Manifest.permission.WRITE_DEVICE_CONFIG import android.annotation.TargetApi import android.app.job.JobInfo @@ -61,7 +62,7 @@ object SafetyCenterFlags { Flag( "safety_center_notifications_min_delay", defaultValue = Duration.ofHours(2), - DurationParser() + DurationParser(), ) /** @@ -72,7 +73,7 @@ object SafetyCenterFlags { Flag( "safety_center_notifications_allowed_sources", defaultValue = emptySet(), - SetParser(StringParser()) + SetParser(StringParser()), ) /** @@ -83,7 +84,7 @@ object SafetyCenterFlags { Flag( "safety_center_notifications_immediate_behavior_issues", defaultValue = emptySet(), - SetParser(StringParser()) + SetParser(StringParser()), ) /** @@ -98,7 +99,7 @@ object SafetyCenterFlags { Flag( "safety_center_notification_resurface_interval", defaultValue = Duration.ofDays(-1), - DurationParser() + DurationParser(), ) /** Flag that determines whether we should replace the IconAction of the lock screen source. */ @@ -119,7 +120,7 @@ object SafetyCenterFlags { Flag( "safety_center_refresh_sources_timeouts_millis", defaultValue = getAllRefreshTimeoutsMap(TEST_TIMEOUT), - MapParser(IntParser(), DurationParser()) + MapParser(IntParser(), DurationParser()), ) /** @@ -130,7 +131,7 @@ object SafetyCenterFlags { Flag( "safety_center_resolve_action_timeout_millis", defaultValue = TIMEOUT_LONG, - DurationParser() + DurationParser(), ) /** Flag that determines a duration after which a temporarily hidden issue will resurface. */ @@ -138,7 +139,7 @@ object SafetyCenterFlags { Flag( "safety_center_temp_hidden_issue_resurface_delay_millis", defaultValue = Duration.ofDays(2), - DurationParser() + DurationParser(), ) /** @@ -149,7 +150,7 @@ object SafetyCenterFlags { Flag( "safety_center_hide_resolved_ui_transition_delay_millis", defaultValue = Duration.ofMillis(400), - DurationParser() + DurationParser(), ) /** @@ -161,7 +162,7 @@ object SafetyCenterFlags { Flag( "safety_center_untracked_sources", defaultValue = emptySet(), - SetParser(StringParser()) + SetParser(StringParser()), ) /** @@ -173,7 +174,7 @@ object SafetyCenterFlags { Flag( "safety_center_resurface_issue_max_counts", defaultValue = emptyMap(), - MapParser(IntParser(), LongParser()) + MapParser(IntParser(), LongParser()), ) /** @@ -187,7 +188,7 @@ object SafetyCenterFlags { Flag( "safety_center_resurface_issue_delays_millis", defaultValue = emptyMap(), - MapParser(IntParser(), DurationParser()) + MapParser(IntParser(), DurationParser()), ) /** @@ -199,7 +200,7 @@ object SafetyCenterFlags { Flag( "safety_center_issue_category_allowlists", defaultValue = emptyMap(), - MapParser(IntParser(), SetParser(StringParser(), delimiter = "|")) + MapParser(IntParser(), SetParser(StringParser(), delimiter = "|")), ) /** @@ -211,7 +212,7 @@ object SafetyCenterFlags { Flag( "safety_center_actions_to_override_with_default_intent", defaultValue = emptyMap(), - MapParser(StringParser(), SetParser(StringParser(), delimiter = "|")) + MapParser(StringParser(), SetParser(StringParser(), delimiter = "|")), ) /** @@ -223,7 +224,7 @@ object SafetyCenterFlags { Flag( "safety_center_background_refresh_denied_sources", defaultValue = emptySet(), - SetParser(StringParser()) + SetParser(StringParser()), ) /** @@ -245,7 +246,7 @@ object SafetyCenterFlags { Flag( "safety_center_qs_tile_component_setting_flags", defaultValue = PackageManager.DONT_KILL_APP, - IntParser() + IntParser(), ) /** @@ -253,13 +254,13 @@ object SafetyCenterFlags { * expand-and-collapse list. */ private val showSubpagesFlag = - Flag("safety_center_show_subpages", defaultValue = false, BooleanParser()) + Flag("safety_center_show_subpages", defaultValue = SdkLevel.isAtLeastU(), BooleanParser()) private val overrideRefreshOnPageOpenSourcesFlag = Flag( "safety_center_override_refresh_on_page_open_sources", defaultValue = setOf(), - SetParser(StringParser()) + SetParser(StringParser()), ) /** @@ -272,7 +273,7 @@ object SafetyCenterFlags { // do not set defaultValue to true, do not want background refreshes running // during other tests defaultValue = false, - BooleanParser() + BooleanParser(), ) /** @@ -286,7 +287,7 @@ object SafetyCenterFlags { Flag( "safety_center_periodic_background_interval_millis", defaultValue = Duration.ofDays(1), - DurationParser() + DurationParser(), ) /** Flag for allowlisting additional certificates for a given package. */ @@ -294,7 +295,7 @@ object SafetyCenterFlags { Flag( "safety_center_additional_allow_package_certs", defaultValue = emptyMap(), - MapParser(StringParser(), SetParser(StringParser(), delimiter = "|")) + MapParser(StringParser(), SetParser(StringParser(), delimiter = "|")), ) /** Every Safety Center flag. */ @@ -323,7 +324,7 @@ object SafetyCenterFlags { showSubpagesFlag, overrideRefreshOnPageOpenSourcesFlag, backgroundRefreshIsEnabledFlag, - periodicBackgroundRefreshIntervalFlag + periodicBackgroundRefreshIntervalFlag, ) /** A property that allows getting and setting the [isEnabledFlag]. */ @@ -453,7 +454,7 @@ object SafetyCenterFlags { REFRESH_REASON_DEVICE_LOCALE_CHANGE to refreshTimeout, REFRESH_REASON_SAFETY_CENTER_ENABLED to refreshTimeout, REFRESH_REASON_OTHER to refreshTimeout, - REFRESH_REASON_PERIODIC to refreshTimeout + REFRESH_REASON_PERIODIC to refreshTimeout, ) private interface Parser<T> { @@ -486,7 +487,7 @@ object SafetyCenterFlags { private class SetParser<T>( private val elementParser: Parser<T>, - private val delimiter: String = "," + private val delimiter: String = ",", ) : Parser<Set<T>> { override fun parseFromString(stringValue: String) = stringValue.split(delimiter).map(elementParser::parseFromString).toSet() @@ -499,7 +500,7 @@ object SafetyCenterFlags { private val keyParser: Parser<K>, private val valueParser: Parser<V>, private val entriesDelimiter: String = ",", - private val pairDelimiter: String = ":" + private val pairDelimiter: String = ":", ) : Parser<Map<K, V>> { override fun parseFromString(stringValue: String) = stringValue.split(entriesDelimiter).associate { pair -> @@ -532,13 +533,13 @@ object SafetyCenterFlags { } private fun writeDeviceConfigProperty(name: String, stringValue: String?) { - callWithShellPermissionIdentity(WRITE_DEVICE_CONFIG) { + callWithShellPermissionIdentity(WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG) { val valueWasSet = DeviceConfig.setProperty( NAMESPACE_PRIVACY, name, stringValue, /* makeDefault */ - false + false, ) require(valueWasSet) { "Could not set $name to: $stringValue" } } diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt index 261e179dd..231cec821 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt @@ -48,7 +48,7 @@ class SafetyCenterTestConfigs(private val context: Context) { context.packageManager .getPackageInfo( context.packageName, - PackageInfoFlags.of(GET_SIGNING_CERTIFICATES.toLong()) + PackageInfoFlags.of(GET_SIGNING_CERTIFICATES.toLong()), ) .signingInfo!! .apkContentsSigners[0] @@ -220,25 +220,25 @@ class SafetyCenterTestConfigs(private val context: Context) { .addSafetySource( issueOnlySafetySourceWithDuplicationInfo( SOURCE_ID_1, - DEDUPLICATION_GROUP_1 + DEDUPLICATION_GROUP_1, ) ) .addSafetySource( issueOnlySafetySourceWithDuplicationInfo( SOURCE_ID_2, - DEDUPLICATION_GROUP_1 + DEDUPLICATION_GROUP_1, ) ) .addSafetySource( issueOnlySafetySourceWithDuplicationInfo( SOURCE_ID_3, - DEDUPLICATION_GROUP_2 + DEDUPLICATION_GROUP_2, ) ) .addSafetySource( issueOnlySafetySourceWithDuplicationInfo( SOURCE_ID_4, - DEDUPLICATION_GROUP_3 + DEDUPLICATION_GROUP_3, ) ) .build() @@ -248,13 +248,13 @@ class SafetyCenterTestConfigs(private val context: Context) { .addSafetySource( issueOnlySafetySourceWithDuplicationInfo( SOURCE_ID_5, - DEDUPLICATION_GROUP_1 + DEDUPLICATION_GROUP_1, ) ) .addSafetySource( issueOnlySafetySourceWithDuplicationInfo( SOURCE_ID_6, - DEDUPLICATION_GROUP_3 + DEDUPLICATION_GROUP_3, ) ) .build() @@ -264,7 +264,7 @@ class SafetyCenterTestConfigs(private val context: Context) { .addSafetySource( issueOnlySafetySourceWithDuplicationInfo( SOURCE_ID_7, - DEDUPLICATION_GROUP_3 + DEDUPLICATION_GROUP_3, ) ) .build() diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt index 289bc32a8..15f8d02ae 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestData.kt @@ -32,6 +32,8 @@ import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION +import android.safetycenter.SafetyCenterEntryGroup +import android.safetycenter.SafetyCenterEntryOrGroup import android.safetycenter.SafetyCenterIssue import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK @@ -80,7 +82,7 @@ class SafetyCenterTestData(context: Context) { ), safetyCenterResourcesApk.getStringByName( "overall_severity_level_ok_review_summary" - ) + ), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_UNKNOWN) .build() @@ -91,7 +93,7 @@ class SafetyCenterTestData(context: Context) { */ fun safetyCenterStatusOneAlert( statusResource: String, - overallSeverityLevel: Int + overallSeverityLevel: Int, ): SafetyCenterStatus = safetyCenterStatusNAlerts(statusResource, overallSeverityLevel, 1) /** @@ -105,7 +107,7 @@ class SafetyCenterTestData(context: Context) { ): SafetyCenterStatus = SafetyCenterStatus.Builder( safetyCenterResourcesApk.getStringByName(statusResource), - getAlertString(numAlerts) + getAlertString(numAlerts), ) .setSeverityLevel(overallSeverityLevel) .build() @@ -114,12 +116,10 @@ class SafetyCenterTestData(context: Context) { * Returns an information [SafetyCenterStatus] that has "Tip(s) available" as a summary for the * given [numTipIssues]. */ - fun safetyCenterStatusTips( - numTipIssues: Int, - ): SafetyCenterStatus = + fun safetyCenterStatusTips(numTipIssues: Int): SafetyCenterStatus = SafetyCenterStatus.Builder( safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"), - getIcuPluralsString("overall_severity_level_tip_summary", numTipIssues) + getIcuPluralsString("overall_severity_level_tip_summary", numTipIssues), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK) .build() @@ -128,15 +128,13 @@ class SafetyCenterTestData(context: Context) { * Returns an information [SafetyCenterStatus] that has "Action(s) taken" as a summary for the * given [numAutomaticIssues]. */ - fun safetyCenterStatusActionsTaken( - numAutomaticIssues: Int, - ): SafetyCenterStatus = + fun safetyCenterStatusActionsTaken(numAutomaticIssues: Int): SafetyCenterStatus = SafetyCenterStatus.Builder( safetyCenterResourcesApk.getStringByName("overall_severity_level_ok_title"), getIcuPluralsString( "overall_severity_level_action_taken_summary", - numAutomaticIssues - ) + numAutomaticIssues, + ), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK) .build() @@ -150,7 +148,7 @@ class SafetyCenterTestData(context: Context) { safetyCenterResourcesApk.getStringByName( "overall_severity_level_critical_safety_warning_title" ), - getAlertString(numAlerts) + getAlertString(numAlerts), ) .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING) .build() @@ -165,7 +163,7 @@ class SafetyCenterTestData(context: Context) { userId: Int = UserHandle.myUserId(), title: CharSequence = "OK", pendingIntent: PendingIntent? = - safetySourceTestData.createTestActivityRedirectPendingIntent() + safetySourceTestData.createTestActivityRedirectPendingIntent(), ) = SafetyCenterEntry.Builder(entryId(sourceId, userId), title) .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN) @@ -183,7 +181,7 @@ class SafetyCenterTestData(context: Context) { userId: Int = UserHandle.myUserId(), title: CharSequence = "OK", pendingIntent: PendingIntent? = - safetySourceTestData.createTestActivityRedirectPendingIntent() + safetySourceTestData.createTestActivityRedirectPendingIntent(), ) = safetyCenterEntryDefaultBuilder(sourceId, userId, title, pendingIntent).build() /** @@ -194,7 +192,7 @@ class SafetyCenterTestData(context: Context) { fun safetyCenterEntryDefaultStaticBuilder( sourceId: String, userId: Int = UserHandle.myUserId(), - title: CharSequence = "OK" + title: CharSequence = "OK", ) = SafetyCenterEntry.Builder(entryId(sourceId, userId), title) .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED) @@ -219,7 +217,7 @@ class SafetyCenterTestData(context: Context) { fun safetyCenterEntryUnspecified( sourceId: String, pendingIntent: PendingIntent? = - safetySourceTestData.createTestActivityRedirectPendingIntent() + safetySourceTestData.createTestActivityRedirectPendingIntent(), ) = SafetyCenterEntry.Builder(entryId(sourceId), "Unspecified title") .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED) @@ -237,7 +235,7 @@ class SafetyCenterTestData(context: Context) { fun safetyCenterEntryOkBuilder( sourceId: String, userId: Int = UserHandle.myUserId(), - title: CharSequence = "Ok title" + title: CharSequence = "Ok title", ) = SafetyCenterEntry.Builder(entryId(sourceId, userId), title) .setSeverityLevel(ENTRY_SEVERITY_LEVEL_OK) @@ -252,7 +250,7 @@ class SafetyCenterTestData(context: Context) { fun safetyCenterEntryOk( sourceId: String, userId: Int = UserHandle.myUserId(), - title: CharSequence = "Ok title" + title: CharSequence = "Ok title", ) = safetyCenterEntryOkBuilder(sourceId, userId, title).build() /** @@ -262,7 +260,7 @@ class SafetyCenterTestData(context: Context) { */ fun safetyCenterEntryRecommendation( sourceId: String, - summary: String = "Recommendation summary" + summary: String = "Recommendation summary", ) = SafetyCenterEntry.Builder(entryId(sourceId), "Recommendation title") .setSeverityLevel(ENTRY_SEVERITY_LEVEL_RECOMMENDATION) @@ -283,6 +281,32 @@ class SafetyCenterTestData(context: Context) { .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION) .build() + fun singletonSafetyCenterEntryOrGroup( + groupId: String, + entry: SafetyCenterEntry, + groupSummary: String? = null, + ) = + // TODO: b/361404288 - Replace with platform version check + if (SafetyCenterFlags.showSubpages) { + val summary = + if (groupSummary == null && entry.severityLevel > ENTRY_SEVERITY_LEVEL_OK) { + entry.summary + } else groupSummary ?: "OK" + + SafetyCenterEntryOrGroup( + SafetyCenterEntryGroup.Builder(groupId, "OK") + .setSeverityLevel(entry.severityLevel) + .setSeverityUnspecifiedIconType( + SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION + ) + .setSummary(summary) + .setEntries(listOf(entry)) + .build() + ) + } else { + SafetyCenterEntryOrGroup(entry) + } + /** * Returns an information [SafetyCenterIssue] for the given source and user id that is * consistent with information [SafetySourceIssue]s used in [SafetySourceTestData]. @@ -291,12 +315,12 @@ class SafetyCenterTestData(context: Context) { sourceId: String, userId: Int = UserHandle.myUserId(), attributionTitle: String? = "OK", - groupId: String? = SINGLE_SOURCE_GROUP_ID + groupId: String? = SINGLE_SOURCE_GROUP_ID, ) = SafetyCenterIssue.Builder( issueId(sourceId, INFORMATION_ISSUE_ID, userId = userId), "Information issue title", - "Information issue summary" + "Information issue summary", ) .setSeverityLevel(ISSUE_SEVERITY_LEVEL_OK) .setShouldConfirmDismissal(false) @@ -307,10 +331,10 @@ class SafetyCenterTestData(context: Context) { sourceId, INFORMATION_ISSUE_ID, INFORMATION_ISSUE_ACTION_ID, - userId + userId, ), "Review", - safetySourceTestData.createTestActivityRedirectPendingIntent() + safetySourceTestData.createTestActivityRedirectPendingIntent(), ) .build() ) @@ -332,12 +356,12 @@ class SafetyCenterTestData(context: Context) { userId: Int = UserHandle.myUserId(), attributionTitle: String? = "OK", groupId: String? = SINGLE_SOURCE_GROUP_ID, - confirmationDialog: Boolean = false + confirmationDialog: Boolean = false, ) = SafetyCenterIssue.Builder( issueId(sourceId, RECOMMENDATION_ISSUE_ID, userId = userId), "Recommendation issue title", - "Recommendation issue summary" + "Recommendation issue summary", ) .setSeverityLevel(ISSUE_SEVERITY_LEVEL_RECOMMENDATION) .setActions( @@ -347,10 +371,10 @@ class SafetyCenterTestData(context: Context) { sourceId, RECOMMENDATION_ISSUE_ID, RECOMMENDATION_ISSUE_ACTION_ID, - userId + userId, ), "See issue", - safetySourceTestData.createTestActivityRedirectPendingIntent() + safetySourceTestData.createTestActivityRedirectPendingIntent(), ) .apply { if (confirmationDialog && SdkLevel.isAtLeastU()) { @@ -359,7 +383,7 @@ class SafetyCenterTestData(context: Context) { "Confirmation title", "Confirmation text", "Confirmation yes", - "Confirmation no" + "Confirmation no", ) ) } @@ -384,12 +408,12 @@ class SafetyCenterTestData(context: Context) { isActionInFlight: Boolean = false, userId: Int = UserHandle.myUserId(), attributionTitle: String? = "OK", - groupId: String? = SINGLE_SOURCE_GROUP_ID + groupId: String? = SINGLE_SOURCE_GROUP_ID, ) = SafetyCenterIssue.Builder( issueId(sourceId, CRITICAL_ISSUE_ID, userId = userId), "Critical issue title", - "Critical issue summary" + "Critical issue summary", ) .setSeverityLevel(ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING) .setActions( @@ -399,10 +423,10 @@ class SafetyCenterTestData(context: Context) { sourceId, CRITICAL_ISSUE_ID, CRITICAL_ISSUE_ACTION_ID, - userId + userId, ), "Solve issue", - safetySourceTestData.criticalIssueActionPendingIntent + safetySourceTestData.criticalIssueActionPendingIntent, ) .setWillResolve(true) .setIsInFlight(isActionInFlight) @@ -432,7 +456,7 @@ class SafetyCenterTestData(context: Context) { val messageFormat = MessageFormat( safetyCenterResourcesApk.getStringByName(name, formatArgs), - Locale.getDefault() + Locale.getDefault(), ) val arguments = ArrayMap<String, Any>() arguments["count"] = count @@ -448,7 +472,7 @@ class SafetyCenterTestData(context: Context) { .build(), emptyList(), emptyList(), - emptyList() + emptyList(), ) /** Creates an ID for a Safety Center entry. */ @@ -465,7 +489,7 @@ class SafetyCenterTestData(context: Context) { sourceId: String, sourceIssueId: String, issueTypeId: String = ISSUE_TYPE_ID, - userId: Int = UserHandle.myUserId() + userId: Int = UserHandle.myUserId(), ) = SafetyCenterIds.encodeToString( SafetyCenterIssueId.newBuilder() @@ -485,7 +509,7 @@ class SafetyCenterTestData(context: Context) { sourceId: String, sourceIssueId: String, sourceIssueActionId: String, - userId: Int = UserHandle.myUserId() + userId: Int = UserHandle.myUserId(), ) = SafetyCenterIds.encodeToString( SafetyCenterIssueActionId.newBuilder() @@ -546,7 +570,7 @@ class SafetyCenterTestData(context: Context) { private fun SafetyCenterData.copy( issues: List<SafetyCenterIssue> = this.issues, dismissedIssues: List<SafetyCenterIssue> = this.dismissedIssues, - extras: Bundle = this.extras + extras: Bundle = this.extras, ): SafetyCenterData = SafetyCenterData.Builder(status) .apply { diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt index a138675d3..ac646648a 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestHelper.kt @@ -108,7 +108,7 @@ class SafetyCenterTestHelper(val context: Context) { } assumeTrue( "Cannot toggle SafetyCenter using DeviceConfig", - safetyCenterCanBeToggledUsingDeviceConfig() + safetyCenterCanBeToggledUsingDeviceConfig(), ) setEnabledWaitingForSafetyCenterBroadcastIdle(value, safetyCenterConfig) } @@ -132,7 +132,7 @@ class SafetyCenterTestHelper(val context: Context) { val listener = SafetyCenterTestListener() safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission( directExecutor(), - listener + listener, ) if (skipInitialData) { listener.receiveSafetyCenterData() @@ -145,14 +145,14 @@ class SafetyCenterTestHelper(val context: Context) { fun setData( safetySourceId: String, safetySourceData: SafetySourceData?, - safetyEvent: SafetyEvent = EVENT_SOURCE_STATE_CHANGED + safetyEvent: SafetyEvent = EVENT_SOURCE_STATE_CHANGED, ) { Log.d(TAG, "setData for $safetySourceId") require(isEnabled()) safetyCenterManager.setSafetySourceDataWithPermission( safetySourceId, safetySourceData, - safetyEvent + safetyEvent, ) } @@ -173,7 +173,7 @@ class SafetyCenterTestHelper(val context: Context) { private fun setEnabledWaitingForSafetyCenterBroadcastIdle( value: Boolean, - safetyCenterConfig: SafetyCenterConfig + safetyCenterConfig: SafetyCenterConfig, ) = callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE, READ_SAFETY_CENTER_STATUS) { val enabledChangedReceiver = SafetyCenterEnabledChangedReceiver(context) diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt index 8ce5c25d4..46e9b6593 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt @@ -58,7 +58,7 @@ class SafetyCenterTestListener : OnSafetyCenterDataChangedListener { */ fun receiveSafetyCenterData( timeout: Duration = TIMEOUT_LONG, - matching: (SafetyCenterData) -> Boolean = { true } + matching: (SafetyCenterData) -> Boolean = { true }, ): SafetyCenterData = runBlockingWithTimeout(timeout) { var safetyCenterData = dataChannel.receive() @@ -78,7 +78,7 @@ class SafetyCenterTestListener : OnSafetyCenterDataChangedListener { */ fun waitForSafetyCenterRefresh( timeout: Duration = TIMEOUT_LONG, - withErrorEntry: Boolean? = null + withErrorEntry: Boolean? = null, ): SafetyCenterData { receiveSafetyCenterData(timeout) { it.status.refreshStatus == SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS || diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestRule.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestRule.kt index dcbc4ebe9..c89b29b2a 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestRule.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestRule.kt @@ -23,7 +23,7 @@ import org.junit.runners.model.Statement /** A JUnit [TestRule] that performs setup and reset steps before and after Safety Center tests. */ class SafetyCenterTestRule( private val safetyCenterTestHelper: SafetyCenterTestHelper, - private val withNotifications: Boolean = false + private val withNotifications: Boolean = false, ) : TestRule { override fun apply(base: Statement, description: Description): Statement { diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt index 8386228b8..77d338f90 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceIntentHandler.kt @@ -114,7 +114,7 @@ class SafetySourceIntentHandler { private suspend fun SafetyCenterManager.processRefreshSafetySources( intent: Intent, - userId: Int + userId: Int, ) { val broadcastId = intent.getStringExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID) if (broadcastId.isNullOrEmpty()) { @@ -190,7 +190,7 @@ class SafetySourceIntentHandler { private fun createResolveActionSuccessEvent( sourceIssueId: String, - sourceIssueActionId: String + sourceIssueActionId: String, ) = SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED) .setSafetySourceIssueId(sourceIssueId) @@ -218,7 +218,7 @@ class SafetySourceIntentHandler { private suspend fun SafetyCenterManager.processRequest( request: Request, - safetyEventForResponse: (Response) -> SafetyEvent + safetyEventForResponse: (Response) -> SafetyEvent, ) { val response = mutex.withLock { requestsToResponses[request] } ?: return val safetyEvent = response.overrideSafetyEvent ?: safetyEventForResponse(response) @@ -242,25 +242,25 @@ class SafetySourceIntentHandler { /** Creates a refresh [Request] based on the given [sourceId] and [userId]. */ data class Refresh( override val sourceId: String, - override val userId: Int = UserHandle.myUserId() + override val userId: Int = UserHandle.myUserId(), ) : Request /** Creates a rescan [Request] based on the given [sourceId] and [userId]. */ data class Rescan( override val sourceId: String, - override val userId: Int = UserHandle.myUserId() + override val userId: Int = UserHandle.myUserId(), ) : Request /** Creates a resolve action [Request] based on the given [sourceId] and [userId]. */ data class ResolveAction( override val sourceId: String, - override val userId: Int = UserHandle.myUserId() + override val userId: Int = UserHandle.myUserId(), ) : Request /** Creates an issue dismissal [Request] based on the given [sourceId] and [userId]. */ data class DismissIssue( override val sourceId: String, - override val userId: Int = UserHandle.myUserId() + override val userId: Int = UserHandle.myUserId(), ) : Request } @@ -295,7 +295,7 @@ class SafetySourceIntentHandler { data class SetData( val safetySourceData: SafetySourceData, val overrideBroadcastId: String? = null, - override val overrideSafetyEvent: SafetyEvent? = null + override val overrideSafetyEvent: SafetyEvent? = null, ) : Response } diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt index 29072c989..6b86df0dd 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceReceiver.kt @@ -86,7 +86,7 @@ class SafetySourceReceiver : BroadcastReceiver() { NotificationChannel( NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID, - IMPORTANCE_DEFAULT + IMPORTANCE_DEFAULT, ) ) startForeground( @@ -98,7 +98,7 @@ class SafetySourceReceiver : BroadcastReceiver() { "ForegroundService" ) .setSmallIcon(android.R.drawable.ic_info) - .build() + .build(), ) serviceScope.launch { try { @@ -150,7 +150,7 @@ class SafetySourceReceiver : BroadcastReceiver() { componentName, if (enabled) COMPONENT_ENABLED_STATE_ENABLED else COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP + PackageManager.DONT_KILL_APP, ) } @@ -165,7 +165,7 @@ class SafetySourceReceiver : BroadcastReceiver() { fun SafetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( refreshReason: Int, safetySourceIds: List<String>? = null, - timeout: Duration = TIMEOUT_LONG + timeout: Duration = TIMEOUT_LONG, ): String = callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) { refreshSafetySourcesWithPermission(refreshReason, safetySourceIds) @@ -174,7 +174,7 @@ class SafetySourceReceiver : BroadcastReceiver() { fun SafetyCenterManager.refreshSafetySourcesWithoutReceiverPermissionAndWait( refreshReason: Int, - safetySourceIds: List<String>? = null + safetySourceIds: List<String>? = null, ) { refreshSafetySourcesWithPermission(refreshReason, safetySourceIds) WaitForBroadcasts.waitForBroadcasts() @@ -183,16 +183,14 @@ class SafetySourceReceiver : BroadcastReceiver() { fun setSafetyCenterEnabledWithReceiverPermissionAndWait( value: Boolean, - timeout: Duration = TIMEOUT_LONG + timeout: Duration = TIMEOUT_LONG, ): Boolean = callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) { SafetyCenterFlags.isEnabled = value receiveSafetyCenterEnabledChanged(timeout) } - fun setSafetyCenterEnabledWithoutReceiverPermissionAndWait( - value: Boolean, - ) { + fun setSafetyCenterEnabledWithoutReceiverPermissionAndWait(value: Boolean) { SafetyCenterFlags.isEnabled = value WaitForBroadcasts.waitForBroadcasts() receiveSafetyCenterEnabledChanged(TIMEOUT_SHORT) @@ -201,7 +199,7 @@ class SafetySourceReceiver : BroadcastReceiver() { fun SafetyCenterManager.executeSafetyCenterIssueActionWithPermissionAndWait( issueId: String, issueActionId: String, - timeout: Duration = TIMEOUT_LONG + timeout: Duration = TIMEOUT_LONG, ) { callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) { executeSafetyCenterIssueActionWithPermission(issueId, issueActionId) @@ -211,7 +209,7 @@ class SafetySourceReceiver : BroadcastReceiver() { fun SafetyCenterManager.dismissSafetyCenterIssueWithPermissionAndWait( issueId: String, - timeout: Duration = TIMEOUT_LONG + timeout: Duration = TIMEOUT_LONG, ) { callWithShellPermissionIdentity(SEND_SAFETY_CENTER_UPDATE) { dismissSafetyCenterIssueWithPermission(issueId) diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt index 7e77c0827..aad665004 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt @@ -63,11 +63,11 @@ class SafetySourceTestData(private val context: Context) { */ fun createTestActivityRedirectPendingIntent( explicit: Boolean = true, - identifier: String? = null + identifier: String? = null, ) = createRedirectPendingIntent( context, - createTestActivityIntent(context, explicit).setIdentifier(identifier) + createTestActivityIntent(context, explicit).setIdentifier(identifier), ) /** A [SafetySourceData] with a [SEVERITY_LEVEL_UNSPECIFIED] [SafetySourceStatus]. */ @@ -77,7 +77,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Unspecified title", "Unspecified summary", - SEVERITY_LEVEL_UNSPECIFIED + SEVERITY_LEVEL_UNSPECIFIED, ) .setEnabled(false) .build() @@ -94,7 +94,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Clickable disabled title", "Clickable disabled summary", - SEVERITY_LEVEL_UNSPECIFIED + SEVERITY_LEVEL_UNSPECIFIED, ) .setEnabled(false) .setPendingIntent(createTestActivityRedirectPendingIntent()) @@ -111,7 +111,7 @@ class SafetySourceTestData(private val context: Context) { fun defaultInformationIssueBuilder( id: String = INFORMATION_ISSUE_ID, title: String = "Information issue title", - summary: String = "Information issue summary" + summary: String = "Information issue summary", ) = SafetySourceIssue.Builder(id, title, summary, SEVERITY_LEVEL_INFORMATION, ISSUE_TYPE_ID) .addAction(action()) @@ -120,7 +120,7 @@ class SafetySourceTestData(private val context: Context) { fun action( id: String = INFORMATION_ISSUE_ACTION_ID, label: String = "Review", - pendingIntent: PendingIntent = createTestActivityRedirectPendingIntent() + pendingIntent: PendingIntent = createTestActivityRedirectPendingIntent(), ) = Action.Builder(id, label, pendingIntent).build() /** @@ -133,7 +133,7 @@ class SafetySourceTestData(private val context: Context) { "Information issue title", "Information issue summary", SEVERITY_LEVEL_INFORMATION, - ISSUE_TYPE_ID + ISSUE_TYPE_ID, ) .setSubtitle("Information issue subtitle") .addAction(action()) @@ -149,7 +149,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Unspecified title", "Unspecified summary", - SEVERITY_LEVEL_UNSPECIFIED + SEVERITY_LEVEL_UNSPECIFIED, ) .setPendingIntent(createTestActivityRedirectPendingIntent()) .build() @@ -167,7 +167,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Unspecified title for Work", "Unspecified summary", - SEVERITY_LEVEL_UNSPECIFIED + SEVERITY_LEVEL_UNSPECIFIED, ) .setPendingIntent(createTestActivityRedirectPendingIntent()) .build() @@ -185,7 +185,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Unspecified title for Private", "Unspecified summary", - SEVERITY_LEVEL_UNSPECIFIED + SEVERITY_LEVEL_UNSPECIFIED, ) .setPendingIntent(createTestActivityRedirectPendingIntent()) .build() @@ -292,7 +292,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Ok title for Work", "Ok summary", - SEVERITY_LEVEL_INFORMATION + SEVERITY_LEVEL_INFORMATION, ) .setPendingIntent(createTestActivityRedirectPendingIntent()) .build() @@ -310,7 +310,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Ok title for Private", "Ok summary", - SEVERITY_LEVEL_INFORMATION + SEVERITY_LEVEL_INFORMATION, ) .setPendingIntent(createTestActivityRedirectPendingIntent()) .build() @@ -339,20 +339,20 @@ class SafetySourceTestData(private val context: Context) { fun defaultRecommendationIssueBuilder( title: String = "Recommendation issue title", summary: String = "Recommendation issue summary", - confirmationDialog: Boolean = false + confirmationDialog: Boolean = false, ) = SafetySourceIssue.Builder( RECOMMENDATION_ISSUE_ID, title, summary, SEVERITY_LEVEL_RECOMMENDATION, - ISSUE_TYPE_ID + ISSUE_TYPE_ID, ) .addAction( Action.Builder( RECOMMENDATION_ISSUE_ACTION_ID, "See issue", - createTestActivityRedirectPendingIntent() + createTestActivityRedirectPendingIntent(), ) .apply { if (confirmationDialog && SdkLevel.isAtLeastU()) { @@ -418,7 +418,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Recommendation title", "Recommendation summary", - SEVERITY_LEVEL_RECOMMENDATION + SEVERITY_LEVEL_RECOMMENDATION, ) .setPendingIntent(createTestActivityRedirectPendingIntent()) .build() @@ -476,7 +476,7 @@ class SafetySourceTestData(private val context: Context) { fun resolvingActionPendingIntent( sourceId: String = SINGLE_SOURCE_ID, sourceIssueId: String = CRITICAL_ISSUE_ID, - sourceIssueActionId: String = CRITICAL_ISSUE_ACTION_ID + sourceIssueActionId: String = CRITICAL_ISSUE_ACTION_ID, ) = broadcastPendingIntent( Intent(ACTION_RESOLVE_ACTION) @@ -498,7 +498,7 @@ class SafetySourceTestData(private val context: Context) { Action.Builder( CRITICAL_ISSUE_ACTION_ID, "Solve issue", - criticalIssueActionPendingIntent(sourceId = sourceId) + criticalIssueActionPendingIntent(sourceId = sourceId), ) .setWillResolve(true) .build() @@ -510,7 +510,7 @@ class SafetySourceTestData(private val context: Context) { Action.Builder( CRITICAL_ISSUE_ACTION_ID, "Solve issue", - criticalIssueActionPendingIntent + criticalIssueActionPendingIntent, ) .setWillResolve(true) .setConfirmationDialogDetails(CONFIRMATION_DETAILS) @@ -521,7 +521,7 @@ class SafetySourceTestData(private val context: Context) { Action.Builder( CRITICAL_ISSUE_ACTION_ID, "Redirect", - createTestActivityRedirectPendingIntent() + createTestActivityRedirectPendingIntent(), ) .build() @@ -537,7 +537,7 @@ class SafetySourceTestData(private val context: Context) { Action.Builder( CRITICAL_ISSUE_ACTION_ID, "Solve issue", - criticalIssueActionPendingIntent(sourceId = sourceId) + criticalIssueActionPendingIntent(sourceId = sourceId), ) .setWillResolve(true) .setSuccessMessage("Issue solved") @@ -550,7 +550,7 @@ class SafetySourceTestData(private val context: Context) { "Critical issue title", "Critical issue summary", SEVERITY_LEVEL_CRITICAL_WARNING, - ISSUE_TYPE_ID + ISSUE_TYPE_ID, ) .addAction(criticalResolvingActionWithSuccessMessage) .build() @@ -562,7 +562,7 @@ class SafetySourceTestData(private val context: Context) { "Critical issue title", "Critical issue summary", SEVERITY_LEVEL_CRITICAL_WARNING, - ISSUE_TYPE_ID + ISSUE_TYPE_ID, ) .addAction(criticalResolvingActionWithSuccessMessage(sourceId = sourceId)) .build() @@ -577,13 +577,13 @@ class SafetySourceTestData(private val context: Context) { "Critical issue title 2", "Critical issue summary 2", SEVERITY_LEVEL_CRITICAL_WARNING, - ISSUE_TYPE_ID + ISSUE_TYPE_ID, ) .addAction( Action.Builder( CRITICAL_ISSUE_ACTION_ID, "Go solve issue", - createTestActivityRedirectPendingIntent() + createTestActivityRedirectPendingIntent(), ) .build() ) @@ -620,7 +620,7 @@ class SafetySourceTestData(private val context: Context) { "Critical issue title", "Critical issue summary", SEVERITY_LEVEL_CRITICAL_WARNING, - ISSUE_TYPE_ID + ISSUE_TYPE_ID, ) .addAction(criticalResolvingAction(sourceId)) @@ -679,7 +679,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Critical title", "Critical summary", - SEVERITY_LEVEL_CRITICAL_WARNING + SEVERITY_LEVEL_CRITICAL_WARNING, ) .setPendingIntent(createTestActivityRedirectPendingIntent()) .build() @@ -811,7 +811,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Critical title", "Critical summary", - SEVERITY_LEVEL_CRITICAL_WARNING + SEVERITY_LEVEL_CRITICAL_WARNING, ) .setPendingIntent(createTestActivityRedirectPendingIntent()) .build() @@ -829,7 +829,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Critical title", "Critical summary", - SEVERITY_LEVEL_CRITICAL_WARNING + SEVERITY_LEVEL_CRITICAL_WARNING, ) .setPendingIntent(createTestActivityRedirectPendingIntent()) .build() @@ -854,7 +854,7 @@ class SafetySourceTestData(private val context: Context) { SafetySourceStatus.Builder( "Critical title 2", "Critical summary 2", - SEVERITY_LEVEL_CRITICAL_WARNING + SEVERITY_LEVEL_CRITICAL_WARNING, ) .setPendingIntent(createTestActivityRedirectPendingIntent()) .build() @@ -870,7 +870,7 @@ class SafetySourceTestData(private val context: Context) { severityLevel: Int, entrySummary: String, withIssue: Boolean = false, - entryTitle: String = "Entry title" + entryTitle: String = "Entry title", ) = SafetySourceData.Builder() .setStatus( @@ -886,13 +886,13 @@ class SafetySourceTestData(private val context: Context) { "Issue title", "Issue summary", max(severityLevel, SEVERITY_LEVEL_INFORMATION), - ISSUE_TYPE_ID + ISSUE_TYPE_ID, ) .addAction( Action.Builder( "action_id", "Action", - createTestActivityRedirectPendingIntent() + createTestActivityRedirectPendingIntent(), ) .build() ) @@ -907,7 +907,7 @@ class SafetySourceTestData(private val context: Context) { context, 0, intent.addFlags(FLAG_RECEIVER_FOREGROUND).setPackage(context.packageName), - PendingIntent.FLAG_IMMUTABLE + PendingIntent.FLAG_IMMUTABLE, ) companion object { @@ -945,7 +945,7 @@ class SafetySourceTestData(private val context: Context) { CONFIRMATION_TITLE, CONFIRMATION_TEXT, CONFIRMATION_YES, - CONFIRMATION_NO + CONFIRMATION_NO, ) /** A [SafetyEvent] to push arbitrary changes to Safety Center. */ @@ -979,7 +979,7 @@ class SafetySourceTestData(private val context: Context) { context, 0 /* requestCode */, intent, - PendingIntent.FLAG_IMMUTABLE + PendingIntent.FLAG_IMMUTABLE, ) } } diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SettingsPackage.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SettingsPackage.kt index 2ba127f4e..8fef70ce3 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SettingsPackage.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SettingsPackage.kt @@ -38,7 +38,7 @@ object SettingsPackage { PackageManager.MATCH_DIRECT_BOOT_AWARE or PackageManager.MATCH_DIRECT_BOOT_UNAWARE) .toLong() - ) + ), )!! .activityInfo .packageName diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/StatusBarNotificationWithChannel.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/StatusBarNotificationWithChannel.kt index 53ea34362..a4569b72b 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/StatusBarNotificationWithChannel.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/StatusBarNotificationWithChannel.kt @@ -22,5 +22,5 @@ import android.service.notification.StatusBarNotification /** Tuple of [StatusBarNotification] and the [NotificationChannel] it was posted to. */ data class StatusBarNotificationWithChannel( val statusBarNotification: StatusBarNotification, - val channel: NotificationChannel + val channel: NotificationChannel, ) diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt index eceffb74f..12b4f7fd2 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestActivity.kt @@ -52,10 +52,12 @@ class TestActivity : Activity() { fun enableHighPriorityAlias() { setAliasEnabledState(COMPONENT_ENABLED_STATE_ENABLED) } + /** @see [enableHighPriorityAlias] */ fun disableHighPriorityAlias() { setAliasEnabledState(COMPONENT_ENABLED_STATE_DISABLED) } + private fun setAliasEnabledState(state: Int) { val name = ComponentName(getApplicationContext(), TestActivity::class.java.name + "Priority") diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestNotificationListener.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestNotificationListener.kt index 21bf76fad..17b520349 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestNotificationListener.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/TestNotificationListener.kt @@ -115,7 +115,7 @@ class TestNotificationListener : NotificationListenerService() { */ fun waitForSingleNotificationMatching( characteristics: NotificationCharacteristics, - timeout: Duration = TIMEOUT_LONG + timeout: Duration = TIMEOUT_LONG, ): StatusBarNotificationWithChannel { return waitForNotificationsMatching(characteristics, timeout = timeout).first() } @@ -128,12 +128,12 @@ class TestNotificationListener : NotificationListenerService() { */ fun waitForNotificationsMatching( vararg characteristics: NotificationCharacteristics, - timeout: Duration = TIMEOUT_LONG + timeout: Duration = TIMEOUT_LONG, ): List<StatusBarNotificationWithChannel> { val charsList = characteristics.toList() return waitForNotificationsToSatisfy( timeout = timeout, - description = "notification(s) matching characteristics $charsList" + description = "notification(s) matching characteristics $charsList", ) { NotificationCharacteristics.areMatching(it, charsList) } @@ -147,7 +147,7 @@ class TestNotificationListener : NotificationListenerService() { */ fun waitForSuccessNotification( successMessage: String, - onNotification: (StatusBarNotification) -> Unit = {} + onNotification: (StatusBarNotification) -> Unit = {}, ) { // Only wait for the notification event and don't wait for all notifications to "settle" // as this notification is auto-cancelled after 10s; which can cause flakyness. @@ -185,7 +185,7 @@ class TestNotificationListener : NotificationListenerService() { timeout: Duration = TIMEOUT_LONG, forAtLeast: Duration = TIMEOUT_SHORT, description: String, - predicate: (List<StatusBarNotificationWithChannel>) -> Boolean + predicate: (List<StatusBarNotificationWithChannel>) -> Boolean, ): List<StatusBarNotificationWithChannel> { // First we wait at most timeout for the active notifications to satisfy the given // predicate or otherwise we throw: @@ -198,7 +198,7 @@ class TestNotificationListener : NotificationListenerService() { throw AssertionError( "Expected: $description, but notifications were " + "${getSafetyCenterNotifications()} after waiting for $timeout", - e + e, ) } @@ -298,7 +298,7 @@ class TestNotificationListener : NotificationListenerService() { getInstanceOrThrow().cancelNotification(key) waitForNotificationsToSatisfy( timeout = TIMEOUT_LONG, - description = "no notification with the key $key" + description = "no notification with the key $key", ) { notifications -> notifications.none { it.statusBarNotification.key == key } } @@ -327,7 +327,7 @@ class TestNotificationListener : NotificationListenerService() { throw IllegalStateException( "Notification dismissal was not recorded in the issue cache: " + dumpIssueDismissalsRepositoryState(), - e + e, ) } } @@ -362,7 +362,7 @@ class TestNotificationListener : NotificationListenerService() { fun reset(context: Context) { waitForNotificationsToSatisfy( forAtLeast = Duration.ZERO, - description = "all Safety Center notifications removed in tear down" + description = "all Safety Center notifications removed in tear down", ) { it.isEmpty() } diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt index 0e062692a..3dfefeecf 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/UiTestHelper.kt @@ -175,7 +175,7 @@ object UiTestHelper { fun waitGroupShownOnHomepage(context: Context, group: SafetySourcesGroup) { waitAllTextDisplayed( context.getString(group.titleResId), - context.getString(group.summaryResId) + context.getString(group.summaryResId), ) } @@ -197,6 +197,7 @@ object UiTestHelper { /** Opens the subpage by clicking on the group title. */ fun clickOpenSubpage(context: Context, group: SafetySourcesGroup) { waitDisplayed(By.text(context.getString(group.titleResId))) { it.click() } + getUiDevice().waitForIdle() } /** Clicks the more issues card button to show or hide additional issues. */ diff --git a/tests/utils/safetycenter/res/layout/test_activity.xml b/tests/utils/safetycenter/res/layout/test_activity.xml index edbe3641a..b0b7523c8 100644 --- a/tests/utils/safetycenter/res/layout/test_activity.xml +++ b/tests/utils/safetycenter/res/layout/test_activity.xml @@ -19,6 +19,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:orientation="vertical" > <Button android:id="@+id/button" android:layout_width="wrap_content" diff --git a/tests/utils/safetycenter/res/values/styles.xml b/tests/utils/safetycenter/res/values/styles.xml deleted file mode 100644 index ce54568ed..000000000 --- a/tests/utils/safetycenter/res/values/styles.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<resources xmlns:android="http://schemas.android.com/apk/res/android"> - <!-- - TODO(b/309578419): Make activities handle insets properly and then remove this. - --> - <style name="OptOutEdgeToEdgeEnforcement"> - <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> - </style> -</resources> |