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

Commit 27a354bf authored by Christine Franks's avatar Christine Franks
Browse files

Add API to hide cursor for virtual mice

Bug: 216244627
Test: atest FrameworksServicesTests:com.android.server.companion.virtual
CTS-Coverage-Bug: 208247880
Change-Id: Ie1a2bc526a705f2f9788898afbff87f5a9448f85
parent 40818219
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2742,6 +2742,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 {
+3 −0
Original line number Diff line number Diff line
@@ -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);
}
+16 −0
Original line number Diff line number Diff line
@@ -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
+10 −1
Original line number Diff line number Diff line
@@ -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();

@@ -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
@@ -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);

+51 −41
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -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());
    }
@@ -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();
        }
    }

@@ -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);
@@ -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()
@@ -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) {
@@ -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");
            }
@@ -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");
            }
@@ -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");
            }
@@ -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");
            }
@@ -354,7 +365,6 @@ class InputController {
                fout.println("          type: " + inputDeviceDescriptor.getType());
                fout.println("          phys: " + inputDeviceDescriptor.getPhys());
            }
            fout.println("      Active mouse display id: " + mActivePointerDisplayId);
        }
    }

Loading