Do not hold indicators for apps that become paused

If an app op becomes "paused" (microphone muted or disabled by toggle),
remove the indicator immediately as opposed to holding for 5s.

Also, pass the value that we are using for mic muted to
PermissionManager, so they are in sync.

Test: atest SystemUITests
Test: manual
Fixes: 184891081
Change-Id: I4d46fc6e1cefa45c0d718cc01f40c8f060dafee7
This commit is contained in:
Fabian Kozynski
2021-04-12 11:47:15 -04:00
parent 0190323cf1
commit 60864b944e
10 changed files with 252 additions and 61 deletions

View File

@@ -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);
}

View File

@@ -885,6 +885,24 @@ public final class PermissionManager {
return mUsageHelper.getOpUsageData(new AudioManager().isMicrophoneMute());
}
/**
* @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.

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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
}
}
}

View File

@@ -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)"

View File

@@ -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 {

View File

@@ -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
@@ -531,6 +543,40 @@ public class AppOpsControllerTest extends SysuiTestCase {
assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(micIdx).getCode());
}
@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},
@@ -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);

View File

@@ -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
)
}
@@ -142,19 +147,28 @@ class PrivacyDialogControllerTest : SysuiTestCase() {
dialogProvider.starter = null
}
@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 {

View File

@@ -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)