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

Commit 9214d4fc authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Android (Google) Code Review
Browse files

Merge "InputController: Wait for associated display sync for input devices" into main

parents 4c44c37a 4b74275b
Loading
Loading
Loading
Loading
+20 −15
Original line number Diff line number Diff line
@@ -692,32 +692,37 @@ class InputController {

        private int mInputDeviceId = IInputConstants.INVALID_INPUT_DEVICE_ID;

        WaitForDevice(String deviceName, int vendorId, int productId) {
        WaitForDevice(String deviceName, int vendorId, int productId, int associatedDisplayId) {
            mListener = new InputManager.InputDeviceListener() {
                @Override
                public void onInputDeviceAdded(int deviceId) {
                    final InputDevice device = InputManagerGlobal.getInstance().getInputDevice(
                            deviceId);
                    Objects.requireNonNull(device, "Newly added input device was null.");
                    if (!device.getName().equals(deviceName)) {
                        return;
                    }
                    final InputDeviceIdentifier id = device.getIdentifier();
                    if (id.getVendorId() != vendorId || id.getProductId() != productId) {
                        return;
                    }
                    mInputDeviceId = deviceId;
                    mDeviceAddedLatch.countDown();
                    onInputDeviceChanged(deviceId);
                }

                @Override
                public void onInputDeviceRemoved(int deviceId) {

                }

                @Override
                public void onInputDeviceChanged(int deviceId) {
                    if (isMatchingDevice(deviceId)) {
                        mInputDeviceId = deviceId;
                        mDeviceAddedLatch.countDown();
                    }
                }

                private boolean isMatchingDevice(int deviceId) {
                    final InputDevice device = InputManagerGlobal.getInstance().getInputDevice(
                            deviceId);
                    Objects.requireNonNull(device, "Newly added input device was null.");
                    if (!device.getName().equals(deviceName)) {
                        return false;
                    }
                    final InputDeviceIdentifier id = device.getIdentifier();
                    if (id.getVendorId() != vendorId || id.getProductId() != productId) {
                        return false;
                    }
                    return device.getAssociatedDisplayId() == associatedDisplayId;
                }
            };
            InputManagerGlobal.getInstance().registerInputDeviceListener(mListener, mHandler);
@@ -799,7 +804,7 @@ class InputController {
        final int inputDeviceId;

        setUniqueIdAssociation(displayId, phys);
        try (WaitForDevice waiter = new WaitForDevice(deviceName, vendorId, productId)) {
        try (WaitForDevice waiter = new WaitForDevice(deviceName, vendorId, productId, displayId)) {
            ptr = deviceOpener.get();
            // See INVALID_PTR in libs/input/VirtualInputDevice.cpp.
            if (ptr == 0) {
+13 −5
Original line number Diff line number Diff line
@@ -19,11 +19,10 @@ package com.android.server.companion.virtual;
import static com.google.common.truth.Truth.assertWithMessage;

import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;

import android.hardware.display.DisplayManagerInternal;
@@ -86,9 +85,8 @@ public class InputControllerTest {
        LocalServices.removeServiceForTest(InputManagerInternal.class);
        LocalServices.addService(InputManagerInternal.class, mInputManagerInternalMock);

        final DisplayInfo displayInfo = new DisplayInfo();
        displayInfo.uniqueId = "uniqueId";
        doReturn(displayInfo).when(mDisplayManagerInternalMock).getDisplayInfo(anyInt());
        setUpDisplay(1 /* displayId */);
        setUpDisplay(2 /* displayId */);
        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
        LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);

@@ -100,6 +98,16 @@ public class InputControllerTest {
                threadVerifier);
    }

    void setUpDisplay(int displayId) {
        final String uniqueId = "uniqueId:" + displayId;
        doAnswer((inv) -> {
            final DisplayInfo displayInfo = new DisplayInfo();
            displayInfo.uniqueId = uniqueId;
            return displayInfo;
        }).when(mDisplayManagerInternalMock).getDisplayInfo(eq(displayId));
        mInputManagerMockHelper.addDisplayIdMapping(uniqueId, displayId);
    }

    @After
    public void tearDown() {
        mInputManagerMockHelper.tearDown();
+20 −4
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;

import android.hardware.input.IInputDevicesChangedListener;
@@ -28,12 +27,15 @@ import android.hardware.input.IInputManager;
import android.hardware.input.InputManagerGlobal;
import android.os.RemoteException;
import android.testing.TestableLooper;
import android.view.Display;
import android.view.InputDevice;

import org.mockito.invocation.InvocationOnMock;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.IntStream;

@@ -49,6 +51,10 @@ class InputManagerMockHelper {
    private final InputManagerGlobal.TestSession mInputManagerGlobalSession;
    private final List<InputDevice> mDevices = new ArrayList<>();
    private IInputDevicesChangedListener mDevicesChangedListener;
    private final Map<String /* uniqueId */, Integer /* displayId */> mDisplayIdMapping =
            new HashMap<>();
    private final Map<String /* phys */, String /* uniqueId */> mUniqueIdAssociation =
            new HashMap<>();

    InputManagerMockHelper(TestableLooper testableLooper,
            InputController.NativeWrapper nativeWrapperMock, IInputManager iInputManagerMock)
@@ -73,8 +79,10 @@ class InputManagerMockHelper {
        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
        doAnswer(inv -> mDevices.get(inv.getArgument(0)))
                .when(mIInputManagerMock).getInputDevice(anyInt());
        doNothing().when(mIInputManagerMock).addUniqueIdAssociation(anyString(), anyString());
        doNothing().when(mIInputManagerMock).removeUniqueIdAssociation(anyString());
        doAnswer(inv -> mUniqueIdAssociation.put(inv.getArgument(0), inv.getArgument(1))).when(
                mIInputManagerMock).addUniqueIdAssociation(anyString(), anyString());
        doAnswer(inv -> mUniqueIdAssociation.remove(inv.getArgument(0))).when(
                mIInputManagerMock).removeUniqueIdAssociation(anyString());

        // Set a new instance of InputManager for testing that uses the IInputManager mock as the
        // interface to the server.
@@ -87,17 +95,25 @@ class InputManagerMockHelper {
        }
    }

    public void addDisplayIdMapping(String uniqueId, int displayId) {
        mDisplayIdMapping.put(uniqueId, displayId);
    }

    private long handleNativeOpenInputDevice(InvocationOnMock inv) {
        Objects.requireNonNull(mDevicesChangedListener,
                "InputController did not register an InputDevicesChangedListener.");

        final String phys = inv.getArgument(3);
        final InputDevice device = new InputDevice.Builder()
                .setId(mDevices.size())
                .setName(inv.getArgument(0))
                .setVendorId(inv.getArgument(1))
                .setProductId(inv.getArgument(2))
                .setDescriptor(inv.getArgument(3))
                .setDescriptor(phys)
                .setExternal(true)
                .setAssociatedDisplayId(
                        mDisplayIdMapping.getOrDefault(mUniqueIdAssociation.get(phys),
                                Display.INVALID_DISPLAY))
                .build();

        mDevices.add(device);
+8 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -2015,6 +2016,13 @@ public class VirtualDeviceManagerServiceTest {
                eq(virtualDevice), any(), any())).thenReturn(displayId);
        virtualDevice.createVirtualDisplay(VIRTUAL_DISPLAY_CONFIG, mVirtualDisplayCallback,
                NONBLOCKED_APP_PACKAGE_NAME);
        final String uniqueId = UNIQUE_ID + displayId;
        doAnswer(inv -> {
            final DisplayInfo displayInfo = new DisplayInfo();
            displayInfo.uniqueId = uniqueId;
            return displayInfo;
        }).when(mDisplayManagerInternalMock).getDisplayInfo(eq(displayId));
        mInputManagerMockHelper.addDisplayIdMapping(uniqueId, displayId);
    }

    private ComponentName getPermissionDialogComponent() {