diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index 32919bdd771c6..0e6cfb1df9dea 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -75,7 +75,6 @@ import java.util.function.IntConsumer; @SystemService(Context.VIRTUAL_DEVICE_SERVICE) public final class VirtualDeviceManager { - private static final boolean DEBUG = false; private static final String TAG = "VirtualDeviceManager"; private static final int DEFAULT_VIRTUAL_DISPLAY_FLAGS = @@ -84,7 +83,6 @@ public final class VirtualDeviceManager { | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL | DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH - | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS; /** diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index f7675e835eb20..23d108fbe36a0 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -419,6 +419,15 @@ public final class DisplayManager { @TestApi public static final int VIRTUAL_DISPLAY_FLAG_OWN_FOCUS = 1 << 14; + /** + * Virtual display flags: Indicates that the display should not be a part of the default + * DisplayGroup and instead be part of a DisplayGroup associated with its virtual device. + * + * @see #createVirtualDisplay + * @hide + */ + public static final int VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP = 1 << 15; + /** @hide */ @IntDef(prefix = {"MATCH_CONTENT_FRAMERATE_"}, value = { diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java index 881199964d450..ddb924353a435 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java @@ -145,7 +145,7 @@ final class DisplayDeviceInfo { /** * Flag: Indicates that the display should always be unlocked. Only valid on virtual displays * that aren't in the default display group. - * @see #FLAG_OWN_DISPLAY_GROUP + * @see #FLAG_OWN_DISPLAY_GROUP and #FLAG_DEVICE_DISPLAY_GROUP * @hide */ public static final int FLAG_ALWAYS_UNLOCKED = 1 << 15; @@ -171,6 +171,14 @@ final class DisplayDeviceInfo { */ public static final int FLAG_OWN_FOCUS = 1 << 17; + /** + * Flag: indicates that the display should not be a part of the default {@link DisplayGroup} and + * instead be part of a {@link DisplayGroup} associated with the Virtual Device. + * + * @hide + */ + public static final int FLAG_DEVICE_DISPLAY_GROUP = 1 << 18; + /** * Touch attachment: Display does not receive touch. */ diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index a7e6b7fdb8628..0d1aca88fa702 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -25,6 +25,7 @@ import static android.hardware.display.DisplayManager.EventsMask; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; @@ -1276,6 +1277,9 @@ public final class DisplayManagerService extends SystemService { if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; } + if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) == 0 && virtualDevice != null) { + flags |= VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP; + } if (projection != null) { try { @@ -1403,7 +1407,7 @@ public final class DisplayManagerService extends SystemService { // If the display is to be added to a device display group, we need to make the // LogicalDisplayMapper aware of the link between the new display and its associated virtual // device before triggering DISPLAY_DEVICE_EVENT_ADDED. - if (virtualDevice != null && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) == 0) { + if ((flags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) { try { final int virtualDeviceId = virtualDevice.getDeviceId(); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice( diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index d0e518b876dd4..d24630d61609e 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -20,6 +20,7 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAY import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION; @@ -32,6 +33,7 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TOUCH import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; import static com.android.server.display.DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED; +import static com.android.server.display.DisplayDeviceInfo.FLAG_DEVICE_DISPLAY_GROUP; import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP; import static com.android.server.display.DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED; import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED; @@ -466,6 +468,9 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mInfo.flags |= FLAG_OWN_DISPLAY_GROUP; } } + if ((mFlags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) { + mInfo.flags |= FLAG_DEVICE_DISPLAY_GROUP; + } if ((mFlags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE; @@ -498,11 +503,15 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mInfo.flags |= FLAG_TRUSTED; } if ((mFlags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0) { - if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { + if ((mInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0 + || (mFlags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) { mInfo.flags |= FLAG_ALWAYS_UNLOCKED; } else { - Slog.w(TAG, "Ignoring VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED as it " - + "requires VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP."); + Slog.w( + TAG, + "Ignoring VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED as it requires" + + " VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP or" + + " VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP."); } } if ((mFlags & VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED) != 0) { diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java index 5af05584c07a1..303b24066b9d5 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -16,7 +16,9 @@ package com.android.server.display; +import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY; import static android.Manifest.permission.ADD_TRUSTED_DISPLAY; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; @@ -724,9 +726,6 @@ public class DisplayManagerServiceTest { registerDefaultDisplays(displayManager); when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); - when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)) - .thenReturn(PackageManager.PERMISSION_DENIED); - IVirtualDevice virtualDevice = mock(IVirtualDevice.class); when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice)) .thenReturn(true); @@ -780,9 +779,6 @@ public class DisplayManagerServiceTest { registerDefaultDisplays(displayManager); when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); - when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)) - .thenReturn(PackageManager.PERMISSION_DENIED); - IVirtualDevice virtualDevice = mock(IVirtualDevice.class); when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice)) .thenReturn(true); @@ -792,7 +788,7 @@ public class DisplayManagerServiceTest { // virtual device. final VirtualDisplayConfig.Builder builder1 = new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320) - .setUniqueId("uniqueId --- device display group 1"); + .setUniqueId("uniqueId --- device display group"); int displayId1 = localService.createVirtualDisplay( @@ -808,7 +804,7 @@ public class DisplayManagerServiceTest { final VirtualDisplayConfig.Builder builder2 = new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320) .setFlags(VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) - .setUniqueId("uniqueId --- device display group 1"); + .setUniqueId("uniqueId --- own display group"); int displayId2 = localService.createVirtualDisplay( @@ -826,6 +822,99 @@ public class DisplayManagerServiceTest { displayGroupId2); } + @Test + public void displaysInDeviceOrOwnDisplayGroupShouldPreserveAlwaysUnlockedFlag() + throws Exception { + DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); + DisplayManagerInternal localService = displayManager.new LocalService(); + + registerDefaultDisplays(displayManager); + when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); + + IVirtualDevice virtualDevice = mock(IVirtualDevice.class); + when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice)) + .thenReturn(true); + when(virtualDevice.getDeviceId()).thenReturn(1); + + // Allow an ALWAYS_UNLOCKED display to be created. + when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)) + .thenReturn(PackageManager.PERMISSION_GRANTED); + + when(mContext.checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY)) + .thenReturn(PackageManager.PERMISSION_GRANTED); + + // Create a virtual display in a device display group. + final VirtualDisplayConfig deviceDisplayGroupDisplayConfig = + new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320) + .setUniqueId("uniqueId --- device display group 1") + .setFlags(VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) + .build(); + + int deviceDisplayGroupDisplayId = + localService.createVirtualDisplay( + deviceDisplayGroupDisplayConfig, + mMockAppToken /* callback */, + virtualDevice /* virtualDeviceToken */, + mock(DisplayWindowPolicyController.class), + PACKAGE_NAME); + + // Check that FLAG_ALWAYS_UNLOCKED is set. + assertNotEquals( + "FLAG_ALWAYS_UNLOCKED should be set for displays created in a device display" + + " group.", + (displayManager.getDisplayDeviceInfoInternal(deviceDisplayGroupDisplayId).flags + & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED), + 0); + + // Create a virtual display in its own display group. + final VirtualDisplayConfig ownDisplayGroupConfig = + new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320) + .setUniqueId("uniqueId --- own display group 1") + .setFlags( + VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED + | VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) + .build(); + + int ownDisplayGroupDisplayId = + localService.createVirtualDisplay( + ownDisplayGroupConfig, + mMockAppToken /* callback */, + virtualDevice /* virtualDeviceToken */, + mock(DisplayWindowPolicyController.class), + PACKAGE_NAME); + + // Check that FLAG_ALWAYS_UNLOCKED is set. + assertNotEquals( + "FLAG_ALWAYS_UNLOCKED should be set for displays created in their own display" + + " group.", + (displayManager.getDisplayDeviceInfoInternal(ownDisplayGroupDisplayId).flags + & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED), + 0); + + // Create a virtual display in a device display group. + final VirtualDisplayConfig defaultDisplayGroupConfig = + new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320) + .setUniqueId("uniqueId --- default display group 1") + .setFlags(VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) + .build(); + + int defaultDisplayGroupDisplayId = + localService.createVirtualDisplay( + defaultDisplayGroupConfig, + mMockAppToken /* callback */, + null /* virtualDeviceToken */, + mock(DisplayWindowPolicyController.class), + PACKAGE_NAME); + + // Check that FLAG_ALWAYS_UNLOCKED is not set. + assertEquals( + "FLAG_ALWAYS_UNLOCKED should not be set for displays created in the default" + + " display group.", + (displayManager.getDisplayDeviceInfoInternal(defaultDisplayGroupDisplayId).flags + & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED), + 0); + } + @Test public void testGetDisplayIdToMirror() throws Exception { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);