Merge "Hide indicators when camera/mic disabled" into sc-dev
This commit is contained in:
@@ -26,8 +26,7 @@ public class AppOpItem {
|
|||||||
private String mPackageName;
|
private String mPackageName;
|
||||||
private long mTimeStarted;
|
private long mTimeStarted;
|
||||||
private StringBuilder mState;
|
private StringBuilder mState;
|
||||||
// This is only used for items with mCode == AppOpsManager.OP_RECORD_AUDIO
|
private boolean mIsDisabled;
|
||||||
private boolean mSilenced;
|
|
||||||
|
|
||||||
public AppOpItem(int code, int uid, String packageName, long timeStarted) {
|
public AppOpItem(int code, int uid, String packageName, long timeStarted) {
|
||||||
this.mCode = code;
|
this.mCode = code;
|
||||||
@@ -58,16 +57,16 @@ public class AppOpItem {
|
|||||||
return mTimeStarted;
|
return mTimeStarted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSilenced(boolean silenced) {
|
public void setDisabled(boolean misDisabled) {
|
||||||
mSilenced = silenced;
|
this.mIsDisabled = misDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSilenced() {
|
public boolean isDisabled() {
|
||||||
return mSilenced;
|
return mIsDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return mState.append(mSilenced).append(")").toString();
|
return mState.append(mIsDisabled).append(")").toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.systemui.appops;
|
package com.android.systemui.appops;
|
||||||
|
|
||||||
|
import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
|
||||||
|
import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
|
||||||
import static android.media.AudioManager.ACTION_MICROPHONE_MUTE_CHANGED;
|
import static android.media.AudioManager.ACTION_MICROPHONE_MUTE_CHANGED;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
@@ -45,6 +47,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
|
|||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
import com.android.systemui.dagger.qualifiers.Background;
|
import com.android.systemui.dagger.qualifiers.Background;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
|
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
|
||||||
import com.android.systemui.util.Assert;
|
import com.android.systemui.util.Assert;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
@@ -64,7 +67,8 @@ import javax.inject.Inject;
|
|||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsController,
|
public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsController,
|
||||||
AppOpsManager.OnOpActiveChangedInternalListener,
|
AppOpsManager.OnOpActiveChangedInternalListener,
|
||||||
AppOpsManager.OnOpNotedListener, Dumpable {
|
AppOpsManager.OnOpNotedListener, IndividualSensorPrivacyController.Callback,
|
||||||
|
Dumpable {
|
||||||
|
|
||||||
// This is the minimum time that we will keep AppOps that are noted on record. If multiple
|
// This is the minimum time that we will keep AppOps that are noted on record. If multiple
|
||||||
// occurrences of the same (op, package, uid) happen in a shorter interval, they will not be
|
// occurrences of the same (op, package, uid) happen in a shorter interval, they will not be
|
||||||
@@ -77,8 +81,8 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
|
|||||||
private final AppOpsManager mAppOps;
|
private final AppOpsManager mAppOps;
|
||||||
private final AudioManager mAudioManager;
|
private final AudioManager mAudioManager;
|
||||||
private final LocationManager mLocationManager;
|
private final LocationManager mLocationManager;
|
||||||
// TODO ntmyren: remove t
|
|
||||||
private final PackageManager mPackageManager;
|
private final PackageManager mPackageManager;
|
||||||
|
private final IndividualSensorPrivacyController mSensorPrivacyController;
|
||||||
|
|
||||||
// mLocationProviderPackages are cached and updated only occasionally
|
// mLocationProviderPackages are cached and updated only occasionally
|
||||||
private static final long LOCATION_PROVIDER_UPDATE_FREQUENCY_MS = 30000;
|
private static final long LOCATION_PROVIDER_UPDATE_FREQUENCY_MS = 30000;
|
||||||
@@ -91,6 +95,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
|
|||||||
private final PermissionFlagsCache mFlagsCache;
|
private final PermissionFlagsCache mFlagsCache;
|
||||||
private boolean mListening;
|
private boolean mListening;
|
||||||
private boolean mMicMuted;
|
private boolean mMicMuted;
|
||||||
|
private boolean mCameraDisabled;
|
||||||
|
|
||||||
@GuardedBy("mActiveItems")
|
@GuardedBy("mActiveItems")
|
||||||
private final List<AppOpItem> mActiveItems = new ArrayList<>();
|
private final List<AppOpItem> mActiveItems = new ArrayList<>();
|
||||||
@@ -118,6 +123,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
|
|||||||
DumpManager dumpManager,
|
DumpManager dumpManager,
|
||||||
PermissionFlagsCache cache,
|
PermissionFlagsCache cache,
|
||||||
AudioManager audioManager,
|
AudioManager audioManager,
|
||||||
|
IndividualSensorPrivacyController sensorPrivacyController,
|
||||||
BroadcastDispatcher dispatcher
|
BroadcastDispatcher dispatcher
|
||||||
) {
|
) {
|
||||||
mDispatcher = dispatcher;
|
mDispatcher = dispatcher;
|
||||||
@@ -129,7 +135,10 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
|
|||||||
mCallbacksByCode.put(OPS[i], new ArraySet<>());
|
mCallbacksByCode.put(OPS[i], new ArraySet<>());
|
||||||
}
|
}
|
||||||
mAudioManager = audioManager;
|
mAudioManager = audioManager;
|
||||||
mMicMuted = audioManager.isMicrophoneMute();
|
mSensorPrivacyController = sensorPrivacyController;
|
||||||
|
mMicMuted = audioManager.isMicrophoneMute()
|
||||||
|
|| mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
|
||||||
|
mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
|
||||||
mLocationManager = context.getSystemService(LocationManager.class);
|
mLocationManager = context.getSystemService(LocationManager.class);
|
||||||
mPackageManager = context.getPackageManager();
|
mPackageManager = context.getPackageManager();
|
||||||
dumpManager.registerDumpable(TAG, this);
|
dumpManager.registerDumpable(TAG, this);
|
||||||
@@ -147,6 +156,12 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
|
|||||||
mAppOps.startWatchingActive(OPS, this);
|
mAppOps.startWatchingActive(OPS, this);
|
||||||
mAppOps.startWatchingNoted(OPS, this);
|
mAppOps.startWatchingNoted(OPS, this);
|
||||||
mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler);
|
mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler);
|
||||||
|
mSensorPrivacyController.addCallback(this);
|
||||||
|
|
||||||
|
mMicMuted = mAudioManager.isMicrophoneMute()
|
||||||
|
|| mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
|
||||||
|
mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
|
||||||
|
|
||||||
mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged(
|
mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged(
|
||||||
mAudioManager.getActiveRecordingConfigurations()));
|
mAudioManager.getActiveRecordingConfigurations()));
|
||||||
mDispatcher.registerReceiverWithHandler(this,
|
mDispatcher.registerReceiverWithHandler(this,
|
||||||
@@ -156,6 +171,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
|
|||||||
mAppOps.stopWatchingActive(this);
|
mAppOps.stopWatchingActive(this);
|
||||||
mAppOps.stopWatchingNoted(this);
|
mAppOps.stopWatchingNoted(this);
|
||||||
mAudioManager.unregisterAudioRecordingCallback(mAudioRecordingCallback);
|
mAudioManager.unregisterAudioRecordingCallback(mAudioRecordingCallback);
|
||||||
|
mSensorPrivacyController.removeCallback(this);
|
||||||
|
|
||||||
mBGHandler.removeCallbacksAndMessages(null); // null removes all
|
mBGHandler.removeCallbacksAndMessages(null); // null removes all
|
||||||
mDispatcher.unregisterReceiver(this);
|
mDispatcher.unregisterReceiver(this);
|
||||||
@@ -235,11 +251,13 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
|
|||||||
if (item == null && active) {
|
if (item == null && active) {
|
||||||
item = new AppOpItem(code, uid, packageName, System.currentTimeMillis());
|
item = new AppOpItem(code, uid, packageName, System.currentTimeMillis());
|
||||||
if (code == AppOpsManager.OP_RECORD_AUDIO) {
|
if (code == AppOpsManager.OP_RECORD_AUDIO) {
|
||||||
item.setSilenced(isAnyRecordingPausedLocked(uid));
|
item.setDisabled(isAnyRecordingPausedLocked(uid));
|
||||||
|
} else if (code == AppOpsManager.OP_CAMERA) {
|
||||||
|
item.setDisabled(mCameraDisabled);
|
||||||
}
|
}
|
||||||
mActiveItems.add(item);
|
mActiveItems.add(item);
|
||||||
if (DEBUG) Log.w(TAG, "Added item: " + item.toString());
|
if (DEBUG) Log.w(TAG, "Added item: " + item.toString());
|
||||||
return !item.isSilenced();
|
return !item.isDisabled();
|
||||||
} else if (item != null && !active) {
|
} else if (item != null && !active) {
|
||||||
mActiveItems.remove(item);
|
mActiveItems.remove(item);
|
||||||
if (DEBUG) Log.w(TAG, "Removed item: " + item.toString());
|
if (DEBUG) Log.w(TAG, "Removed item: " + item.toString());
|
||||||
@@ -409,7 +427,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
|
|||||||
AppOpItem item = mActiveItems.get(i);
|
AppOpItem item = mActiveItems.get(i);
|
||||||
if ((userId == UserHandle.USER_ALL
|
if ((userId == UserHandle.USER_ALL
|
||||||
|| UserHandle.getUserId(item.getUid()) == userId)
|
|| UserHandle.getUserId(item.getUid()) == userId)
|
||||||
&& isUserVisible(item) && !item.isSilenced()) {
|
&& isUserVisible(item) && !item.isDisabled()) {
|
||||||
list.add(item);
|
list.add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -512,22 +530,27 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateRecordingPausedStatus() {
|
private void updateSensorDisabledStatus() {
|
||||||
synchronized (mActiveItems) {
|
synchronized (mActiveItems) {
|
||||||
int size = mActiveItems.size();
|
int size = mActiveItems.size();
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
AppOpItem item = mActiveItems.get(i);
|
AppOpItem item = mActiveItems.get(i);
|
||||||
|
|
||||||
|
boolean paused = false;
|
||||||
if (item.getCode() == AppOpsManager.OP_RECORD_AUDIO) {
|
if (item.getCode() == AppOpsManager.OP_RECORD_AUDIO) {
|
||||||
boolean paused = isAnyRecordingPausedLocked(item.getUid());
|
paused = isAnyRecordingPausedLocked(item.getUid());
|
||||||
if (item.isSilenced() != paused) {
|
} else if (item.getCode() == AppOpsManager.OP_CAMERA) {
|
||||||
item.setSilenced(paused);
|
paused = mCameraDisabled;
|
||||||
notifySuscribers(
|
}
|
||||||
item.getCode(),
|
|
||||||
item.getUid(),
|
if (item.isDisabled() != paused) {
|
||||||
item.getPackageName(),
|
item.setDisabled(paused);
|
||||||
!item.isSilenced()
|
notifySuscribers(
|
||||||
);
|
item.getCode(),
|
||||||
}
|
item.getUid(),
|
||||||
|
item.getPackageName(),
|
||||||
|
!item.isDisabled()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -552,14 +575,27 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
|
|||||||
recordings.add(recording);
|
recordings.add(recording);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateRecordingPausedStatus();
|
updateSensorDisabledStatus();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
mMicMuted = mAudioManager.isMicrophoneMute();
|
mMicMuted = mAudioManager.isMicrophoneMute()
|
||||||
updateRecordingPausedStatus();
|
|| mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
|
||||||
|
updateSensorDisabledStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSensorBlockedChanged(int sensor, boolean blocked) {
|
||||||
|
mBGHandler.post(() -> {
|
||||||
|
if (sensor == INDIVIDUAL_SENSOR_CAMERA) {
|
||||||
|
mCameraDisabled = blocked;
|
||||||
|
} else if (sensor == INDIVIDUAL_SENSOR_MICROPHONE) {
|
||||||
|
mMicMuted = mAudioManager.isMicrophoneMute() || blocked;
|
||||||
|
}
|
||||||
|
updateSensorDisabledStatus();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class H extends Handler {
|
protected class H extends Handler {
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.policy;
|
package com.android.systemui.statusbar.policy;
|
||||||
|
|
||||||
import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
|
import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
|
||||||
import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
|
import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
|
||||||
|
|
||||||
import android.hardware.SensorPrivacyManager;
|
import android.hardware.SensorPrivacyManager;
|
||||||
import android.hardware.SensorPrivacyManager.IndividualSensor;
|
import android.hardware.SensorPrivacyManager.IndividualSensor;
|
||||||
@@ -30,7 +30,8 @@ import java.util.Set;
|
|||||||
|
|
||||||
public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPrivacyController {
|
public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPrivacyController {
|
||||||
|
|
||||||
private static final int[] SENSORS = new int[] {CAMERA, MICROPHONE};
|
private static final int[] SENSORS = new int[] {INDIVIDUAL_SENSOR_CAMERA,
|
||||||
|
INDIVIDUAL_SENSOR_MICROPHONE};
|
||||||
|
|
||||||
private final @NonNull SensorPrivacyManager mSensorPrivacyManager;
|
private final @NonNull SensorPrivacyManager mSensorPrivacyManager;
|
||||||
private final SparseBooleanArray mState = new SparseBooleanArray();
|
private final SparseBooleanArray mState = new SparseBooleanArray();
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.android.systemui.appops;
|
package com.android.systemui.appops;
|
||||||
|
|
||||||
|
import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
|
||||||
|
import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertFalse;
|
import static junit.framework.TestCase.assertFalse;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -49,6 +52,7 @@ import androidx.test.filters.SmallTest;
|
|||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
|
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -81,6 +85,8 @@ public class AppOpsControllerTest extends SysuiTestCase {
|
|||||||
private PermissionFlagsCache mFlagsCache;
|
private PermissionFlagsCache mFlagsCache;
|
||||||
@Mock
|
@Mock
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
|
@Mock
|
||||||
|
private IndividualSensorPrivacyController mSensorPrivacyController;
|
||||||
@Mock(stubOnly = true)
|
@Mock(stubOnly = true)
|
||||||
private AudioManager mAudioManager;
|
private AudioManager mAudioManager;
|
||||||
@Mock()
|
@Mock()
|
||||||
@@ -118,12 +124,18 @@ public class AppOpsControllerTest extends SysuiTestCase {
|
|||||||
when(mAudioManager.getActiveRecordingConfigurations())
|
when(mAudioManager.getActiveRecordingConfigurations())
|
||||||
.thenReturn(List.of(mPausedMockRecording));
|
.thenReturn(List.of(mPausedMockRecording));
|
||||||
|
|
||||||
|
when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
|
||||||
|
.thenReturn(false);
|
||||||
|
when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
|
||||||
|
.thenReturn(false);
|
||||||
|
|
||||||
mController = new AppOpsControllerImpl(
|
mController = new AppOpsControllerImpl(
|
||||||
mContext,
|
mContext,
|
||||||
mTestableLooper.getLooper(),
|
mTestableLooper.getLooper(),
|
||||||
mDumpManager,
|
mDumpManager,
|
||||||
mFlagsCache,
|
mFlagsCache,
|
||||||
mAudioManager,
|
mAudioManager,
|
||||||
|
mSensorPrivacyController,
|
||||||
mDispatcher
|
mDispatcher
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -133,6 +145,7 @@ public class AppOpsControllerTest extends SysuiTestCase {
|
|||||||
mController.setListening(true);
|
mController.setListening(true);
|
||||||
verify(mAppOpsManager, times(1)).startWatchingActive(AppOpsControllerImpl.OPS, mController);
|
verify(mAppOpsManager, times(1)).startWatchingActive(AppOpsControllerImpl.OPS, mController);
|
||||||
verify(mDispatcher, times(1)).registerReceiverWithHandler(eq(mController), any(), any());
|
verify(mDispatcher, times(1)).registerReceiverWithHandler(eq(mController), any(), any());
|
||||||
|
verify(mSensorPrivacyController, times(1)).addCallback(mController);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -140,6 +153,7 @@ public class AppOpsControllerTest extends SysuiTestCase {
|
|||||||
mController.setListening(false);
|
mController.setListening(false);
|
||||||
verify(mAppOpsManager, times(1)).stopWatchingActive(mController);
|
verify(mAppOpsManager, times(1)).stopWatchingActive(mController);
|
||||||
verify(mDispatcher, times(1)).unregisterReceiver(mController);
|
verify(mDispatcher, times(1)).unregisterReceiver(mController);
|
||||||
|
verify(mSensorPrivacyController, times(1)).removeCallback(mController);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -476,6 +490,71 @@ public class AppOpsControllerTest extends SysuiTestCase {
|
|||||||
AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, false);
|
AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAudioFilteredWhenMicDisabled() {
|
||||||
|
mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA},
|
||||||
|
mCallback);
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
|
mController.onOpActiveChanged(
|
||||||
|
AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
|
List<AppOpItem> list = mController.getActiveAppOps();
|
||||||
|
assertEquals(1, list.size());
|
||||||
|
assertEquals(AppOpsManager.OP_RECORD_AUDIO, 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(INDIVIDUAL_SENSOR_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(INDIVIDUAL_SENSOR_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_RECORD_AUDIO, list.get(micIdx).getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCameraFilteredWhenCameraDisabled() {
|
||||||
|
mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_CAMERA},
|
||||||
|
mCallback);
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
|
mController.onOpActiveChanged(
|
||||||
|
AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
|
List<AppOpItem> list = mController.getActiveAppOps();
|
||||||
|
assertEquals(1, list.size());
|
||||||
|
assertEquals(AppOpsManager.OP_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(INDIVIDUAL_SENSOR_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(INDIVIDUAL_SENSOR_CAMERA, false);
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
|
|
||||||
|
list = mController.getActiveAppOps();
|
||||||
|
assertEquals(2, list.size());
|
||||||
|
int cameraIdx = list.get(0).getCode() == AppOpsManager.OP_CAMERA ? 0 : 1;
|
||||||
|
assertEquals(AppOpsManager.OP_CAMERA, list.get(cameraIdx).getCode());
|
||||||
|
}
|
||||||
|
|
||||||
private class TestHandler extends AppOpsControllerImpl.H {
|
private class TestHandler extends AppOpsControllerImpl.H {
|
||||||
TestHandler(Looper looper) {
|
TestHandler(Looper looper) {
|
||||||
mController.super(looper);
|
mController.super(looper);
|
||||||
|
|||||||
Reference in New Issue
Block a user