Loading core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -2761,6 +2761,7 @@ package android.companion.virtual { method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.LaunchCallback); method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setShowPointerIcon(boolean); } public final class VirtualDeviceParams implements android.os.Parcelable { core/java/android/companion/virtual/IVirtualDevice.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -77,4 +77,7 @@ interface IVirtualDevice { void launchPendingIntent( int displayId, in PendingIntent pendingIntent, in ResultReceiver resultReceiver); PointF getCursorPosition(IBinder token); /** Sets whether to show or hide the cursor while this virtual device is active. */ void setShowPointerIcon(boolean showPointerIcon); } core/java/android/companion/virtual/VirtualDeviceManager.java +16 −0 Original line number Diff line number Diff line Loading @@ -337,6 +337,22 @@ public final class VirtualDeviceManager { } } /** * Sets the visibility of the pointer icon for this VirtualDevice's associated displays. * * @param showPointerIcon True if the pointer should be shown; false otherwise. The default * visibility is true. */ @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) @NonNull public void setShowPointerIcon(boolean showPointerIcon) { try { mVirtualDevice.setShowPointerIcon(showPointerIcon); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns the display flags that should be added to a particular virtual display. * Additional device-level flags from {@link Loading core/java/android/hardware/input/InputManagerInternal.java +10 −1 Original line number Diff line number Diff line Loading @@ -87,6 +87,12 @@ public abstract class InputManagerInternal { */ public abstract void setVirtualMousePointerDisplayId(int pointerDisplayId); /** * Gets the display id that the MouseCursorController is being forced to target. Returns * {@link android.view.Display#INVALID_DISPLAY} if there is no override */ public abstract int getVirtualMousePointerDisplayId(); /** Gets the current position of the mouse cursor. */ public abstract PointF getCursorPosition(); Loading @@ -94,7 +100,7 @@ public abstract class InputManagerInternal { * Sets the pointer acceleration. * See {@code frameworks/native/include/input/VelocityControl.h#VelocityControlParameters}. */ public abstract void setPointerAcceleration(float acceleration); public abstract void setPointerAcceleration(float acceleration, int displayId); /** * Sets the eligibility of windows on a given display for pointer capture. If a display is Loading @@ -103,6 +109,9 @@ public abstract class InputManagerInternal { */ public abstract void setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible); /** Sets the visibility of the cursor. */ public abstract void setPointerIconVisible(boolean visible, int displayId); /** Registers the {@link LidSwitchCallback} to begin receiving notifications. */ public abstract void registerLidSwitchCallback(@NonNull LidSwitchCallback callbacks); Loading services/companion/java/com/android/server/companion/virtual/InputController.java +51 −41 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ import android.hardware.input.VirtualMouseRelativeEvent; import android.hardware.input.VirtualMouseScrollEvent; import android.hardware.input.VirtualTouchEvent; import android.os.IBinder; import android.os.IInputConstants; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Slog; Loading @@ -43,6 +42,7 @@ import com.android.server.LocalServices; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Iterator; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; Loading Loading @@ -76,13 +76,6 @@ class InputController { 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 * multiple mice could be concurrently registered, mice that are associated with a different * display than the current target display should not be allowed to affect the current target. */ @VisibleForTesting int mActivePointerDisplayId; InputController(@NonNull Object lock) { this(lock, new NativeWrapper()); } Loading @@ -91,18 +84,21 @@ class InputController { InputController(@NonNull Object lock, @NonNull NativeWrapper nativeWrapper) { mLock = lock; mNativeWrapper = nativeWrapper; mActivePointerDisplayId = Display.INVALID_DISPLAY; mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); } void close() { synchronized (mLock) { for (InputDeviceDescriptor inputDeviceDescriptor : mInputDeviceDescriptors.values()) { mNativeWrapper.closeUinput(inputDeviceDescriptor.getFileDescriptor()); final Iterator<Map.Entry<IBinder, InputDeviceDescriptor>> iterator = mInputDeviceDescriptors.entrySet().iterator(); if (iterator.hasNext()) { final Map.Entry<IBinder, InputDeviceDescriptor> entry = iterator.next(); final IBinder token = entry.getKey(); final InputDeviceDescriptor inputDeviceDescriptor = entry.getValue(); iterator.remove(); closeInputDeviceDescriptorLocked(token, inputDeviceDescriptor); } mInputDeviceDescriptors.clear(); resetMouseValuesLocked(); } } Loading Loading @@ -150,8 +146,6 @@ class InputController { new InputDeviceDescriptor(fd, binderDeathRecipient, InputDeviceDescriptor.TYPE_MOUSE, displayId, phys)); mInputManagerInternal.setVirtualMousePointerDisplayId(displayId); mInputManagerInternal.setPointerAcceleration(1); mActivePointerDisplayId = displayId; } try { deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0); Loading Loading @@ -197,23 +191,44 @@ class InputController { throw new IllegalArgumentException( "Could not unregister input device for given token"); } closeInputDeviceDescriptorLocked(token, inputDeviceDescriptor); } } @GuardedBy("mLock") private void closeInputDeviceDescriptorLocked(IBinder token, InputDeviceDescriptor inputDeviceDescriptor) { 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). // id if there's another mouse (choose the most recent). The inputDeviceDescriptor must be // removed from the mInputDeviceDescriptors instance variable prior to this point. if (inputDeviceDescriptor.isMouse()) { updateMouseValuesLocked(); if (mInputManagerInternal.getVirtualMousePointerDisplayId() == inputDeviceDescriptor.getDisplayId()) { updateActivePointerDisplayIdLocked(); } } } void setShowPointerIcon(boolean visible, int displayId) { mInputManagerInternal.setPointerIconVisible(visible, displayId); } void setPointerAcceleration(float pointerAcceleration, int displayId) { mInputManagerInternal.setPointerAcceleration(pointerAcceleration, displayId); } void setDisplayEligibilityForPointerCapture(boolean isEligible, int displayId) { mInputManagerInternal.setDisplayEligibilityForPointerCapture(displayId, isEligible); } @GuardedBy("mLock") private void updateMouseValuesLocked() { private void updateActivePointerDisplayIdLocked() { InputDeviceDescriptor mostRecentlyCreatedMouse = null; for (InputDeviceDescriptor otherInputDeviceDescriptor : mInputDeviceDescriptors.values()) { for (InputDeviceDescriptor otherInputDeviceDescriptor : mInputDeviceDescriptors.values()) { if (otherInputDeviceDescriptor.isMouse()) { if (mostRecentlyCreatedMouse == null || (otherInputDeviceDescriptor.getCreationOrderNumber() Loading @@ -225,18 +240,10 @@ class InputController { if (mostRecentlyCreatedMouse != null) { mInputManagerInternal.setVirtualMousePointerDisplayId( mostRecentlyCreatedMouse.getDisplayId()); mActivePointerDisplayId = mostRecentlyCreatedMouse.getDisplayId(); } else { // All mice have been unregistered; reset all values. resetMouseValuesLocked(); } } private void resetMouseValuesLocked() { // All mice have been unregistered mInputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY); mInputManagerInternal.setPointerAcceleration( IInputConstants.DEFAULT_POINTER_ACCELERATION); mActivePointerDisplayId = Display.INVALID_DISPLAY; } } private static String createPhys(@PhysType String type) { Loading Loading @@ -269,7 +276,8 @@ class InputController { throw new IllegalArgumentException( "Could not send button event to input device for given token"); } if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) { if (inputDeviceDescriptor.getDisplayId() != mInputManagerInternal.getVirtualMousePointerDisplayId()) { throw new IllegalStateException( "Display id associated with this mouse is not currently targetable"); } Loading Loading @@ -300,7 +308,8 @@ class InputController { throw new IllegalArgumentException( "Could not send relative event to input device for given token"); } if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) { if (inputDeviceDescriptor.getDisplayId() != mInputManagerInternal.getVirtualMousePointerDisplayId()) { throw new IllegalStateException( "Display id associated with this mouse is not currently targetable"); } Loading @@ -317,7 +326,8 @@ class InputController { throw new IllegalArgumentException( "Could not send scroll event to input device for given token"); } if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) { if (inputDeviceDescriptor.getDisplayId() != mInputManagerInternal.getVirtualMousePointerDisplayId()) { throw new IllegalStateException( "Display id associated with this mouse is not currently targetable"); } Loading @@ -334,7 +344,8 @@ class InputController { throw new IllegalArgumentException( "Could not get cursor position for input device for given token"); } if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) { if (inputDeviceDescriptor.getDisplayId() != mInputManagerInternal.getVirtualMousePointerDisplayId()) { throw new IllegalStateException( "Display id associated with this mouse is not currently targetable"); } Loading @@ -354,7 +365,6 @@ class InputController { fout.println(" type: " + inputDeviceDescriptor.getType()); fout.println(" phys: " + inputDeviceDescriptor.getPhys()); } fout.println(" Active mouse display id: " + mActivePointerDisplayId); } } Loading Loading
core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -2761,6 +2761,7 @@ package android.companion.virtual { method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.LaunchCallback); method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setShowPointerIcon(boolean); } public final class VirtualDeviceParams implements android.os.Parcelable {
core/java/android/companion/virtual/IVirtualDevice.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -77,4 +77,7 @@ interface IVirtualDevice { void launchPendingIntent( int displayId, in PendingIntent pendingIntent, in ResultReceiver resultReceiver); PointF getCursorPosition(IBinder token); /** Sets whether to show or hide the cursor while this virtual device is active. */ void setShowPointerIcon(boolean showPointerIcon); }
core/java/android/companion/virtual/VirtualDeviceManager.java +16 −0 Original line number Diff line number Diff line Loading @@ -337,6 +337,22 @@ public final class VirtualDeviceManager { } } /** * Sets the visibility of the pointer icon for this VirtualDevice's associated displays. * * @param showPointerIcon True if the pointer should be shown; false otherwise. The default * visibility is true. */ @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) @NonNull public void setShowPointerIcon(boolean showPointerIcon) { try { mVirtualDevice.setShowPointerIcon(showPointerIcon); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns the display flags that should be added to a particular virtual display. * Additional device-level flags from {@link Loading
core/java/android/hardware/input/InputManagerInternal.java +10 −1 Original line number Diff line number Diff line Loading @@ -87,6 +87,12 @@ public abstract class InputManagerInternal { */ public abstract void setVirtualMousePointerDisplayId(int pointerDisplayId); /** * Gets the display id that the MouseCursorController is being forced to target. Returns * {@link android.view.Display#INVALID_DISPLAY} if there is no override */ public abstract int getVirtualMousePointerDisplayId(); /** Gets the current position of the mouse cursor. */ public abstract PointF getCursorPosition(); Loading @@ -94,7 +100,7 @@ public abstract class InputManagerInternal { * Sets the pointer acceleration. * See {@code frameworks/native/include/input/VelocityControl.h#VelocityControlParameters}. */ public abstract void setPointerAcceleration(float acceleration); public abstract void setPointerAcceleration(float acceleration, int displayId); /** * Sets the eligibility of windows on a given display for pointer capture. If a display is Loading @@ -103,6 +109,9 @@ public abstract class InputManagerInternal { */ public abstract void setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible); /** Sets the visibility of the cursor. */ public abstract void setPointerIconVisible(boolean visible, int displayId); /** Registers the {@link LidSwitchCallback} to begin receiving notifications. */ public abstract void registerLidSwitchCallback(@NonNull LidSwitchCallback callbacks); Loading
services/companion/java/com/android/server/companion/virtual/InputController.java +51 −41 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ import android.hardware.input.VirtualMouseRelativeEvent; import android.hardware.input.VirtualMouseScrollEvent; import android.hardware.input.VirtualTouchEvent; import android.os.IBinder; import android.os.IInputConstants; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Slog; Loading @@ -43,6 +42,7 @@ import com.android.server.LocalServices; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Iterator; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; Loading Loading @@ -76,13 +76,6 @@ class InputController { 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 * multiple mice could be concurrently registered, mice that are associated with a different * display than the current target display should not be allowed to affect the current target. */ @VisibleForTesting int mActivePointerDisplayId; InputController(@NonNull Object lock) { this(lock, new NativeWrapper()); } Loading @@ -91,18 +84,21 @@ class InputController { InputController(@NonNull Object lock, @NonNull NativeWrapper nativeWrapper) { mLock = lock; mNativeWrapper = nativeWrapper; mActivePointerDisplayId = Display.INVALID_DISPLAY; mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); } void close() { synchronized (mLock) { for (InputDeviceDescriptor inputDeviceDescriptor : mInputDeviceDescriptors.values()) { mNativeWrapper.closeUinput(inputDeviceDescriptor.getFileDescriptor()); final Iterator<Map.Entry<IBinder, InputDeviceDescriptor>> iterator = mInputDeviceDescriptors.entrySet().iterator(); if (iterator.hasNext()) { final Map.Entry<IBinder, InputDeviceDescriptor> entry = iterator.next(); final IBinder token = entry.getKey(); final InputDeviceDescriptor inputDeviceDescriptor = entry.getValue(); iterator.remove(); closeInputDeviceDescriptorLocked(token, inputDeviceDescriptor); } mInputDeviceDescriptors.clear(); resetMouseValuesLocked(); } } Loading Loading @@ -150,8 +146,6 @@ class InputController { new InputDeviceDescriptor(fd, binderDeathRecipient, InputDeviceDescriptor.TYPE_MOUSE, displayId, phys)); mInputManagerInternal.setVirtualMousePointerDisplayId(displayId); mInputManagerInternal.setPointerAcceleration(1); mActivePointerDisplayId = displayId; } try { deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0); Loading Loading @@ -197,23 +191,44 @@ class InputController { throw new IllegalArgumentException( "Could not unregister input device for given token"); } closeInputDeviceDescriptorLocked(token, inputDeviceDescriptor); } } @GuardedBy("mLock") private void closeInputDeviceDescriptorLocked(IBinder token, InputDeviceDescriptor inputDeviceDescriptor) { 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). // id if there's another mouse (choose the most recent). The inputDeviceDescriptor must be // removed from the mInputDeviceDescriptors instance variable prior to this point. if (inputDeviceDescriptor.isMouse()) { updateMouseValuesLocked(); if (mInputManagerInternal.getVirtualMousePointerDisplayId() == inputDeviceDescriptor.getDisplayId()) { updateActivePointerDisplayIdLocked(); } } } void setShowPointerIcon(boolean visible, int displayId) { mInputManagerInternal.setPointerIconVisible(visible, displayId); } void setPointerAcceleration(float pointerAcceleration, int displayId) { mInputManagerInternal.setPointerAcceleration(pointerAcceleration, displayId); } void setDisplayEligibilityForPointerCapture(boolean isEligible, int displayId) { mInputManagerInternal.setDisplayEligibilityForPointerCapture(displayId, isEligible); } @GuardedBy("mLock") private void updateMouseValuesLocked() { private void updateActivePointerDisplayIdLocked() { InputDeviceDescriptor mostRecentlyCreatedMouse = null; for (InputDeviceDescriptor otherInputDeviceDescriptor : mInputDeviceDescriptors.values()) { for (InputDeviceDescriptor otherInputDeviceDescriptor : mInputDeviceDescriptors.values()) { if (otherInputDeviceDescriptor.isMouse()) { if (mostRecentlyCreatedMouse == null || (otherInputDeviceDescriptor.getCreationOrderNumber() Loading @@ -225,18 +240,10 @@ class InputController { if (mostRecentlyCreatedMouse != null) { mInputManagerInternal.setVirtualMousePointerDisplayId( mostRecentlyCreatedMouse.getDisplayId()); mActivePointerDisplayId = mostRecentlyCreatedMouse.getDisplayId(); } else { // All mice have been unregistered; reset all values. resetMouseValuesLocked(); } } private void resetMouseValuesLocked() { // All mice have been unregistered mInputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY); mInputManagerInternal.setPointerAcceleration( IInputConstants.DEFAULT_POINTER_ACCELERATION); mActivePointerDisplayId = Display.INVALID_DISPLAY; } } private static String createPhys(@PhysType String type) { Loading Loading @@ -269,7 +276,8 @@ class InputController { throw new IllegalArgumentException( "Could not send button event to input device for given token"); } if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) { if (inputDeviceDescriptor.getDisplayId() != mInputManagerInternal.getVirtualMousePointerDisplayId()) { throw new IllegalStateException( "Display id associated with this mouse is not currently targetable"); } Loading Loading @@ -300,7 +308,8 @@ class InputController { throw new IllegalArgumentException( "Could not send relative event to input device for given token"); } if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) { if (inputDeviceDescriptor.getDisplayId() != mInputManagerInternal.getVirtualMousePointerDisplayId()) { throw new IllegalStateException( "Display id associated with this mouse is not currently targetable"); } Loading @@ -317,7 +326,8 @@ class InputController { throw new IllegalArgumentException( "Could not send scroll event to input device for given token"); } if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) { if (inputDeviceDescriptor.getDisplayId() != mInputManagerInternal.getVirtualMousePointerDisplayId()) { throw new IllegalStateException( "Display id associated with this mouse is not currently targetable"); } Loading @@ -334,7 +344,8 @@ class InputController { throw new IllegalArgumentException( "Could not get cursor position for input device for given token"); } if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) { if (inputDeviceDescriptor.getDisplayId() != mInputManagerInternal.getVirtualMousePointerDisplayId()) { throw new IllegalStateException( "Display id associated with this mouse is not currently targetable"); } Loading @@ -354,7 +365,6 @@ class InputController { fout.println(" type: " + inputDeviceDescriptor.getType()); fout.println(" phys: " + inputDeviceDescriptor.getPhys()); } fout.println(" Active mouse display id: " + mActivePointerDisplayId); } } Loading