diff options
Diffstat (limited to 'tests')
50 files changed, 743 insertions, 119 deletions
diff --git a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt index 0cf1fa665..6500b3926 100644 --- a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt +++ b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt @@ -111,6 +111,7 @@ class RolesPersistenceTest { assertThat(persistedState).isNull() } + private fun getState(): RolesState = when (stateVersion) { StateVersion.VERSION_UNDEFINED -> stateVersionUndefined diff --git a/tests/cts/permission/Android.bp b/tests/cts/permission/Android.bp index 8849f41a7..ed7fcea25 100644 --- a/tests/cts/permission/Android.bp +++ b/tests/cts/permission/Android.bp @@ -30,6 +30,7 @@ android_test { "general-tests", "sts", "mts-permission", + "mcts-permission", ], // Include both the 32 and 64 bit versions compile_multilib: "both", @@ -52,6 +53,8 @@ android_test { "sts-device-util", "platform-test-rules", "CtsVirtualDeviceCommonLib", + "android.permission.flags-aconfig-java", + "androidx.test.rules", ], jni_libs: [ "libctspermission_jni", diff --git a/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml b/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml index ef4d82dfc..ece3ba1c7 100644 --- a/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml +++ b/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml @@ -34,6 +34,7 @@ <uses-permission android:name="android.permission.WRITE_CALENDAR" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.BODY_SENSORS" /> + <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.cts.appthatrequestcustompermission.TEST_PERMISSION" /> <application /> diff --git a/tests/cts/permission/sdk28/Android.bp b/tests/cts/permission/sdk28/Android.bp index 3043c9329..2bdffabe5 100644 --- a/tests/cts/permission/sdk28/Android.bp +++ b/tests/cts/permission/sdk28/Android.bp @@ -29,5 +29,6 @@ android_test { "cts", "general-tests", "mts-permission", + "mcts-permission", ], } diff --git a/tests/cts/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt b/tests/cts/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt index e7bad2b05..42b9067f3 100644 --- a/tests/cts/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt +++ b/tests/cts/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt @@ -92,15 +92,6 @@ class AccessibilityPrivacySourceTest { ) @get:Rule - val deviceConfigA11ySourceEnabled = - DeviceConfigStateChangerRule( - context, - DeviceConfig.NAMESPACE_PRIVACY, - ACCESSIBILITY_SOURCE_ENABLED, - true.toString() - ) - - @get:Rule val deviceConfigA11yListenerDisabled = DeviceConfigStateChangerRule( context, @@ -233,26 +224,6 @@ class AccessibilityPrivacySourceTest { } @Test - fun testJobWithAccessibilityFeatureDisabledDoesNotSendNotification() { - setDeviceConfigPrivacyProperty(ACCESSIBILITY_SOURCE_ENABLED, false.toString()) - mAccessibilityServiceRule.enableService() - runJobAndWaitUntilCompleted() - assertEmptyNotification(permissionControllerPackage, ACCESSIBILITY_NOTIFICATION_ID) - } - - @Test - fun testJobWithAccessibilityFeatureDisabledDoesNotSendIssueToSafetyCenter() { - setDeviceConfigPrivacyProperty(ACCESSIBILITY_SOURCE_ENABLED, false.toString()) - mAccessibilityServiceRule.enableService() - runJobAndWaitUntilCompleted() - assertSafetyCenterIssueDoesNotExist( - SC_ACCESSIBILITY_SOURCE_ID, - safetyCenterIssueId, - SC_ACCESSIBILITY_ISSUE_TYPE_ID - ) - } - - @Test fun testJobWithSafetyCenterDisabledDoesNotSendNotification() { setDeviceConfigPrivacyProperty(SAFETY_CENTER_ENABLED, false.toString()) mAccessibilityServiceRule.enableService() @@ -332,7 +303,6 @@ class AccessibilityPrivacySourceTest { companion object { private const val SC_ACCESSIBILITY_SOURCE_ID = "AndroidAccessibility" - private const val ACCESSIBILITY_SOURCE_ENABLED = "sc_accessibility_source_enabled" private const val SAFETY_CENTER_ENABLED = "safety_center_is_enabled" private const val ACCESSIBILITY_LISTENER_ENABLED = "sc_accessibility_listener_enabled" private const val ACCESSIBILITY_JOB_INTERVAL_MILLIS = "sc_accessibility_job_interval_millis" diff --git a/tests/cts/permission/src/android/permission/cts/AppWidgetManagerPermissionTest.java b/tests/cts/permission/src/android/permission/cts/AppWidgetManagerPermissionTest.java index 294896d97..fa43bfb18 100644 --- a/tests/cts/permission/src/android/permission/cts/AppWidgetManagerPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/AppWidgetManagerPermissionTest.java @@ -20,7 +20,8 @@ import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.pm.PackageManager; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; /** * Test that protected AppWidgetManager APIs cannot be called without permissions diff --git a/tests/cts/permission/src/android/permission/cts/CameraPermissionTest.java b/tests/cts/permission/src/android/permission/cts/CameraPermissionTest.java index 99f2862f1..981735388 100644 --- a/tests/cts/permission/src/android/permission/cts/CameraPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/CameraPermissionTest.java @@ -19,7 +19,8 @@ package android.permission.cts; import android.hardware.Camera; import android.os.Environment; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; + +import androidx.test.filters.MediumTest; import java.io.FileOutputStream; diff --git a/tests/cts/permission/src/android/permission/cts/ContactsProviderTest.java b/tests/cts/permission/src/android/permission/cts/ContactsProviderTest.java index 984fd6cfe..69b64d790 100644 --- a/tests/cts/permission/src/android/permission/cts/ContactsProviderTest.java +++ b/tests/cts/permission/src/android/permission/cts/ContactsProviderTest.java @@ -19,7 +19,8 @@ package android.permission.cts; import android.content.ContentValues; import android.provider.ContactsContract; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; /** * Verify permissions are enforced. diff --git a/tests/cts/permission/src/android/permission/cts/MinMaxSdkVersionTest.kt b/tests/cts/permission/src/android/permission/cts/MinMaxSdkVersionTest.kt index 58eaf598c..4679fbee8 100644 --- a/tests/cts/permission/src/android/permission/cts/MinMaxSdkVersionTest.kt +++ b/tests/cts/permission/src/android/permission/cts/MinMaxSdkVersionTest.kt @@ -80,7 +80,7 @@ class MinMaxSdkVersionTest { mContext!! .packageManager .getPackageInfo(TEST_APP_PKG_NAME, PackageManager.GET_PERMISSIONS) - return packageInfo.requestedPermissions.any { it == permName } + return packageInfo.requestedPermissions!!.any { it == permName } } companion object { diff --git a/tests/cts/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java index 835ba124c..3d9ba8214 100644 --- a/tests/cts/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java @@ -21,7 +21,8 @@ import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.MediumTest; + +import androidx.test.filters.MediumTest; import java.util.List; diff --git a/tests/cts/permission/src/android/permission/cts/NoAudioPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoAudioPermissionTest.java index c2c42a10d..50498b1d5 100644 --- a/tests/cts/permission/src/android/permission/cts/NoAudioPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoAudioPermissionTest.java @@ -25,9 +25,10 @@ import android.media.AudioManager; import android.media.AudioRecord; import android.media.MediaRecorder; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; +import androidx.test.filters.SmallTest; + /** * Verify the audio related operations require specific permissions. */ diff --git a/tests/cts/permission/src/android/permission/cts/NoBroadcastPackageRemovedPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoBroadcastPackageRemovedPermissionTest.java index 5630c5b8c..1a46842b2 100644 --- a/tests/cts/permission/src/android/permission/cts/NoBroadcastPackageRemovedPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoBroadcastPackageRemovedPermissionTest.java @@ -19,7 +19,8 @@ package android.permission.cts; import android.content.Intent; import android.os.Bundle; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; /** * Verify Context related methods without specific BROADCAST series permissions. diff --git a/tests/cts/permission/src/android/permission/cts/NoCaptureVideoPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoCaptureVideoPermissionTest.java index 6ad048308..e0573044c 100644 --- a/tests/cts/permission/src/android/permission/cts/NoCaptureVideoPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoCaptureVideoPermissionTest.java @@ -22,9 +22,10 @@ import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.media.ImageReader; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; import android.util.DisplayMetrics; +import androidx.test.filters.SmallTest; + /** * Verify the capture system video output permission requirements. */ diff --git a/tests/cts/permission/src/android/permission/cts/NoKeyPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoKeyPermissionTest.java index 5a0b25993..ac77947d9 100644 --- a/tests/cts/permission/src/android/permission/cts/NoKeyPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoKeyPermissionTest.java @@ -19,7 +19,8 @@ package android.permission.cts; import android.app.KeyguardManager; import android.content.Context; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; /** * Verify the key input related operations require specific permissions. diff --git a/tests/cts/permission/src/android/permission/cts/NoNetworkStatePermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoNetworkStatePermissionTest.java index b8d2ee21a..5dc73d520 100644 --- a/tests/cts/permission/src/android/permission/cts/NoNetworkStatePermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoNetworkStatePermissionTest.java @@ -19,7 +19,8 @@ package android.permission.cts; import android.content.Context; import android.net.ConnectivityManager; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; import java.net.InetAddress; diff --git a/tests/cts/permission/src/android/permission/cts/NoReadLogsPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoReadLogsPermissionTest.java index b6fb84dc7..f0d70b2ce 100644 --- a/tests/cts/permission/src/android/permission/cts/NoReadLogsPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoReadLogsPermissionTest.java @@ -21,7 +21,8 @@ import android.system.Os; import android.system.OsConstants; import android.system.StructStat; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; + +import androidx.test.filters.MediumTest; import java.io.BufferedReader; import java.io.IOException; diff --git a/tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java index 0ccebed04..437aa19c4 100644 --- a/tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java @@ -24,10 +24,12 @@ import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.os.Vibrator; +import android.os.VibratorManager; import android.platform.test.annotations.AppModeFull; import android.telephony.gsm.SmsManager; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; import java.io.IOException; import java.io.InputStream; @@ -121,7 +123,17 @@ public class NoSystemFunctionPermissionTest extends AndroidTestCase { */ @SmallTest public void testVibrator() { - Vibrator vibrator = (Vibrator)getContext().getSystemService(Context.VIBRATOR_SERVICE); + Vibrator vibrator = mContext.getSystemService(VibratorManager.class).getDefaultVibrator(); + + if (!vibrator.hasVibrator()) { + // Run the test only if a vibrator is present. + return; + } + + if (!vibrator.hasVibrator()) { + // If the test device does not have a vibrator, then abort test. + return; + } try { vibrator.cancel(); diff --git a/tests/cts/permission/src/android/permission/cts/NoWakeLockPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoWakeLockPermissionTest.java index 030f341aa..95c4da727 100644 --- a/tests/cts/permission/src/android/permission/cts/NoWakeLockPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoWakeLockPermissionTest.java @@ -26,7 +26,8 @@ import android.net.wifi.WifiManager.WifiLock; import android.os.PowerManager; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; /** * Verify the Wake Lock related operations require specific permissions. diff --git a/tests/cts/permission/src/android/permission/cts/NoWallpaperPermissionsTest.java b/tests/cts/permission/src/android/permission/cts/NoWallpaperPermissionsTest.java index 18e4375bc..fc1d6b59f 100644 --- a/tests/cts/permission/src/android/permission/cts/NoWallpaperPermissionsTest.java +++ b/tests/cts/permission/src/android/permission/cts/NoWallpaperPermissionsTest.java @@ -27,7 +27,8 @@ import android.content.Context; import android.graphics.Bitmap; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; import org.junit.function.ThrowingRunnable; diff --git a/tests/cts/permission/src/android/permission/cts/PackageManagerRequiringPermissionsTest.java b/tests/cts/permission/src/android/permission/cts/PackageManagerRequiringPermissionsTest.java index df3ec3c64..7ebb09f98 100644 --- a/tests/cts/permission/src/android/permission/cts/PackageManagerRequiringPermissionsTest.java +++ b/tests/cts/permission/src/android/permission/cts/PackageManagerRequiringPermissionsTest.java @@ -21,7 +21,8 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.platform.test.annotations.AppModeFull; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; /** * Verify the PackageManager related operations require specific permissions. diff --git a/tests/cts/permission/src/android/permission/cts/PermissionControllerTest.java b/tests/cts/permission/src/android/permission/cts/PermissionControllerTest.java index 05b45c9b1..4367d2bf6 100644 --- a/tests/cts/permission/src/android/permission/cts/PermissionControllerTest.java +++ b/tests/cts/permission/src/android/permission/cts/PermissionControllerTest.java @@ -423,7 +423,7 @@ public class PermissionControllerTest { } assertThat(permissionInfos).isNotEmpty(); - assertThat(runtimePermissions.size()).isEqualTo(5); + assertThat(runtimePermissions.size()).isEqualTo(6); assertRuntimePermissionLabelsAreValid(runtimePermissions, permissionInfos, 4, APP2); } diff --git a/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java b/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java index 05aa41d69..543a3cbbd 100644 --- a/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java +++ b/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java @@ -23,18 +23,26 @@ import static com.android.compatibility.common.util.SystemUtil.runWithShellPermi import static com.google.common.truth.Truth.assertThat; import android.companion.virtual.VirtualDeviceManager; +import android.companion.virtual.VirtualDeviceParams; import android.content.Context; import android.content.pm.PackageManager; 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.FakeAssociationRule; import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.compatibility.common.util.AdoptShellPermissionsRule; import com.android.compatibility.common.util.SystemUtil; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -52,15 +60,28 @@ public class PermissionUpdateListenerTest { + "CtsAppThatRequestsCalendarContactsBodySensorCustomPermission.apk"; private static final String PACKAGE_NAME = "android.permission.cts.appthatrequestcustompermission"; - private static final String PERMISSION_NAME = "android.permission.READ_CONTACTS"; + private static final String PERMISSION_NAME = "android.permission.RECORD_AUDIO"; private static final int TIMEOUT = 10000; - private final Context mContext = + private final Context mDefaultContext = InstrumentationRegistry.getInstrumentation().getContext(); - private final PackageManager mPackageManager = mContext.getPackageManager(); + private final PackageManager mPackageManager = mDefaultContext.getPackageManager(); private int mTestAppUid; + private VirtualDeviceManager mVirtualDeviceManager; + + @Rule + public FakeAssociationRule mFakeAssociationRule = new FakeAssociationRule(); + + @Rule + public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule( + InstrumentationRegistry.getInstrumentation().getUiAutomation(), + android.Manifest.permission.CREATE_VIRTUAL_DEVICE); + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Before public void setup() throws PackageManager.NameNotFoundException, InterruptedException { runShellCommandOrThrow("pm install " + APK); @@ -69,6 +90,7 @@ public class PermissionUpdateListenerTest { SystemUtil.waitForBroadcasts(); Thread.sleep(1000); mTestAppUid = mPackageManager.getPackageUid(PACKAGE_NAME, 0); + mVirtualDeviceManager = mDefaultContext.getSystemService(VirtualDeviceManager.class); } @After @@ -89,7 +111,7 @@ public class PermissionUpdateListenerTest { runWithShellPermissionIdentity(() -> { mPackageManager.addOnPermissionsChangeListener(permissionsChangedListener); mPackageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, - mContext.getUser()); + mDefaultContext.getUser()); }); countDownLatch.await(TIMEOUT, TimeUnit.MILLISECONDS); runWithShellPermissionIdentity(() -> { @@ -100,61 +122,117 @@ public class PermissionUpdateListenerTest { } @Test - public void testGrantPermissionNotifyListener() throws InterruptedException { + @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) + public void testVirtualDeviceGrantPermissionNotifyListener() throws InterruptedException { + VirtualDeviceManager.VirtualDevice virtualDevice = + mVirtualDeviceManager.createVirtualDevice( + mFakeAssociationRule.getAssociationInfo().getId(), + new VirtualDeviceParams.Builder().build()); + Context deviceContext = mDefaultContext.createDeviceContext(virtualDevice.getDeviceId()); + testGrantPermissionNotifyListener(deviceContext, virtualDevice.getPersistentDeviceId()); + } + + @Test + public void testDefaultDeviceGrantPermissionNotifyListener() throws InterruptedException { + testGrantPermissionNotifyListener( + mDefaultContext, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT); + } + + private void testGrantPermissionNotifyListener( + Context context, String expectedDeviceId) throws InterruptedException { + final PackageManager packageManager = context.getPackageManager(); TestOnPermissionsChangedListener permissionsChangedListener = new TestOnPermissionsChangedListener(1); runWithShellPermissionIdentity(() -> { - mPackageManager.addOnPermissionsChangeListener(permissionsChangedListener); - mPackageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, - mContext.getUser()); + packageManager.addOnPermissionsChangeListener(permissionsChangedListener); + packageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, + mDefaultContext.getUser()); }); permissionsChangedListener.waitForPermissionChangedCallbacks(); runWithShellPermissionIdentity(() -> { - mPackageManager.removeOnPermissionsChangeListener(permissionsChangedListener); + packageManager.removeOnPermissionsChangeListener(permissionsChangedListener); }); String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid); - assertThat(deviceId).isEqualTo(VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT); + assertThat(deviceId).isEqualTo(expectedDeviceId); } @Test - public void testRevokePermissionNotifyListener() throws InterruptedException { + public void testDefaultDeviceRevokePermissionNotifyListener() throws InterruptedException { + testRevokePermissionNotifyListener( + mDefaultContext, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) + public void testVirtualDeviceRevokePermissionNotifyListener() throws InterruptedException { + VirtualDeviceManager.VirtualDevice virtualDevice = + mVirtualDeviceManager.createVirtualDevice( + mFakeAssociationRule.getAssociationInfo().getId(), + new VirtualDeviceParams.Builder().build()); + Context deviceContext = mDefaultContext.createDeviceContext(virtualDevice.getDeviceId()); + testRevokePermissionNotifyListener( + deviceContext, virtualDevice.getPersistentDeviceId()); + } + + private void testRevokePermissionNotifyListener( + Context context, String expectedDeviceId) throws InterruptedException { + final PackageManager packageManager = context.getPackageManager(); TestOnPermissionsChangedListener permissionsChangedListener = new TestOnPermissionsChangedListener(1); runWithShellPermissionIdentity(() -> { - mPackageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, - mContext.getUser()); - mPackageManager.addOnPermissionsChangeListener(permissionsChangedListener); - mPackageManager.revokeRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, - mContext.getUser()); + packageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, + mDefaultContext.getUser()); + packageManager.addOnPermissionsChangeListener(permissionsChangedListener); + packageManager.revokeRuntimePermission(PACKAGE_NAME, PERMISSION_NAME, + mDefaultContext.getUser()); }); permissionsChangedListener.waitForPermissionChangedCallbacks(); runWithShellPermissionIdentity(() -> { - mPackageManager.removeOnPermissionsChangeListener(permissionsChangedListener); + packageManager.removeOnPermissionsChangeListener(permissionsChangedListener); }); String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid); - assertThat(deviceId).isEqualTo(VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT); + assertThat(deviceId).isEqualTo(expectedDeviceId); } @Test - public void testUpdatePermissionFlagsNotifyListener() throws InterruptedException { + public void testDefaultDeviceUpdatePermissionFlagsNotifyListener() throws InterruptedException { + testUpdatePermissionFlagsNotifyListener( + mDefaultContext, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) + public void testVirtualDeviceUpdatePermissionFlagsNotifyListener() throws InterruptedException { + VirtualDeviceManager.VirtualDevice virtualDevice = + mVirtualDeviceManager.createVirtualDevice( + mFakeAssociationRule.getAssociationInfo().getId(), + new VirtualDeviceParams.Builder().build()); + Context deviceContext = mDefaultContext.createDeviceContext(virtualDevice.getDeviceId()); + testUpdatePermissionFlagsNotifyListener( + deviceContext, virtualDevice.getPersistentDeviceId()); + } + + private void testUpdatePermissionFlagsNotifyListener( + Context context, String expectedDeviceId) throws InterruptedException { TestOnPermissionsChangedListener permissionsChangedListener = new TestOnPermissionsChangedListener(1); + final PackageManager packageManager = context.getPackageManager(); runWithShellPermissionIdentity(() -> { - mPackageManager.addOnPermissionsChangeListener(permissionsChangedListener); + packageManager.addOnPermissionsChangeListener(permissionsChangedListener); int flag = PackageManager.FLAG_PERMISSION_USER_SET; - mPackageManager.updatePermissionFlags(PERMISSION_NAME, PACKAGE_NAME, flag, flag, - mContext.getUser()); + packageManager.updatePermissionFlags(PERMISSION_NAME, PACKAGE_NAME, flag, flag, + mDefaultContext.getUser()); }); permissionsChangedListener.waitForPermissionChangedCallbacks(); runWithShellPermissionIdentity(() -> { - mPackageManager.removeOnPermissionsChangeListener(permissionsChangedListener); + packageManager.removeOnPermissionsChangeListener(permissionsChangedListener); }); String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid); - assertThat(deviceId).isEqualTo(VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT); + assertThat(deviceId).isEqualTo(expectedDeviceId); } private class TestOnPermissionsChangedListener diff --git a/tests/cts/permission/src/android/permission/cts/ProviderPermissionTest.java b/tests/cts/permission/src/android/permission/cts/ProviderPermissionTest.java index 9f5a813d1..83c2ffaee 100644 --- a/tests/cts/permission/src/android/permission/cts/ProviderPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/ProviderPermissionTest.java @@ -35,12 +35,11 @@ import android.provider.ContactsContract; import android.provider.Settings; import android.provider.Telephony; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; import android.util.Log; import androidx.test.InstrumentationRegistry; +import androidx.test.filters.MediumTest; -import java.util.ArrayList; import java.util.List; import java.util.Objects; diff --git a/tests/cts/permission/src/android/permission/cts/RebootPermissionTest.java b/tests/cts/permission/src/android/permission/cts/RebootPermissionTest.java index b1d3d5afb..13f17dce8 100644 --- a/tests/cts/permission/src/android/permission/cts/RebootPermissionTest.java +++ b/tests/cts/permission/src/android/permission/cts/RebootPermissionTest.java @@ -18,7 +18,8 @@ package android.permission.cts; import android.content.Intent; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; /** * Verify that rebooting requires Permission. diff --git a/tests/cts/permission/src/android/permission/cts/RevokePermissionTest.kt b/tests/cts/permission/src/android/permission/cts/RevokePermissionTest.kt index 05235e141..c67707f5f 100644 --- a/tests/cts/permission/src/android/permission/cts/RevokePermissionTest.kt +++ b/tests/cts/permission/src/android/permission/cts/RevokePermissionTest.kt @@ -53,13 +53,7 @@ class RevokePermissionTest { fun testRevokePermissionNotRequested() { testRevoke( packageName = APP_PKG_NAME, - permission = CAMERA, - throwableType = SecurityException::class.java, - throwableMessages = - listOf( - "has not requested permission", - "Permission $CAMERA isn't requested by package $APP_PKG_NAME" - ) + permission = CAMERA ) } @@ -104,13 +98,7 @@ class RevokePermissionTest { testRevoke( packageName = APP_PKG_NAME, permission = CAMERA, - reason = "test reason", - throwableType = SecurityException::class.java, - throwableMessages = - listOf( - "has not requested permission", - "Permission $CAMERA isn't requested by package $APP_PKG_NAME" - ) + reason = "test reason" ) } diff --git a/tests/cts/permission/telephony/Android.bp b/tests/cts/permission/telephony/Android.bp index bbfe06c55..5ded57ab3 100644 --- a/tests/cts/permission/telephony/Android.bp +++ b/tests/cts/permission/telephony/Android.bp @@ -26,6 +26,7 @@ android_test { "cts", "general-tests", "mts-permission", + "mcts-permission", ], // Include both the 32 and 64 bit versions compile_multilib: "both", diff --git a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt index c37b71cd4..09f4c7f08 100644 --- a/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt +++ b/tests/cts/permissionmultidevice/src/android/permissionmultidevice/cts/DeviceAwarePermissionGrantTest.kt @@ -74,7 +74,7 @@ class DeviceAwarePermissionGrantTest { uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false) } - @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS) + @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) @Test fun onHostDevice_requestPermissionForHostDevice_shouldGrantPermission() { testGrantPermissionForDevice( @@ -87,7 +87,7 @@ class DeviceAwarePermissionGrantTest { ) } - @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS) + @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) @Test fun onHostDevice_requestPermissionForRemoteDevice_shouldGrantPermission() { testGrantPermissionForDevice( @@ -100,7 +100,7 @@ class DeviceAwarePermissionGrantTest { ) } - @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS) + @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) @Test fun onRemoteDevice_requestPermissionForHostDevice_shouldGrantPermission() { testGrantPermissionForDevice( @@ -113,7 +113,7 @@ class DeviceAwarePermissionGrantTest { ) } - @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS) + @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) @Test fun onRemoteDevice_requestPermissionForRemoteDevice_shouldGrantPermission() { testGrantPermissionForDevice( diff --git a/tests/cts/permissionmultiuser/Android.bp b/tests/cts/permissionmultiuser/Android.bp index f577c82e3..b86b02205 100644 --- a/tests/cts/permissionmultiuser/Android.bp +++ b/tests/cts/permissionmultiuser/Android.bp @@ -43,5 +43,6 @@ android_test { "cts", "general-tests", "mts-permission", + "mcts-permission", ], } diff --git a/tests/cts/permissionpolicy/Android.bp b/tests/cts/permissionpolicy/Android.bp index 127de939c..7a481b7ff 100644 --- a/tests/cts/permissionpolicy/Android.bp +++ b/tests/cts/permissionpolicy/Android.bp @@ -26,6 +26,7 @@ android_test { "cts", "general-tests", "mts-permission", + "mcts-permission", ], libs: ["android.test.base"], static_libs: [ @@ -36,6 +37,7 @@ android_test { "androidx.test.ext.junit-nodeps", "truth", "permission-test-util-lib", + "androidx.test.rules", ], srcs: [ "src/**/*.java", diff --git a/tests/cts/permissionpolicy/res/raw/android_manifest.xml b/tests/cts/permissionpolicy/res/raw/android_manifest.xml index cc68a8a37..15f1d7e3d 100644 --- a/tests/cts/permissionpolicy/res/raw/android_manifest.xml +++ b/tests/cts/permissionpolicy/res/raw/android_manifest.xml @@ -1020,6 +1020,13 @@ <permission android:name="android.permission.BIND_SATELLITE_GATEWAY_SERVICE" android:protectionLevel="signature" /> + <!-- @SystemApi @hide Required for an application in order to access the last known cell id. + @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") --> + <permission android:name="android.permission.ACCESS_LAST_KNOWN_CELL_ID" + android:protectionLevel="signature" + android:label="@string/permlab_accessLastKnownCellId" + android:description="@string/permdesc_accessLastKnownCellId"/> + <!-- ====================================================================== --> <!-- Permissions for accessing external storage --> <!-- ====================================================================== --> @@ -2869,6 +2876,16 @@ <permission android:name="android.permission.MANAGE_SENSORS" android:protectionLevel="signature" /> + <!-- Must be required by a DomainSelectionService to ensure that only the + system can bind to it. + <p>Protection level: signature + @SystemApi + @hide + @FlaggedApi("com.android.internal.telephony.flags.use_oem_domain_selection_service") + --> + <permission android:name="android.permission.BIND_DOMAIN_SELECTION_SERVICE" + android:protectionLevel="signature" /> + <!-- Must be required by an ImsService to ensure that only the system can bind to it. <p>Protection level: signature|privileged|vendorPrivileged @@ -3056,7 +3073,7 @@ types of interactions @hide --> <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" - android:protectionLevel="signature|installer|role" /> + android:protectionLevel="signature|installer|module|role" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <!-- Allows interaction across profiles in the same profile group. --> @@ -3444,6 +3461,13 @@ <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. + @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") + --> + <permission android:name="android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK" + android:protectionLevel="internal|role" /> + <!-- 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. @@ -3619,6 +3643,13 @@ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS" android:protectionLevel="internal|role" /> + <!-- Allows an application to manage policy related to content protection. + <p>Protection level: internal|role + @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") + --> + <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION" + 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_* @@ -3643,6 +3674,13 @@ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL" android:protectionLevel="internal|role" /> + <!-- Allows an application to access EnhancedConfirmationManager. + @SystemApi + @FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled") + @hide This is not a third-party API (intended for OEMs and system apps). --> + <permission android:name="android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES" + android:protectionLevel="signature|installer" /> + <!-- @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" @@ -3694,6 +3732,18 @@ <permission android:name="android.permission.ACTIVITY_EMBEDDING" android:protectionLevel="signature|privileged" /> + <!-- Allows an application to embed any other apps in untrusted embedding mode without the need + for the embedded app to consent. + <p>For now, this permission is only granted to the Assistant application selected by + the user. + {@see https://developer.android.com/guide/topics/large-screens/activity-embedding#trust_model} + @SystemApi + @FlaggedApi("com.android.window.flags.untrusted_embedding_any_app_permission") + @hide + --> + <permission android:name="android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE" + android:protectionLevel="internal|role" /> + <!-- Allows an application to start any activity, regardless of permission protection or exported state. @hide --> @@ -3865,6 +3915,14 @@ android:description="@string/permdesc_useDataInBackground" android:protectionLevel="normal" /> + <!-- 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_uuid_presence") + --> + <permission android:name="android.permission.REQUEST_OBSERVE_DEVICE_UUID_PRESENCE" + android:protectionLevel="signature|privileged" /> + <!-- Allows app to request to be associated with a device via {@link android.companion.CompanionDeviceManager} as a "watch" @@ -4783,7 +4841,7 @@ <p>Protection level: signature --> <permission android:name="android.permission.BIND_NFC_SERVICE" - android:protectionLevel="signature" /> + android:protectionLevel="signature|module" /> <!-- Must be required by a {@link android.service.quickaccesswallet.QuickAccessWalletService} to ensure that only the system can bind to it. @@ -4925,7 +4983,7 @@ <p>Intended for use by ROLE_ASSISTANT and signature apps only. --> <permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" - android:protectionLevel="signature|role"/> + android:protectionLevel="signature|module|role"/> <!-- Must be required by a {@link android.service.credentials.CredentialProviderService}, to ensure that only the system can bind to it. @@ -5070,6 +5128,13 @@ <permission android:name="android.permission.BIND_REMOTE_DISPLAY" android:protectionLevel="signature" /> + <!-- Must be required by a android.media.tv.ad.TvAdService to ensure that only the system can + bind to it. + <p>Protection level: signature|privileged + --> + <permission android:name="android.permission.BIND_TV_AD_SERVICE" + android:protectionLevel="signature|privileged" /> + <!-- Must be required by a {@link android.media.tv.TvInputService} to ensure that only the system can bind to it. <p>Protection level: signature|privileged @@ -5232,6 +5297,13 @@ <permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" android:protectionLevel="signature" /> + <!-- Allows low-level access for monitoring changes to sticky modifier state, when A11y + Sitcky keys feature is enabled. + <p>Not for use by third-party applications. + @hide --> + <permission android:name="android.permission.MONITOR_STICKY_MODIFIER_STATE" + android:protectionLevel="signature" /> + <!-- Allows an app to schedule a prioritized alarm that can be used to perform background work even when the device is in doze. <p>Not for use by third-party applications. @@ -5517,7 +5589,7 @@ <!-- @SystemApi Allows an application to manage the holders of a role. @hide --> <permission android:name="android.permission.MANAGE_ROLE_HOLDERS" - android:protectionLevel="signature|installer" /> + android:protectionLevel="signature|installer|module" /> <!-- @SystemApi Allows an application to manage the holders of roles associated with default applications. @@ -5537,7 +5609,7 @@ <!-- @SystemApi Allows an application to observe role holder changes. @hide --> <permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" - android:protectionLevel="signature|installer" /> + android:protectionLevel="signature|installer|module" /> <!-- Allows an application to manage the companion devices. @hide --> @@ -5555,10 +5627,10 @@ <permission android:name="android.permission.DELIVER_COMPANION_MESSAGES" android:protectionLevel="normal" /> - <!-- @SystemApi Allows an application to send and receive messages via CDM transports. + <!-- Allows an application to use companion transports @hide --> <permission android:name="android.permission.USE_COMPANION_TRANSPORTS" - android:protectionLevel="signature|module" /> + android:protectionLevel="signature" /> <!-- Allows an application to create new companion device associations. @SystemApi @@ -6435,10 +6507,24 @@ <permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" android:protectionLevel="signature" /> + <!-- Allows privileged apps to access the background face authentication. + @SystemApi + @FlaggedApi("android.hardware.biometrics.face_background_authentication") + @hide --> + <permission android:name="android.permission.USE_BACKGROUND_FACE_AUTHENTICATION" + android:protectionLevel="signature|privileged" /> + <!-- Allows the system to control the BiometricDialog (SystemUI). Reserved for the system. @hide --> <permission android:name="android.permission.MANAGE_BIOMETRIC_DIALOG" android:protectionLevel="signature" /> + <!-- Allows an application to set the BiometricDialog (SystemUI) logo . + <p>Not for use by third-party applications. + @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") +--> + <permission android:name="android.permission.SET_BIOMETRIC_DIALOG_LOGO" + android:protectionLevel="signature" /> + <!-- Allows an application to control keyguard. Only allowed for system processes. @hide --> <permission android:name="android.permission.CONTROL_KEYGUARD" @@ -6967,6 +7053,16 @@ android:label="@string/permlab_foregroundServiceFileManagement" android:protectionLevel="normal|instant" /> + <!-- @FlaggedApi("android.content.pm.introduce_media_processing_type") + Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "mediaProcessing". + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROCESSING" + android:description="@string/permdesc_foregroundServiceMediaProcessing" + android:label="@string/permlab_foregroundServiceMediaProcessing" + android:protectionLevel="normal|instant" /> + <!-- Allows a regular application to use {@link android.app.Service#startForeground Service.startForeground} with the type "specialUse". <p>Protection level: normal|appop|instant @@ -7070,6 +7166,13 @@ <permission android:name="android.permission.MANAGE_ACCESSIBILITY" android:protectionLevel="signature|setup|recents|role" /> + <!-- @FlaggedApi("com.android.server.accessibility.motion_event_observing") + @hide + @TestApi + Allows an accessibility service to observe motion events without consuming them. --> + <permission android:name="android.permission.ACCESSIBILITY_MOTION_EVENT_OBSERVING" + android:protectionLevel="signature" /> + <!-- @SystemApi Allows an app to grant a profile owner access to device identifiers. <p>Not for use by third-party applications. @deprecated @@ -7500,6 +7603,16 @@ <permission android:name="android.permission.RUN_USER_INITIATED_JOBS" android:protectionLevel="normal"/> + <!-- @FlaggedApi("android.app.job.backup_jobs_exemption") + Gives applications whose <b>primary use case</b> is to backup or sync content increased + job execution allowance in order to complete the related work. The jobs must have a valid + content URI trigger and network constraint set. + <p>This is a special access permission that can be revoked by the system or the user. + <p>Protection level: signature|privileged|appop + --> + <permission android:name="android.permission.RUN_BACKUP_JOBS" + android:protectionLevel="signature|privileged|appop"/> + <!-- Allows a browser to invoke the set of credential candidate query apis. <p>Protection level: normal --> @@ -7511,7 +7624,7 @@ --> <permission android:name="android.permission.CREDENTIAL_MANAGER_SET_ORIGIN" android:protectionLevel="normal"/> - + <!-- Allows specifying candidate credential providers to be queried in Credential Manager get flows, or to be preferred as a default in the Credential Manager create flows. <p>Protection level: normal --> @@ -7675,6 +7788,46 @@ <permission android:name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW" android:protectionLevel="signature|privileged" /> + <!-- @FlaggedApi("com.android.server.notification.flags.redact_otp_notifications_from_untrusted_listeners") + Allows apps with a NotificationListenerService to receive notifications with sensitive + information + <p>Apps with a NotificationListenerService without this permission will not be able + to view certain types of sensitive information contained in notifications + <p>Protection level: signature|role + --> + <permission android:name="android.permission.RECEIVE_SENSITIVE_NOTIFICATIONS" + android:protectionLevel="signature|role" /> + + <!-- @SystemApi + @FlaggedApi("android.app.bic_client") + Allows app to call BackgroundInstallControlManager API to retrieve silently installed apps + for all users on device. + <p>Apps with a BackgroundInstallControlManager client will not be able to call any API without + this permission. + <p>Protection level: signature|role + @hide + --> + <permission android:name="android.permission.GET_BACKGROUND_INSTALLED_PACKAGES" + android:protectionLevel="signature|role" /> + + <!-- @SystemApi Allows an application to read the system grammatical gender. + @FlaggedApi("android.app.system_terms_of_address_enabled") + <p>Protection level: signature|privileged + @hide + --> + <permission android:name="android.permission.READ_SYSTEM_GRAMMATICAL_GENDER" + android:protectionLevel="signature|privileged"/> + + <!-- @SystemApi + @FlaggedApi("android.content.pm.emergency_install_permission") + Allows each app store in the system image to designate another app in the system image to + update the app store + <p>Protection level: signature|privileged + @hide + --> + <permission android:name="android.permission.EMERGENCY_INSTALL_PACKAGES" + android:protectionLevel="signature|privileged" /> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> diff --git a/tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml b/tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml index dcd8ec4bd..d87fe65b8 100644 --- a/tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml +++ b/tests/cts/permissionpolicy/res/raw/automotive_android_manifest.xml @@ -206,6 +206,42 @@ android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_control_car_powertrain" android:description="@string/car_permission_desc_control_car_powertrain"/> + <permission android:name="android.car.permission.READ_CAR_SEAT_BELTS" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_read_car_seat_belts" + android:description="@string/car_permission_desc_read_car_seat_belts"/> + <permission android:name="android.car.permission.CONTROL_CAR_DYNAMICS_STATE" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_control_car_dynamics_state" + android:description="@string/car_permission_desc_control_car_dynamics_state"/> + <permission android:name="android.car.permission.READ_IMPACT_SENSORS" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_read_impact_sensors" + android:description="@string/car_permission_desc_read_impact_sensors"/> + <permission android:name="android.car.permission.READ_HEAD_UP_DISPLAY" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_read_head_up_display" + android:description="@string/car_permission_desc_read_head_up_display"/> + <permission android:name="android.car.permission.CONTROL_HEAD_UP_DISPLAY" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_control_head_up_display" + android:description="@string/car_permission_desc_control_head_up_display"/> + <permission android:name="android.car.permission.READ_VALET_MODE" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_read_valet_mode" + android:description="@string/car_permission_desc_read_valet_mode"/> + <permission android:name="android.car.permission.CONTROL_VALET_MODE" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_control_valet_mode" + android:description="@string/car_permission_desc_control_valet_mode"/> + <permission android:name="android.car.permission.READ_CAR_AIRBAGS" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_read_car_airbags" + android:description="@string/car_permission_desc_read_car_airbags"/> + <permission android:name="android.car.permission.READ_ULTRASONICS_SENSOR_DATA" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_read_ultrasonics_sensor_data" + android:description="@string/car_permission_desc_read_ultrasonics_sensor_data"/> <permission android:name="android.car.permission.CAR_NAVIGATION_MANAGER" android:protectionLevel="signature|privileged" android:label="@string/car_permission_car_navigation_manager" @@ -574,4 +610,9 @@ android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_query_display_compatibility" android:description="@string/car_permission_desc_query_display_compatibility"/> + <permission + android:name="android.car.permission.READ_PERSIST_TETHERING_SETTINGS" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_read_persist_tethering_settings" + android:description="@string/car_permission_desc_read_persist_tethering_settings" /> </manifest> diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ContactsProviderTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ContactsProviderTest.java index d8dc11a14..f34170a9b 100644 --- a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ContactsProviderTest.java +++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/ContactsProviderTest.java @@ -21,7 +21,8 @@ import android.content.ContentValues; import android.platform.test.annotations.AppModeFull; import android.provider.ContactsContract; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; /** * Verify that deprecated contacts permissions are not enforced. diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoCaptureAudioOutputPermissionTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoCaptureAudioOutputPermissionTest.java index 0f7638694..ef38573ab 100644 --- a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoCaptureAudioOutputPermissionTest.java +++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/NoCaptureAudioOutputPermissionTest.java @@ -21,7 +21,8 @@ import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder.AudioSource; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; /** * Verify the capture system video output permission requirements. diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionMaxSdkVersionTest.java b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionMaxSdkVersionTest.java index b02b32f22..8bf3e83a4 100644 --- a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionMaxSdkVersionTest.java +++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/PermissionMaxSdkVersionTest.java @@ -19,7 +19,8 @@ package android.permission.cts; import android.content.pm.PackageManager; import android.os.Process; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.filters.SmallTest; /** * Verify permission behaviors with android:maxSdkVersion diff --git a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt index ffb68114d..6b3ae5f2e 100644 --- a/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt +++ b/tests/cts/permissionpolicy/src/android/permissionpolicy/cts/RuntimePermissionProperties.kt @@ -74,7 +74,7 @@ class RuntimePermissionProperties { private val platformPkg = pm.getPackageInfo("android", GET_PERMISSIONS) private val platformRuntimePerms = - platformPkg.permissions.filter { it.protection == PROTECTION_DANGEROUS } + platformPkg.permissions!!.filter { it.protection == PROTECTION_DANGEROUS } private val platformBgPermNames = platformRuntimePerms.mapNotNull { it.backgroundPermission } @Test @@ -96,7 +96,7 @@ class RuntimePermissionProperties { @Test fun allAppOpPermissionNeedAnAppOp() { val platformAppOpPerms = - platformPkg.permissions + platformPkg.permissions!! .filter { (it.protectionFlags and PROTECTION_FLAG_APPOP) != 0 } .filter { // Grandfather incomplete definition of PACKAGE_USAGE_STATS diff --git a/tests/cts/permissionui/Android.bp b/tests/cts/permissionui/Android.bp index 12fdbe533..06b8e4640 100644 --- a/tests/cts/permissionui/Android.bp +++ b/tests/cts/permissionui/Android.bp @@ -42,6 +42,7 @@ android_test { "CtsAccessibilityCommon", "platform-test-rules", "platform-test-annotations", + "android.permission.flags-aconfig-java", ], data: [ ":CtsPermissionPolicyApp25", diff --git a/tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt index b47fba56f..6f80ea5d6 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/BasePermissionTest.kt @@ -111,6 +111,11 @@ abstract class BasePermissionTest { @JvmStatic protected val isAutomotive = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) + @JvmStatic + protected val isAutomotiveSplitscreen = isAutomotive && + packageManager.hasSystemFeature( + /* PackageManager.FEATURE_CAR_SPLITSCREEN_MULTITASKING */ + "android.software.car.splitscreen_multitasking") } @get:Rule val screenRecordRule = ScreenRecordRule(false, false) diff --git a/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationManagerTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationManagerTest.kt new file mode 100644 index 000000000..83f53b252 --- /dev/null +++ b/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationManagerTest.kt @@ -0,0 +1,144 @@ +/* + * 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.Context +import android.content.pm.PackageManager +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 androidx.test.filters.SdkSuppress +import androidx.test.platform.app.InstrumentationRegistry +import com.android.compatibility.common.util.SystemUtil.eventually +import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Rule +import org.junit.Test + +@AppModeFull(reason = "Instant apps cannot install packages") +@SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName = "VanillaIceCream") +@RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) +class EnhancedConfirmationManagerTest : BaseUsePermissionTest() { + + private val apkName = APP_APK_NAME_31 + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val context: Context = instrumentation.targetContext + private val ecm by lazy { context.getSystemService(EnhancedConfirmationManager::class.java)!! } + + @Rule + @JvmField + val mCheckFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + + @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) + @Test + fun givenStoreAppThenIsNotRestrictedFromProtectedSetting() { + installPackageWithInstallSourceAndMetadataFromStore(apkName) + runWithShellPermissionIdentity { + eventually { assertFalse(ecm.isRestricted(APP_PACKAGE_NAME, PROTECTED_SETTING)) } + } + } + + @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) + @Test + fun givenLocalAppThenIsRestrictedFromProtectedSetting() { + installPackageWithInstallSourceAndMetadataFromLocalFile(apkName) + runWithShellPermissionIdentity { + eventually { assertTrue(ecm.isRestricted(APP_PACKAGE_NAME, PROTECTED_SETTING)) } + } + } + + @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) + @Test + fun givenDownloadedThenAppIsRestrictedFromProtectedSetting() { + installPackageWithInstallSourceAndMetadataFromDownloadedFile(apkName) + runWithShellPermissionIdentity { + eventually { assertTrue(ecm.isRestricted(APP_PACKAGE_NAME, PROTECTED_SETTING)) } + } + } + + @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) + @Test + fun givenExplicitlyRestrictedAppThenIsRestrictedFromProtectedSetting() { + installPackageWithInstallSourceAndMetadataFromStore(apkName) + runWithShellPermissionIdentity { + eventually { assertFalse(ecm.isRestricted(APP_PACKAGE_NAME, PROTECTED_SETTING)) } + setAppEcmState(context, APP_PACKAGE_NAME, MODE_ERRORED) + eventually { assertTrue(ecm.isRestricted(APP_PACKAGE_NAME, PROTECTED_SETTING)) } + } + } + + @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) + @Test + fun givenRestrictedAppThenIsNotRestrictedFromNonProtectedSetting() { + installPackageWithInstallSourceAndMetadataFromDownloadedFile(apkName) + runWithShellPermissionIdentity { + eventually { assertFalse(ecm.isRestricted(APP_PACKAGE_NAME, NON_PROTECTED_SETTING)) } + } + } + + @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) + @Test + fun givenRestrictedAppThenClearRestrictionNotAllowedByDefault() { + installPackageWithInstallSourceAndMetadataFromDownloadedFile(apkName) + runWithShellPermissionIdentity { + eventually { assertFalse(ecm.isClearRestrictionAllowed(APP_PACKAGE_NAME)) } + } + } + + @RequiresFlagsEnabled(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) + @Test + fun givenRestrictedAppWhenClearRestrictionThenNotRestrictedFromProtectedSetting() { + installPackageWithInstallSourceAndMetadataFromDownloadedFile(apkName) + runWithShellPermissionIdentity { + eventually { assertTrue(ecm.isRestricted(APP_PACKAGE_NAME, PROTECTED_SETTING)) } + ecm.setClearRestrictionAllowed(APP_PACKAGE_NAME) + eventually { assertTrue(ecm.isClearRestrictionAllowed(APP_PACKAGE_NAME)) } + ecm.clearRestriction(APP_PACKAGE_NAME) + eventually { assertFalse(ecm.isRestricted(APP_PACKAGE_NAME, PROTECTED_SETTING)) } + } + } + + companion object { + private const val NON_PROTECTED_SETTING = "example_setting_which_is_not_protected" + private const val PROTECTED_SETTING = "android:bind_accessibility_service" + private const val MODE_ERRORED = 2 + + @Throws(PackageManager.NameNotFoundException::class) + private fun setAppEcmState(context: Context, packageName: String, mode: Int) { + val appOpsManager = context.getSystemService(AppOpsManager::class.java)!! + appOpsManager.setMode( + AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS, + context.packageManager + .getApplicationInfoAsUser( + packageName, + /* flags */ 0, + android.os.Process.myUserHandle() + ) + .uid, + packageName, + mode + ) + } + } +} diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt index 3a8a6a838..b81432369 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionTapjackingTest.kt @@ -43,6 +43,9 @@ class PermissionTapjackingTest : BaseUsePermissionTest() { // PermissionController for television uses a floating window. assumeFalse(isTv) + // Automotive split-screen multitasking uses multi-window mode + assumeFalse(isAutomotiveSplitscreen) + assertAppHasPermission(ACCESS_FINE_LOCATION, false) requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {} @@ -63,6 +66,9 @@ class PermissionTapjackingTest : BaseUsePermissionTest() { // PermissionController for television uses a floating window. assumeFalse(isTv) + // Automotive split-screen multitasking uses multi-window mode + assumeFalse(isAutomotiveSplitscreen) + assertAppHasPermission(ACCESS_FINE_LOCATION, false) requestAppPermissionsForNoResult(ACCESS_FINE_LOCATION) {} diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt index 018a6e486..1f1aba1e7 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/PhotoPickerPermissionTest.kt @@ -20,6 +20,8 @@ import android.Manifest.permission.ACCESS_MEDIA_LOCATION import android.Manifest.permission.READ_MEDIA_IMAGES import android.Manifest.permission.READ_MEDIA_VIDEO import android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED +import android.app.UiAutomation.ROTATION_FREEZE_270 +import android.app.UiAutomation.ROTATION_UNFREEZE import android.content.pm.PackageManager import android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME import android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT @@ -466,13 +468,31 @@ class PhotoPickerPermissionTest : BaseUsePermissionTest() { } @Test + fun testDismissAfterActivityRecreatedWithPickerOpen() { + installPackage(APP_APK_PATH_LATEST) + requestAppPermissionsAndAssertResult( + READ_MEDIA_IMAGES to false, + READ_MEDIA_VISUAL_USER_SELECTED to true, + waitForWindowTransition = false + ) { + doAndWaitForWindowTransition { click(By.res(SELECT_BUTTON)) } + clickImageOrVideo() + try { + doAndWaitForWindowTransition { uiAutomation.setRotation(ROTATION_FREEZE_270) } + clickImageOrVideo() + doAndWaitForWindowTransition { clickAllow() } + } finally { + uiAutomation.setRotation(ROTATION_UNFREEZE) + } + } + } + + @Test fun testCanSelectPhotosInSettings() { installPackage(APP_APK_PATH_LATEST) navigateToIndividualPermissionSetting(READ_MEDIA_IMAGES) click(By.res(SELECT_RADIO_BUTTON)) - doAndWaitForWindowTransition { - click(By.res(EDIT_PHOTOS_BUTTON)) - } + doAndWaitForWindowTransition { click(By.res(EDIT_PHOTOS_BUTTON)) } clickImageOrVideo() clickAllow() } diff --git a/tests/cts/role/Android.bp b/tests/cts/role/Android.bp index 368a45263..a2e3255c3 100644 --- a/tests/cts/role/Android.bp +++ b/tests/cts/role/Android.bp @@ -39,6 +39,7 @@ android_test { "cts", "general-tests", "mts-permission", + "mcts-permission", ], data: [ diff --git a/tests/cts/safetycenter/Android.bp b/tests/cts/safetycenter/Android.bp index 6e0fedec0..e49587c39 100644 --- a/tests/cts/safetycenter/Android.bp +++ b/tests/cts/safetycenter/Android.bp @@ -48,5 +48,6 @@ android_test { "cts", "general-tests", "mts-permission", + "mcts-permission", ], } 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 963c593cd..8bcc724f3 100644 --- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt +++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt @@ -3796,6 +3796,17 @@ class SafetyCenterManagerTest { assertThat(lastUpdated[key]).isNotNull() } + @Test + fun setSafetySourceData_dynamicHiddenWithIssueOnlyData_allowed() { + safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.hiddenSourceConfig) + val expectedData = SafetySourceTestData.issuesOnly(safetySourceTestData.informationIssue) + + safetyCenterTestHelper.setData(DYNAMIC_HIDDEN_ID, expectedData) + + val actualData = safetyCenterManager.getSafetySourceDataWithPermission(DYNAMIC_HIDDEN_ID) + assertThat(actualData).isEqualTo(expectedData) + } + private fun dumpLastUpdated(): Map<String, String> { val dump = SystemUtil.runShellCommand("dumpsys safety_center data") return dump diff --git a/tests/hostside/safetycenter/helper-app/Android.bp b/tests/hostside/safetycenter/helper-app/Android.bp index d15caceaa..04e660134 100644 --- a/tests/hostside/safetycenter/helper-app/Android.bp +++ b/tests/hostside/safetycenter/helper-app/Android.bp @@ -31,6 +31,7 @@ android_test_helper_app { static_libs: [ "androidx.test.rules", "androidx.test.ext.junit", + "safety-center-pending-intents", "safety-center-test-util-lib", ], } diff --git a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt index 784701b8a..0f1356ca4 100644 --- a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt +++ b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetyCenterInteractionLoggingHelperTests.kt @@ -19,14 +19,21 @@ package android.safetycenter.hostside.device import android.content.Context import android.os.Bundle import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_ID +import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ID +import android.safetycenter.SafetyCenterManager.EXTRA_SAFETY_SOURCE_ISSUE_ID import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterActivity +import com.android.safetycenter.testing.SafetyCenterActivityLauncher.launchSafetyCenterQsActivity import com.android.safetycenter.testing.SafetyCenterActivityLauncher.openPageAndExit import com.android.safetycenter.testing.SafetyCenterFlags import com.android.safetycenter.testing.SafetyCenterTestConfigs +import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID import com.android.safetycenter.testing.SafetyCenterTestHelper import com.android.safetycenter.testing.SafetyCenterTestRule +import com.android.safetycenter.testing.SafetySourceTestData +import com.android.safetycenter.testing.SafetySourceTestData.Companion.INFORMATION_ISSUE_ID +import com.android.safetycenter.testing.UiTestHelper.waitAllTextDisplayed import org.junit.Before import org.junit.Rule import org.junit.Test @@ -47,6 +54,7 @@ class SafetyCenterInteractionLoggingHelperTests { private val context: Context = ApplicationProvider.getApplicationContext() private val safetyCenterTestHelper = SafetyCenterTestHelper(context) private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context) + private val safetySourceTestData = SafetySourceTestData(context) @get:Rule val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper) @@ -61,6 +69,34 @@ class SafetyCenterInteractionLoggingHelperTests { } @Test + fun openSafetyCenterFullFromQs() { + safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) + safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue) + + context.launchSafetyCenterQsActivity { + openPageAndExit("Settings") { waitAllTextDisplayed("OK") } + } + } + + @Test + fun openSafetyCenterWithIssueIntent() { + safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) + + safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, safetySourceTestData.informationWithIssue) + + val extras = Bundle() + extras.putString(EXTRA_SAFETY_SOURCE_ID, SINGLE_SOURCE_ID) + extras.putString(EXTRA_SAFETY_SOURCE_ISSUE_ID, INFORMATION_ISSUE_ID) + + context.launchSafetyCenterActivity(extras) {} + } + + @Test + fun openSafetyCenterQs() { + context.launchSafetyCenterQsActivity {} + } + + @Test fun openSubpageFromIntentExtra() { val config = safetyCenterTestConfigs.singleSourceConfig safetyCenterTestHelper.setConfig(config) 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 458516379..dc3cb3fc2 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 @@ -21,12 +21,16 @@ import android.safetycenter.SafetySourceData import android.safetycenter.SafetySourceIssue import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.safetycenter.pendingintents.PendingIntentSender +import com.android.safetycenter.testing.SafetyCenterActivityLauncher import com.android.safetycenter.testing.SafetyCenterFlags import com.android.safetycenter.testing.SafetyCenterTestConfigs import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_ID import com.android.safetycenter.testing.SafetyCenterTestHelper import com.android.safetycenter.testing.SafetyCenterTestRule import com.android.safetycenter.testing.SafetySourceTestData +import com.android.safetycenter.testing.StatusBarNotificationWithChannel +import com.android.safetycenter.testing.TestNotificationListener import org.junit.Before import org.junit.Rule import org.junit.Test @@ -49,7 +53,9 @@ class SafetyCenterNotificationLoggingHelperTests { private val safetySourceTestData = SafetySourceTestData(context) private val safetyCenterTestConfigs = SafetyCenterTestConfigs(context) - @get:Rule val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper) + @get:Rule + val safetyCenterTestRule = + SafetyCenterTestRule(safetyCenterTestHelper, withNotifications = true) @Before fun setUp() { @@ -64,6 +70,13 @@ class SafetyCenterNotificationLoggingHelperTests { safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, newTestDataWithNotifiableIssue()) } + @Test + fun openSafetyCenterFromNotification() { + safetyCenterTestHelper.setData(SINGLE_SOURCE_ID, newTestDataWithNotifiableIssue()) + + sendContentPendingIntent(TestNotificationListener.waitForSingleNotification()) + } + private fun newTestDataWithNotifiableIssue(): SafetySourceData = safetySourceTestData .defaultCriticalDataBuilder() @@ -74,4 +87,17 @@ class SafetyCenterNotificationLoggingHelperTests { .build() ) .build() + + companion object { + private fun sendContentPendingIntent( + statusBarNotificationWithChannel: StatusBarNotificationWithChannel + ) { + val contentIntent = + statusBarNotificationWithChannel.statusBarNotification.notification.contentIntent + SafetyCenterActivityLauncher.executeBlockAndExit( + launchActivity = { PendingIntentSender.send(contentIntent) }, + block = {} // No action required + ) + } + } } diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt index 5fe9e0a2a..91222d045 100644 --- a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt +++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt @@ -24,10 +24,13 @@ import com.android.compatibility.common.util.ApiLevelUtil import com.android.os.AtomsProto.Atom import com.android.os.AtomsProto.SafetyCenterInteractionReported import com.android.os.AtomsProto.SafetyCenterInteractionReported.Action +import com.android.os.AtomsProto.SafetyCenterInteractionReported.NavigationSource import com.android.os.AtomsProto.SafetyCenterInteractionReported.ViewType import com.android.tradefed.testtype.DeviceJUnit4ClassRunner import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test import com.google.common.truth.Truth.assertThat +import java.math.BigInteger +import java.security.MessageDigest import org.junit.After import org.junit.Assume.assumeTrue import org.junit.Before @@ -67,15 +70,76 @@ class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() { val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED) - assertThat(safetyCenterViewedAtoms).isNotEmpty() + assertThat(safetyCenterViewedAtoms).hasSize(1) + with(safetyCenterViewedAtoms.first()) { + assertThat(navigationSource).isEqualTo(NavigationSource.SOURCE_UNKNOWN) + assertThat(viewType).isEqualTo(ViewType.FULL) + } } @Test - fun sendNotification_recordsNotificationPostedEvent() { + fun openSafetyCenterQs_recordsSafetyCenterViewedEvent() { + helperAppRule.runTest(TEST_CLASS_NAME, "openSafetyCenterQs") + + val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED) + + assertThat(safetyCenterViewedAtoms).hasSize(1) + with(safetyCenterViewedAtoms.first()) { + assertThat(navigationSource).isEqualTo(NavigationSource.QUICK_SETTINGS_TILE) + assertThat(viewType).isEqualTo(ViewType.QUICK_SETTINGS) + } + } + + @Test + fun openSafetyCenterFullFromQs_recordsViewEventWithCorrectSource() { + helperAppRule.runTest(TEST_CLASS_NAME, "openSafetyCenterFullFromQs") + + val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED) + + val viewTypesToNavSources = + safetyCenterViewedAtoms.associate { Pair(it.viewType, it.navigationSource) } + assertThat(viewTypesToNavSources) + .containsEntry(ViewType.FULL, NavigationSource.QUICK_SETTINGS_TILE) + } + + @Test + fun openSafetyCenterWithIssueIntent_recordsViewEventWithAssociatedIssueMetadata() { + helperAppRule.runTest(TEST_CLASS_NAME, testMethodName = "openSafetyCenterWithIssueIntent") + + val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED) + + assertThat(safetyCenterViewedAtoms).hasSize(1) + with(safetyCenterViewedAtoms.first()) { + assertThat(navigationSource).isEqualTo(NavigationSource.NOTIFICATION) + assertThat(encodedSafetySourceId).isEqualTo(ENCODED_SINGLE_SOURCE_ID) + assertThat(encodedIssueTypeId).isEqualTo(ENCODED_ISSUE_TYPE_ID) + } + } + + @Test + fun openSafetyCenterWithNotification_recordsViewEventWithAssociatedIssueMetadata() { assumeAtLeastUpsideDownCake("Safety Center notification APIs require Android U+") helperAppRule.runTest( testClassName = ".SafetyCenterNotificationLoggingHelperTests", + testMethodName = "openSafetyCenterFromNotification" + ) + + val safetyCenterViewedAtoms = getInteractionReportedAtoms(Action.SAFETY_CENTER_VIEWED) + + assertThat(safetyCenterViewedAtoms).hasSize(1) + with(safetyCenterViewedAtoms.first()) { + assertThat(navigationSource).isEqualTo(NavigationSource.NOTIFICATION) + assertThat(encodedSafetySourceId).isEqualTo(ENCODED_SINGLE_SOURCE_ID) + assertThat(encodedIssueTypeId).isEqualTo(ENCODED_ISSUE_TYPE_ID) + } + } + + @Test + fun sendNotification_recordsNotificationPostedEvent() { + assumeAtLeastUpsideDownCake("Safety Center notification APIs require Android U+") + helperAppRule.runTest( + testClassName = ".SafetyCenterNotificationLoggingHelperTests", testMethodName = "sendNotification" ) @@ -97,8 +161,7 @@ class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() { assertThat(safetyCenterViewedAtoms).hasSize(1) with(safetyCenterViewedAtoms.first()) { assertThat(viewType).isEqualTo(ViewType.SUBPAGE) - assertThat(navigationSource) - .isEqualTo(SafetyCenterInteractionReported.NavigationSource.SOURCE_UNKNOWN) + assertThat(navigationSource).isEqualTo(NavigationSource.SOURCE_UNKNOWN) assertThat(sessionId).isNotNull() } } @@ -113,8 +176,7 @@ class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() { val subpageViewedEvent = safetyCenterViewedAtoms.find { it.viewType == ViewType.SUBPAGE } assertThat(subpageViewedEvent).isNotNull() - assertThat(subpageViewedEvent!!.navigationSource) - .isEqualTo(SafetyCenterInteractionReported.NavigationSource.SAFETY_CENTER) + assertThat(subpageViewedEvent!!.navigationSource).isEqualTo(NavigationSource.SAFETY_CENTER) assertThat(safetyCenterViewedAtoms.map { it.sessionId }.distinct()).hasSize(1) } @@ -129,8 +191,7 @@ class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() { assertThat(safetyCenterViewedAtoms).hasSize(1) with(safetyCenterViewedAtoms.first()) { assertThat(viewType).isEqualTo(ViewType.SUBPAGE) - assertThat(navigationSource) - .isEqualTo(SafetyCenterInteractionReported.NavigationSource.SETTINGS) + assertThat(navigationSource).isEqualTo(NavigationSource.SETTINGS) assertThat(sessionId).isNotNull() } } @@ -148,5 +209,27 @@ class SafetyCenterInteractionLoggingHostTest : BaseHostJUnit4Test() { private companion object { const val TEST_CLASS_NAME = ".SafetyCenterInteractionLoggingHelperTests" + + // LINT.IfChange(single_source_id) + val ENCODED_SINGLE_SOURCE_ID = encodeId("test_single_source_id") + // LINT.ThenChange(/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt:issue_type_id) + + // LINT.IfChange(issue_type_id) + val ENCODED_ISSUE_TYPE_ID = encodeId("issue_type_id") + // LINT.ThenChange(/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt:issue_type_id) + + /** + * Encodes a string into an long ID. The ID is a SHA-256 of the string, truncated to 64 + * bits. + */ + fun encodeId(id: String?): Long { + if (id == null) return 0 + + val digest = MessageDigest.getInstance("MD5") + digest.update(id.toByteArray()) + + // Truncate to the size of a long + return BigInteger(digest.digest()).toLong() + } } } diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt index edf76e888..fe75a05a2 100644 --- a/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt +++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/rules/RequireSafetyCenterRule.kt @@ -24,14 +24,23 @@ import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement +/** toBooleanString() doesn't seem available on all Kotlin versions we need to support. */ +private fun String.toBooleanStrictInt(): Boolean = + when (this) { + "true" -> true + "false" -> false + else -> + throw IllegalArgumentException("The string doesn't represent a boolean value: $this") + } + /** JUnit rule for host side tests that requires Safety Center to be supported and enabled. */ class RequireSafetyCenterRule(private val hostTestClass: BaseHostJUnit4Test) : TestRule { private val safetyCenterSupported: Boolean by lazy { - shellCommandStdoutOrThrow("cmd safety_center supported").toBooleanStrict() + shellCommandStdoutOrThrow("cmd safety_center supported").toBooleanStrictInt() } private val safetyCenterEnabled: Boolean by lazy { - shellCommandStdoutOrThrow("cmd safety_center enabled").toBooleanStrict() + shellCommandStdoutOrThrow("cmd safety_center enabled").toBooleanStrictInt() } override fun apply(base: Statement, description: Description): Statement { 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 60c3b4d6a..fd3749094 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt @@ -159,6 +159,14 @@ class SafetyCenterTestConfigs(private val context: Context) { /** A [SafetyCenterConfig] with a dynamic source in a different, missing package. */ val singleSourceOtherPackageConfig = singleSourceConfig(dynamicOtherPackageSafetySource) + /** A [SafetyCenterConfig] with a dynamic hidden-by-default source. */ + val hiddenSourceConfig = + singleSourceConfig( + dynamicSafetySourceBuilder(DYNAMIC_HIDDEN_ID) + .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN) + .build() + ) + /** A simple [SafetyCenterConfig] with a source supporting all profiles. */ val singleSourceAllProfileConfig = singleSourceConfig( @@ -848,7 +856,9 @@ class SafetyCenterTestConfigs(private val context: Context) { * ID of the only source provided in [singleSourceConfig], [severityZeroConfig] and * [noPageOpenConfig]. */ + // LINT.IfChange(single_source_id) const val SINGLE_SOURCE_ID = "test_single_source_id" + // LINT.ThenChange(/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt:single_source_id) /** ID of the only source provided in [singleSourceAllProfileConfig]. */ const val SINGLE_SOURCE_ALL_PROFILE_ID = "test_single_source_all_profile_id" 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 2c4f856bb..66be55fa8 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetySourceTestData.kt @@ -802,7 +802,9 @@ class SafetySourceTestData(private val context: Context) { const val CRITICAL_ISSUE_ACTION_ID = "critical_issue_action_id" /** Issue type ID for all the issues in this file */ + // LINT.IfChange(issue_type_id) const val ISSUE_TYPE_ID = "issue_type_id" + // LINT.ThenChange(/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetyCenterInteractionLoggingHostTest.kt:issue_type_id) const val CONFIRMATION_TITLE = "Confirmation title" const val CONFIRMATION_TEXT = "Confirmation text" |