Merge "Add API to hide cursor for virtual mice"
This commit is contained in:
committed by
Android (Google) Code Review
commit
0ba7aa9321
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
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).
|
||||
if (inputDeviceDescriptor.isMouse()) {
|
||||
updateMouseValuesLocked();
|
||||
}
|
||||
closeInputDeviceDescriptorLocked(token, inputDeviceDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void updateMouseValuesLocked() {
|
||||
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). The inputDeviceDescriptor must be
|
||||
// removed from the mInputDeviceDescriptors instance variable prior to this point.
|
||||
if (inputDeviceDescriptor.isMouse()) {
|
||||
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 updateActivePointerDisplayIdLocked() {
|
||||
InputDeviceDescriptor mostRecentlyCreatedMouse = null;
|
||||
for (InputDeviceDescriptor otherInputDeviceDescriptor :
|
||||
mInputDeviceDescriptors.values()) {
|
||||
for (InputDeviceDescriptor otherInputDeviceDescriptor : mInputDeviceDescriptors.values()) {
|
||||
if (otherInputDeviceDescriptor.isMouse()) {
|
||||
if (mostRecentlyCreatedMouse == null
|
||||
|| (otherInputDeviceDescriptor.getCreationOrderNumber()
|
||||
@@ -225,20 +240,12 @@ class InputController {
|
||||
if (mostRecentlyCreatedMouse != null) {
|
||||
mInputManagerInternal.setVirtualMousePointerDisplayId(
|
||||
mostRecentlyCreatedMouse.getDisplayId());
|
||||
mActivePointerDisplayId = mostRecentlyCreatedMouse.getDisplayId();
|
||||
} else {
|
||||
// All mice have been unregistered; reset all values.
|
||||
resetMouseValuesLocked();
|
||||
// All mice have been unregistered
|
||||
mInputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY);
|
||||
}
|
||||
}
|
||||
|
||||
private void resetMouseValuesLocked() {
|
||||
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());
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.input.InputManagerInternal;
|
||||
import android.hardware.input.VirtualKeyEvent;
|
||||
import android.hardware.input.VirtualMouseButtonEvent;
|
||||
import android.hardware.input.VirtualMouseRelativeEvent;
|
||||
@@ -56,8 +55,8 @@ import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.window.DisplayWindowPolicyController;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.LocalServices;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -83,6 +82,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
private final VirtualDeviceParams mParams;
|
||||
private final Map<Integer, PowerManager.WakeLock> mPerDisplayWakelocks = new ArrayMap<>();
|
||||
private final IVirtualDeviceActivityListener mActivityListener;
|
||||
// The default setting for showing the pointer on new displays.
|
||||
@GuardedBy("mVirtualDeviceLock")
|
||||
private boolean mDefaultShowPointerIcon = true;
|
||||
|
||||
private ActivityListener createListenerAdapter(int displayId) {
|
||||
return new ActivityListener() {
|
||||
@@ -382,6 +384,25 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void setShowPointerIcon(boolean showPointerIcon) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
|
||||
"Permission required to unregister this input device");
|
||||
|
||||
final long binderToken = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mVirtualDeviceLock) {
|
||||
mDefaultShowPointerIcon = showPointerIcon;
|
||||
for (int displayId : mVirtualDisplayIds) {
|
||||
mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(binderToken);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
|
||||
fout.println(" VirtualDevice: ");
|
||||
@@ -392,6 +413,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
for (int id : mVirtualDisplayIds) {
|
||||
fout.println(" " + id);
|
||||
}
|
||||
fout.println(" mDefaultShowPointerIcon: " + mDefaultShowPointerIcon);
|
||||
}
|
||||
mInputController.dump(fout);
|
||||
}
|
||||
@@ -403,15 +425,16 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
"Virtual device already have a virtual display with ID " + displayId);
|
||||
}
|
||||
mVirtualDisplayIds.add(displayId);
|
||||
mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
|
||||
mInputController.setPointerAcceleration(1f, displayId);
|
||||
mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
|
||||
displayId);
|
||||
|
||||
// Since we're being called in the middle of the display being created, we post a
|
||||
// task to grab the wakelock instead of doing it synchronously here, to avoid
|
||||
// reentrancy problems.
|
||||
mContext.getMainThreadHandler().post(() -> addWakeLockForDisplay(displayId));
|
||||
|
||||
LocalServices.getService(
|
||||
InputManagerInternal.class).setDisplayEligibilityForPointerCapture(displayId,
|
||||
false);
|
||||
final GenericWindowPolicyController dwpc =
|
||||
new GenericWindowPolicyController(FLAG_SECURE,
|
||||
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
|
||||
@@ -471,9 +494,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
mPerDisplayWakelocks.remove(displayId);
|
||||
}
|
||||
mVirtualDisplayIds.remove(displayId);
|
||||
LocalServices.getService(
|
||||
InputManagerInternal.class).setDisplayEligibilityForPointerCapture(
|
||||
displayId, true);
|
||||
mWindowPolicyControllers.remove(displayId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ import android.os.CombinedVibration;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.IInputConstants;
|
||||
import android.os.IVibratorStateListener;
|
||||
import android.os.InputEventInjectionResult;
|
||||
import android.os.InputEventInjectionSync;
|
||||
@@ -273,10 +274,19 @@ public class InputManagerService extends IInputManager.Stub
|
||||
private final Map<String, Integer> mRuntimeAssociations = new ArrayMap<>();
|
||||
@GuardedBy("mAssociationLock")
|
||||
private final Map<String, String> mUniqueIdAssociations = new ArrayMap<>();
|
||||
private final Object mPointerDisplayIdLock = new Object();
|
||||
|
||||
private final Object mAdditionalDisplayInputPropertiesLock = new Object();
|
||||
|
||||
// Forces the MouseCursorController to target a specific display id.
|
||||
@GuardedBy("mPointerDisplayIdLock")
|
||||
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
||||
private int mOverriddenPointerDisplayId = Display.INVALID_DISPLAY;
|
||||
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
||||
private final SparseArray<AdditionalDisplayInputProperties> mAdditionalDisplayInputProperties =
|
||||
new SparseArray<>();
|
||||
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
||||
private int mIconType = PointerIcon.TYPE_NOT_SPECIFIED;
|
||||
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
||||
private PointerIcon mIcon;
|
||||
|
||||
|
||||
// Holds all the registered gesture monitors that are implemented as spy windows. The spy
|
||||
@@ -583,11 +593,26 @@ public class InputManagerService extends IInputManager.Stub
|
||||
}
|
||||
|
||||
private void setDisplayViewportsInternal(List<DisplayViewport> viewports) {
|
||||
final DisplayViewport[] vArray = new DisplayViewport[viewports.size()];
|
||||
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||
final DisplayViewport[] vArray = new DisplayViewport[viewports.size()];
|
||||
for (int i = viewports.size() - 1; i >= 0; --i) {
|
||||
vArray[i] = viewports.get(i);
|
||||
}
|
||||
nativeSetDisplayViewports(mPtr, vArray);
|
||||
nativeSetDisplayViewports(mPtr, vArray);
|
||||
|
||||
if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
|
||||
final AdditionalDisplayInputProperties properties =
|
||||
mAdditionalDisplayInputProperties.get(mOverriddenPointerDisplayId);
|
||||
if (properties != null) {
|
||||
updatePointerIconVisibleLocked(properties.pointerIconVisible);
|
||||
updatePointerAccelerationLocked(properties.pointerAcceleration);
|
||||
return;
|
||||
}
|
||||
}
|
||||
updatePointerIconVisibleLocked(
|
||||
AdditionalDisplayInputProperties.DEFAULT_POINTER_ICON_VISIBLE);
|
||||
updatePointerAccelerationLocked(IInputConstants.DEFAULT_POINTER_ACCELERATION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1796,10 +1821,60 @@ public class InputManagerService extends IInputManager.Stub
|
||||
nativeSetPointerSpeed(mPtr, speed);
|
||||
}
|
||||
|
||||
private void setPointerAcceleration(float acceleration) {
|
||||
private void setPointerAcceleration(float acceleration, int displayId) {
|
||||
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||
AdditionalDisplayInputProperties properties =
|
||||
mAdditionalDisplayInputProperties.get(displayId);
|
||||
if (properties == null) {
|
||||
properties = new AdditionalDisplayInputProperties();
|
||||
mAdditionalDisplayInputProperties.put(displayId, properties);
|
||||
}
|
||||
properties.pointerAcceleration = acceleration;
|
||||
if (properties.allDefaults()) {
|
||||
mAdditionalDisplayInputProperties.remove(displayId);
|
||||
}
|
||||
if (mOverriddenPointerDisplayId == displayId) {
|
||||
updatePointerAccelerationLocked(acceleration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
||||
private void updatePointerAccelerationLocked(float acceleration) {
|
||||
nativeSetPointerAcceleration(mPtr, acceleration);
|
||||
}
|
||||
|
||||
private void setPointerIconVisible(boolean visible, int displayId) {
|
||||
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||
AdditionalDisplayInputProperties properties =
|
||||
mAdditionalDisplayInputProperties.get(displayId);
|
||||
if (properties == null) {
|
||||
properties = new AdditionalDisplayInputProperties();
|
||||
mAdditionalDisplayInputProperties.put(displayId, properties);
|
||||
}
|
||||
properties.pointerIconVisible = visible;
|
||||
if (properties.allDefaults()) {
|
||||
mAdditionalDisplayInputProperties.remove(displayId);
|
||||
}
|
||||
if (mOverriddenPointerDisplayId == displayId) {
|
||||
updatePointerIconVisibleLocked(visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
||||
private void updatePointerIconVisibleLocked(boolean visible) {
|
||||
if (visible) {
|
||||
if (mIconType == PointerIcon.TYPE_CUSTOM) {
|
||||
nativeSetCustomPointerIcon(mPtr, mIcon);
|
||||
} else {
|
||||
nativeSetPointerIconType(mPtr, mIconType);
|
||||
}
|
||||
} else {
|
||||
nativeSetPointerIconType(mPtr, PointerIcon.TYPE_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerPointerSpeedSettingObserver() {
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
|
||||
@@ -1934,13 +2009,27 @@ public class InputManagerService extends IInputManager.Stub
|
||||
}
|
||||
|
||||
private void setVirtualMousePointerDisplayId(int displayId) {
|
||||
synchronized (mPointerDisplayIdLock) {
|
||||
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||
mOverriddenPointerDisplayId = displayId;
|
||||
if (displayId != Display.INVALID_DISPLAY) {
|
||||
final AdditionalDisplayInputProperties properties =
|
||||
mAdditionalDisplayInputProperties.get(displayId);
|
||||
if (properties != null) {
|
||||
updatePointerAccelerationLocked(properties.pointerAcceleration);
|
||||
updatePointerIconVisibleLocked(properties.pointerIconVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO(b/215597605): trigger MousePositionTracker update
|
||||
nativeNotifyPointerDisplayIdChanged(mPtr);
|
||||
}
|
||||
|
||||
private int getVirtualMousePointerDisplayId() {
|
||||
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||
return mOverriddenPointerDisplayId;
|
||||
}
|
||||
}
|
||||
|
||||
private void setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible) {
|
||||
nativeSetDisplayEligibilityForPointerCapture(mPtr, displayId, isEligible);
|
||||
}
|
||||
@@ -2230,15 +2319,44 @@ public class InputManagerService extends IInputManager.Stub
|
||||
|
||||
// Binder call
|
||||
@Override
|
||||
public void setPointerIconType(int iconId) {
|
||||
nativeSetPointerIconType(mPtr, iconId);
|
||||
public void setPointerIconType(int iconType) {
|
||||
if (iconType == PointerIcon.TYPE_CUSTOM) {
|
||||
throw new IllegalArgumentException("Use setCustomPointerIcon to set custom pointers");
|
||||
}
|
||||
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||
mIcon = null;
|
||||
mIconType = iconType;
|
||||
if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
|
||||
final AdditionalDisplayInputProperties properties =
|
||||
mAdditionalDisplayInputProperties.get(mOverriddenPointerDisplayId);
|
||||
if (properties == null || properties.pointerIconVisible) {
|
||||
nativeSetPointerIconType(mPtr, mIconType);
|
||||
}
|
||||
} else {
|
||||
nativeSetPointerIconType(mPtr, mIconType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Binder call
|
||||
@Override
|
||||
public void setCustomPointerIcon(PointerIcon icon) {
|
||||
Objects.requireNonNull(icon);
|
||||
nativeSetCustomPointerIcon(mPtr, icon);
|
||||
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||
mIconType = PointerIcon.TYPE_CUSTOM;
|
||||
mIcon = icon;
|
||||
if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
|
||||
final AdditionalDisplayInputProperties properties =
|
||||
mAdditionalDisplayInputProperties.get(mOverriddenPointerDisplayId);
|
||||
if (properties == null || properties.pointerIconVisible) {
|
||||
// Only set the icon if it is not currently hidden; otherwise, it will be set
|
||||
// once it's no longer hidden.
|
||||
nativeSetCustomPointerIcon(mPtr, mIcon);
|
||||
}
|
||||
} else {
|
||||
nativeSetCustomPointerIcon(mPtr, mIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2567,6 +2685,7 @@ public class InputManagerService extends IInputManager.Stub
|
||||
pw.println("Input Manager Service (Java) State:");
|
||||
dumpAssociations(pw, " " /*prefix*/);
|
||||
dumpSpyWindowGestureMonitors(pw, " " /*prefix*/);
|
||||
dumpDisplayInputPropertiesValues(pw, " " /* prefix */);
|
||||
}
|
||||
|
||||
private void dumpAssociations(PrintWriter pw, String prefix) {
|
||||
@@ -2607,6 +2726,25 @@ public class InputManagerService extends IInputManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
private void dumpDisplayInputPropertiesValues(PrintWriter pw, String prefix) {
|
||||
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||
if (mAdditionalDisplayInputProperties.size() != 0) {
|
||||
pw.println(prefix + "mAdditionalDisplayInputProperties:");
|
||||
for (int i = 0; i < mAdditionalDisplayInputProperties.size(); i++) {
|
||||
pw.println(prefix + " displayId: "
|
||||
+ mAdditionalDisplayInputProperties.keyAt(i));
|
||||
final AdditionalDisplayInputProperties properties =
|
||||
mAdditionalDisplayInputProperties.valueAt(i);
|
||||
pw.println(prefix + " pointerAcceleration: " + properties.pointerAcceleration);
|
||||
pw.println(prefix + " pointerIconVisible: " + properties.pointerIconVisible);
|
||||
}
|
||||
}
|
||||
if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
|
||||
pw.println(prefix + "mOverriddenPointerDisplayId: " + mOverriddenPointerDisplayId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkCallingPermission(String permission, String func) {
|
||||
// Quick check: if the calling permission is me, it's all okay.
|
||||
if (Binder.getCallingPid() == Process.myPid()) {
|
||||
@@ -2630,8 +2768,8 @@ public class InputManagerService extends IInputManager.Stub
|
||||
synchronized (mInputFilterLock) { }
|
||||
synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
|
||||
synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
|
||||
synchronized (mPointerDisplayIdLock) { /* Test if blocked by pointer display id lock */ }
|
||||
synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ }
|
||||
synchronized (mAdditionalDisplayInputPropertiesLock) { /* Test if blocked by props lock */ }
|
||||
nativeMonitor(mPtr);
|
||||
}
|
||||
|
||||
@@ -3084,7 +3222,7 @@ public class InputManagerService extends IInputManager.Stub
|
||||
// Native callback.
|
||||
@SuppressWarnings("unused")
|
||||
private int getPointerDisplayId() {
|
||||
synchronized (mPointerDisplayIdLock) {
|
||||
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||
// Prefer the override to all other displays.
|
||||
if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
|
||||
return mOverriddenPointerDisplayId;
|
||||
@@ -3579,14 +3717,19 @@ public class InputManagerService extends IInputManager.Stub
|
||||
InputManagerService.this.setVirtualMousePointerDisplayId(pointerDisplayId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVirtualMousePointerDisplayId() {
|
||||
return InputManagerService.this.getVirtualMousePointerDisplayId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointF getCursorPosition() {
|
||||
return mWindowManagerCallbacks.getCursorPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPointerAcceleration(float acceleration) {
|
||||
InputManagerService.this.setPointerAcceleration(acceleration);
|
||||
public void setPointerAcceleration(float acceleration, int displayId) {
|
||||
InputManagerService.this.setPointerAcceleration(acceleration, displayId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3594,6 +3737,11 @@ public class InputManagerService extends IInputManager.Stub
|
||||
InputManagerService.this.setDisplayEligibilityForPointerCapture(displayId, isEligible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPointerIconVisible(boolean visible, int displayId) {
|
||||
InputManagerService.this.setPointerIconVisible(visible, displayId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerLidSwitchCallback(LidSwitchCallback callbacks) {
|
||||
registerLidSwitchCallbackInternal(callbacks);
|
||||
@@ -3621,4 +3769,21 @@ public class InputManagerService extends IInputManager.Stub
|
||||
new InputShellCommand().exec(this, in, out, err, args, callback, resultReceiver);
|
||||
}
|
||||
|
||||
private static class AdditionalDisplayInputProperties {
|
||||
|
||||
static final boolean DEFAULT_POINTER_ICON_VISIBLE = true;
|
||||
static final float DEFAULT_POINTER_ACCELERATION =
|
||||
(float) IInputConstants.DEFAULT_POINTER_ACCELERATION;
|
||||
|
||||
// The pointer acceleration for this display.
|
||||
public float pointerAcceleration = DEFAULT_POINTER_ACCELERATION;
|
||||
|
||||
// Whether the pointer icon should be visible or hidden on this display.
|
||||
public boolean pointerIconVisible = DEFAULT_POINTER_ICON_VISIBLE;
|
||||
|
||||
public boolean allDefaults() {
|
||||
return Float.compare(pointerAcceleration, DEFAULT_POINTER_ACCELERATION) == 0
|
||||
&& pointerIconVisible == DEFAULT_POINTER_ICON_VISIBLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
@@ -30,7 +29,6 @@ import android.hardware.input.InputManager;
|
||||
import android.hardware.input.InputManagerInternal;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.IInputConstants;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayInfo;
|
||||
@@ -81,17 +79,15 @@ public class InputControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unregisterInputDevice_allMiceUnregistered_unsetValues() {
|
||||
public void unregisterInputDevice_allMiceUnregistered_clearPointerDisplayId() {
|
||||
final IBinder deviceToken = new Binder();
|
||||
mInputController.createMouse("name", /*vendorId= */ 1, /*productId= */ 1, deviceToken,
|
||||
/* displayId= */ 1);
|
||||
verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(1));
|
||||
verify(mInputManagerInternalMock).setPointerAcceleration(eq(1f));
|
||||
doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
|
||||
mInputController.unregisterInputDevice(deviceToken);
|
||||
verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(
|
||||
eq(Display.INVALID_DISPLAY));
|
||||
verify(mInputManagerInternalMock).setPointerAcceleration(
|
||||
eq((float) IInputConstants.DEFAULT_POINTER_ACCELERATION));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,14 +96,11 @@ public class InputControllerTest {
|
||||
mInputController.createMouse("name", /*vendorId= */ 1, /*productId= */ 1, deviceToken,
|
||||
/* displayId= */ 1);
|
||||
verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(1));
|
||||
verify(mInputManagerInternalMock).setPointerAcceleration(eq(1f));
|
||||
final IBinder deviceToken2 = new Binder();
|
||||
mInputController.createMouse("name", /*vendorId= */ 1, /*productId= */ 1, deviceToken2,
|
||||
/* displayId= */ 2);
|
||||
verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(2));
|
||||
mInputController.unregisterInputDevice(deviceToken);
|
||||
verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(1));
|
||||
verify(mInputManagerInternalMock, times(0)).setPointerAcceleration(
|
||||
eq((float) IInputConstants.DEFAULT_POINTER_ACCELERATION));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.android.server.companion.virtual;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -27,6 +29,7 @@ import static org.mockito.Mockito.doCallRealMethod;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
@@ -117,6 +120,8 @@ public class VirtualDeviceManagerServiceTest {
|
||||
LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
|
||||
|
||||
doNothing().when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt());
|
||||
doNothing().when(mInputManagerInternalMock).setPointerAcceleration(anyFloat(), anyInt());
|
||||
doNothing().when(mInputManagerInternalMock).setPointerIconVisible(anyBoolean(), anyInt());
|
||||
LocalServices.removeServiceForTest(InputManagerInternal.class);
|
||||
LocalServices.addService(InputManagerInternal.class, mInputManagerInternalMock);
|
||||
|
||||
@@ -353,7 +358,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
mInputController.mInputDeviceDescriptors.put(BINDER,
|
||||
new InputController.InputDeviceDescriptor(fd, () -> {}, /* type= */ 2,
|
||||
/* displayId= */ 1, PHYS));
|
||||
mInputController.mActivePointerDisplayId = 1;
|
||||
doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
|
||||
mDeviceImpl.sendButtonEvent(BINDER, new VirtualMouseButtonEvent.Builder()
|
||||
.setButtonCode(buttonCode)
|
||||
.setAction(action).build());
|
||||
@@ -394,7 +399,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
mInputController.mInputDeviceDescriptors.put(BINDER,
|
||||
new InputController.InputDeviceDescriptor(fd, () -> {}, /* type= */ 2,
|
||||
/* displayId= */ 1, PHYS));
|
||||
mInputController.mActivePointerDisplayId = 1;
|
||||
doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
|
||||
mDeviceImpl.sendRelativeEvent(BINDER, new VirtualMouseRelativeEvent.Builder()
|
||||
.setRelativeX(x).setRelativeY(y).build());
|
||||
verify(mNativeWrapperMock).writeRelativeEvent(fd, x, y);
|
||||
@@ -435,7 +440,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
mInputController.mInputDeviceDescriptors.put(BINDER,
|
||||
new InputController.InputDeviceDescriptor(fd, () -> {}, /* type= */ 2,
|
||||
/* displayId= */ 1, PHYS));
|
||||
mInputController.mActivePointerDisplayId = 1;
|
||||
doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
|
||||
mDeviceImpl.sendScrollEvent(BINDER, new VirtualMouseScrollEvent.Builder()
|
||||
.setXAxisMovement(x)
|
||||
.setYAxisMovement(y).build());
|
||||
@@ -508,4 +513,19 @@ public class VirtualDeviceManagerServiceTest {
|
||||
verify(mNativeWrapperMock).writeTouchEvent(fd, pointerId, toolType, action, x, y, pressure,
|
||||
majorAxisSize);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setShowPointerIcon_setsValueForAllDisplays() {
|
||||
mDeviceImpl.mVirtualDisplayIds.add(1);
|
||||
mDeviceImpl.mVirtualDisplayIds.add(2);
|
||||
mDeviceImpl.mVirtualDisplayIds.add(3);
|
||||
mDeviceImpl.createVirtualMouse(1, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
|
||||
mDeviceImpl.createVirtualMouse(2, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
|
||||
mDeviceImpl.createVirtualMouse(3, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
|
||||
mDeviceImpl.setShowPointerIcon(false);
|
||||
verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(false), anyInt());
|
||||
verify(mInputManagerInternalMock, never()).setPointerIconVisible(eq(true), anyInt());
|
||||
mDeviceImpl.setShowPointerIcon(true);
|
||||
verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(true), anyInt());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user