Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3da7b8b7 authored by Phill Hayers's avatar Phill Hayers Committed by Android (Google) Code Review
Browse files

Merge "Assign virtual devices to a device display group."

parents 384e8af6 9fcd0d00
Loading
Loading
Loading
Loading
+39 −11
Original line number Diff line number Diff line
@@ -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,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;
        }
@@ -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) {
+62 −3
Original line number Diff line number Diff line
@@ -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;
    }

+112 −0
Original line number Diff line number Diff line
@@ -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);
+102 −2
Original line number Diff line number Diff line
@@ -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,
@@ -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;