summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java50
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java65
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java112
-rw-r--r--services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java104
4 files changed, 315 insertions, 16 deletions
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 19069ea891a4..5eb15e09f09e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -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;
}
@@ -1369,12 +1377,20 @@ 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 "
- + "because the virtual display adapter is not available.");
+ Slog.w(
+ TAG,
+ "Rejecting request to create private virtual display "
+ + "because the virtual display adapter is not available.");
return -1;
}
@@ -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
@@ -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) {
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 70c9e23c6af8..cb97e2832854 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -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;
@@ -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;
@@ -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;
@@ -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);
@@ -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);
@@ -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
@@ -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;
}
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 6860abf40b56..062bde8f080b 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -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;
@@ -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);
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 0b33c30fd7e8..657bda633ab5 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -369,6 +369,98 @@ public class LogicalDisplayMapperTest {
}
@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,
DEVICE_STATE_CLOSED,
@@ -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;