diff options
10 files changed, 252 insertions, 61 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 0541934fd665..17578266b51e 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2009,6 +2009,7 @@ package android.permission { public final class PermissionManager { method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData(); + method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.permission.PermGroupUsage> getIndicatorAppOpUsageData(boolean); method @NonNull public android.content.AttributionSource registerAttributionSource(@NonNull android.content.AttributionSource); } diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 1a40f0640a8d..17c90d64ce6a 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -886,6 +886,24 @@ public final class PermissionManager { } /** + * @param micMuted whether to consider the microphone muted when retrieving audio ops + * @return A list of permission groups currently or recently used by all apps by all users in + * the current profile group. + * + * @hide + */ + @TestApi + @NonNull + @RequiresPermission(Manifest.permission.GET_APP_OPS_STATS) + public List<PermGroupUsage> getIndicatorAppOpUsageData(boolean micMuted) { + // Lazily initialize the usage helper + if (mUsageHelper == null) { + mUsageHelper = new PermissionUsageHelper(mContext); + } + return mUsageHelper.getOpUsageData(micMuted); + } + + /** * Determine if a package should be shown in indicators. Only a select few roles, and the * system app itself, are hidden. These values are updated at most every 15 seconds. * @hide diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java index 2661d8913a3f..b544599d0979 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java @@ -60,17 +60,31 @@ public interface AppOpsController { /** * Returns a copy of the list containing all the active AppOps that the controller tracks. * - * @return List of active AppOps information + * @return List of active AppOps information, without paused elements. */ List<AppOpItem> getActiveAppOps(); /** + * Returns a copy of the list containing all the active AppOps that the controller tracks. + * + * @param showPaused {@code true} to also obtain paused items. {@code false} otherwise. + * @return List of active AppOps information + */ + List<AppOpItem> getActiveAppOps(boolean showPaused); + + /** * Returns a copy of the list containing all the active AppOps that the controller tracks, for * a given user id. * * @param userId User id to track + * @param showPaused {@code true} to also obtain paused items. {@code false} otherwise. * * @return List of active AppOps information for that user id */ - List<AppOpItem> getActiveAppOpsForUser(int userId); + List<AppOpItem> getActiveAppOpsForUser(int userId, boolean showPaused); + + /** + * @return whether this controller is considering the microphone as muted. + */ + boolean isMicMuted(); } diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java index 994401db4380..534f93ec0e47 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java @@ -241,9 +241,9 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon AppOpItem item = getAppOpItemLocked(mActiveItems, code, uid, packageName); if (item == null && active) { item = new AppOpItem(code, uid, packageName, mClock.elapsedRealtime()); - if (code == AppOpsManager.OP_RECORD_AUDIO) { + if (isOpMicrophone(code)) { item.setDisabled(isAnyRecordingPausedLocked(uid)); - } else if (code == AppOpsManager.OP_CAMERA) { + } else if (isOpCamera(code)) { item.setDisabled(mCameraDisabled); } mActiveItems.add(item); @@ -298,6 +298,11 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon return PermissionManager.shouldShowPackageForIndicatorCached(mContext, packageName); } + @WorkerThread + public List<AppOpItem> getActiveAppOps() { + return getActiveAppOps(false); + } + /** * Returns a copy of the list containing all the active AppOps that the controller tracks. * @@ -306,8 +311,8 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon * @return List of active AppOps information */ @WorkerThread - public List<AppOpItem> getActiveAppOps() { - return getActiveAppOpsForUser(UserHandle.USER_ALL); + public List<AppOpItem> getActiveAppOps(boolean showPaused) { + return getActiveAppOpsForUser(UserHandle.USER_ALL, showPaused); } /** @@ -321,7 +326,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon * @return List of active AppOps information for that user id */ @WorkerThread - public List<AppOpItem> getActiveAppOpsForUser(int userId) { + public List<AppOpItem> getActiveAppOpsForUser(int userId, boolean showPaused) { Assert.isNotMainThread(); List<AppOpItem> list = new ArrayList<>(); synchronized (mActiveItems) { @@ -330,7 +335,8 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon AppOpItem item = mActiveItems.get(i); if ((userId == UserHandle.USER_ALL || UserHandle.getUserId(item.getUid()) == userId) - && isUserVisible(item.getPackageName()) && !item.isDisabled()) { + && isUserVisible(item.getPackageName()) + && (showPaused || !item.isDisabled())) { list.add(item); } } @@ -441,9 +447,9 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon AppOpItem item = mActiveItems.get(i); boolean paused = false; - if (item.getCode() == AppOpsManager.OP_RECORD_AUDIO) { + if (isOpMicrophone(item.getCode())) { paused = isAnyRecordingPausedLocked(item.getUid()); - } else if (item.getCode() == AppOpsManager.OP_CAMERA) { + } else if (isOpCamera(item.getCode())) { paused = mCameraDisabled; } @@ -502,6 +508,19 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon }); } + @Override + public boolean isMicMuted() { + return mMicMuted; + } + + private boolean isOpCamera(int op) { + return op == AppOpsManager.OP_CAMERA || op == AppOpsManager.OP_PHONE_CALL_CAMERA; + } + + private boolean isOpMicrophone(int op) { + return op == AppOpsManager.OP_RECORD_AUDIO || op == AppOpsManager.OP_PHONE_CALL_MICROPHONE; + } + protected class H extends Handler { H(Looper looper) { super(looper); diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt index f87ea7c61ca8..feb27d804e5e 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt @@ -29,6 +29,7 @@ import android.util.Log import androidx.annotation.MainThread import androidx.annotation.VisibleForTesting import androidx.annotation.WorkerThread +import com.android.systemui.appops.AppOpsController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main @@ -48,7 +49,6 @@ private val defaultDialogProvider = object : PrivacyDialogController.DialogProvi return PrivacyDialog(context, list, starter) } } - /** * Controller for [PrivacyDialog]. * @@ -66,6 +66,7 @@ class PrivacyDialogController( private val uiExecutor: Executor, private val privacyLogger: PrivacyLogger, private val keyguardStateController: KeyguardStateController, + private val appOpsController: AppOpsController, @VisibleForTesting private val dialogProvider: DialogProvider ) { @@ -79,7 +80,8 @@ class PrivacyDialogController( @Background backgroundExecutor: Executor, @Main uiExecutor: Executor, privacyLogger: PrivacyLogger, - keyguardStateController: KeyguardStateController + keyguardStateController: KeyguardStateController, + appOpsController: AppOpsController ) : this( permissionManager, packageManager, @@ -90,6 +92,7 @@ class PrivacyDialogController( uiExecutor, privacyLogger, keyguardStateController, + appOpsController, defaultDialogProvider ) @@ -127,7 +130,9 @@ class PrivacyDialogController( } @WorkerThread - private fun permGroupUsage(): List<PermGroupUsage> = permissionManager.indicatorAppOpUsageData + private fun permGroupUsage(): List<PermGroupUsage> { + return permissionManager.getIndicatorAppOpUsageData(appOpsController.isMicMuted) + } /** * Show the [PrivacyDialog] @@ -261,4 +266,4 @@ class PrivacyDialogController( starter: (String, Int) -> Unit ): PrivacyDialog } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt index 4c617edd8542..63ec6e5db017 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt @@ -54,7 +54,8 @@ private const val UNKNOWN_TIMESTAMP = -1L data class PrivacyItem( val privacyType: PrivacyType, val application: PrivacyApplication, - val timeStampElapsed: Long = UNKNOWN_TIMESTAMP + val timeStampElapsed: Long = UNKNOWN_TIMESTAMP, + val paused: Boolean = false ) { val log = "(${privacyType.logName}, ${application.packageName}(${application.uid}), " + "$timeStampElapsed)" diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt index f7e2a31ce727..8b27b6ecbfd1 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt @@ -257,7 +257,7 @@ class PrivacyItemController @Inject constructor( privacyList = emptyList() return } - val list = appOpsController.getActiveAppOpsForUser(UserHandle.USER_ALL).filter { + val list = appOpsController.getActiveAppOps(true).filter { UserHandle.getUserId(it.uid) in currentUserIds || it.code == AppOpsManager.OP_PHONE_CALL_MICROPHONE || it.code == AppOpsManager.OP_PHONE_CALL_CAMERA @@ -279,7 +279,9 @@ class PrivacyItemController @Inject constructor( // Anything earlier than this timestamp can be removed val removeBeforeTime = systemClock.elapsedRealtime() - TIME_TO_HOLD_INDICATORS - val mustKeep = privacyList.filter { it.timeStampElapsed > removeBeforeTime && it !in list } + val mustKeep = privacyList.filter { + it.timeStampElapsed > removeBeforeTime && !(it isIn list) + } // There are items we must keep because they haven't been around for enough time. if (mustKeep.isNotEmpty()) { @@ -291,7 +293,18 @@ class PrivacyItemController @Inject constructor( logger.logPrivacyItemsUpdateScheduled(delay) holdingRunnableCanceler = bgExecutor.executeDelayed(updateListAndNotifyChanges, delay) } - return list + mustKeep + return list.filter { !it.paused } + mustKeep + } + + /** + * Ignores the paused status to determine if the element is in the list + */ + private infix fun PrivacyItem.isIn(list: List<PrivacyItem>): Boolean { + return list.any { + it.privacyType == privacyType && + it.application == application && + it.timeStampElapsed == timeStampElapsed + } } private fun toPrivacyItem(appOpItem: AppOpItem): PrivacyItem? { @@ -308,7 +321,7 @@ class PrivacyItemController @Inject constructor( return null } val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid) - return PrivacyItem(type, app, appOpItem.timeStartedElapsed) + return PrivacyItem(type, app, appOpItem.timeStartedElapsed, appOpItem.isDisabled) } interface Callback { diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java index 3f0831cadd1f..78c67170d185 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java @@ -233,9 +233,9 @@ public class AppOpsControllerTest extends SysuiTestCase { TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); assertEquals(2, - mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID)).size()); - assertEquals(1, - mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID_OTHER)).size()); + mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID), false).size()); + assertEquals(1, mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID_OTHER), + false).size()); } @Test @@ -245,11 +245,11 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, TEST_UID_NON_USER_SENSITIVE, mExemptedRolePkgName, true); assertEquals(0, mController.getActiveAppOpsForUser( - UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE)).size()); + UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE), false).size()); mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, TEST_UID_NON_USER_SENSITIVE, SYSTEM_PKG, true); assertEquals(0, mController.getActiveAppOpsForUser( - UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE)).size()); + UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE), false).size()); } @Test @@ -441,7 +441,19 @@ public class AppOpsControllerTest extends SysuiTestCase { } @Test - public void testOnlyRecordAudioPaused() { + public void testPausedPhoneCallMicrophoneFilteredOut() { + mController.addCallback(new int[]{AppOpsManager.OP_PHONE_CALL_MICROPHONE}, mCallback); + mTestableLooper.processAllMessages(); + + mController.onOpActiveChanged( + AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + + assertTrue(mController.getActiveAppOps().isEmpty()); + } + + @Test + public void testOnlyRecordAudioPhoneCallMicrophonePaused() { mController.addCallback(new int[]{ AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA @@ -532,6 +544,40 @@ public class AppOpsControllerTest extends SysuiTestCase { } @Test + public void testPhoneCallMicrophoneFilteredWhenMicDisabled() { + mController.addCallback( + new int[]{AppOpsManager.OP_PHONE_CALL_MICROPHONE, AppOpsManager.OP_CAMERA}, + mCallback); + mTestableLooper.processAllMessages(); + mController.onOpActiveChanged( + AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + List<AppOpItem> list = mController.getActiveAppOps(); + assertEquals(1, list.size()); + assertEquals(AppOpsManager.OP_PHONE_CALL_MICROPHONE, list.get(0).getCode()); + assertFalse(list.get(0).isDisabled()); + + // Add a camera op, and disable the microphone. The camera op should be the only op returned + mController.onSensorBlockedChanged(MICROPHONE, true); + mController.onOpActiveChanged( + AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + list = mController.getActiveAppOps(); + assertEquals(1, list.size()); + assertEquals(AppOpsManager.OP_CAMERA, list.get(0).getCode()); + + + // Re enable the microphone, and verify the op returns + mController.onSensorBlockedChanged(MICROPHONE, false); + mTestableLooper.processAllMessages(); + + list = mController.getActiveAppOps(); + assertEquals(2, list.size()); + int micIdx = list.get(0).getCode() == AppOpsManager.OP_CAMERA ? 1 : 0; + assertEquals(AppOpsManager.OP_PHONE_CALL_MICROPHONE, list.get(micIdx).getCode()); + } + + @Test public void testCameraFilteredWhenCameraDisabled() { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA}, mCallback); @@ -563,6 +609,39 @@ public class AppOpsControllerTest extends SysuiTestCase { assertEquals(AppOpsManager.OP_CAMERA, list.get(cameraIdx).getCode()); } + @Test + public void testPhoneCallCameraFilteredWhenCameraDisabled() { + mController.addCallback( + new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_PHONE_CALL_CAMERA}, + mCallback); + mTestableLooper.processAllMessages(); + mController.onOpActiveChanged( + AppOpsManager.OP_PHONE_CALL_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + List<AppOpItem> list = mController.getActiveAppOps(); + assertEquals(1, list.size()); + assertEquals(AppOpsManager.OP_PHONE_CALL_CAMERA, list.get(0).getCode()); + assertFalse(list.get(0).isDisabled()); + + // Add an audio op, and disable the camera. The audio op should be the only op returned + mController.onSensorBlockedChanged(CAMERA, true); + mController.onOpActiveChanged( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); + list = mController.getActiveAppOps(); + assertEquals(1, list.size()); + assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(0).getCode()); + + // Re enable the camera, and verify the op returns + mController.onSensorBlockedChanged(CAMERA, false); + mTestableLooper.processAllMessages(); + + list = mController.getActiveAppOps(); + assertEquals(2, list.size()); + int cameraIdx = list.get(0).getCode() == AppOpsManager.OP_PHONE_CALL_CAMERA ? 0 : 1; + assertEquals(AppOpsManager.OP_PHONE_CALL_CAMERA, list.get(cameraIdx).getCode()); + } + private class TestHandler extends AppOpsControllerImpl.H { TestHandler(Looper looper) { mController.super(looper); diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt index 791dd121852f..05a1e4ff474d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt @@ -28,6 +28,7 @@ import android.permission.PermissionManager import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.appops.AppOpsController import com.android.systemui.plugins.ActivityStarter import com.android.systemui.privacy.logging.PrivacyLogger import com.android.systemui.settings.UserTracker @@ -43,6 +44,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString import org.mockito.Captor @@ -86,6 +88,8 @@ class PrivacyDialogControllerTest : SysuiTestCase() { private lateinit var privacyLogger: PrivacyLogger @Mock private lateinit var keyguardStateController: KeyguardStateController + @Mock + private lateinit var appOpsController: AppOpsController @Captor private lateinit var dialogDismissedCaptor: ArgumentCaptor<PrivacyDialog.OnDialogDismissed> @Captor @@ -131,6 +135,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { uiExecutor, privacyLogger, keyguardStateController, + appOpsController, dialogProvider ) } @@ -143,18 +148,27 @@ class PrivacyDialogControllerTest : SysuiTestCase() { } @Test + fun testMicMutedParameter() { + `when`(appOpsController.isMicMuted).thenReturn(true) + controller.showDialog(context) + backgroundExecutor.runAllReady() + + verify(permissionManager).getIndicatorAppOpUsageData(true) + } + + @Test fun testPermissionManagerOnlyCalledInBackgroundThread() { controller.showDialog(context) - verify(permissionManager, never()).indicatorAppOpUsageData + verify(permissionManager, never()).getIndicatorAppOpUsageData(anyBoolean()) backgroundExecutor.runAllReady() - verify(permissionManager).indicatorAppOpUsageData + verify(permissionManager).getIndicatorAppOpUsageData(anyBoolean()) } @Test fun testPackageManagerOnlyCalledInBackgroundThread() { val usage = createMockPermGroupUsage() `when`(usage.isPhoneCall).thenReturn(false) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn(listOf(usage)) + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) controller.showDialog(context) verify(packageManager, never()).getApplicationInfoAsUser(anyString(), anyInt(), anyInt()) @@ -217,7 +231,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { isPhoneCall = false, attribution = TEST_ATTRIBUTION ) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn(listOf(usage)) + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) controller.showDialog(context) exhaustExecutors() @@ -246,7 +260,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { packageName = "${TEST_PACKAGE_NAME}_microphone", permGroupName = PERM_MICROPHONE ) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn( + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( listOf(usage_microphone, usage_camera) ) @@ -269,7 +283,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { packageName = "${TEST_PACKAGE_NAME}_recent", isActive = false ) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn( + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( listOf(usage_recent, usage_active) ) @@ -292,7 +306,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { isActive = true, lastAccess = 1L ) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn( + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( listOf(usage_active, usage_active_moreRecent) ) controller.showDialog(context) @@ -319,7 +333,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { isActive = false, lastAccess = 2L ) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn( + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( listOf(usage_recent, usage_mostRecent, usage_moreRecent) ) @@ -342,7 +356,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { permGroupName = PERM_LOCATION ) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn( + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( listOf(usage_camera, usage_location, usage_microphone) ) `when`(privacyItemController.micCameraAvailable).thenReturn(false) @@ -366,7 +380,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { permGroupName = PERM_LOCATION ) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn( + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( listOf(usage_camera, usage_location, usage_microphone) ) `when`(privacyItemController.locationAvailable).thenReturn(false) @@ -392,7 +406,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { permGroupName = PERM_LOCATION ) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn( + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( listOf(usage_camera, usage_location, usage_microphone) ) `when`(privacyItemController.micCameraAvailable).thenReturn(true) @@ -416,7 +430,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { permGroupName = PERM_LOCATION ) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn( + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn( listOf(usage_camera, usage_location, usage_microphone) ) `when`(privacyItemController.micCameraAvailable).thenReturn(false) @@ -433,7 +447,8 @@ class PrivacyDialogControllerTest : SysuiTestCase() { val usage_enterprise = createMockPermGroupUsage( uid = generateUidForUser(ENT_USER_ID) ) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn(listOf(usage_enterprise)) + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())) + .thenReturn(listOf(usage_enterprise)) controller.showDialog(context) exhaustExecutors() @@ -446,7 +461,8 @@ class PrivacyDialogControllerTest : SysuiTestCase() { val usage_other = createMockPermGroupUsage( uid = generateUidForUser(ENT_USER_ID + 1) ) - `when`(permissionManager.indicatorAppOpUsageData).thenReturn(listOf(usage_other)) + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())) + .thenReturn(listOf(usage_other)) controller.showDialog(context) exhaustExecutors() @@ -514,7 +530,8 @@ class PrivacyDialogControllerTest : SysuiTestCase() { } private fun setUpDefaultMockResponses() { - `when`(permissionManager.indicatorAppOpUsageData).thenReturn(emptyList()) + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(emptyList()) + `when`(appOpsController.isMicMuted).thenReturn(false) `when`(packageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) .thenAnswer { diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt index bba1c6a00675..e4d7b1b7d451 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt @@ -46,7 +46,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor -import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyList import org.mockito.Captor import org.mockito.Mock @@ -156,7 +156,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { fun testDistinctItems() { doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0), AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0))) - .`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + .`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.addCallback(callback) executor.runAllReady() @@ -168,7 +168,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { fun testSimilarItemsDifferentTimeStamp() { doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0), AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 1))) - .`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + .`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.addCallback(callback) executor.runAllReady() @@ -215,7 +215,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { @Test fun testMultipleCallbacksAreUpdated() { - doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean()) val otherCallback = mock(PrivacyItemController.Callback::class.java) privacyItemController.addCallback(callback) @@ -233,7 +233,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { @Test fun testRemoveCallback() { - doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean()) val otherCallback = mock(PrivacyItemController.Callback::class.java) privacyItemController.addCallback(callback) privacyItemController.addCallback(otherCallback) @@ -254,7 +254,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { fun testListShouldNotHaveNull() { doReturn(listOf(AppOpItem(AppOpsManager.OP_ACTIVATE_VPN, TEST_UID, "", 0), AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0))) - .`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + .`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.addCallback(callback) executor.runAllReady() executor.runAllReady() @@ -292,7 +292,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0), AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0))) - .`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + .`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.addCallback(callback) executor.runAllReady() @@ -306,7 +306,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { @Test fun testNotUpdated_LocationChangeWhenOnlyMicCamera() { doReturn(listOf(AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0))) - .`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + .`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.addCallback(callback) changeLocation(false) @@ -338,7 +338,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { fun testLogListUpdated() { doReturn(listOf( AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0)) - ).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + ).`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.addCallback(callback) executor.runAllReady() @@ -362,10 +362,10 @@ class PrivacyItemControllerTest : SysuiTestCase() { } @Test - fun testListRequestedForAllUsers() { + fun testListRequestedShowPaused() { privacyItemController.addCallback(callback) executor.runAllReady() - verify(appOpsController).getActiveAppOpsForUser(UserHandle.USER_ALL) + verify(appOpsController).getActiveAppOps(true) } @Test @@ -377,7 +377,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { doReturn(listOf( AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0), AppOpItem(AppOpsManager.OP_CAMERA, otherUserUid, TEST_PACKAGE_NAME, 0)) - ).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + ).`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.userTrackerCallback.onUserChanged(otherUser, mContext) executor.runAllReady() @@ -401,7 +401,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0), AppOpItem(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, 0), AppOpItem(AppOpsManager.OP_PHONE_CALL_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0)) - ).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + ).`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.userTrackerCallback.onUserChanged(otherUser, mContext) executor.runAllReady() @@ -424,7 +424,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, 0), AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0), AppOpItem(AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID, TEST_PACKAGE_NAME, 0)) - ).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + ).`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.userTrackerCallback.onUserChanged(otherUser, mContext) executor.runAllReady() @@ -442,7 +442,7 @@ class PrivacyItemControllerTest : SysuiTestCase() { fun testPassageOfTimeDoesNotRemoveIndicators() { doReturn(listOf( AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime) - )).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + )).`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.addCallback(callback) @@ -458,12 +458,12 @@ class PrivacyItemControllerTest : SysuiTestCase() { // Start with some element at time 0 doReturn(listOf( AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime) - )).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + )).`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.addCallback(callback) executor.runAllReady() // Then remove it at time HOLD + 1 - doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean()) fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS + 1) verify(appOpsController).addCallback(any(), capture(argCaptorCallback)) @@ -481,12 +481,12 @@ class PrivacyItemControllerTest : SysuiTestCase() { // Start with some element at time 0 doReturn(listOf( AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime) - )).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + )).`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.addCallback(callback) executor.runAllReady() // Then remove it at time HOLD - 1 - doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean()) fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS - 1) verify(appOpsController).addCallback(any(), capture(argCaptorCallback)) @@ -504,12 +504,12 @@ class PrivacyItemControllerTest : SysuiTestCase() { // Start with some element at time 0 doReturn(listOf( AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, elapsedTime) - )).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + )).`when`(appOpsController).getActiveAppOps(anyBoolean()) privacyItemController.addCallback(callback) executor.runAllReady() // Then remove it at time HOLD - 1 - doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) + doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOps(anyBoolean()) fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS - 1) verify(appOpsController).addCallback(any(), capture(argCaptorCallback)) @@ -525,6 +525,30 @@ class PrivacyItemControllerTest : SysuiTestCase() { assertTrue(privacyItemController.privacyList.isEmpty()) } + @Test + fun testPausedElementsAreRemoved() { + val item = AppOpItem( + AppOpsManager.OP_RECORD_AUDIO, + TEST_UID, + TEST_PACKAGE_NAME, + elapsedTime + ) + `when`(appOpsController.getActiveAppOps(anyBoolean())).thenReturn(listOf(item)) + privacyItemController.addCallback(callback) + executor.runAllReady() + + item.isDisabled = true + fakeClock.advanceTime(1) + verify(appOpsController).addCallback(any(), capture(argCaptorCallback)) + argCaptorCallback.value.onActiveStateChanged( + AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, false) + + executor.runAllReady() + + verify(callback).onPrivacyItemsChanged(emptyList()) + assertTrue(privacyItemController.privacyList.isEmpty()) + } + private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value) private fun changeLocation(value: Boolean?) = changeProperty(LOCATION_INDICATOR, value) |