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