Loading core/java/android/hardware/input/IInputManager.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -122,9 +122,9 @@ interface IInputManager { void removePortAssociation(in String inputPort); // Add a runtime association between the input device and display. void addUniqueIdAssociation(in String inputDeviceName, in String displayUniqueId); void addUniqueIdAssociation(in String inputPort, in String displayUniqueId); // Remove the runtime association between the input device and display. void removeUniqueIdAssociation(in String inputDeviceName); void removeUniqueIdAssociation(in String inputPort); InputSensorInfo[] getSensorList(int deviceId); Loading core/java/android/hardware/input/InputManager.java +8 −9 Original line number Diff line number Diff line Loading @@ -1359,19 +1359,18 @@ public final class InputManager { } /** * Add a runtime association between the input device name and display, by unique id. Input * device names are expected to be unique. * @param inputDeviceName The name of the input device. * Add a runtime association between the input port and display, by unique id. Input ports are * expected to be unique. * @param inputPort The port of the input device. * @param displayUniqueId The unique id of the associated display. * <p> * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}. * </p> * @hide */ public void addUniqueIdAssociation(@NonNull String inputDeviceName, @NonNull String displayUniqueId) { public void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) { try { mIm.addUniqueIdAssociation(inputDeviceName, displayUniqueId); mIm.addUniqueIdAssociation(inputPort, displayUniqueId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading @@ -1379,15 +1378,15 @@ public final class InputManager { /** * Removes a runtime association between the input device and display. * @param inputDeviceName The name of the input device. * @param inputPort The port of the input device. * <p> * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}. * </p> * @hide */ public void removeUniqueIdAssociation(@NonNull String inputDeviceName) { public void removeUniqueIdAssociation(@NonNull String inputPort) { try { mIm.removeUniqueIdAssociation(inputDeviceName); mIm.removeUniqueIdAssociation(inputPort); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading services/companion/java/com/android/server/companion/virtual/InputController.java +69 −33 Original line number Diff line number Diff line Loading @@ -18,8 +18,11 @@ package com.android.server.companion.virtual; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.StringDef; import android.graphics.Point; import android.graphics.PointF; import android.hardware.display.DisplayManagerInternal; import android.hardware.input.InputManager; import android.hardware.input.InputManagerInternal; import android.hardware.input.VirtualKeyEvent; import android.hardware.input.VirtualMouseButtonEvent; Loading Loading @@ -48,6 +51,20 @@ class InputController { private static final String TAG = "VirtualInputController"; private static final AtomicLong sNextPhysId = new AtomicLong(1); static final String PHYS_TYPE_KEYBOARD = "Keyboard"; static final String PHYS_TYPE_MOUSE = "Mouse"; static final String PHYS_TYPE_TOUCHSCREEN = "Touchscreen"; @StringDef(prefix = { "PHYS_TYPE_" }, value = { PHYS_TYPE_KEYBOARD, PHYS_TYPE_MOUSE, PHYS_TYPE_TOUCHSCREEN, }) @Retention(RetentionPolicy.SOURCE) @interface PhysType { } private final Object mLock; /* Token -> file descriptor associations. */ Loading @@ -56,6 +73,8 @@ class InputController { final Map<IBinder, InputDeviceDescriptor> mInputDeviceDescriptors = new ArrayMap<>(); private final NativeWrapper mNativeWrapper; private final DisplayManagerInternal mDisplayManagerInternal; private final InputManagerInternal mInputManagerInternal; /** * Because the pointer is a singleton, it can only be targeted at one display at a time. Because Loading @@ -73,6 +92,8 @@ class InputController { mLock = lock; mNativeWrapper = nativeWrapper; mActivePointerDisplayId = Display.INVALID_DISPLAY; mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); } void close() { Loading @@ -90,7 +111,9 @@ class InputController { int productId, @NonNull IBinder deviceToken, int displayId) { final int fd = mNativeWrapper.openUinputKeyboard(deviceName, vendorId, productId); final String phys = createPhys(PHYS_TYPE_KEYBOARD); setUniqueIdAssociation(displayId, phys); final int fd = mNativeWrapper.openUinputKeyboard(deviceName, vendorId, productId, phys); if (fd < 0) { throw new RuntimeException( "A native error occurred when creating keyboard: " + -fd); Loading @@ -99,7 +122,7 @@ class InputController { synchronized (mLock) { mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(fd, binderDeathRecipient, InputDeviceDescriptor.TYPE_KEYBOARD, displayId)); InputDeviceDescriptor.TYPE_KEYBOARD, displayId, phys)); } try { deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0); Loading @@ -114,7 +137,9 @@ class InputController { int productId, @NonNull IBinder deviceToken, int displayId) { final int fd = mNativeWrapper.openUinputMouse(deviceName, vendorId, productId); final String phys = createPhys(PHYS_TYPE_MOUSE); setUniqueIdAssociation(displayId, phys); final int fd = mNativeWrapper.openUinputMouse(deviceName, vendorId, productId, phys); if (fd < 0) { throw new RuntimeException( "A native error occurred when creating mouse: " + -fd); Loading @@ -123,11 +148,9 @@ class InputController { synchronized (mLock) { mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(fd, binderDeathRecipient, InputDeviceDescriptor.TYPE_MOUSE, displayId)); final InputManagerInternal inputManagerInternal = LocalServices.getService(InputManagerInternal.class); inputManagerInternal.setVirtualMousePointerDisplayId(displayId); inputManagerInternal.setPointerAcceleration(1); InputDeviceDescriptor.TYPE_MOUSE, displayId, phys)); mInputManagerInternal.setVirtualMousePointerDisplayId(displayId); mInputManagerInternal.setPointerAcceleration(1); mActivePointerDisplayId = displayId; } try { Loading @@ -144,7 +167,9 @@ class InputController { @NonNull IBinder deviceToken, int displayId, @NonNull Point screenSize) { final int fd = mNativeWrapper.openUinputTouchscreen(deviceName, vendorId, productId, final String phys = createPhys(PHYS_TYPE_TOUCHSCREEN); setUniqueIdAssociation(displayId, phys); final int fd = mNativeWrapper.openUinputTouchscreen(deviceName, vendorId, productId, phys, screenSize.y, screenSize.x); if (fd < 0) { throw new RuntimeException( Loading @@ -154,7 +179,7 @@ class InputController { synchronized (mLock) { mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(fd, binderDeathRecipient, InputDeviceDescriptor.TYPE_TOUCHSCREEN, displayId)); InputDeviceDescriptor.TYPE_TOUCHSCREEN, displayId, phys)); } try { deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0); Loading @@ -174,6 +199,7 @@ class InputController { } token.unlinkToDeath(inputDeviceDescriptor.getDeathRecipient(), /* flags= */ 0); mNativeWrapper.closeUinput(inputDeviceDescriptor.getFileDescriptor()); InputManager.getInstance().removeUniqueIdAssociation(inputDeviceDescriptor.getPhys()); // Reset values to the default if all virtual mice are unregistered, or set display // id if there's another mouse (choose the most recent). Loading @@ -197,9 +223,7 @@ class InputController { } } if (mostRecentlyCreatedMouse != null) { final InputManagerInternal inputManagerInternal = LocalServices.getService(InputManagerInternal.class); inputManagerInternal.setVirtualMousePointerDisplayId( mInputManagerInternal.setVirtualMousePointerDisplayId( mostRecentlyCreatedMouse.getDisplayId()); mActivePointerDisplayId = mostRecentlyCreatedMouse.getDisplayId(); } else { Loading @@ -209,14 +233,21 @@ class InputController { } private void resetMouseValuesLocked() { final InputManagerInternal inputManagerInternal = LocalServices.getService(InputManagerInternal.class); inputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY); inputManagerInternal.setPointerAcceleration( mInputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY); mInputManagerInternal.setPointerAcceleration( IInputConstants.DEFAULT_POINTER_ACCELERATION); mActivePointerDisplayId = Display.INVALID_DISPLAY; } private static String createPhys(@PhysType String type) { return String.format("virtual%s:%d", type, sNextPhysId.getAndIncrement()); } private void setUniqueIdAssociation(int displayId, String phys) { final String displayUniqueId = mDisplayManagerInternal.getDisplayInfo(displayId).uniqueId; InputManager.getInstance().addUniqueIdAssociation(phys, displayUniqueId); } boolean sendKeyEvent(@NonNull IBinder token, @NonNull VirtualKeyEvent event) { synchronized (mLock) { final InputDeviceDescriptor inputDeviceDescriptor = mInputDeviceDescriptors.get( Loading Loading @@ -321,17 +352,18 @@ class InputController { fout.println(" creationOrder: " + inputDeviceDescriptor.getCreationOrderNumber()); fout.println(" type: " + inputDeviceDescriptor.getType()); fout.println(" phys: " + inputDeviceDescriptor.getPhys()); } fout.println(" Active mouse display id: " + mActivePointerDisplayId); } } private static native int nativeOpenUinputKeyboard(String deviceName, int vendorId, int productId); private static native int nativeOpenUinputMouse(String deviceName, int vendorId, int productId); int productId, String phys); private static native int nativeOpenUinputMouse(String deviceName, int vendorId, int productId, String phys); private static native int nativeOpenUinputTouchscreen(String deviceName, int vendorId, int productId, int height, int width); int productId, String phys, int height, int width); private static native boolean nativeCloseUinput(int fd); private static native boolean nativeWriteKeyEvent(int fd, int androidKeyCode, int action); private static native boolean nativeWriteButtonEvent(int fd, int buttonCode, int action); Loading @@ -345,20 +377,18 @@ class InputController { /** Wrapper around the static native methods for tests. */ @VisibleForTesting protected static class NativeWrapper { public int openUinputKeyboard(String deviceName, int vendorId, int productId) { return nativeOpenUinputKeyboard(deviceName, vendorId, productId); public int openUinputKeyboard(String deviceName, int vendorId, int productId, String phys) { return nativeOpenUinputKeyboard(deviceName, vendorId, productId, phys); } public int openUinputMouse(String deviceName, int vendorId, int productId) { return nativeOpenUinputMouse(deviceName, vendorId, productId); public int openUinputMouse(String deviceName, int vendorId, int productId, String phys) { return nativeOpenUinputMouse(deviceName, vendorId, productId, phys); } public int openUinputTouchscreen(String deviceName, int vendorId, int productId, int height, int width) { return nativeOpenUinputTouchscreen(deviceName, vendorId, productId, height, width); public int openUinputTouchscreen(String deviceName, int vendorId, int productId, String phys, int height, int width) { return nativeOpenUinputTouchscreen(deviceName, vendorId, productId, phys, height, width); } public boolean closeUinput(int fd) { Loading Loading @@ -410,15 +440,17 @@ class InputController { private final IBinder.DeathRecipient mDeathRecipient; private final @Type int mType; private final int mDisplayId; private final String mPhys; // Monotonically increasing number; devices with lower numbers were created earlier. private final long mCreationOrderNumber; InputDeviceDescriptor(int fd, IBinder.DeathRecipient deathRecipient, @Type int type, int displayId) { InputDeviceDescriptor(int fd, IBinder.DeathRecipient deathRecipient, @Type int type, int displayId, String phys) { mFd = fd; mDeathRecipient = deathRecipient; mType = type; mDisplayId = displayId; mPhys = phys; mCreationOrderNumber = sNextCreationOrderNumber.getAndIncrement(); } Loading @@ -445,6 +477,10 @@ class InputController { public long getCreationOrderNumber() { return mCreationOrderNumber; } public String getPhys() { return mPhys; } } private final class BinderDeathRecipient implements IBinder.DeathRecipient { Loading services/core/java/com/android/server/input/InputManagerService.java +13 −16 Original line number Diff line number Diff line Loading @@ -2285,14 +2285,8 @@ public class InputManagerService extends IInputManager.Stub nativeNotifyPortAssociationsChanged(mPtr); } /** * Add a runtime association between the input device name and the display unique id. * @param inputDeviceName The name of the input device. * @param displayUniqueId The unique id of the associated display. */ @Override // Binder call public void addUniqueIdAssociation(@NonNull String inputDeviceName, @NonNull String displayUniqueId) { public void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) { if (!checkCallingPermission( android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, "addNameAssociation()")) { Loading @@ -2300,20 +2294,16 @@ public class InputManagerService extends IInputManager.Stub "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); } Objects.requireNonNull(inputDeviceName); Objects.requireNonNull(inputPort); Objects.requireNonNull(displayUniqueId); synchronized (mAssociationsLock) { mUniqueIdAssociations.put(inputDeviceName, displayUniqueId); mUniqueIdAssociations.put(inputPort, displayUniqueId); } nativeChangeUniqueIdAssociation(mPtr); } /** * Remove the runtime association between the input device and the display. * @param inputDeviceName The port of the input device to be cleared. */ @Override // Binder call public void removeUniqueIdAssociation(@NonNull String inputDeviceName) { public void removeUniqueIdAssociation(@NonNull String inputPort) { if (!checkCallingPermission( android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, "removeUniqueIdAssociation()")) { Loading @@ -2321,9 +2311,9 @@ public class InputManagerService extends IInputManager.Stub "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); } Objects.requireNonNull(inputDeviceName); Objects.requireNonNull(inputPort); synchronized (mAssociationsLock) { mUniqueIdAssociations.remove(inputDeviceName); mUniqueIdAssociations.remove(inputPort); } nativeChangeUniqueIdAssociation(mPtr); } Loading Loading @@ -2594,6 +2584,13 @@ public class InputManagerService extends IInputManager.Stub pw.println(" display: " + v); }); } if (!mUniqueIdAssociations.isEmpty()) { pw.println("Unique Id Associations:"); mUniqueIdAssociations.forEach((k, v) -> { pw.print(" port: " + k); pw.println(" uniqueId: " + v); }); } } } Loading services/core/jni/com_android_server_companion_virtual_InputController.cpp +21 −15 Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ static std::map<int, int> KEY_CODE_MAPPING = { }; /** Creates a new uinput device and assigns a file descriptor. */ static int openUinput(const char* readableName, jint vendorId, jint productId, static int openUinput(const char* readableName, jint vendorId, jint productId, const char* phys, DeviceType deviceType, jint screenHeight, jint screenWidth) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(::open("/dev/uinput", O_WRONLY | O_NONBLOCK))); if (fd < 0) { Loading @@ -194,6 +194,8 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, return -errno; } ioctl(fd, UI_SET_PHYS, phys); ioctl(fd, UI_SET_EVBIT, EV_KEY); ioctl(fd, UI_SET_EVBIT, EV_SYN); switch (deviceType) { Loading Loading @@ -295,28 +297,30 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, return fd.release(); } static int openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId, static int openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId, jstring phys, DeviceType deviceType, int screenHeight, int screenWidth) { ScopedUtfChars readableName(env, name); return openUinput(readableName.c_str(), vendorId, productId, deviceType, screenHeight, screenWidth); ScopedUtfChars readablePhys(env, phys); return openUinput(readableName.c_str(), vendorId, productId, readablePhys.c_str(), deviceType, screenHeight, screenWidth); } static int nativeOpenUinputKeyboard(JNIEnv* env, jobject thiz, jstring name, jint vendorId, jint productId) { return openUinputJni(env, name, vendorId, productId, DeviceType::KEYBOARD, /* screenHeight */ 0, /* screenWidth */ 0); jint productId, jstring phys) { return openUinputJni(env, name, vendorId, productId, phys, DeviceType::KEYBOARD, /* screenHeight */ 0, /* screenWidth */ 0); } static int nativeOpenUinputMouse(JNIEnv* env, jobject thiz, jstring name, jint vendorId, jint productId) { return openUinputJni(env, name, vendorId, productId, DeviceType::MOUSE, /* screenHeight */ 0, /* screenWidth */ 0); jint productId, jstring phys) { return openUinputJni(env, name, vendorId, productId, phys, DeviceType::MOUSE, /* screenHeight */ 0, /* screenWidth */ 0); } static int nativeOpenUinputTouchscreen(JNIEnv* env, jobject thiz, jstring name, jint vendorId, jint productId, jint height, jint width) { return openUinputJni(env, name, vendorId, productId, DeviceType::TOUCHSCREEN, height, width); jint productId, jstring phys, jint height, jint width) { return openUinputJni(env, name, vendorId, productId, phys, DeviceType::TOUCHSCREEN, height, width); } static bool nativeCloseUinput(JNIEnv* env, jobject thiz, jint fd) { Loading Loading @@ -435,9 +439,11 @@ static bool nativeWriteScrollEvent(JNIEnv* env, jobject thiz, jint fd, jfloat xA } static JNINativeMethod methods[] = { {"nativeOpenUinputKeyboard", "(Ljava/lang/String;II)I", (void*)nativeOpenUinputKeyboard}, {"nativeOpenUinputMouse", "(Ljava/lang/String;II)I", (void*)nativeOpenUinputMouse}, {"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IIII)I", {"nativeOpenUinputKeyboard", "(Ljava/lang/String;IILjava/lang/String;)I", (void*)nativeOpenUinputKeyboard}, {"nativeOpenUinputMouse", "(Ljava/lang/String;IILjava/lang/String;)I", (void*)nativeOpenUinputMouse}, {"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IILjava/lang/String;II)I", (void*)nativeOpenUinputTouchscreen}, {"nativeCloseUinput", "(I)Z", (void*)nativeCloseUinput}, {"nativeWriteKeyEvent", "(III)Z", (void*)nativeWriteKeyEvent}, Loading Loading
core/java/android/hardware/input/IInputManager.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -122,9 +122,9 @@ interface IInputManager { void removePortAssociation(in String inputPort); // Add a runtime association between the input device and display. void addUniqueIdAssociation(in String inputDeviceName, in String displayUniqueId); void addUniqueIdAssociation(in String inputPort, in String displayUniqueId); // Remove the runtime association between the input device and display. void removeUniqueIdAssociation(in String inputDeviceName); void removeUniqueIdAssociation(in String inputPort); InputSensorInfo[] getSensorList(int deviceId); Loading
core/java/android/hardware/input/InputManager.java +8 −9 Original line number Diff line number Diff line Loading @@ -1359,19 +1359,18 @@ public final class InputManager { } /** * Add a runtime association between the input device name and display, by unique id. Input * device names are expected to be unique. * @param inputDeviceName The name of the input device. * Add a runtime association between the input port and display, by unique id. Input ports are * expected to be unique. * @param inputPort The port of the input device. * @param displayUniqueId The unique id of the associated display. * <p> * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}. * </p> * @hide */ public void addUniqueIdAssociation(@NonNull String inputDeviceName, @NonNull String displayUniqueId) { public void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) { try { mIm.addUniqueIdAssociation(inputDeviceName, displayUniqueId); mIm.addUniqueIdAssociation(inputPort, displayUniqueId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading @@ -1379,15 +1378,15 @@ public final class InputManager { /** * Removes a runtime association between the input device and display. * @param inputDeviceName The name of the input device. * @param inputPort The port of the input device. * <p> * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}. * </p> * @hide */ public void removeUniqueIdAssociation(@NonNull String inputDeviceName) { public void removeUniqueIdAssociation(@NonNull String inputPort) { try { mIm.removeUniqueIdAssociation(inputDeviceName); mIm.removeUniqueIdAssociation(inputPort); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading
services/companion/java/com/android/server/companion/virtual/InputController.java +69 −33 Original line number Diff line number Diff line Loading @@ -18,8 +18,11 @@ package com.android.server.companion.virtual; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.StringDef; import android.graphics.Point; import android.graphics.PointF; import android.hardware.display.DisplayManagerInternal; import android.hardware.input.InputManager; import android.hardware.input.InputManagerInternal; import android.hardware.input.VirtualKeyEvent; import android.hardware.input.VirtualMouseButtonEvent; Loading Loading @@ -48,6 +51,20 @@ class InputController { private static final String TAG = "VirtualInputController"; private static final AtomicLong sNextPhysId = new AtomicLong(1); static final String PHYS_TYPE_KEYBOARD = "Keyboard"; static final String PHYS_TYPE_MOUSE = "Mouse"; static final String PHYS_TYPE_TOUCHSCREEN = "Touchscreen"; @StringDef(prefix = { "PHYS_TYPE_" }, value = { PHYS_TYPE_KEYBOARD, PHYS_TYPE_MOUSE, PHYS_TYPE_TOUCHSCREEN, }) @Retention(RetentionPolicy.SOURCE) @interface PhysType { } private final Object mLock; /* Token -> file descriptor associations. */ Loading @@ -56,6 +73,8 @@ class InputController { final Map<IBinder, InputDeviceDescriptor> mInputDeviceDescriptors = new ArrayMap<>(); private final NativeWrapper mNativeWrapper; private final DisplayManagerInternal mDisplayManagerInternal; private final InputManagerInternal mInputManagerInternal; /** * Because the pointer is a singleton, it can only be targeted at one display at a time. Because Loading @@ -73,6 +92,8 @@ class InputController { mLock = lock; mNativeWrapper = nativeWrapper; mActivePointerDisplayId = Display.INVALID_DISPLAY; mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); } void close() { Loading @@ -90,7 +111,9 @@ class InputController { int productId, @NonNull IBinder deviceToken, int displayId) { final int fd = mNativeWrapper.openUinputKeyboard(deviceName, vendorId, productId); final String phys = createPhys(PHYS_TYPE_KEYBOARD); setUniqueIdAssociation(displayId, phys); final int fd = mNativeWrapper.openUinputKeyboard(deviceName, vendorId, productId, phys); if (fd < 0) { throw new RuntimeException( "A native error occurred when creating keyboard: " + -fd); Loading @@ -99,7 +122,7 @@ class InputController { synchronized (mLock) { mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(fd, binderDeathRecipient, InputDeviceDescriptor.TYPE_KEYBOARD, displayId)); InputDeviceDescriptor.TYPE_KEYBOARD, displayId, phys)); } try { deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0); Loading @@ -114,7 +137,9 @@ class InputController { int productId, @NonNull IBinder deviceToken, int displayId) { final int fd = mNativeWrapper.openUinputMouse(deviceName, vendorId, productId); final String phys = createPhys(PHYS_TYPE_MOUSE); setUniqueIdAssociation(displayId, phys); final int fd = mNativeWrapper.openUinputMouse(deviceName, vendorId, productId, phys); if (fd < 0) { throw new RuntimeException( "A native error occurred when creating mouse: " + -fd); Loading @@ -123,11 +148,9 @@ class InputController { synchronized (mLock) { mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(fd, binderDeathRecipient, InputDeviceDescriptor.TYPE_MOUSE, displayId)); final InputManagerInternal inputManagerInternal = LocalServices.getService(InputManagerInternal.class); inputManagerInternal.setVirtualMousePointerDisplayId(displayId); inputManagerInternal.setPointerAcceleration(1); InputDeviceDescriptor.TYPE_MOUSE, displayId, phys)); mInputManagerInternal.setVirtualMousePointerDisplayId(displayId); mInputManagerInternal.setPointerAcceleration(1); mActivePointerDisplayId = displayId; } try { Loading @@ -144,7 +167,9 @@ class InputController { @NonNull IBinder deviceToken, int displayId, @NonNull Point screenSize) { final int fd = mNativeWrapper.openUinputTouchscreen(deviceName, vendorId, productId, final String phys = createPhys(PHYS_TYPE_TOUCHSCREEN); setUniqueIdAssociation(displayId, phys); final int fd = mNativeWrapper.openUinputTouchscreen(deviceName, vendorId, productId, phys, screenSize.y, screenSize.x); if (fd < 0) { throw new RuntimeException( Loading @@ -154,7 +179,7 @@ class InputController { synchronized (mLock) { mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(fd, binderDeathRecipient, InputDeviceDescriptor.TYPE_TOUCHSCREEN, displayId)); InputDeviceDescriptor.TYPE_TOUCHSCREEN, displayId, phys)); } try { deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0); Loading @@ -174,6 +199,7 @@ class InputController { } token.unlinkToDeath(inputDeviceDescriptor.getDeathRecipient(), /* flags= */ 0); mNativeWrapper.closeUinput(inputDeviceDescriptor.getFileDescriptor()); InputManager.getInstance().removeUniqueIdAssociation(inputDeviceDescriptor.getPhys()); // Reset values to the default if all virtual mice are unregistered, or set display // id if there's another mouse (choose the most recent). Loading @@ -197,9 +223,7 @@ class InputController { } } if (mostRecentlyCreatedMouse != null) { final InputManagerInternal inputManagerInternal = LocalServices.getService(InputManagerInternal.class); inputManagerInternal.setVirtualMousePointerDisplayId( mInputManagerInternal.setVirtualMousePointerDisplayId( mostRecentlyCreatedMouse.getDisplayId()); mActivePointerDisplayId = mostRecentlyCreatedMouse.getDisplayId(); } else { Loading @@ -209,14 +233,21 @@ class InputController { } private void resetMouseValuesLocked() { final InputManagerInternal inputManagerInternal = LocalServices.getService(InputManagerInternal.class); inputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY); inputManagerInternal.setPointerAcceleration( mInputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY); mInputManagerInternal.setPointerAcceleration( IInputConstants.DEFAULT_POINTER_ACCELERATION); mActivePointerDisplayId = Display.INVALID_DISPLAY; } private static String createPhys(@PhysType String type) { return String.format("virtual%s:%d", type, sNextPhysId.getAndIncrement()); } private void setUniqueIdAssociation(int displayId, String phys) { final String displayUniqueId = mDisplayManagerInternal.getDisplayInfo(displayId).uniqueId; InputManager.getInstance().addUniqueIdAssociation(phys, displayUniqueId); } boolean sendKeyEvent(@NonNull IBinder token, @NonNull VirtualKeyEvent event) { synchronized (mLock) { final InputDeviceDescriptor inputDeviceDescriptor = mInputDeviceDescriptors.get( Loading Loading @@ -321,17 +352,18 @@ class InputController { fout.println(" creationOrder: " + inputDeviceDescriptor.getCreationOrderNumber()); fout.println(" type: " + inputDeviceDescriptor.getType()); fout.println(" phys: " + inputDeviceDescriptor.getPhys()); } fout.println(" Active mouse display id: " + mActivePointerDisplayId); } } private static native int nativeOpenUinputKeyboard(String deviceName, int vendorId, int productId); private static native int nativeOpenUinputMouse(String deviceName, int vendorId, int productId); int productId, String phys); private static native int nativeOpenUinputMouse(String deviceName, int vendorId, int productId, String phys); private static native int nativeOpenUinputTouchscreen(String deviceName, int vendorId, int productId, int height, int width); int productId, String phys, int height, int width); private static native boolean nativeCloseUinput(int fd); private static native boolean nativeWriteKeyEvent(int fd, int androidKeyCode, int action); private static native boolean nativeWriteButtonEvent(int fd, int buttonCode, int action); Loading @@ -345,20 +377,18 @@ class InputController { /** Wrapper around the static native methods for tests. */ @VisibleForTesting protected static class NativeWrapper { public int openUinputKeyboard(String deviceName, int vendorId, int productId) { return nativeOpenUinputKeyboard(deviceName, vendorId, productId); public int openUinputKeyboard(String deviceName, int vendorId, int productId, String phys) { return nativeOpenUinputKeyboard(deviceName, vendorId, productId, phys); } public int openUinputMouse(String deviceName, int vendorId, int productId) { return nativeOpenUinputMouse(deviceName, vendorId, productId); public int openUinputMouse(String deviceName, int vendorId, int productId, String phys) { return nativeOpenUinputMouse(deviceName, vendorId, productId, phys); } public int openUinputTouchscreen(String deviceName, int vendorId, int productId, int height, int width) { return nativeOpenUinputTouchscreen(deviceName, vendorId, productId, height, width); public int openUinputTouchscreen(String deviceName, int vendorId, int productId, String phys, int height, int width) { return nativeOpenUinputTouchscreen(deviceName, vendorId, productId, phys, height, width); } public boolean closeUinput(int fd) { Loading Loading @@ -410,15 +440,17 @@ class InputController { private final IBinder.DeathRecipient mDeathRecipient; private final @Type int mType; private final int mDisplayId; private final String mPhys; // Monotonically increasing number; devices with lower numbers were created earlier. private final long mCreationOrderNumber; InputDeviceDescriptor(int fd, IBinder.DeathRecipient deathRecipient, @Type int type, int displayId) { InputDeviceDescriptor(int fd, IBinder.DeathRecipient deathRecipient, @Type int type, int displayId, String phys) { mFd = fd; mDeathRecipient = deathRecipient; mType = type; mDisplayId = displayId; mPhys = phys; mCreationOrderNumber = sNextCreationOrderNumber.getAndIncrement(); } Loading @@ -445,6 +477,10 @@ class InputController { public long getCreationOrderNumber() { return mCreationOrderNumber; } public String getPhys() { return mPhys; } } private final class BinderDeathRecipient implements IBinder.DeathRecipient { Loading
services/core/java/com/android/server/input/InputManagerService.java +13 −16 Original line number Diff line number Diff line Loading @@ -2285,14 +2285,8 @@ public class InputManagerService extends IInputManager.Stub nativeNotifyPortAssociationsChanged(mPtr); } /** * Add a runtime association between the input device name and the display unique id. * @param inputDeviceName The name of the input device. * @param displayUniqueId The unique id of the associated display. */ @Override // Binder call public void addUniqueIdAssociation(@NonNull String inputDeviceName, @NonNull String displayUniqueId) { public void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) { if (!checkCallingPermission( android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, "addNameAssociation()")) { Loading @@ -2300,20 +2294,16 @@ public class InputManagerService extends IInputManager.Stub "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); } Objects.requireNonNull(inputDeviceName); Objects.requireNonNull(inputPort); Objects.requireNonNull(displayUniqueId); synchronized (mAssociationsLock) { mUniqueIdAssociations.put(inputDeviceName, displayUniqueId); mUniqueIdAssociations.put(inputPort, displayUniqueId); } nativeChangeUniqueIdAssociation(mPtr); } /** * Remove the runtime association between the input device and the display. * @param inputDeviceName The port of the input device to be cleared. */ @Override // Binder call public void removeUniqueIdAssociation(@NonNull String inputDeviceName) { public void removeUniqueIdAssociation(@NonNull String inputPort) { if (!checkCallingPermission( android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, "removeUniqueIdAssociation()")) { Loading @@ -2321,9 +2311,9 @@ public class InputManagerService extends IInputManager.Stub "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); } Objects.requireNonNull(inputDeviceName); Objects.requireNonNull(inputPort); synchronized (mAssociationsLock) { mUniqueIdAssociations.remove(inputDeviceName); mUniqueIdAssociations.remove(inputPort); } nativeChangeUniqueIdAssociation(mPtr); } Loading Loading @@ -2594,6 +2584,13 @@ public class InputManagerService extends IInputManager.Stub pw.println(" display: " + v); }); } if (!mUniqueIdAssociations.isEmpty()) { pw.println("Unique Id Associations:"); mUniqueIdAssociations.forEach((k, v) -> { pw.print(" port: " + k); pw.println(" uniqueId: " + v); }); } } } Loading
services/core/jni/com_android_server_companion_virtual_InputController.cpp +21 −15 Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ static std::map<int, int> KEY_CODE_MAPPING = { }; /** Creates a new uinput device and assigns a file descriptor. */ static int openUinput(const char* readableName, jint vendorId, jint productId, static int openUinput(const char* readableName, jint vendorId, jint productId, const char* phys, DeviceType deviceType, jint screenHeight, jint screenWidth) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(::open("/dev/uinput", O_WRONLY | O_NONBLOCK))); if (fd < 0) { Loading @@ -194,6 +194,8 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, return -errno; } ioctl(fd, UI_SET_PHYS, phys); ioctl(fd, UI_SET_EVBIT, EV_KEY); ioctl(fd, UI_SET_EVBIT, EV_SYN); switch (deviceType) { Loading Loading @@ -295,28 +297,30 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, return fd.release(); } static int openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId, static int openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId, jstring phys, DeviceType deviceType, int screenHeight, int screenWidth) { ScopedUtfChars readableName(env, name); return openUinput(readableName.c_str(), vendorId, productId, deviceType, screenHeight, screenWidth); ScopedUtfChars readablePhys(env, phys); return openUinput(readableName.c_str(), vendorId, productId, readablePhys.c_str(), deviceType, screenHeight, screenWidth); } static int nativeOpenUinputKeyboard(JNIEnv* env, jobject thiz, jstring name, jint vendorId, jint productId) { return openUinputJni(env, name, vendorId, productId, DeviceType::KEYBOARD, /* screenHeight */ 0, /* screenWidth */ 0); jint productId, jstring phys) { return openUinputJni(env, name, vendorId, productId, phys, DeviceType::KEYBOARD, /* screenHeight */ 0, /* screenWidth */ 0); } static int nativeOpenUinputMouse(JNIEnv* env, jobject thiz, jstring name, jint vendorId, jint productId) { return openUinputJni(env, name, vendorId, productId, DeviceType::MOUSE, /* screenHeight */ 0, /* screenWidth */ 0); jint productId, jstring phys) { return openUinputJni(env, name, vendorId, productId, phys, DeviceType::MOUSE, /* screenHeight */ 0, /* screenWidth */ 0); } static int nativeOpenUinputTouchscreen(JNIEnv* env, jobject thiz, jstring name, jint vendorId, jint productId, jint height, jint width) { return openUinputJni(env, name, vendorId, productId, DeviceType::TOUCHSCREEN, height, width); jint productId, jstring phys, jint height, jint width) { return openUinputJni(env, name, vendorId, productId, phys, DeviceType::TOUCHSCREEN, height, width); } static bool nativeCloseUinput(JNIEnv* env, jobject thiz, jint fd) { Loading Loading @@ -435,9 +439,11 @@ static bool nativeWriteScrollEvent(JNIEnv* env, jobject thiz, jint fd, jfloat xA } static JNINativeMethod methods[] = { {"nativeOpenUinputKeyboard", "(Ljava/lang/String;II)I", (void*)nativeOpenUinputKeyboard}, {"nativeOpenUinputMouse", "(Ljava/lang/String;II)I", (void*)nativeOpenUinputMouse}, {"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IIII)I", {"nativeOpenUinputKeyboard", "(Ljava/lang/String;IILjava/lang/String;)I", (void*)nativeOpenUinputKeyboard}, {"nativeOpenUinputMouse", "(Ljava/lang/String;IILjava/lang/String;)I", (void*)nativeOpenUinputMouse}, {"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IILjava/lang/String;II)I", (void*)nativeOpenUinputTouchscreen}, {"nativeCloseUinput", "(I)Z", (void*)nativeCloseUinput}, {"nativeWriteKeyEvent", "(III)Z", (void*)nativeWriteKeyEvent}, Loading