summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt182
-rw-r--r--tests/cts/permissionpolicy/res/raw/android_manifest.xml6
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt51
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt22
-rw-r--r--tests/cts/role/src/android/app/role/cts/RoleManagerSecurityTest.kt148
-rw-r--r--tests/functional/safetycenter/safetycenteractivity/Android.bp1
-rw-r--r--tests/functional/safetycenter/safetycenteractivity/src/android/safetycenter/functional/ui/SafetyCenterActivityTest.kt34
-rw-r--r--tests/utils/safetycenter/Android.bp1
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt103
9 files changed, 377 insertions, 171 deletions
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/permissionpolicy/res/raw/android_manifest.xml b/tests/cts/permissionpolicy/res/raw/android_manifest.xml
index ceefe3dfd..2547b9786 100644
--- a/tests/cts/permissionpolicy/res/raw/android_manifest.xml
+++ b/tests/cts/permissionpolicy/res/raw/android_manifest.xml
@@ -8995,13 +8995,13 @@
<!-- @SystemApi
@FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled")
- This permission is required to access the specific text classifier you need from the
+ This permission is required to access the specific text classifier from the
TextClassificationManager.
- <p>Protection level: signature|role
+ <p>Protection level: signature|role|privileged
@hide
-->
<permission android:name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE"
- android:protectionLevel="signature|role"
+ android:protectionLevel="signature|role|privileged"
android:featureFlag="android.permission.flags.text_classifier_choice_api_enabled"/>
<!-- Attribution for Geofencing service. -->
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt
index f52e32344..1e6923592 100644
--- a/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt
+++ b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt
@@ -36,6 +36,7 @@ import android.os.Build
import android.os.Process
import android.provider.DeviceConfig
import android.provider.Settings
+import android.server.wm.WindowManagerStateHelper
import android.text.Spanned
import android.text.style.ClickableSpan
import android.util.Log
@@ -247,6 +248,8 @@ abstract class BaseUsePermissionTest : BasePermissionTest() {
DENIED_WITH_PREJUDICE
}
+ private val windowManagerStateHelper = WindowManagerStateHelper()
+
private val platformResources = context.createPackageContext("android", 0).resources
private val permissionToLabelResNameMap =
mapOf(
@@ -674,21 +677,20 @@ abstract class BaseUsePermissionTest : BasePermissionTest() {
crossinline block: () -> Unit,
): Instrumentation.ActivityResult {
// Request the permissions
- lateinit var future: CompletableFuture<Instrumentation.ActivityResult>
- doAndWaitForWindowTransition {
- future =
- startActivityForFuture(
- Intent().apply {
- component =
- ComponentName(
- APP_PACKAGE_NAME,
- "$APP_PACKAGE_NAME.RequestPermissionsActivity"
- )
- putExtra("$APP_PACKAGE_NAME.PERMISSIONS", permissions)
- putExtra("$APP_PACKAGE_NAME.ASK_TWICE", askTwice)
- }
- )
- }
+ val future =
+ startActivityForFuture(
+ Intent().apply {
+ component =
+ ComponentName(
+ APP_PACKAGE_NAME,
+ "$APP_PACKAGE_NAME.RequestPermissionsActivity"
+ )
+ putExtra("$APP_PACKAGE_NAME.PERMISSIONS", permissions)
+ putExtra("$APP_PACKAGE_NAME.ASK_TWICE", askTwice)
+ }
+ )
+
+ waitForPermissionRequestActivity()
// Notification permission prompt is shown first, so get it out of the way
clickNotificationPermissionRequestAllowButtonIfAvailable()
@@ -701,6 +703,25 @@ abstract class BaseUsePermissionTest : BasePermissionTest() {
return future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
}
+ /**
+ * This method waits for permission controller activity to be in a valid state, the timeout
+ * is 5 seconds.
+ */
+ fun waitForPermissionRequestActivity() {
+ val requestPermissionIntent = Intent(PackageManager.ACTION_REQUEST_PERMISSIONS)
+ val componentName =
+ requestPermissionIntent.resolveActivity(context.packageManager)
+ ?: throw RuntimeException("Permission request is not handled by any activity.")
+ try {
+ windowManagerStateHelper.waitForValidState(componentName)
+ } catch (ex: Exception) {
+ // It doesn't mean a test would fail, it just meant that the test would proceed before
+ // waiting for permission request dialog. Permission request dialog should eventually
+ // come on the screen when ui-automator is trying to search for ui element.
+ Log.w(LOG_TAG, "Couldn't wait for permission request activity.", ex)
+ }
+ }
+
protected inline fun requestAppPermissionsAndAssertResult(
permissions: Array<out String?>,
permissionAndExpectedGrantResults: Array<out Pair<String?, Boolean>>,
diff --git a/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt
index 798b1942f..e1cb76171 100644
--- a/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt
+++ b/tests/cts/permissionui/src/android/permissionui/cts/CameraMicIndicatorsPermissionTest.kt
@@ -123,7 +123,6 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase {
.toString()
private val cameraLabel = originalCameraLabel.lowercase()
private val micLabel = originalMicLabel.lowercase()
- private var wasEnabled = false
private var isScreenOn = false
private var screenTimeoutBeforeTest: Long = 0L
private lateinit var carMicPrivacyChipId: String
@@ -181,7 +180,6 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase {
isScreenOn = true
}
uiDevice.findObject(By.text("Close"))?.click()
- wasEnabled = setIndicatorsEnabledStateIfNeeded(true)
// If the change Id is not present, then isChangeEnabled will return true. To bypass this,
// the change is set to "false" if present.
assumeFalse(
@@ -193,23 +191,6 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase {
install()
}
- private fun setIndicatorsEnabledStateIfNeeded(shouldBeEnabled: Boolean): Boolean {
- var currentlyEnabled = false
- runWithShellPermissionIdentity {
- currentlyEnabled =
- DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, INDICATORS_FLAG, true)
- if (currentlyEnabled != shouldBeEnabled) {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- INDICATORS_FLAG,
- shouldBeEnabled.toString(),
- false,
- )
- }
- }
- return currentlyEnabled
- }
-
@After
fun tearDown() {
// Skip the tests as Camera and Mic are not supported for visible background users.
@@ -225,9 +206,6 @@ class CameraMicIndicatorsPermissionTest : StsExtraBusinessLogicTestCase {
{ assertIndicatorsShown(false, false, false) },
AUTO_MIC_INDICATOR_DISMISSAL_TIMEOUT_MS,
)
- if (!wasEnabled) {
- setIndicatorsEnabledStateIfNeeded(false)
- }
runWithShellPermissionIdentity {
Settings.System.putLong(
context.contentResolver,
diff --git a/tests/cts/role/src/android/app/role/cts/RoleManagerSecurityTest.kt b/tests/cts/role/src/android/app/role/cts/RoleManagerSecurityTest.kt
new file mode 100644
index 000000000..59a8c21b2
--- /dev/null
+++ b/tests/cts/role/src/android/app/role/cts/RoleManagerSecurityTest.kt
@@ -0,0 +1,148 @@
+/*
+ * 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.app.role.RoleManager
+import android.content.Context
+import android.os.Build
+import android.os.Process
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.SystemUtil
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.Executor
+import java.util.concurrent.TimeUnit
+import java.util.function.Consumer
+import org.junit.After
+import org.junit.Assert.fail
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests {@link RoleManager} security fixes. */
+@RunWith(AndroidJUnit4::class)
+class RoleManagerSecurityTest {
+ private var browserRoleHolder: String? = null
+
+ @Before
+ fun setUp() {
+ saveBrowserRoleHolder()
+ }
+
+ @After
+ fun tearDown() {
+ restoreBrowserRoleHolder()
+ }
+
+ private fun saveBrowserRoleHolder() {
+ val roleHolders: List<String> = getRoleHolders(RoleManager.ROLE_BROWSER, roleManager)
+ browserRoleHolder = if (roleHolders.isNotEmpty()) roleHolders[0] else null
+ }
+
+ private fun restoreBrowserRoleHolder() {
+ browserRoleHolder?.let { packageName ->
+ addRoleHolderAsUser(
+ RoleManager.ROLE_BROWSER,
+ packageName,
+ Process.myUserHandle(),
+ true,
+ roleManager,
+ context.mainExecutor,
+ )
+ }
+ }
+
+ private fun getRoleHolders(roleName: String, roleManager: RoleManager): List<String> {
+ return SystemUtil.callWithShellPermissionIdentity { roleManager.getRoleHolders(roleName) }
+ }
+
+ private fun addRoleHolderAsUser(
+ roleName: String,
+ packageName: String,
+ userHandle: UserHandle,
+ expectSuccess: Boolean,
+ roleManager: RoleManager,
+ executor: Executor,
+ ) {
+ val future = CallbackFuture()
+ SystemUtil.runWithShellPermissionIdentity {
+ roleManager.addRoleHolderAsUser(roleName, packageName, 0, userHandle, executor, future)
+ }
+ assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isEqualTo(expectSuccess)
+ }
+
+ @SdkSuppress(
+ minSdkVersion = Build.VERSION_CODES.S,
+ maxSdkVersion = Build.VERSION_CODES.TIRAMISU,
+ )
+ @Test
+ fun cannotGetDefaultApplicationOnOlderSdk() {
+ assumeTrue(roleManager.isRoleAvailable(RoleManager.ROLE_BROWSER))
+ try {
+ roleManager.getDefaultApplication(RoleManager.ROLE_BROWSER)
+ } catch (e: NoSuchMethodError) {
+ // Expected when permission module hasn't been updated
+ } catch (e: IllegalStateException) {
+ // Expected when permission module has been updated, and SDK 33 or below
+ } catch (e: Throwable) {
+ fail("Missing patch for cveBugId = [379362792]")
+ }
+ }
+
+ @SdkSuppress(
+ minSdkVersion = Build.VERSION_CODES.S,
+ maxSdkVersion = Build.VERSION_CODES.TIRAMISU,
+ )
+ @Test
+ fun cannotSetDefaultApplicationOnOlderSdk() {
+ assumeTrue(roleManager.isRoleAvailable(RoleManager.ROLE_BROWSER))
+ val future = CallbackFuture()
+ try {
+ roleManager.setDefaultApplication(
+ RoleManager.ROLE_BROWSER,
+ APP_PACKAGE_NAME,
+ 0,
+ context.mainExecutor,
+ future,
+ )
+ future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ } catch (e: NoSuchMethodError) {
+ // Expected when permission module hasn't been updated
+ } catch (e: IllegalStateException) {
+ // Expected when permission module has been updated, and SDK 33 or below
+ } catch (e: Throwable) {
+ fail("Missing patch for cveBugId = [379362792]")
+ }
+ }
+
+ private class CallbackFuture : CompletableFuture<Boolean?>(), Consumer<Boolean?> {
+ override fun accept(successful: Boolean?) {
+ complete(successful)
+ }
+ }
+
+ companion object {
+ private const val TIMEOUT_MILLIS: Long = (15 * 1000).toLong()
+ private const val APP_PACKAGE_NAME: String = "android.app.role.cts.app"
+
+ private val context: Context = InstrumentationRegistry.getInstrumentation().targetContext
+ private val roleManager: RoleManager = context.getSystemService(RoleManager::class.java)
+ }
+}
diff --git a/tests/functional/safetycenter/safetycenteractivity/Android.bp b/tests/functional/safetycenter/safetycenteractivity/Android.bp
index ea5f9f286..2346a0d5f 100644
--- a/tests/functional/safetycenter/safetycenteractivity/Android.bp
+++ b/tests/functional/safetycenter/safetycenteractivity/Android.bp
@@ -29,6 +29,7 @@ android_test {
"src/**/*.kt",
],
static_libs: [
+ "aconfig_settingstheme_exported_flags_java_lib",
"androidx.test.rules",
"androidx.test.ext.junit",
"compatibility-device-preconditions",
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 09a32f058..fb577e8f6 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
@@ -21,6 +21,9 @@ import android.os.Build
import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.os.Bundle
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ID
import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID
import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING
@@ -74,6 +77,7 @@ 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 com.android.settingslib.widget.theme.flags.Flags as SettingsThemeFlags
import java.util.regex.Pattern
import org.junit.After
import org.junit.Assume.assumeFalse
@@ -95,6 +99,8 @@ class SafetyCenterActivityTest {
@get:Rule(order = 2) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper)
@get:Rule(order = 3) val disableAnimationRule = DisableAnimationRule()
@get:Rule(order = 4) val freezeRotationRule = FreezeRotationRule()
+ @get:Rule(order = 5)
+ val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
@After
fun clearDataAfterTest() {
@@ -567,6 +573,8 @@ class SafetyCenterActivityTest {
}
@Test
+ // TODO: b/398188361 - Update this for expressive theme
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun issueCard_noAttribution_hasProperContentDescriptions() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.issueOnlySourceNoGroupTitleConfig)
@@ -581,6 +589,8 @@ class SafetyCenterActivityTest {
@Test
@SdkSuppress(minSdkVersion = UPSIDE_DOWN_CAKE)
+ // TODO: b/398188361 - Update this for expressive theme
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun issueCard_withAttribution_hasProperContentDescriptions() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
@@ -693,7 +703,7 @@ class SafetyCenterActivityTest {
@Test
fun issueCard_resolveIssue_successConfirmationShown() {
- SafetyCenterFlags.hideResolvedIssueUiTransitionDelay = TIMEOUT_LONG
+ SafetyCenterFlags.setHideResolvedIssueUiTransitionDelay(context, TIMEOUT_LONG)
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
// Set the initial data for the source
@@ -829,7 +839,7 @@ class SafetyCenterActivityTest {
@Test
fun issueCard_resolveIssue_noSuccessMessage_noResolutionUiShown_issueDismisses() {
- SafetyCenterFlags.hideResolvedIssueUiTransitionDelay = TIMEOUT_LONG
+ SafetyCenterFlags.setHideResolvedIssueUiTransitionDelay(context, TIMEOUT_LONG)
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig)
// Set the initial data for the source
@@ -954,6 +964,8 @@ class SafetyCenterActivityTest {
}
@Test
+ // TODO: b/379849464 - Fix this for expressive design and stop disabling this flag
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun launchActivity_fromQuickSettings_issuesExpanded() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
safetyCenterTestHelper.setData(
@@ -978,6 +990,8 @@ class SafetyCenterActivityTest {
}
@Test
+ // TODO: b/379849464 - Fix this for expressive design and stop disabling this flag
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun launchActivity_fromNotification_targetIssueAlreadyFirstIssue() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
safetyCenterTestHelper.setData(
@@ -1003,6 +1017,8 @@ class SafetyCenterActivityTest {
}
@Test
+ // TODO: b/379849464 - Fix this for expressive design and stop disabling this flag
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun launchActivity_fromNotification_targetIssueSamePriorityAsFirstIssue_reorderedFirstIssue() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
safetyCenterTestHelper.setData(
@@ -1028,6 +1044,8 @@ class SafetyCenterActivityTest {
}
@Test
+ // TODO: b/379849464 - Fix this for expressive design and stop disabling this flag
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun launchActivity_fromNotification_targetLowerPriorityAsFirstIssue_reorderedSecondIssue() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
safetyCenterTestHelper.setData(
@@ -1052,6 +1070,8 @@ class SafetyCenterActivityTest {
}
@Test
+ // TODO: b/379849464 - Fix this for expressive design and stop disabling this flag
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun launchActivity_fromNotification_targetIssueNotFound() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
safetyCenterTestHelper.setData(
@@ -1091,6 +1111,8 @@ class SafetyCenterActivityTest {
}
@Test
+ // TODO: b/379849464 - Fix this for expressive design and stop disabling this flag
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun moreIssuesCard_moreIssuesCardShown_additionalIssueCardsCollapsed() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
safetyCenterTestHelper.setData(
@@ -1113,6 +1135,8 @@ class SafetyCenterActivityTest {
}
@Test
+ // TODO: b/379849464 - Fix this for expressive design and stop disabling this flag
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun moreIssuesCard_expandAdditionalIssueCards() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
safetyCenterTestHelper.setData(
@@ -1139,6 +1163,8 @@ class SafetyCenterActivityTest {
}
@Test
+ // TODO: b/379849464 - Fix this for expressive design and stop disabling this flag
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun moreIssuesCard_rotation_cardsStillExpanded() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
safetyCenterTestHelper.setData(
@@ -1173,6 +1199,8 @@ class SafetyCenterActivityTest {
}
@Test
+ // TODO: b/379849464 - Fix this for expressive design and stop disabling this flag
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun moreIssuesCard_withThreeIssues_showsTopIssuesAndMoreIssuesCard() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
safetyCenterTestHelper.setData(
@@ -1197,6 +1225,8 @@ class SafetyCenterActivityTest {
}
@Test
+ // TODO: b/379849464 - Fix this for expressive design and stop disabling this flag
+ @RequiresFlagsDisabled(SettingsThemeFlags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED)
fun moreIssuesCard_twoIssuesAlreadyShown_expandAdditionalIssueCards() {
safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig)
safetyCenterTestHelper.setData(
diff --git a/tests/utils/safetycenter/Android.bp b/tests/utils/safetycenter/Android.bp
index fab8c8dde..11fd3951d 100644
--- a/tests/utils/safetycenter/Android.bp
+++ b/tests/utils/safetycenter/Android.bp
@@ -36,6 +36,7 @@ android_library {
"kotlinx-coroutines-android",
"safety-center-internal-data",
"safety-center-resources-lib",
+ "SettingsLibSettingsTheme",
// TODO(b/326414126): aconfig: support multi-container library
"com.android.permission.flags-aconfig-java",
],
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 7efbba7a0..66c5f46c4 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt
@@ -21,6 +21,7 @@ import android.Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG
import android.Manifest.permission.WRITE_DEVICE_CONFIG
import android.annotation.TargetApi
import android.app.job.JobInfo
+import android.content.Context
import android.content.pm.PackageManager
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.provider.DeviceConfig
@@ -38,12 +39,16 @@ import com.android.modules.utils.build.SdkLevel
import com.android.safetycenter.testing.Coroutines.TEST_TIMEOUT
import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG
import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity
+import com.android.settingslib.widget.SettingsThemeHelper
import java.time.Duration
import kotlin.reflect.KProperty
/** A class that facilitates working with Safety Center flags. */
object SafetyCenterFlags {
+ /** This is a hidden API constant within [DeviceConfig]. */
+ private const val NAMESPACE_SETTINGS_UI = "settings_ui"
+
/** Flag that determines whether Safety Center is enabled. */
private val isEnabledFlag =
Flag("safety_center_is_enabled", defaultValue = SdkLevel.isAtLeastU(), BooleanParser())
@@ -143,8 +148,7 @@ object SafetyCenterFlags {
)
/**
- * Flag that determines the time for which Safety Center will wait before starting dismissal of
- * resolved issue UI
+ * Flag that determines how long Safety Center will wait before hiding the resolved issue UI.
*/
private val hideResolveUiTransitionDelayFlag =
Flag(
@@ -154,6 +158,18 @@ object SafetyCenterFlags {
)
/**
+ * Flag that determines how long an expressive BannerMessagePreference will wait before hiding
+ * the resolved UI.
+ */
+ private val bannerMessagePrefHideResolvedContentTransitionDelayFlag =
+ Flag(
+ "banner_message_pref_hide_resolved_content_delay_millis",
+ defaultValue = Duration.ofMillis(400),
+ DurationParser(),
+ namespace = NAMESPACE_SETTINGS_UI,
+ )
+
+ /**
* Flag containing a comma delimited lists of source IDs that we won't track when deciding if a
* broadcast is completed. We still send broadcasts to (and handle API calls from) these sources
* as normal.
@@ -312,6 +328,7 @@ object SafetyCenterFlags {
resolveActionTimeoutFlag,
tempHiddenIssueResurfaceDelayFlag,
hideResolveUiTransitionDelayFlag,
+ bannerMessagePrefHideResolvedContentTransitionDelayFlag,
untrackedSourcesFlag,
resurfaceIssueMaxCountsFlag,
resurfaceIssueDelaysFlag,
@@ -357,9 +374,28 @@ object SafetyCenterFlags {
/** A property that allows getting and setting the [tempHiddenIssueResurfaceDelayFlag]. */
var tempHiddenIssueResurfaceDelay: Duration by tempHiddenIssueResurfaceDelayFlag
+ // TODO: b/379849464 - replace remaining usages and make this private
/** A property that allows getting and setting the [hideResolveUiTransitionDelayFlag]. */
var hideResolvedIssueUiTransitionDelay: Duration by hideResolveUiTransitionDelayFlag
+ /**
+ * A property that allows getting and setting the
+ * [bannerMessagePrefHideResolvedContentTransitionDelayFlag]
+ */
+ private var bannerMessagePrefHideResolvedContentTransitionDelay: Duration by
+ bannerMessagePrefHideResolvedContentTransitionDelayFlag
+
+ /**
+ * Sets the proper hide_resolved_issue_ui_transition_delay flag based on expressive design
+ * state.
+ */
+ fun setHideResolvedIssueUiTransitionDelay(context: Context, value: Duration) =
+ if (SettingsThemeHelper.isExpressiveTheme(context)) {
+ bannerMessagePrefHideResolvedContentTransitionDelay = value
+ } else {
+ hideResolvedIssueUiTransitionDelay = value
+ }
+
/** A property that allows getting and setting the [untrackedSourcesFlag]. */
var untrackedSources: Set<String> by untrackedSourcesFlag
@@ -396,14 +432,23 @@ object SafetyCenterFlags {
* This snapshot is only taken once and cached afterwards. [setup] must be called at least once
* prior to modifying any flag for the snapshot to be taken with the right values.
*/
- @Volatile lateinit var snapshot: Properties
+ @Volatile lateinit var snapshot: Map<String, Properties>
- private val lazySnapshot: Properties by lazy {
+ private val lazySnapshot: Map<String, Properties> by lazy {
callWithShellPermissionIdentity(READ_DEVICE_CONFIG) {
- DeviceConfig.getProperties(NAMESPACE_PRIVACY, *FLAGS.map { it.name }.toTypedArray())
+ mapOf(
+ NAMESPACE_PRIVACY to fetchPropertiesForNamespace(NAMESPACE_PRIVACY),
+ NAMESPACE_SETTINGS_UI to fetchPropertiesForNamespace(NAMESPACE_SETTINGS_UI),
+ )
}
}
+ private fun fetchPropertiesForNamespace(namespace: String) =
+ DeviceConfig.getProperties(
+ namespace,
+ *FLAGS.filter { it.namespace == namespace }.map { it.name }.toTypedArray(),
+ )
+
/**
* Takes a snapshot of all Safety Center flags and sets them up to their default values.
*
@@ -414,7 +459,7 @@ object SafetyCenterFlags {
fun setup() {
snapshot = lazySnapshot
FLAGS.filter { it.name != isEnabledFlag.name }
- .forEach { writeDeviceConfigProperty(it.name, it.defaultStringValue) }
+ .forEach { it.writeToDeviceConfig(it.defaultStringValue) }
}
/**
@@ -431,8 +476,8 @@ object SafetyCenterFlags {
FLAGS.filter { it.name != isEnabledFlag.name }
.forEach {
val key = it.name
- val value = snapshot.getString(key, /* defaultValue */ null)
- writeDeviceConfigProperty(key, value)
+ val value = snapshot[it.namespace]?.getString(key, /* defaultValue */ null)
+ it.writeToDeviceConfig(value)
}
}
@@ -442,8 +487,8 @@ object SafetyCenterFlags {
}
/** Returns the [isEnabledFlag] value of the Safety Center flags snapshot. */
- fun Properties.isSafetyCenterEnabled() =
- getBoolean(isEnabledFlag.name, isEnabledFlag.defaultValue)
+ fun Map<String, Properties>.isSafetyCenterEnabled(): Boolean =
+ this[NAMESPACE_PRIVACY]!!.getBoolean(isEnabledFlag.name, isEnabledFlag.defaultValue)
@TargetApi(UPSIDE_DOWN_CAKE)
private fun getAllRefreshTimeoutsMap(refreshTimeout: Duration): Map<Int, Duration> =
@@ -516,32 +561,32 @@ object SafetyCenterFlags {
.joinToString(entriesDelimiter)
}
- private class Flag<T>(val name: String, val defaultValue: T, private val parser: Parser<T>) {
+ private class Flag<T>(
+ val name: String,
+ val defaultValue: T,
+ private val parser: Parser<T>,
+ val namespace: String = NAMESPACE_PRIVACY,
+ ) {
val defaultStringValue = parser.toString(defaultValue)
operator fun getValue(thisRef: Any?, property: KProperty<*>): T =
- readDeviceConfigProperty(name)?.let(parser::parseFromString) ?: defaultValue
+ readFromDeviceConfig(name)?.let(parser::parseFromString) ?: defaultValue
- operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
- writeDeviceConfigProperty(name, parser.toString(value))
- }
- }
+ private fun readFromDeviceConfig(name: String): String? =
+ callWithShellPermissionIdentity(READ_DEVICE_CONFIG) {
+ DeviceConfig.getProperty(namespace, name)
+ }
- private fun readDeviceConfigProperty(name: String): String? =
- callWithShellPermissionIdentity(READ_DEVICE_CONFIG) {
- DeviceConfig.getProperty(NAMESPACE_PRIVACY, name)
+ operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
+ writeToDeviceConfig(parser.toString(value))
}
- private fun writeDeviceConfigProperty(name: String, stringValue: String?) {
- callWithShellPermissionIdentity(WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG) {
- val valueWasSet =
- DeviceConfig.setProperty(
- NAMESPACE_PRIVACY,
- name,
- stringValue, /* makeDefault */
- false,
- )
- require(valueWasSet) { "Could not set $name to: $stringValue" }
+ fun writeToDeviceConfig(stringValue: String?) {
+ callWithShellPermissionIdentity(WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG) {
+ val valueWasSet =
+ DeviceConfig.setProperty(namespace, name, stringValue, /* makeDefault */ false)
+ require(valueWasSet) { "Could not set $name to: $stringValue" }
+ }
}
}
}