Merge "Fixed that the camera will not be blocked on the virtual display in special cases" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ab0c667365
@@ -30,6 +30,8 @@ import android.util.Slog;
|
|||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles blocking access to the camera for apps running on virtual devices.
|
* Handles blocking access to the camera for apps running on virtual devices.
|
||||||
*/
|
*/
|
||||||
@@ -50,11 +52,23 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
|
|||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private ArrayMap<String, InjectionSessionData> mPackageToSessionData = new ArrayMap<>();
|
private ArrayMap<String, InjectionSessionData> mPackageToSessionData = new ArrayMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping from camera ID to open camera app associations. Key is the camera id, value is the
|
||||||
|
* information of the app's uid and package name.
|
||||||
|
*/
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private ArrayMap<String, OpenCameraInfo> mAppsToBlockOnVirtualDevice = new ArrayMap<>();
|
||||||
|
|
||||||
static class InjectionSessionData {
|
static class InjectionSessionData {
|
||||||
public int appUid;
|
public int appUid;
|
||||||
public ArrayMap<String, CameraInjectionSession> cameraIdToSession = new ArrayMap<>();
|
public ArrayMap<String, CameraInjectionSession> cameraIdToSession = new ArrayMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class OpenCameraInfo {
|
||||||
|
public String packageName;
|
||||||
|
public int packageUid;
|
||||||
|
}
|
||||||
|
|
||||||
interface CameraAccessBlockedCallback {
|
interface CameraAccessBlockedCallback {
|
||||||
/**
|
/**
|
||||||
* Called whenever an app was blocked from accessing a camera.
|
* Called whenever an app was blocked from accessing a camera.
|
||||||
@@ -98,6 +112,33 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Need to block camera access for applications running on virtual displays.
|
||||||
|
* <p>
|
||||||
|
* Apps that open the camera on the main display will need to block camera access if moved to a
|
||||||
|
* virtual display.
|
||||||
|
*
|
||||||
|
* @param runningUids uids of the application running on the virtual display
|
||||||
|
*/
|
||||||
|
public void blockCameraAccessIfNeeded(Set<Integer> runningUids) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
for (int i = 0; i < mAppsToBlockOnVirtualDevice.size(); i++) {
|
||||||
|
final String cameraId = mAppsToBlockOnVirtualDevice.keyAt(i);
|
||||||
|
final OpenCameraInfo openCameraInfo = mAppsToBlockOnVirtualDevice.get(cameraId);
|
||||||
|
int packageUid = openCameraInfo.packageUid;
|
||||||
|
if (runningUids.contains(packageUid)) {
|
||||||
|
final String packageName = openCameraInfo.packageName;
|
||||||
|
InjectionSessionData data = mPackageToSessionData.get(packageName);
|
||||||
|
if (data == null) {
|
||||||
|
data = new InjectionSessionData();
|
||||||
|
data.appUid = packageUid;
|
||||||
|
mPackageToSessionData.put(packageName, data);
|
||||||
|
}
|
||||||
|
startBlocking(packageName, cameraId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
@@ -115,10 +156,13 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
|
|||||||
public void onCameraOpened(@NonNull String cameraId, @NonNull String packageName) {
|
public void onCameraOpened(@NonNull String cameraId, @NonNull String packageName) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
try {
|
try {
|
||||||
final ApplicationInfo ainfo =
|
final ApplicationInfo ainfo = mPackageManager.getApplicationInfo(packageName, 0);
|
||||||
mPackageManager.getApplicationInfo(packageName, 0);
|
|
||||||
InjectionSessionData data = mPackageToSessionData.get(packageName);
|
InjectionSessionData data = mPackageToSessionData.get(packageName);
|
||||||
if (!mVirtualDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(ainfo.uid)) {
|
if (!mVirtualDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(ainfo.uid)) {
|
||||||
|
OpenCameraInfo openCameraInfo = new OpenCameraInfo();
|
||||||
|
openCameraInfo.packageName = packageName;
|
||||||
|
openCameraInfo.packageUid = ainfo.uid;
|
||||||
|
mAppsToBlockOnVirtualDevice.put(cameraId, openCameraInfo);
|
||||||
CameraInjectionSession existingSession =
|
CameraInjectionSession existingSession =
|
||||||
(data != null) ? data.cameraIdToSession.get(cameraId) : null;
|
(data != null) ? data.cameraIdToSession.get(cameraId) : null;
|
||||||
if (existingSession != null) {
|
if (existingSession != null) {
|
||||||
@@ -149,6 +193,7 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
|
|||||||
@Override
|
@Override
|
||||||
public void onCameraClosed(@NonNull String cameraId) {
|
public void onCameraClosed(@NonNull String cameraId) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
|
mAppsToBlockOnVirtualDevice.remove(cameraId);
|
||||||
for (int i = mPackageToSessionData.size() - 1; i >= 0; i--) {
|
for (int i = mPackageToSessionData.size() - 1; i >= 0; i--) {
|
||||||
InjectionSessionData data = mPackageToSessionData.valueAt(i);
|
InjectionSessionData data = mPackageToSessionData.valueAt(i);
|
||||||
CameraInjectionSession session = data.cameraIdToSession.get(cameraId);
|
CameraInjectionSession session = data.cameraIdToSession.get(cameraId);
|
||||||
@@ -168,6 +213,9 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
|
|||||||
*/
|
*/
|
||||||
private void startBlocking(String packageName, String cameraId) {
|
private void startBlocking(String packageName, String cameraId) {
|
||||||
try {
|
try {
|
||||||
|
Slog.d(
|
||||||
|
TAG,
|
||||||
|
"startBlocking() cameraId: " + cameraId + " packageName: " + packageName);
|
||||||
mCameraManager.injectCamera(packageName, cameraId, /* externalCamId */ "",
|
mCameraManager.injectCamera(packageName, cameraId, /* externalCamId */ "",
|
||||||
mContext.getMainExecutor(),
|
mContext.getMainExecutor(),
|
||||||
new CameraInjectionSession.InjectionStatusCallback() {
|
new CameraInjectionSession.InjectionStatusCallback() {
|
||||||
|
|||||||
@@ -93,9 +93,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
|
|||||||
final ArraySet<Integer> mRunningUids = new ArraySet<>();
|
final ArraySet<Integer> mRunningUids = new ArraySet<>();
|
||||||
@Nullable private final ActivityListener mActivityListener;
|
@Nullable private final ActivityListener mActivityListener;
|
||||||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||||
|
private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListener =
|
||||||
@Nullable
|
new ArraySet<>();
|
||||||
private RunningAppsChangedListener mRunningAppsChangedListener;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a window policy controller that is generic to the different use cases of virtual
|
* Creates a window policy controller that is generic to the different use cases of virtual
|
||||||
@@ -142,9 +141,14 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
|
|||||||
mActivityListener = activityListener;
|
mActivityListener = activityListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets listener for running applications change. */
|
/** Register a listener for running applications changes. */
|
||||||
public void setRunningAppsChangedListener(@Nullable RunningAppsChangedListener listener) {
|
public void registerRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
|
||||||
mRunningAppsChangedListener = listener;
|
mRunningAppsChangedListener.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Unregister a listener for running applications changes. */
|
||||||
|
public void unregisterRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
|
||||||
|
mRunningAppsChangedListener.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -237,9 +241,11 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
|
|||||||
mHandler.post(() -> mActivityListener.onDisplayEmpty(Display.INVALID_DISPLAY));
|
mHandler.post(() -> mActivityListener.onDisplayEmpty(Display.INVALID_DISPLAY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mRunningAppsChangedListener != null) {
|
mHandler.post(() -> {
|
||||||
mRunningAppsChangedListener.onRunningAppsChanged(runningUids);
|
for (RunningAppsChangedListener listener : mRunningAppsChangedListener) {
|
||||||
}
|
listener.onRunningAppsChanged(runningUids);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -68,16 +68,18 @@ import android.window.DisplayWindowPolicyController;
|
|||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.app.BlockedAppStreamingActivity;
|
import com.android.internal.app.BlockedAppStreamingActivity;
|
||||||
|
import com.android.server.companion.virtual.GenericWindowPolicyController.RunningAppsChangedListener;
|
||||||
import com.android.server.companion.virtual.audio.VirtualAudioController;
|
import com.android.server.companion.virtual.audio.VirtualAudioController;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
|
||||||
final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||||
implements IBinder.DeathRecipient {
|
implements IBinder.DeathRecipient, RunningAppsChangedListener {
|
||||||
|
|
||||||
private static final String TAG = "VirtualDeviceImpl";
|
private static final String TAG = "VirtualDeviceImpl";
|
||||||
|
|
||||||
@@ -101,6 +103,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
|||||||
private final VirtualDeviceParams mParams;
|
private final VirtualDeviceParams mParams;
|
||||||
private final Map<Integer, PowerManager.WakeLock> mPerDisplayWakelocks = new ArrayMap<>();
|
private final Map<Integer, PowerManager.WakeLock> mPerDisplayWakelocks = new ArrayMap<>();
|
||||||
private final IVirtualDeviceActivityListener mActivityListener;
|
private final IVirtualDeviceActivityListener mActivityListener;
|
||||||
|
@NonNull
|
||||||
|
private Consumer<ArraySet<Integer>> mRunningAppsChangedCallback;
|
||||||
// The default setting for showing the pointer on new displays.
|
// The default setting for showing the pointer on new displays.
|
||||||
@GuardedBy("mVirtualDeviceLock")
|
@GuardedBy("mVirtualDeviceLock")
|
||||||
private boolean mDefaultShowPointerIcon = true;
|
private boolean mDefaultShowPointerIcon = true;
|
||||||
@@ -139,21 +143,25 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
|||||||
IBinder token, int ownerUid, OnDeviceCloseListener listener,
|
IBinder token, int ownerUid, OnDeviceCloseListener listener,
|
||||||
PendingTrampolineCallback pendingTrampolineCallback,
|
PendingTrampolineCallback pendingTrampolineCallback,
|
||||||
IVirtualDeviceActivityListener activityListener,
|
IVirtualDeviceActivityListener activityListener,
|
||||||
|
Consumer<ArraySet<Integer>> runningAppsChangedCallback,
|
||||||
VirtualDeviceParams params) {
|
VirtualDeviceParams params) {
|
||||||
this(context, associationInfo, token, ownerUid, /* inputController= */ null, listener,
|
this(context, associationInfo, token, ownerUid, /* inputController= */ null, listener,
|
||||||
pendingTrampolineCallback, activityListener, params);
|
pendingTrampolineCallback, activityListener, runningAppsChangedCallback, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
VirtualDeviceImpl(Context context, AssociationInfo associationInfo, IBinder token,
|
VirtualDeviceImpl(Context context, AssociationInfo associationInfo, IBinder token,
|
||||||
int ownerUid, InputController inputController, OnDeviceCloseListener listener,
|
int ownerUid, InputController inputController, OnDeviceCloseListener listener,
|
||||||
PendingTrampolineCallback pendingTrampolineCallback,
|
PendingTrampolineCallback pendingTrampolineCallback,
|
||||||
IVirtualDeviceActivityListener activityListener, VirtualDeviceParams params) {
|
IVirtualDeviceActivityListener activityListener,
|
||||||
|
Consumer<ArraySet<Integer>> runningAppsChangedCallback,
|
||||||
|
VirtualDeviceParams params) {
|
||||||
UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(ownerUid);
|
UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(ownerUid);
|
||||||
mContext = context.createContextAsUser(ownerUserHandle, 0);
|
mContext = context.createContextAsUser(ownerUserHandle, 0);
|
||||||
mAssociationInfo = associationInfo;
|
mAssociationInfo = associationInfo;
|
||||||
mPendingTrampolineCallback = pendingTrampolineCallback;
|
mPendingTrampolineCallback = pendingTrampolineCallback;
|
||||||
mActivityListener = activityListener;
|
mActivityListener = activityListener;
|
||||||
|
mRunningAppsChangedCallback = runningAppsChangedCallback;
|
||||||
mOwnerUid = ownerUid;
|
mOwnerUid = ownerUid;
|
||||||
mAppToken = token;
|
mAppToken = token;
|
||||||
mParams = params;
|
mParams = params;
|
||||||
@@ -278,6 +286,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRunningAppsChanged(ArraySet<Integer> runningUids) {
|
||||||
|
mRunningAppsChangedCallback.accept(runningUids);
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
VirtualAudioController getVirtualAudioControllerForTesting() {
|
VirtualAudioController getVirtualAudioControllerForTesting() {
|
||||||
return mVirtualAudioController;
|
return mVirtualAudioController;
|
||||||
@@ -529,7 +542,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
|||||||
// reentrancy problems.
|
// reentrancy problems.
|
||||||
mContext.getMainThreadHandler().post(() -> addWakeLockForDisplay(displayId));
|
mContext.getMainThreadHandler().post(() -> addWakeLockForDisplay(displayId));
|
||||||
|
|
||||||
final GenericWindowPolicyController dwpc =
|
final GenericWindowPolicyController gwpc =
|
||||||
new GenericWindowPolicyController(FLAG_SECURE,
|
new GenericWindowPolicyController(FLAG_SECURE,
|
||||||
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
|
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
|
||||||
getAllowedUserHandles(),
|
getAllowedUserHandles(),
|
||||||
@@ -540,8 +553,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
|||||||
mParams.getDefaultActivityPolicy(),
|
mParams.getDefaultActivityPolicy(),
|
||||||
createListenerAdapter(displayId),
|
createListenerAdapter(displayId),
|
||||||
activityInfo -> onActivityBlocked(displayId, activityInfo));
|
activityInfo -> onActivityBlocked(displayId, activityInfo));
|
||||||
mWindowPolicyControllers.put(displayId, dwpc);
|
gwpc.registerRunningAppsChangedListener(/* listener= */ this);
|
||||||
return dwpc;
|
mWindowPolicyControllers.put(displayId, gwpc);
|
||||||
|
return gwpc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,6 +613,10 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
|||||||
wakeLock.release();
|
wakeLock.release();
|
||||||
mPerDisplayWakelocks.remove(displayId);
|
mPerDisplayWakelocks.remove(displayId);
|
||||||
}
|
}
|
||||||
|
GenericWindowPolicyController gwpc = mWindowPolicyControllers.get(displayId);
|
||||||
|
if (gwpc != null) {
|
||||||
|
gwpc.unregisterRunningAppsChangedListener(/* listener= */ this);
|
||||||
|
}
|
||||||
mVirtualDisplayIds.remove(displayId);
|
mVirtualDisplayIds.remove(displayId);
|
||||||
mWindowPolicyControllers.remove(displayId);
|
mWindowPolicyControllers.remove(displayId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,7 +251,10 @@ public class VirtualDeviceManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
this, activityListener, params);
|
this, activityListener,
|
||||||
|
runningUids -> cameraAccessController.blockCameraAccessIfNeeded(
|
||||||
|
runningUids),
|
||||||
|
params);
|
||||||
if (cameraAccessController != null) {
|
if (cameraAccessController != null) {
|
||||||
cameraAccessController.startObservingIfNeeded();
|
cameraAccessController.startObservingIfNeeded();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public final class VirtualAudioController implements AudioPlaybackCallback,
|
|||||||
@NonNull IAudioRoutingCallback routingCallback,
|
@NonNull IAudioRoutingCallback routingCallback,
|
||||||
@Nullable IAudioConfigChangedCallback configChangedCallback) {
|
@Nullable IAudioConfigChangedCallback configChangedCallback) {
|
||||||
mGenericWindowPolicyController = genericWindowPolicyController;
|
mGenericWindowPolicyController = genericWindowPolicyController;
|
||||||
mGenericWindowPolicyController.setRunningAppsChangedListener(/* listener= */ this);
|
mGenericWindowPolicyController.registerRunningAppsChangedListener(/* listener= */ this);
|
||||||
synchronized (mCallbackLock) {
|
synchronized (mCallbackLock) {
|
||||||
mRoutingCallback = routingCallback;
|
mRoutingCallback = routingCallback;
|
||||||
mConfigChangedCallback = configChangedCallback;
|
mConfigChangedCallback = configChangedCallback;
|
||||||
@@ -111,7 +111,8 @@ public final class VirtualAudioController implements AudioPlaybackCallback,
|
|||||||
mAudioPlaybackDetector.unregister();
|
mAudioPlaybackDetector.unregister();
|
||||||
mAudioRecordingDetector.unregister();
|
mAudioRecordingDetector.unregister();
|
||||||
if (mGenericWindowPolicyController != null) {
|
if (mGenericWindowPolicyController != null) {
|
||||||
mGenericWindowPolicyController.setRunningAppsChangedListener(/* listener= */ null);
|
mGenericWindowPolicyController.unregisterRunningAppsChangedListener(
|
||||||
|
/* listener= */ this);
|
||||||
mGenericWindowPolicyController = null;
|
mGenericWindowPolicyController = null;
|
||||||
}
|
}
|
||||||
synchronized (mCallbackLock) {
|
synchronized (mCallbackLock) {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.anyString;
|
|||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ import android.hardware.camera2.CameraInjectionSession;
|
|||||||
import android.hardware.camera2.CameraManager;
|
import android.hardware.camera2.CameraManager;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.testing.TestableContext;
|
import android.testing.TestableContext;
|
||||||
|
import android.util.ArraySet;
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
@@ -73,11 +75,11 @@ public class CameraAccessControllerTest {
|
|||||||
|
|
||||||
private ApplicationInfo mTestAppInfo = new ApplicationInfo();
|
private ApplicationInfo mTestAppInfo = new ApplicationInfo();
|
||||||
private ApplicationInfo mOtherAppInfo = new ApplicationInfo();
|
private ApplicationInfo mOtherAppInfo = new ApplicationInfo();
|
||||||
|
private ArraySet<Integer> mRunningUids = new ArraySet<>();
|
||||||
|
|
||||||
@Captor
|
@Captor
|
||||||
ArgumentCaptor<CameraInjectionSession.InjectionStatusCallback> mInjectionCallbackCaptor;
|
ArgumentCaptor<CameraInjectionSession.InjectionStatusCallback> mInjectionCallbackCaptor;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws PackageManager.NameNotFoundException {
|
public void setUp() throws PackageManager.NameNotFoundException {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
@@ -89,6 +91,7 @@ public class CameraAccessControllerTest {
|
|||||||
mBlockedCallback);
|
mBlockedCallback);
|
||||||
mTestAppInfo.uid = Process.FIRST_APPLICATION_UID;
|
mTestAppInfo.uid = Process.FIRST_APPLICATION_UID;
|
||||||
mOtherAppInfo.uid = Process.FIRST_APPLICATION_UID + 1;
|
mOtherAppInfo.uid = Process.FIRST_APPLICATION_UID + 1;
|
||||||
|
mRunningUids.add(Process.FIRST_APPLICATION_UID);
|
||||||
when(mPackageManager.getApplicationInfo(eq(TEST_APP_PACKAGE), anyInt())).thenReturn(
|
when(mPackageManager.getApplicationInfo(eq(TEST_APP_PACKAGE), anyInt())).thenReturn(
|
||||||
mTestAppInfo);
|
mTestAppInfo);
|
||||||
when(mPackageManager.getApplicationInfo(eq(OTHER_APP_PACKAGE), anyInt())).thenReturn(
|
when(mPackageManager.getApplicationInfo(eq(OTHER_APP_PACKAGE), anyInt())).thenReturn(
|
||||||
@@ -104,7 +107,6 @@ public class CameraAccessControllerTest {
|
|||||||
verify(mCameraManager, never()).injectCamera(any(), any(), any(), any(), any());
|
verify(mCameraManager, never()).injectCamera(any(), any(), any(), any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onCameraOpened_uidRunning_cameraBlocked() throws CameraAccessException {
|
public void onCameraOpened_uidRunning_cameraBlocked() throws CameraAccessException {
|
||||||
when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
|
when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
|
||||||
@@ -128,7 +130,6 @@ public class CameraAccessControllerTest {
|
|||||||
verify(session).close();
|
verify(session).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onCameraClosed_otherCameraClosed_cameraNotUnblocked() throws CameraAccessException {
|
public void onCameraClosed_otherCameraClosed_cameraNotUnblocked() throws CameraAccessException {
|
||||||
when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
|
when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
|
||||||
@@ -197,4 +198,33 @@ public class CameraAccessControllerTest {
|
|||||||
mInjectionCallbackCaptor.getValue().onInjectionError(ERROR_INJECTION_UNSUPPORTED);
|
mInjectionCallbackCaptor.getValue().onInjectionError(ERROR_INJECTION_UNSUPPORTED);
|
||||||
verify(mBlockedCallback).onCameraAccessBlocked(eq(mTestAppInfo.uid));
|
verify(mBlockedCallback).onCameraAccessBlocked(eq(mTestAppInfo.uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void twoCameraAccessesBySameUid_secondOnVirtualDisplay_noCallbackButCameraCanBlocked()
|
||||||
|
throws CameraAccessException {
|
||||||
|
when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
|
||||||
|
eq(mTestAppInfo.uid))).thenReturn(false);
|
||||||
|
mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
|
||||||
|
mController.blockCameraAccessIfNeeded(mRunningUids);
|
||||||
|
|
||||||
|
verify(mCameraManager).injectCamera(eq(TEST_APP_PACKAGE), eq(FRONT_CAMERA), anyString(),
|
||||||
|
any(), mInjectionCallbackCaptor.capture());
|
||||||
|
CameraInjectionSession session = mock(CameraInjectionSession.class);
|
||||||
|
mInjectionCallbackCaptor.getValue().onInjectionSucceeded(session);
|
||||||
|
mInjectionCallbackCaptor.getValue().onInjectionError(ERROR_INJECTION_UNSUPPORTED);
|
||||||
|
verify(mBlockedCallback).onCameraAccessBlocked(eq(mTestAppInfo.uid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void twoCameraAccessesBySameUid_secondOnVirtualDisplay_firstCloseThenOpenCameraUnblock()
|
||||||
|
throws CameraAccessException {
|
||||||
|
when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
|
||||||
|
eq(mTestAppInfo.uid))).thenReturn(false);
|
||||||
|
mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
|
||||||
|
mController.blockCameraAccessIfNeeded(mRunningUids);
|
||||||
|
mController.onCameraClosed(FRONT_CAMERA);
|
||||||
|
mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
|
||||||
|
|
||||||
|
verify(mCameraManager, times(1)).injectCamera(any(), any(), any(), any(), any());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ import org.mockito.MockitoAnnotations;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@Presubmit
|
@Presubmit
|
||||||
@RunWith(AndroidTestingRunner.class)
|
@RunWith(AndroidTestingRunner.class)
|
||||||
@@ -133,6 +134,8 @@ public class VirtualDeviceManagerServiceTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private IVirtualDeviceActivityListener mActivityListener;
|
private IVirtualDeviceActivityListener mActivityListener;
|
||||||
@Mock
|
@Mock
|
||||||
|
private Consumer<ArraySet<Integer>> mRunningAppsChangedCallback;
|
||||||
|
@Mock
|
||||||
IPowerManager mIPowerManagerMock;
|
IPowerManager mIPowerManagerMock;
|
||||||
@Mock
|
@Mock
|
||||||
IThermalService mIThermalServiceMock;
|
IThermalService mIThermalServiceMock;
|
||||||
@@ -207,7 +210,7 @@ public class VirtualDeviceManagerServiceTest {
|
|||||||
mDeviceImpl = new VirtualDeviceImpl(mContext,
|
mDeviceImpl = new VirtualDeviceImpl(mContext,
|
||||||
mAssociationInfo, new Binder(), /* uid */ 0, mInputController,
|
mAssociationInfo, new Binder(), /* uid */ 0, mInputController,
|
||||||
(int associationId) -> {
|
(int associationId) -> {
|
||||||
}, mPendingTrampolineCallback, mActivityListener,
|
}, mPendingTrampolineCallback, mActivityListener, mRunningAppsChangedCallback,
|
||||||
params);
|
params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user