Loading services/core/java/com/android/server/display/DisplayManagerService.java +39 −11 Original line number Diff line number Diff line Loading @@ -1356,11 +1356,19 @@ public final class DisplayManagerService extends SystemService { final long token = Binder.clearCallingIdentity(); try { synchronized (mSyncRoot) { final int displayId = createVirtualDisplayLocked(callback, projection, callingUid, packageName, surface, flags, virtualDisplayConfig); final int displayId = createVirtualDisplayLocked( callback, projection, callingUid, packageName, virtualDevice, surface, flags, virtualDisplayConfig); if (displayId != Display.INVALID_DISPLAY && virtualDevice != null && dwpc != null) { mDisplayWindowPolicyControllers.put(displayId, Pair.create(virtualDevice, dwpc)); mDisplayWindowPolicyControllers.put( displayId, Pair.create(virtualDevice, dwpc)); } return displayId; } Loading @@ -1369,11 +1377,19 @@ public final class DisplayManagerService extends SystemService { } } private int createVirtualDisplayLocked(IVirtualDisplayCallback callback, IMediaProjection projection, int callingUid, String packageName, Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig) { private int createVirtualDisplayLocked( IVirtualDisplayCallback callback, IMediaProjection projection, int callingUid, String packageName, IVirtualDevice virtualDevice, Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig) { if (mVirtualDisplayAdapter == null) { Slog.w(TAG, "Rejecting request to create private virtual display " Slog.w( TAG, "Rejecting request to create private virtual display " + "because the virtual display adapter is not available."); return -1; } Loading @@ -1385,6 +1401,19 @@ public final class DisplayManagerService extends SystemService { return -1; } // 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) { try { final int virtualDeviceId = virtualDevice.getDeviceId(); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice( device, virtualDeviceId); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } // DisplayDevice events are handled manually for Virtual Displays. // TODO: multi-display Fix this so that generic add/remove events are not handled in a // different code path for virtual displays. Currently this happens so that we can Loading @@ -1393,8 +1422,7 @@ public final class DisplayManagerService extends SystemService { // called on the DisplayThread (which we don't want to wait for?). // One option would be to actually wait here on the binder thread // to be notified when the virtual display is created (or failed). mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); if (display != null) { Loading services/core/java/com/android/server/display/LogicalDisplayMapper.java +62 −3 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.os.PowerManager; import android.os.SystemClock; import android.os.SystemProperties; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; import android.util.Slog; Loading Loading @@ -123,6 +124,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { /** Map of all display groups indexed by display group id. */ private final SparseArray<DisplayGroup> mDisplayGroups = new SparseArray<>(); /** * Map of display groups which are linked to virtual devices (all displays in the group are * linked to that device). Keyed by virtual device unique id. */ private final SparseIntArray mDeviceDisplayGroupIds = new SparseIntArray(); private final DisplayDeviceRepository mDisplayDeviceRepo; private final DeviceStateToLayoutMap mDeviceStateToLayoutMap; private final Listener mListener; Loading Loading @@ -157,6 +164,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { */ private final SparseIntArray mDisplayGroupsToUpdate = new SparseIntArray(); /** * ArrayMap of display device unique ID to virtual device ID. Used in {@link * #updateLogicalDisplaysLocked} to establish which Virtual Devices own which Virtual Displays. */ private final ArrayMap<String, Integer> mVirtualDeviceDisplayMapping = new ArrayMap<>(); private int mNextNonDefaultGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; private Layout mCurrentLayout = null; private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE; Loading Loading @@ -362,6 +375,19 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { mDeviceStateToLayoutMap.dumpLocked(ipw); } /** * Creates an association between a displayDevice and a virtual device. Any displays associated * with this virtual device will be grouped together in a single {@link DisplayGroup} unless * created with {@link Display.FLAG_OWN_DISPLAY_GROUP}. * * @param displayDevice the displayDevice to be linked * @param virtualDeviceUniqueId the unique ID of the virtual device. */ void associateDisplayDeviceWithVirtualDevice( DisplayDevice displayDevice, int virtualDeviceUniqueId) { mVirtualDeviceDisplayMapping.put(displayDevice.getUniqueId(), virtualDeviceUniqueId); } void setDeviceStateLocked(int state, boolean isOverrideActive) { Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState + ", interactive=" + mInteractive); Loading Loading @@ -556,6 +582,9 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); // Remove any virtual device mapping which exists for the display. mVirtualDeviceDisplayMapping.remove(device.getUniqueId()); if (layoutDisplay.getAddress().equals(deviceInfo.address)) { layout.removeDisplayLocked(DEFAULT_DISPLAY); Loading Loading @@ -749,24 +778,44 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { // We wait until we sent the EVENT_REMOVED event before actually removing the // group. mDisplayGroups.delete(id); // Remove possible reference to the removed group. int deviceIndex = mDeviceDisplayGroupIds.indexOfValue(id); if (deviceIndex >= 0) { mDeviceDisplayGroupIds.removeAt(deviceIndex); } } } } private void assignDisplayGroupLocked(LogicalDisplay display) { final int displayId = display.getDisplayIdLocked(); final String primaryDisplayUniqueId = display.getPrimaryDisplayDeviceLocked().getUniqueId(); final Integer linkedDeviceUniqueId = mVirtualDeviceDisplayMapping.get(primaryDisplayUniqueId); // Get current display group data int groupId = getDisplayGroupIdFromDisplayIdLocked(displayId); Integer deviceDisplayGroupId = null; if (linkedDeviceUniqueId != null && mDeviceDisplayGroupIds.indexOfKey(linkedDeviceUniqueId) > 0) { deviceDisplayGroupId = mDeviceDisplayGroupIds.get(linkedDeviceUniqueId); } final DisplayGroup oldGroup = getDisplayGroupLocked(groupId); // Get the new display group if a change is needed final DisplayInfo info = display.getDisplayInfoLocked(); final boolean needsOwnDisplayGroup = (info.flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0; final boolean hasOwnDisplayGroup = groupId != Display.DEFAULT_DISPLAY_GROUP; final boolean needsDeviceDisplayGroup = !needsOwnDisplayGroup && linkedDeviceUniqueId != null; final boolean hasDeviceDisplayGroup = deviceDisplayGroupId != null && groupId == deviceDisplayGroupId; if (groupId == Display.INVALID_DISPLAY_GROUP || hasOwnDisplayGroup != needsOwnDisplayGroup) { groupId = assignDisplayGroupIdLocked(needsOwnDisplayGroup); || hasOwnDisplayGroup != needsOwnDisplayGroup || hasDeviceDisplayGroup != needsDeviceDisplayGroup) { groupId = assignDisplayGroupIdLocked( needsOwnDisplayGroup, needsDeviceDisplayGroup, linkedDeviceUniqueId); } // Create a new group if needed Loading Loading @@ -931,7 +980,17 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { display.setPhase(phase); } private int assignDisplayGroupIdLocked(boolean isOwnDisplayGroup) { private int assignDisplayGroupIdLocked( boolean isOwnDisplayGroup, boolean isDeviceDisplayGroup, Integer linkedDeviceUniqueId) { if (isDeviceDisplayGroup && linkedDeviceUniqueId != null) { int deviceDisplayGroupId = mDeviceDisplayGroupIds.get(linkedDeviceUniqueId); // A value of 0 indicates that no device display group was found. if (deviceDisplayGroupId == 0) { deviceDisplayGroupId = mNextNonDefaultGroupId++; mDeviceDisplayGroupIds.put(linkedDeviceUniqueId, deviceDisplayGroupId); } return deviceDisplayGroupId; } return isOwnDisplayGroup ? mNextNonDefaultGroupId++ : Display.DEFAULT_DISPLAY_GROUP; } Loading services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +112 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.display; import static android.Manifest.permission.ADD_TRUSTED_DISPLAY; 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 com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX; Loading Loading @@ -660,6 +661,117 @@ public class DisplayManagerServiceTest { firstDisplayId); } /** Tests that the virtual device is created in a device display group. */ @Test public void createVirtualDisplay_addsDisplaysToDeviceDisplayGroups() throws Exception { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerInternal localService = displayManager.new LocalService(); 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); when(virtualDevice.getDeviceId()).thenReturn(1); // Create a first virtual display. A display group should be created for this display on the // virtual device. final VirtualDisplayConfig.Builder builder1 = new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320) .setUniqueId("uniqueId --- device display group 1"); int displayId1 = localService.createVirtualDisplay( builder1.build(), mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId; // Create a second virtual display. This should be added to the previously created display // group. final VirtualDisplayConfig.Builder builder2 = new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320) .setUniqueId("uniqueId --- device display group 1"); int displayId2 = localService.createVirtualDisplay( builder2.build(), mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId; assertEquals( "Both displays should be added to the same displayGroup.", displayGroupId1, displayGroupId2); } /** * Tests that the virtual display is not added to the device display group when * VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is set. */ @Test public void createVirtualDisplay_addsDisplaysToOwnDisplayGroups() throws Exception { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerInternal localService = displayManager.new LocalService(); 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); when(virtualDevice.getDeviceId()).thenReturn(1); // Create a first virtual display. A display group should be created for this display on the // virtual device. final VirtualDisplayConfig.Builder builder1 = new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320) .setUniqueId("uniqueId --- device display group 1"); int displayId1 = localService.createVirtualDisplay( builder1.build(), mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId; // Create a second virtual display. With the flag VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP, // the display should not be added to the previously created display group. 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"); int displayId2 = localService.createVirtualDisplay( builder2.build(), mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId; assertNotEquals( "Display 1 should be in the device display group and display 2 in its own display" + " group.", displayGroupId1, displayGroupId2); } @Test public void testGetDisplayIdToMirror() throws Exception { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); Loading services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +102 −2 Original line number Diff line number Diff line Loading @@ -368,6 +368,98 @@ public class LogicalDisplayMapperTest { mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3))); } @Test public void testDevicesAreAddedToDeviceDisplayGroups() { // Create the default internal display of the device. LogicalDisplay defaultDisplay = add( createDisplayDevice( Display.TYPE_INTERNAL, 600, 800, DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); // Create 3 virtual displays associated with a first virtual device. int deviceId1 = 1; TestDisplayDevice display1 = createDisplayDevice(Display.TYPE_VIRTUAL, "virtualDevice1Display1", 600, 800, 0); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display1, deviceId1); LogicalDisplay virtualDevice1Display1 = add(display1); TestDisplayDevice display2 = createDisplayDevice(Display.TYPE_VIRTUAL, "virtualDevice1Display2", 600, 800, 0); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display2, deviceId1); LogicalDisplay virtualDevice1Display2 = add(display2); TestDisplayDevice display3 = createDisplayDevice(Display.TYPE_VIRTUAL, "virtualDevice1Display3", 600, 800, 0); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display3, deviceId1); LogicalDisplay virtualDevice1Display3 = add(display3); // Create another 3 virtual displays associated with a second virtual device. int deviceId2 = 2; TestDisplayDevice display4 = createDisplayDevice(Display.TYPE_VIRTUAL, "virtualDevice2Display1", 600, 800, 0); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display4, deviceId2); LogicalDisplay virtualDevice2Display1 = add(display4); TestDisplayDevice display5 = createDisplayDevice(Display.TYPE_VIRTUAL, "virtualDevice2Display2", 600, 800, 0); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display5, deviceId2); LogicalDisplay virtualDevice2Display2 = add(display5); // The final display is created with FLAG_OWN_DISPLAY_GROUP set. TestDisplayDevice display6 = createDisplayDevice( Display.TYPE_VIRTUAL, "virtualDevice2Display3", 600, 800, DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display6, deviceId2); LogicalDisplay virtualDevice2Display3 = add(display6); // Verify that the internal display is in the default display group. assertEquals( DEFAULT_DISPLAY_GROUP, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(defaultDisplay))); // Verify that all the displays for virtual device 1 are in the same (non-default) display // group. int virtualDevice1DisplayGroupId = mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice1Display1)); assertNotEquals(DEFAULT_DISPLAY_GROUP, virtualDevice1DisplayGroupId); assertEquals( virtualDevice1DisplayGroupId, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice1Display2))); assertEquals( virtualDevice1DisplayGroupId, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice1Display3))); // The first 2 displays for virtual device 2 should be in the same non-default group. int virtualDevice2DisplayGroupId = mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice2Display1)); assertNotEquals(DEFAULT_DISPLAY_GROUP, virtualDevice2DisplayGroupId); assertEquals( virtualDevice2DisplayGroupId, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice2Display2))); // virtualDevice2Display3 was created with FLAG_OWN_DISPLAY_GROUP and shouldn't be grouped // with other displays of this device or be in the default display group. assertNotEquals( virtualDevice2DisplayGroupId, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice2Display3))); assertNotEquals( DEFAULT_DISPLAY_GROUP, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice2Display3))); } @Test public void testDeviceShouldBeWoken() { assertTrue(mLogicalDisplayMapper.shouldDeviceBeWoken(DEVICE_STATE_OPEN, Loading Loading @@ -416,14 +508,22 @@ public class LogicalDisplayMapperTest { ///////////////// private TestDisplayDevice createDisplayDevice(int type, int width, int height, int flags) { return createDisplayDevice(new TestUtils.TestDisplayAddress(), type, width, height, flags); return createDisplayDevice( new TestUtils.TestDisplayAddress(), /* uniqueId */ "", type, width, height, flags); } private TestDisplayDevice createDisplayDevice( int type, String uniqueId, int width, int height, int flags) { return createDisplayDevice( new TestUtils.TestDisplayAddress(), uniqueId, type, width, height, flags); } private TestDisplayDevice createDisplayDevice( DisplayAddress address, int type, int width, int height, int flags) { DisplayAddress address, String uniqueId, int type, int width, int height, int flags) { TestDisplayDevice device = new TestDisplayDevice(); DisplayDeviceInfo displayDeviceInfo = device.getSourceInfo(); displayDeviceInfo.type = type; displayDeviceInfo.uniqueId = uniqueId; displayDeviceInfo.width = width; displayDeviceInfo.height = height; displayDeviceInfo.flags = flags; Loading Loading
services/core/java/com/android/server/display/DisplayManagerService.java +39 −11 Original line number Diff line number Diff line Loading @@ -1356,11 +1356,19 @@ public final class DisplayManagerService extends SystemService { final long token = Binder.clearCallingIdentity(); try { synchronized (mSyncRoot) { final int displayId = createVirtualDisplayLocked(callback, projection, callingUid, packageName, surface, flags, virtualDisplayConfig); final int displayId = createVirtualDisplayLocked( callback, projection, callingUid, packageName, virtualDevice, surface, flags, virtualDisplayConfig); if (displayId != Display.INVALID_DISPLAY && virtualDevice != null && dwpc != null) { mDisplayWindowPolicyControllers.put(displayId, Pair.create(virtualDevice, dwpc)); mDisplayWindowPolicyControllers.put( displayId, Pair.create(virtualDevice, dwpc)); } return displayId; } Loading @@ -1369,11 +1377,19 @@ public final class DisplayManagerService extends SystemService { } } private int createVirtualDisplayLocked(IVirtualDisplayCallback callback, IMediaProjection projection, int callingUid, String packageName, Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig) { private int createVirtualDisplayLocked( IVirtualDisplayCallback callback, IMediaProjection projection, int callingUid, String packageName, IVirtualDevice virtualDevice, Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig) { if (mVirtualDisplayAdapter == null) { Slog.w(TAG, "Rejecting request to create private virtual display " Slog.w( TAG, "Rejecting request to create private virtual display " + "because the virtual display adapter is not available."); return -1; } Loading @@ -1385,6 +1401,19 @@ public final class DisplayManagerService extends SystemService { return -1; } // 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) { try { final int virtualDeviceId = virtualDevice.getDeviceId(); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice( device, virtualDeviceId); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } // DisplayDevice events are handled manually for Virtual Displays. // TODO: multi-display Fix this so that generic add/remove events are not handled in a // different code path for virtual displays. Currently this happens so that we can Loading @@ -1393,8 +1422,7 @@ public final class DisplayManagerService extends SystemService { // called on the DisplayThread (which we don't want to wait for?). // One option would be to actually wait here on the binder thread // to be notified when the virtual display is created (or failed). mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); if (display != null) { Loading
services/core/java/com/android/server/display/LogicalDisplayMapper.java +62 −3 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.os.PowerManager; import android.os.SystemClock; import android.os.SystemProperties; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; import android.util.Slog; Loading Loading @@ -123,6 +124,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { /** Map of all display groups indexed by display group id. */ private final SparseArray<DisplayGroup> mDisplayGroups = new SparseArray<>(); /** * Map of display groups which are linked to virtual devices (all displays in the group are * linked to that device). Keyed by virtual device unique id. */ private final SparseIntArray mDeviceDisplayGroupIds = new SparseIntArray(); private final DisplayDeviceRepository mDisplayDeviceRepo; private final DeviceStateToLayoutMap mDeviceStateToLayoutMap; private final Listener mListener; Loading Loading @@ -157,6 +164,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { */ private final SparseIntArray mDisplayGroupsToUpdate = new SparseIntArray(); /** * ArrayMap of display device unique ID to virtual device ID. Used in {@link * #updateLogicalDisplaysLocked} to establish which Virtual Devices own which Virtual Displays. */ private final ArrayMap<String, Integer> mVirtualDeviceDisplayMapping = new ArrayMap<>(); private int mNextNonDefaultGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; private Layout mCurrentLayout = null; private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE; Loading Loading @@ -362,6 +375,19 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { mDeviceStateToLayoutMap.dumpLocked(ipw); } /** * Creates an association between a displayDevice and a virtual device. Any displays associated * with this virtual device will be grouped together in a single {@link DisplayGroup} unless * created with {@link Display.FLAG_OWN_DISPLAY_GROUP}. * * @param displayDevice the displayDevice to be linked * @param virtualDeviceUniqueId the unique ID of the virtual device. */ void associateDisplayDeviceWithVirtualDevice( DisplayDevice displayDevice, int virtualDeviceUniqueId) { mVirtualDeviceDisplayMapping.put(displayDevice.getUniqueId(), virtualDeviceUniqueId); } void setDeviceStateLocked(int state, boolean isOverrideActive) { Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState + ", interactive=" + mInteractive); Loading Loading @@ -556,6 +582,9 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); // Remove any virtual device mapping which exists for the display. mVirtualDeviceDisplayMapping.remove(device.getUniqueId()); if (layoutDisplay.getAddress().equals(deviceInfo.address)) { layout.removeDisplayLocked(DEFAULT_DISPLAY); Loading Loading @@ -749,24 +778,44 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { // We wait until we sent the EVENT_REMOVED event before actually removing the // group. mDisplayGroups.delete(id); // Remove possible reference to the removed group. int deviceIndex = mDeviceDisplayGroupIds.indexOfValue(id); if (deviceIndex >= 0) { mDeviceDisplayGroupIds.removeAt(deviceIndex); } } } } private void assignDisplayGroupLocked(LogicalDisplay display) { final int displayId = display.getDisplayIdLocked(); final String primaryDisplayUniqueId = display.getPrimaryDisplayDeviceLocked().getUniqueId(); final Integer linkedDeviceUniqueId = mVirtualDeviceDisplayMapping.get(primaryDisplayUniqueId); // Get current display group data int groupId = getDisplayGroupIdFromDisplayIdLocked(displayId); Integer deviceDisplayGroupId = null; if (linkedDeviceUniqueId != null && mDeviceDisplayGroupIds.indexOfKey(linkedDeviceUniqueId) > 0) { deviceDisplayGroupId = mDeviceDisplayGroupIds.get(linkedDeviceUniqueId); } final DisplayGroup oldGroup = getDisplayGroupLocked(groupId); // Get the new display group if a change is needed final DisplayInfo info = display.getDisplayInfoLocked(); final boolean needsOwnDisplayGroup = (info.flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0; final boolean hasOwnDisplayGroup = groupId != Display.DEFAULT_DISPLAY_GROUP; final boolean needsDeviceDisplayGroup = !needsOwnDisplayGroup && linkedDeviceUniqueId != null; final boolean hasDeviceDisplayGroup = deviceDisplayGroupId != null && groupId == deviceDisplayGroupId; if (groupId == Display.INVALID_DISPLAY_GROUP || hasOwnDisplayGroup != needsOwnDisplayGroup) { groupId = assignDisplayGroupIdLocked(needsOwnDisplayGroup); || hasOwnDisplayGroup != needsOwnDisplayGroup || hasDeviceDisplayGroup != needsDeviceDisplayGroup) { groupId = assignDisplayGroupIdLocked( needsOwnDisplayGroup, needsDeviceDisplayGroup, linkedDeviceUniqueId); } // Create a new group if needed Loading Loading @@ -931,7 +980,17 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { display.setPhase(phase); } private int assignDisplayGroupIdLocked(boolean isOwnDisplayGroup) { private int assignDisplayGroupIdLocked( boolean isOwnDisplayGroup, boolean isDeviceDisplayGroup, Integer linkedDeviceUniqueId) { if (isDeviceDisplayGroup && linkedDeviceUniqueId != null) { int deviceDisplayGroupId = mDeviceDisplayGroupIds.get(linkedDeviceUniqueId); // A value of 0 indicates that no device display group was found. if (deviceDisplayGroupId == 0) { deviceDisplayGroupId = mNextNonDefaultGroupId++; mDeviceDisplayGroupIds.put(linkedDeviceUniqueId, deviceDisplayGroupId); } return deviceDisplayGroupId; } return isOwnDisplayGroup ? mNextNonDefaultGroupId++ : Display.DEFAULT_DISPLAY_GROUP; } Loading
services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +112 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.display; import static android.Manifest.permission.ADD_TRUSTED_DISPLAY; 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 com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX; Loading Loading @@ -660,6 +661,117 @@ public class DisplayManagerServiceTest { firstDisplayId); } /** Tests that the virtual device is created in a device display group. */ @Test public void createVirtualDisplay_addsDisplaysToDeviceDisplayGroups() throws Exception { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerInternal localService = displayManager.new LocalService(); 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); when(virtualDevice.getDeviceId()).thenReturn(1); // Create a first virtual display. A display group should be created for this display on the // virtual device. final VirtualDisplayConfig.Builder builder1 = new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320) .setUniqueId("uniqueId --- device display group 1"); int displayId1 = localService.createVirtualDisplay( builder1.build(), mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId; // Create a second virtual display. This should be added to the previously created display // group. final VirtualDisplayConfig.Builder builder2 = new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320) .setUniqueId("uniqueId --- device display group 1"); int displayId2 = localService.createVirtualDisplay( builder2.build(), mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId; assertEquals( "Both displays should be added to the same displayGroup.", displayGroupId1, displayGroupId2); } /** * Tests that the virtual display is not added to the device display group when * VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is set. */ @Test public void createVirtualDisplay_addsDisplaysToOwnDisplayGroups() throws Exception { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerInternal localService = displayManager.new LocalService(); 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); when(virtualDevice.getDeviceId()).thenReturn(1); // Create a first virtual display. A display group should be created for this display on the // virtual device. final VirtualDisplayConfig.Builder builder1 = new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320) .setUniqueId("uniqueId --- device display group 1"); int displayId1 = localService.createVirtualDisplay( builder1.build(), mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId; // Create a second virtual display. With the flag VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP, // the display should not be added to the previously created display group. 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"); int displayId2 = localService.createVirtualDisplay( builder2.build(), mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */, mock(DisplayWindowPolicyController.class), PACKAGE_NAME); int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId; assertNotEquals( "Display 1 should be in the device display group and display 2 in its own display" + " group.", displayGroupId1, displayGroupId2); } @Test public void testGetDisplayIdToMirror() throws Exception { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); Loading
services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +102 −2 Original line number Diff line number Diff line Loading @@ -368,6 +368,98 @@ public class LogicalDisplayMapperTest { mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3))); } @Test public void testDevicesAreAddedToDeviceDisplayGroups() { // Create the default internal display of the device. LogicalDisplay defaultDisplay = add( createDisplayDevice( Display.TYPE_INTERNAL, 600, 800, DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); // Create 3 virtual displays associated with a first virtual device. int deviceId1 = 1; TestDisplayDevice display1 = createDisplayDevice(Display.TYPE_VIRTUAL, "virtualDevice1Display1", 600, 800, 0); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display1, deviceId1); LogicalDisplay virtualDevice1Display1 = add(display1); TestDisplayDevice display2 = createDisplayDevice(Display.TYPE_VIRTUAL, "virtualDevice1Display2", 600, 800, 0); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display2, deviceId1); LogicalDisplay virtualDevice1Display2 = add(display2); TestDisplayDevice display3 = createDisplayDevice(Display.TYPE_VIRTUAL, "virtualDevice1Display3", 600, 800, 0); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display3, deviceId1); LogicalDisplay virtualDevice1Display3 = add(display3); // Create another 3 virtual displays associated with a second virtual device. int deviceId2 = 2; TestDisplayDevice display4 = createDisplayDevice(Display.TYPE_VIRTUAL, "virtualDevice2Display1", 600, 800, 0); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display4, deviceId2); LogicalDisplay virtualDevice2Display1 = add(display4); TestDisplayDevice display5 = createDisplayDevice(Display.TYPE_VIRTUAL, "virtualDevice2Display2", 600, 800, 0); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display5, deviceId2); LogicalDisplay virtualDevice2Display2 = add(display5); // The final display is created with FLAG_OWN_DISPLAY_GROUP set. TestDisplayDevice display6 = createDisplayDevice( Display.TYPE_VIRTUAL, "virtualDevice2Display3", 600, 800, DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP); mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(display6, deviceId2); LogicalDisplay virtualDevice2Display3 = add(display6); // Verify that the internal display is in the default display group. assertEquals( DEFAULT_DISPLAY_GROUP, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(defaultDisplay))); // Verify that all the displays for virtual device 1 are in the same (non-default) display // group. int virtualDevice1DisplayGroupId = mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice1Display1)); assertNotEquals(DEFAULT_DISPLAY_GROUP, virtualDevice1DisplayGroupId); assertEquals( virtualDevice1DisplayGroupId, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice1Display2))); assertEquals( virtualDevice1DisplayGroupId, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice1Display3))); // The first 2 displays for virtual device 2 should be in the same non-default group. int virtualDevice2DisplayGroupId = mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice2Display1)); assertNotEquals(DEFAULT_DISPLAY_GROUP, virtualDevice2DisplayGroupId); assertEquals( virtualDevice2DisplayGroupId, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice2Display2))); // virtualDevice2Display3 was created with FLAG_OWN_DISPLAY_GROUP and shouldn't be grouped // with other displays of this device or be in the default display group. assertNotEquals( virtualDevice2DisplayGroupId, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice2Display3))); assertNotEquals( DEFAULT_DISPLAY_GROUP, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked( id(virtualDevice2Display3))); } @Test public void testDeviceShouldBeWoken() { assertTrue(mLogicalDisplayMapper.shouldDeviceBeWoken(DEVICE_STATE_OPEN, Loading Loading @@ -416,14 +508,22 @@ public class LogicalDisplayMapperTest { ///////////////// private TestDisplayDevice createDisplayDevice(int type, int width, int height, int flags) { return createDisplayDevice(new TestUtils.TestDisplayAddress(), type, width, height, flags); return createDisplayDevice( new TestUtils.TestDisplayAddress(), /* uniqueId */ "", type, width, height, flags); } private TestDisplayDevice createDisplayDevice( int type, String uniqueId, int width, int height, int flags) { return createDisplayDevice( new TestUtils.TestDisplayAddress(), uniqueId, type, width, height, flags); } private TestDisplayDevice createDisplayDevice( DisplayAddress address, int type, int width, int height, int flags) { DisplayAddress address, String uniqueId, int type, int width, int height, int flags) { TestDisplayDevice device = new TestDisplayDevice(); DisplayDeviceInfo displayDeviceInfo = device.getSourceInfo(); displayDeviceInfo.type = type; displayDeviceInfo.uniqueId = uniqueId; displayDeviceInfo.width = width; displayDeviceInfo.height = height; displayDeviceInfo.flags = flags; Loading