From bbbb94315ece18a1fd710305638bd0cf7b80e972 Mon Sep 17 00:00:00 2001 From: Mary Xia Date: Mon, 10 Oct 2022 13:29:30 +0000 Subject: [PATCH] Declare new display category and enforce equality match with activity attribute in GWPC Bug:233910285 Test: atest RestrictActivityTest Change-Id: I0452fe45d5d5ba360bbfbe4a15586fcea68d2216 --- core/api/system-current.txt | 1 + .../virtual/VirtualDeviceManager.java | 64 +++++++++- .../display/VirtualDisplayConfig.java | 66 +++++++++- .../GenericWindowPolicyController.java | 26 +++- .../companion/virtual/VirtualDeviceImpl.java | 7 +- .../virtual/VirtualDeviceManagerService.java | 3 +- .../VirtualDeviceManagerServiceTest.java | 119 ++++++++++++++---- .../audio/VirtualAudioControllerTest.java | 31 ++--- 8 files changed, 263 insertions(+), 54 deletions(-) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index e1146b9035532..b32b3b69112a3 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2958,6 +2958,7 @@ package android.companion.virtual { method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close(); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback); method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback); + method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @NonNull java.util.List, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualDpad createVirtualDpad(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index c14bb1beb0252..91547016df8a5 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -350,14 +350,72 @@ public final class VirtualDeviceManager { @VirtualDisplayFlag int flags, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback) { - // TODO(b/205343547): Handle display groups properly instead of creating a new display - // group for every new virtual display created using this API. - // belongs to the same display group. VirtualDisplayConfig config = new VirtualDisplayConfig.Builder( getVirtualDisplayName(), width, height, densityDpi) .setSurface(surface) .setFlags(getVirtualDisplayFlags(flags)) .build(); + return createVirtualDisplayInternal(config, executor, callback); + } + + /** + * Creates a virtual display for this virtual device. All displays created on the same + * device belongs to the same display group. + * + * @param width The width of the virtual display in pixels, must be greater than 0. + * @param height The height of the virtual display in pixels, must be greater than 0. + * @param densityDpi The density of the virtual display in dpi, must be greater than 0. + * @param displayCategories The categories of the virtual display, indicating the type of + * activities allowed to run on the display. Activities can declare their type using + * {@link android.content.pm.ActivityInfo#targetDisplayCategory}. + * @param surface The surface to which the content of the virtual display should + * be rendered, or null if there is none initially. The surface can also be set later using + * {@link VirtualDisplay#setSurface(Surface)}. + * @param flags A combination of virtual display flags accepted by + * {@link DisplayManager#createVirtualDisplay}. In addition, the following flags are + * automatically set for all virtual devices: + * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC VIRTUAL_DISPLAY_FLAG_PUBLIC} and + * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY + * VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}. + * @param executor The executor on which {@code callback} will be invoked. This is ignored + * if {@code callback} is {@code null}. If {@code callback} is specified, this executor must + * not be null. + * @param callback Callback to call when the state of the {@link VirtualDisplay} changes + * @return The newly created virtual display, or {@code null} if the application could + * not create the virtual display. + * + * @see DisplayManager#createVirtualDisplay + */ + @Nullable + public VirtualDisplay createVirtualDisplay( + @IntRange(from = 1) int width, + @IntRange(from = 1) int height, + @IntRange(from = 1) int densityDpi, + @NonNull List displayCategories, + @Nullable Surface surface, + @VirtualDisplayFlag int flags, + @Nullable @CallbackExecutor Executor executor, + @Nullable VirtualDisplay.Callback callback) { + VirtualDisplayConfig config = new VirtualDisplayConfig.Builder( + getVirtualDisplayName(), width, height, densityDpi) + .setDisplayCategories(displayCategories) + .setSurface(surface) + .setFlags(getVirtualDisplayFlags(flags)) + .build(); + return createVirtualDisplayInternal(config, executor, callback); + } + + /** + * @hide + */ + @Nullable + private VirtualDisplay createVirtualDisplayInternal( + @NonNull VirtualDisplayConfig config, + @Nullable @CallbackExecutor Executor executor, + @Nullable VirtualDisplay.Callback callback) { + // TODO(b/205343547): Handle display groups properly instead of creating a new display + // group for every new virtual display created using this API. + // belongs to the same display group. IVirtualDisplayCallback callbackWrapper = new DisplayManagerGlobal.VirtualDisplayCallback(callback, executor); final int displayId; diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java index b76b98d3c37a1..891ba364db2fd 100644 --- a/core/java/android/hardware/display/VirtualDisplayConfig.java +++ b/core/java/android/hardware/display/VirtualDisplayConfig.java @@ -30,6 +30,9 @@ import android.view.Surface; import com.android.internal.util.DataClass; +import java.util.ArrayList; +import java.util.List; + /** * Holds configuration used to create {@link VirtualDisplay} instances. See * {@link MediaProjection#createVirtualDisplay(VirtualDisplayConfig, VirtualDisplay.Callback, Handler)}. @@ -99,6 +102,13 @@ public final class VirtualDisplayConfig implements Parcelable { */ private boolean mWindowManagerMirroring = false; + /** + * The display categories. If set, only corresponding activities from the same category can be + * shown on the display. + */ + @DataClass.PluralOf("displayCategory") + @NonNull private List mDisplayCategories = new ArrayList<>(); + // Code below generated by codegen v1.0.23. @@ -124,7 +134,8 @@ public final class VirtualDisplayConfig implements Parcelable { @Nullable Surface surface, @Nullable String uniqueId, int displayIdToMirror, - boolean windowManagerMirroring) { + boolean windowManagerMirroring, + @NonNull List displayCategories) { this.mName = name; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mName); @@ -147,6 +158,9 @@ public final class VirtualDisplayConfig implements Parcelable { this.mUniqueId = uniqueId; this.mDisplayIdToMirror = displayIdToMirror; this.mWindowManagerMirroring = windowManagerMirroring; + this.mDisplayCategories = displayCategories; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mDisplayCategories); // onConstructed(); // You can define this method to get a callback } @@ -233,6 +247,15 @@ public final class VirtualDisplayConfig implements Parcelable { return mWindowManagerMirroring; } + /** + * The display categories. If set, only corresponding activities from the same category can be + * shown on the display. + */ + @DataClass.Generated.Member + public @NonNull List getDisplayCategories() { + return mDisplayCategories; + } + @Override @DataClass.Generated.Member public void writeToParcel(@NonNull Parcel dest, int flags) { @@ -252,6 +275,7 @@ public final class VirtualDisplayConfig implements Parcelable { if (mSurface != null) dest.writeTypedObject(mSurface, flags); if (mUniqueId != null) dest.writeString(mUniqueId); dest.writeInt(mDisplayIdToMirror); + dest.writeStringList(mDisplayCategories); } @Override @@ -275,6 +299,8 @@ public final class VirtualDisplayConfig implements Parcelable { Surface surface = (flg & 0x20) == 0 ? null : (Surface) in.readTypedObject(Surface.CREATOR); String uniqueId = (flg & 0x40) == 0 ? null : in.readString(); int displayIdToMirror = in.readInt(); + List displayCategories = new ArrayList<>(); + in.readStringList(displayCategories); this.mName = name; com.android.internal.util.AnnotationValidations.validate( @@ -298,6 +324,9 @@ public final class VirtualDisplayConfig implements Parcelable { this.mUniqueId = uniqueId; this.mDisplayIdToMirror = displayIdToMirror; this.mWindowManagerMirroring = windowManagerMirroring; + this.mDisplayCategories = displayCategories; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mDisplayCategories); // onConstructed(); // You can define this method to get a callback } @@ -332,6 +361,7 @@ public final class VirtualDisplayConfig implements Parcelable { private @Nullable String mUniqueId; private int mDisplayIdToMirror; private boolean mWindowManagerMirroring; + private @NonNull List mDisplayCategories; private long mBuilderFieldsSet = 0L; @@ -478,10 +508,30 @@ public final class VirtualDisplayConfig implements Parcelable { return this; } + /** + * The display categories. If set, only corresponding activities from the same category can be + * shown on the display. + */ + @DataClass.Generated.Member + public @NonNull Builder setDisplayCategories(@NonNull List value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x200; + mDisplayCategories = value; + return this; + } + + /** @see #setDisplayCategories */ + @DataClass.Generated.Member + public @NonNull Builder addDisplayCategory(@NonNull String value) { + if (mDisplayCategories == null) setDisplayCategories(new ArrayList<>()); + mDisplayCategories.add(value); + return this; + } + /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull VirtualDisplayConfig build() { checkNotUsed(); - mBuilderFieldsSet |= 0x200; // Mark builder used + mBuilderFieldsSet |= 0x400; // Mark builder used if ((mBuilderFieldsSet & 0x10) == 0) { mFlags = 0; @@ -498,6 +548,9 @@ public final class VirtualDisplayConfig implements Parcelable { if ((mBuilderFieldsSet & 0x100) == 0) { mWindowManagerMirroring = false; } + if ((mBuilderFieldsSet & 0x200) == 0) { + mDisplayCategories = new ArrayList<>(); + } VirtualDisplayConfig o = new VirtualDisplayConfig( mName, mWidth, @@ -507,12 +560,13 @@ public final class VirtualDisplayConfig implements Parcelable { mSurface, mUniqueId, mDisplayIdToMirror, - mWindowManagerMirroring); + mWindowManagerMirroring, + mDisplayCategories); return o; } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x200) != 0) { + if ((mBuilderFieldsSet & 0x400) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -520,10 +574,10 @@ public final class VirtualDisplayConfig implements Parcelable { } @DataClass.Generated( - time = 1646227247934L, + time = 1668534501320L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java", - inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate boolean mWindowManagerMirroring\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)") + inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate boolean mWindowManagerMirroring\nprivate @com.android.internal.util.DataClass.PluralOf(\"displayCategory\") @android.annotation.NonNull java.util.List mDisplayCategories\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)") @Deprecated private void __metadata() {} diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index ce7854d7368ad..28141960f1198 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -130,6 +130,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @Nullable private final @AssociationRequest.DeviceProfile String mDeviceProfile; @Nullable private final SecureWindowCallback mSecureWindowCallback; + @Nullable private final List mDisplayCategories; /** * Creates a window policy controller that is generic to the different use cases of virtual @@ -168,7 +169,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @NonNull PipBlockedCallback pipBlockedCallback, @NonNull ActivityBlockedCallback activityBlockedCallback, @NonNull SecureWindowCallback secureWindowCallback, - @AssociationRequest.DeviceProfile String deviceProfile) { + @AssociationRequest.DeviceProfile String deviceProfile, + @NonNull List displayCategories) { super(); mAllowedUsers = allowedUsers; mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations); @@ -182,6 +184,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController mDeviceProfile = deviceProfile; mPipBlockedCallback = pipBlockedCallback; mSecureWindowCallback = secureWindowCallback; + mDisplayCategories = displayCategories; } /** @@ -319,7 +322,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController if (mDeviceProfile == null) { return true; } - // TODO(b/234075973) : Remove this once proper API is ready. + // TODO(b/234075973) : Remove this once proper API is ready. switch (mDeviceProfile) { case DEVICE_PROFILE_AUTOMOTIVE_PROJECTION: return false; @@ -350,6 +353,15 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController } } + private boolean activityMatchesDisplayCategory(ActivityInfo activityInfo) { + if (mDisplayCategories.isEmpty()) { + return activityInfo.targetDisplayCategory == null; + } + return activityInfo.targetDisplayCategory != null + && mDisplayCategories.contains(activityInfo.targetDisplayCategory); + + } + private boolean canContainActivity(ActivityInfo activityInfo, int windowFlags, int systemWindowFlags) { if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) { @@ -357,9 +369,17 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController } ComponentName activityComponent = activityInfo.getComponentName(); if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent)) { - // The error dialog alerting users that streaming is blocked is always allowed. + // The error dialog alerting users that streaming is blocked is always allowed. Need to + // run before the clauses below to ensure error dialog always shows up. return true; } + if (!activityMatchesDisplayCategory(activityInfo)) { + Slog.d(TAG, String.format( + "The activity's target display category: %s is not found on virtual display" + + " with the following allowed display categories: %s", + activityInfo.targetDisplayCategory, mDisplayCategories.toString())); + return false; + } final UserHandle activityUser = UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid); if (!mAllowedUsers.contains(activityUser)) { diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index 0def25d322efb..7e82918d621fc 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -74,6 +74,7 @@ import com.android.server.companion.virtual.audio.VirtualAudioController; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Consumer; @@ -628,7 +629,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub mInputController.dump(fout); } - GenericWindowPolicyController createWindowPolicyController() { + GenericWindowPolicyController createWindowPolicyController( + @NonNull List displayCategories) { synchronized (mVirtualDeviceLock) { final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(FLAG_SECURE, @@ -643,7 +645,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub this::onEnteringPipBlocked, this::onActivityBlocked, this::onSecureWindowShown, - mAssociationInfo.getDeviceProfile()); + mAssociationInfo.getDeviceProfile(), + displayCategories); gwpc.registerRunningAppsChangedListener(/* listener= */ this); return gwpc; } diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java index a8797a05ed240..fe26700f180b2 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java @@ -332,7 +332,8 @@ public class VirtualDeviceManagerService extends SystemService { GenericWindowPolicyController gwpc; final long token = Binder.clearCallingIdentity(); try { - gwpc = virtualDeviceImpl.createWindowPolicyController(); + gwpc = virtualDeviceImpl.createWindowPolicyController( + virtualDisplayConfig.getDisplayCategories()); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java index 09dc367cceb4a..0bd6f2c2d9038 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java @@ -99,6 +99,7 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.function.Consumer; @Presubmit @@ -181,14 +182,36 @@ public class VirtualDeviceManagerServiceTest { return blockedActivities; } + private Intent createRestrictedActivityBlockedIntent(List displayCategories, + String targetDisplayCategory) { + mDeviceImpl.onVirtualDisplayCreatedLocked( + mDeviceImpl.createWindowPolicyController(displayCategories), DISPLAY_ID); + GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + DISPLAY_ID); + doNothing().when(mContext).startActivityAsUser(any(), any(), any()); + + ArrayList activityInfos = getActivityInfoList( + NONBLOCKED_APP_PACKAGE_NAME, + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoveDevices= */ true, + targetDisplayCategory); + Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( + activityInfos.get(0), mAssociationInfo.getDisplayName()); + gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN); + return blockedAppIntent; + } + + private ArrayList getActivityInfoList( - String packageName, String name, boolean displayOnRemoveDevices) { + String packageName, String name, boolean displayOnRemoveDevices, + String targetDisplayCategory) { ActivityInfo activityInfo = new ActivityInfo(); activityInfo.packageName = packageName; activityInfo.name = name; activityInfo.flags = displayOnRemoveDevices ? FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES : FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES; activityInfo.applicationInfo = mApplicationInfoMock; + activityInfo.targetDisplayCategory = targetDisplayCategory; return new ArrayList<>(Arrays.asList(activityInfo)); } @@ -298,7 +321,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void onVirtualDisplayRemovedLocked_doesNotThrowException() { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); // This call should not throw any exceptions. mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID); } @@ -317,7 +340,7 @@ public class VirtualDeviceManagerServiceTest { public void onVirtualDisplayRemovedLocked_listenersNotified() { mLocalService.registerVirtualDisplayListener(mDisplayListener); mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); mLocalService.onVirtualDisplayRemoved(mDeviceImpl, DISPLAY_ID); TestableLooper.get(this).processAllMessages(); @@ -379,7 +402,7 @@ public class VirtualDeviceManagerServiceTest { nullable(String.class), nullable(String.class), nullable(WorkSource.class), nullable(String.class), anyInt(), eq(null)); mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(), nullable(String.class), nullable(String.class), nullable(WorkSource.class), nullable(String.class), eq(DISPLAY_ID), eq(null)); @@ -388,9 +411,10 @@ public class VirtualDeviceManagerServiceTest { @Test public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired() throws RemoteException { - GenericWindowPolicyController gwpc = mDeviceImpl.createWindowPolicyController(); + GenericWindowPolicyController gwpc = mDeviceImpl.createWindowPolicyController( + new ArrayList<>()); mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); assertThrows(IllegalStateException.class, () -> mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID)); TestableLooper.get(this).processAllMessages(); @@ -409,7 +433,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void onVirtualDisplayRemovedLocked_wakeLockIsReleased() throws RemoteException { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); ArgumentCaptor wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class); TestableLooper.get(this).processAllMessages(); verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(), @@ -425,7 +449,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void addVirtualDisplay_displayNotReleased_wakeLockIsReleased() throws RemoteException { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); ArgumentCaptor wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class); TestableLooper.get(this).processAllMessages(); verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(), @@ -625,7 +649,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void onAudioSessionStarting_hasVirtualAudioController() { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback); @@ -635,7 +659,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void onAudioSessionEnded_noVirtualAudioController() { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback); mDeviceImpl.onAudioSessionEnded(); @@ -646,7 +670,7 @@ public class VirtualDeviceManagerServiceTest { @Test public void close_cleanVirtualAudioController() { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback); mDeviceImpl.close(); @@ -863,14 +887,16 @@ public class VirtualDeviceManagerServiceTest { @Test public void openNonBlockedAppOnVirtualDisplay_doesNotStartBlockedAlertActivity() { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( DISPLAY_ID); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); ArrayList activityInfos = getActivityInfoList( NONBLOCKED_APP_PACKAGE_NAME, - NONBLOCKED_APP_PACKAGE_NAME, /* displayOnRemoveDevices */ true); + NONBLOCKED_APP_PACKAGE_NAME, + /* displayOnRemoveDevices */ true, + /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfos.get(0), mAssociationInfo.getDisplayName()); gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN); @@ -882,14 +908,16 @@ public class VirtualDeviceManagerServiceTest { @Test public void openPermissionControllerOnVirtualDisplay_startBlockedAlertActivity() { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( DISPLAY_ID); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); ArrayList activityInfos = getActivityInfoList( PERMISSION_CONTROLLER_PACKAGE_NAME, - PERMISSION_CONTROLLER_PACKAGE_NAME, /* displayOnRemoveDevices */ false); + PERMISSION_CONTROLLER_PACKAGE_NAME, + /* displayOnRemoveDevices */ false, + /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfos.get(0), mAssociationInfo.getDisplayName()); gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN); @@ -901,14 +929,16 @@ public class VirtualDeviceManagerServiceTest { @Test public void openSettingsOnVirtualDisplay_startBlockedAlertActivity() { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( DISPLAY_ID); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); ArrayList activityInfos = getActivityInfoList( SETTINGS_PACKAGE_NAME, - SETTINGS_PACKAGE_NAME, /* displayOnRemoveDevices */ true); + SETTINGS_PACKAGE_NAME, + /* displayOnRemoveDevices */ true, + /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfos.get(0), mAssociationInfo.getDisplayName()); gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN); @@ -920,14 +950,16 @@ public class VirtualDeviceManagerServiceTest { @Test public void openVendingOnVirtualDisplay_startBlockedAlertActivity() { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( DISPLAY_ID); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); ArrayList activityInfos = getActivityInfoList( VENDING_PACKAGE_NAME, - VENDING_PACKAGE_NAME, /* displayOnRemoveDevices */ true); + VENDING_PACKAGE_NAME, + /* displayOnRemoveDevices */ true, + /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfos.get(0), mAssociationInfo.getDisplayName()); gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN); @@ -939,14 +971,16 @@ public class VirtualDeviceManagerServiceTest { @Test public void openGoogleDialerOnVirtualDisplay_startBlockedAlertActivity() { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( DISPLAY_ID); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); ArrayList activityInfos = getActivityInfoList( GOOGLE_DIALER_PACKAGE_NAME, - GOOGLE_DIALER_PACKAGE_NAME, /* displayOnRemoveDevices */ true); + GOOGLE_DIALER_PACKAGE_NAME, + /* displayOnRemoveDevices */ true, + /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfos.get(0), mAssociationInfo.getDisplayName()); gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN); @@ -958,14 +992,16 @@ public class VirtualDeviceManagerServiceTest { @Test public void openGoogleMapsOnVirtualDisplay_startBlockedAlertActivity() { mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( DISPLAY_ID); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); ArrayList activityInfos = getActivityInfoList( GOOGLE_MAPS_PACKAGE_NAME, - GOOGLE_MAPS_PACKAGE_NAME, /* displayOnRemoveDevices */ true); + GOOGLE_MAPS_PACKAGE_NAME, + /* displayOnRemoveDevices */ true, + /* targetDisplayCategory */ null); Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent( activityInfos.get(0), mAssociationInfo.getDisplayName()); gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN); @@ -978,7 +1014,7 @@ public class VirtualDeviceManagerServiceTest { public void registerRunningAppsChangedListener_onRunningAppsChanged_listenersNotified() { ArraySet uids = new ArraySet<>(Arrays.asList(UID_1, UID_2)); mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( DISPLAY_ID); @@ -993,7 +1029,7 @@ public class VirtualDeviceManagerServiceTest { public void noRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() { ArraySet uids = new ArraySet<>(Arrays.asList(UID_1, UID_2)); mDeviceImpl.onVirtualDisplayCreatedLocked( - mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID); GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( DISPLAY_ID); mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID); @@ -1003,4 +1039,37 @@ public class VirtualDeviceManagerServiceTest { assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(0); } + + @Test + public void nonRestrictedActivityOnRestrictedVirtualDisplay_startBlockedAlertActivity() { + Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"), + /* targetDisplayCategory= */ null); + verify(mContext).startActivityAsUser(argThat(intent -> + intent.filterEquals(blockedAppIntent)), any(), any()); + + } + + @Test + public void restrictedActivityOnRestrictedVirtualDisplay_doesNotStartBlockedAlertActivity() { + Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"), "abc"); + verify(mContext, never()).startActivityAsUser(argThat(intent -> + intent.filterEquals(blockedAppIntent)), any(), any()); + } + + @Test + public void restrictedActivityOnNonRestrictedVirtualDisplay_startBlockedAlertActivity() { + Intent blockedAppIntent = createRestrictedActivityBlockedIntent( + /* displayCategories= */ List.of(), "abc"); + verify(mContext).startActivityAsUser(argThat(intent -> + intent.filterEquals(blockedAppIntent)), any(), any()); + } + + @Test + public void + restrictedActivityOnNonMatchingRestrictedVirtualDisplay_startBlockedAlertActivity() { + Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"), "def"); + verify(mContext).startActivityAsUser(argThat(intent -> + intent.filterEquals(blockedAppIntent)), any(), any()); + } + } diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java index 0262f564911b6..3ca648cbcc303 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java @@ -72,22 +72,25 @@ public class VirtualAudioControllerTest { MockitoAnnotations.initMocks(this); mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); mVirtualAudioController = new VirtualAudioController(mContext); - mGenericWindowPolicyController = new GenericWindowPolicyController( - FLAG_SECURE, - SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, - /* allowedUsers= */ new ArraySet<>(), - /* allowedCrossTaskNavigations= */ new ArraySet<>(), - /* blockedCrossTaskNavigations= */ new ArraySet<>(), - /* allowedActivities= */ new ArraySet<>(), - /* blockedActivities= */ new ArraySet<>(), - VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED, - /* activityListener= */ null, - /* pipBlockedCallback= */ null, - /* activityBlockedCallback= */ null, - /* secureWindowCallback= */ null, - /* deviceProfile= */ DEVICE_PROFILE_APP_STREAMING); + mGenericWindowPolicyController = + new GenericWindowPolicyController( + FLAG_SECURE, + SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, + /* allowedUsers= */ new ArraySet<>(), + /* allowedCrossTaskNavigations= */ new ArraySet<>(), + /* blockedCrossTaskNavigations= */ new ArraySet<>(), + /* allowedActivities= */ new ArraySet<>(), + /* blockedActivities= */ new ArraySet<>(), + VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED, + /* activityListener= */ null, + /* pipBlockedCallback= */ null, + /* activityBlockedCallback= */ null, + /* secureWindowCallback= */ null, + /* deviceProfile= */ DEVICE_PROFILE_APP_STREAMING, + /* displayCategories= */ new ArrayList<>()); } + @Test public void startListening_receivesCallback() throws RemoteException { ArraySet runningUids = new ArraySet<>();