Merge "Do not hold indicators for apps that become paused" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-04-15 21:35:10 +00:00
committed by Android (Google) Code Review
10 changed files with 252 additions and 61 deletions

View File

@@ -2010,6 +2010,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)