Merge "Do not hold indicators for apps that become paused" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
92716ec4ed
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user