RESTRICT AUTOMERGE Add test for mic finishes
Ensure the indicator remains if an app tries to prematurely finish its
own mic usage
Bug: 258672042
Test: atest CtsPermission4TestCases
Change-Id: I5e3feaa80b1dd2c2a7293b33efbe270ee9472c22
diff --git a/tests/tests/permission4/Android.bp b/tests/tests/permission4/Android.bp
index 2ff3bee..72908e2 100644
--- a/tests/tests/permission4/Android.bp
+++ b/tests/tests/permission4/Android.bp
@@ -34,6 +34,7 @@
],
test_suites: [
"cts",
+ "sts",
"vts10",
"general-tests",
"mts-permission",
diff --git a/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp b/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp
index a7e0ab6..9dc1b45 100644
--- a/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp
+++ b/tests/tests/permission4/AppThatAccessesCameraAndMic/Android.bp
@@ -25,6 +25,7 @@
// Tag this module as a cts test artifact
test_suites: [
"cts",
+ "sts",
"vts10",
"general-tests",
],
@@ -36,6 +37,6 @@
],
srcs: [
- "src/**/*.kt"
+ "src/**/*.kt",
],
}
diff --git a/tests/tests/permission4/AppThatAccessesCameraAndMic/src/android/permission4/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt b/tests/tests/permission4/AppThatAccessesCameraAndMic/src/android/permission4/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt
index 659f228..f7a5c31 100644
--- a/tests/tests/permission4/AppThatAccessesCameraAndMic/src/android/permission4/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt
+++ b/tests/tests/permission4/AppThatAccessesCameraAndMic/src/android/permission4/cts/appthataccessescameraandmic/AccessCameraOrMicActivity.kt
@@ -42,6 +42,7 @@
private const val USE_CAMERA = "use_camera"
private const val USE_MICROPHONE = "use_microphone"
private const val USE_HOTWORD = "use_hotword"
+private const val FINISH_EARLY = "finish_early"
private const val USE_DURATION_MS = 10000L
private const val SAMPLE_RATE_HZ = 44100
@@ -62,12 +63,14 @@
private var runMic = false
private var hotwordFinished = false
private var runHotword = false
+ private var finishEarly = false
override fun onStart() {
super.onStart()
runCamera = intent.getBooleanExtra(USE_CAMERA, false)
runMic = intent.getBooleanExtra(USE_MICROPHONE, false)
runHotword = intent.getBooleanExtra(USE_HOTWORD, false)
+ finishEarly = intent.getBooleanExtra(FINISH_EARLY, false)
if (runMic) {
useMic()
@@ -193,6 +196,11 @@
AudioRecord.getMinBufferSize(SAMPLE_RATE_HZ, CHANNEL_IN_MONO, ENCODING_PCM_16BIT)
recorder = AudioRecord(MIC, SAMPLE_RATE_HZ, CHANNEL_IN_MONO, ENCODING_PCM_16BIT, minSize)
recorder?.startRecording()
+ if (finishEarly) {
+ appOpsManager = getSystemService(AppOpsManager::class.java)
+ appOpsManager?.finishOp(AppOpsManager.OPSTR_RECORD_AUDIO, Process.myUid(), packageName)
+ return
+ }
GlobalScope.launch {
delay(USE_DURATION_MS)
micFinished = true
diff --git a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
index fe9037a..ae666d9 100644
--- a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
+++ b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
@@ -27,6 +27,7 @@
import android.os.Build
import android.os.Process
import android.permission.PermissionManager
+import android.platform.test.annotations.AsbSecurityTest
import android.provider.DeviceConfig
import android.provider.Settings
import android.server.wm.WindowManagerStateHelper
@@ -60,6 +61,7 @@
private const val USE_CAMERA = "use_camera"
private const val USE_MICROPHONE = "use_microphone"
private const val USE_HOTWORD = "use_hotword"
+private const val FINISH_EARLY = "finish_early"
private const val INTENT_ACTION = "test.action.USE_CAMERA_OR_MIC"
private const val PRIVACY_CHIP_ID = "com.android.systemui:id/privacy_chip"
private const val CAR_MIC_PRIVACY_CHIP_ID = "com.android.systemui:id/mic_privacy_chip"
@@ -167,11 +169,17 @@
Thread.sleep(DELAY_MILLIS)
}
- private fun openApp(useMic: Boolean, useCamera: Boolean, useHotword: Boolean) {
+ private fun openApp(
+ useMic: Boolean,
+ useCamera: Boolean,
+ useHotword: Boolean,
+ finishEarly: Boolean = false
+ ) {
context.startActivity(Intent(INTENT_ACTION).apply {
putExtra(USE_CAMERA, useCamera)
putExtra(USE_MICROPHONE, useMic)
putExtra(USE_HOTWORD, useHotword)
+ putExtra(FINISH_EARLY, finishEarly)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
})
}
@@ -191,6 +199,13 @@
}
@Test
+ @AsbSecurityTest(cveBugId = [242537498])
+ fun testMicIndicatorWithManualFinishOpStillShows() {
+ changeSafetyCenterFlag(false.toString())
+ testCameraAndMicIndicator(useMic = true, useCamera = false, finishEarly = true)
+ }
+
+ @Test
fun testHotwordIndicatorBehavior() {
changeSafetyCenterFlag(false.toString())
testCameraAndMicIndicator(useMic = false, useCamera = false, useHotword = true)
@@ -268,10 +283,11 @@
useCamera: Boolean,
useHotword: Boolean = false,
chainUsage: Boolean = false,
- safetyCenterEnabled: Boolean = false
+ safetyCenterEnabled: Boolean = false,
+ finishEarly: Boolean = false
) {
var chainAttribution: AttributionSource? = null
- openApp(useMic, useCamera, useHotword)
+ openApp(useMic, useCamera, useHotword, finishEarly)
try {
eventually {
val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
@@ -286,20 +302,23 @@
}
}
- if (isTv) {
- assertTvIndicatorsShown(useMic, useCamera, useHotword)
- } else if (isCar) {
- assertCarIndicatorsShown(useMic, useCamera, useHotword, chainUsage)
- } else {
- // Hotword gets remapped to RECORD_AUDIO on handheld, so handheld should show a mic
- // indicator
+ if (!isTv && !isCar) {
uiDevice.openQuickSettings()
- assertPrivacyChipAndIndicatorsPresent(
- useMic,
- useCamera,
- chainUsage,
- safetyCenterEnabled
- )
+ }
+ assertIndicatorsShown(useMic, useCamera, useHotword, chainUsage,
+ safetyCenterEnabled)
+
+ if (finishEarly) {
+ // Assert that the indicator doesn't go away
+ val indicatorGoneException: Exception? = try {
+ eventually {
+ assertIndicatorsShown(false, false, false)
+ }
+ null
+ } catch (e: Exception) {
+ e
+ }
+ assertNotNull("Expected the indicator to be present", indicatorGoneException)
}
} finally {
if (chainAttribution != null) {
@@ -309,8 +328,25 @@
}
}
+ private fun assertIndicatorsShown(
+ useMic: Boolean,
+ useCamera: Boolean,
+ useHotword: Boolean = false,
+ chainUsage: Boolean = false,
+ safetyCenterEnabled: Boolean = false,
+ ) {
+ if (isTv) {
+ assertTvIndicatorsShown(useMic, useCamera, useHotword)
+ } else if (isCar) {
+ assertCarIndicatorsShown(useMic, useCamera, useHotword, chainUsage)
+ } else {
+ assertPrivacyChipAndIndicatorsPresent(useMic, useCamera, chainUsage,
+ safetyCenterEnabled)
+ }
+ }
+
private fun assertTvIndicatorsShown(useMic: Boolean, useCamera: Boolean, useHotword: Boolean) {
- if (useMic || useHotword) {
+ if (useMic || useHotword || (!useMic && !useCamera && !useHotword)) {
val found = WindowManagerStateHelper()
.waitFor("Waiting for the mic indicator window to come up") {
it.containsWindow(TV_MIC_INDICATOR_WINDOW_TITLE) &&
@@ -345,7 +381,7 @@
assertNotNull("Did not find camera chip", cameraPrivacyChip)
// Click to chip to show the panel.
cameraPrivacyChip.click()
- } else if (useHotword) {
+ } else {
assertNull("Found mic chip, but did not expect to", micPrivacyChip)
assertNull("Found camera chip, but did not expect to", cameraPrivacyChip)
}
@@ -357,18 +393,7 @@
assertChainMicAndOtherCameraUsed(false)
return@eventually
}
- if (useHotword) {
- // There should be no privacy panel when using hot word
- val micLabelView = uiDevice.findObject(UiSelector().textContains(micLabel))
- assertFalse("View with text $micLabel found, but did not expect to",
- micLabelView.exists())
- val cameraLabelView = uiDevice.findObject(UiSelector().textContains(cameraLabel))
- assertFalse("View with text $cameraLabel found, but did not expect to",
- cameraLabelView.exists())
- val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
- assertFalse("View with text $APP_LABEL found, but did not expect to",
- appView.exists())
- } else if (useMic) {
+ if (useMic) {
// There should be a mic privacy panel after mic privacy chip is clicked
val micLabelView = uiDevice.findObject(UiSelector().textContains(micLabel))
assertTrue("View with text $micLabel not found", micLabelView.exists())
@@ -380,6 +405,17 @@
assertTrue("View with text $cameraLabel not found", cameraLabelView.exists())
val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
assertTrue("View with text $APP_LABEL not found", appView.exists())
+ } else {
+ // There should be no privacy panel when using hot word
+ val micLabelView = uiDevice.findObject(UiSelector().textContains(micLabel))
+ assertFalse("View with text $micLabel found, but did not expect to",
+ micLabelView.exists())
+ val cameraLabelView = uiDevice.findObject(UiSelector().textContains(cameraLabel))
+ assertFalse("View with text $cameraLabel found, but did not expect to",
+ cameraLabelView.exists())
+ val appView = uiDevice.findObject(UiSelector().textContains(APP_LABEL))
+ assertFalse("View with text $APP_LABEL found, but did not expect to",
+ appView.exists())
}
}
}
@@ -419,6 +455,7 @@
uiDevice.findObjects(By.res(SAFETY_CENTER_ITEM_ID)).size > 0)
}
}
+ uiDevice.pressBack()
}
private fun createChainAttribution(): AttributionSource? {