Merge changes from topics "presubmit-am-e1ccffb4201944be9e638acb9f6f4dfc", "presubmit-am-e6236e948fb14688bc4afb3adb9e745b" into tm-dev am: dd2c72a65d
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17351976 Change-Id: If2730b470e595c52d2d175f35ab33a61a6c9c08d Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -75,8 +75,15 @@ public abstract class InputManagerInternal {
|
|||||||
/**
|
/**
|
||||||
* Sets the display id that the MouseCursorController will be forced to target. Pass
|
* Sets the display id that the MouseCursorController will be forced to target. Pass
|
||||||
* {@link android.view.Display#INVALID_DISPLAY} to clear the override.
|
* {@link android.view.Display#INVALID_DISPLAY} to clear the override.
|
||||||
|
*
|
||||||
|
* Note: This method generally blocks until the pointer display override has propagated.
|
||||||
|
* When setting a new override, the caller should ensure that an input device that can control
|
||||||
|
* the mouse pointer is connected. If a new override is set when no such input device is
|
||||||
|
* connected, the caller may be blocked for an arbitrary period of time.
|
||||||
|
*
|
||||||
|
* @return true if the pointer displayId was set successfully, or false if it fails.
|
||||||
*/
|
*/
|
||||||
public abstract void setVirtualMousePointerDisplayId(int pointerDisplayId);
|
public abstract boolean setVirtualMousePointerDisplayId(int pointerDisplayId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the display id that the MouseCursorController is being forced to target. Returns
|
* Gets the display id that the MouseCursorController is being forced to target. Returns
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>&
|
|||||||
PointerController::~PointerController() {
|
PointerController::~PointerController() {
|
||||||
mDisplayInfoListener->onPointerControllerDestroyed();
|
mDisplayInfoListener->onPointerControllerDestroyed();
|
||||||
mUnregisterWindowInfosListener(mDisplayInfoListener);
|
mUnregisterWindowInfosListener(mDisplayInfoListener);
|
||||||
|
mContext.getPolicy()->onPointerDisplayIdChanged(ADISPLAY_ID_NONE, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::mutex& PointerController::getLock() const {
|
std::mutex& PointerController::getLock() const {
|
||||||
@@ -255,6 +256,12 @@ void PointerController::setDisplayViewport(const DisplayViewport& viewport) {
|
|||||||
getAdditionalMouseResources = true;
|
getAdditionalMouseResources = true;
|
||||||
}
|
}
|
||||||
mCursorController.setDisplayViewport(viewport, getAdditionalMouseResources);
|
mCursorController.setDisplayViewport(viewport, getAdditionalMouseResources);
|
||||||
|
if (viewport.displayId != mLocked.pointerDisplayId) {
|
||||||
|
float xPos, yPos;
|
||||||
|
mCursorController.getPosition(&xPos, &yPos);
|
||||||
|
mContext.getPolicy()->onPointerDisplayIdChanged(viewport.displayId, xPos, yPos);
|
||||||
|
mLocked.pointerDisplayId = viewport.displayId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointerController::updatePointerIcon(int32_t iconId) {
|
void PointerController::updatePointerIcon(int32_t iconId) {
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ private:
|
|||||||
|
|
||||||
struct Locked {
|
struct Locked {
|
||||||
Presentation presentation;
|
Presentation presentation;
|
||||||
|
int32_t pointerDisplayId = ADISPLAY_ID_NONE;
|
||||||
|
|
||||||
std::vector<gui::DisplayInfo> mDisplayInfos;
|
std::vector<gui::DisplayInfo> mDisplayInfos;
|
||||||
std::unordered_map<int32_t /* displayId */, TouchSpotController> spotControllers;
|
std::unordered_map<int32_t /* displayId */, TouchSpotController> spotControllers;
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ public:
|
|||||||
std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) = 0;
|
std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) = 0;
|
||||||
virtual int32_t getDefaultPointerIconId() = 0;
|
virtual int32_t getDefaultPointerIconId() = 0;
|
||||||
virtual int32_t getCustomPointerIconId() = 0;
|
virtual int32_t getCustomPointerIconId() = 0;
|
||||||
|
virtual void onPointerDisplayIdChanged(int32_t displayId, float xPos, float yPos) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -56,9 +56,11 @@ public:
|
|||||||
std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) override;
|
std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) override;
|
||||||
virtual int32_t getDefaultPointerIconId() override;
|
virtual int32_t getDefaultPointerIconId() override;
|
||||||
virtual int32_t getCustomPointerIconId() override;
|
virtual int32_t getCustomPointerIconId() override;
|
||||||
|
virtual void onPointerDisplayIdChanged(int32_t displayId, float xPos, float yPos) override;
|
||||||
|
|
||||||
bool allResourcesAreLoaded();
|
bool allResourcesAreLoaded();
|
||||||
bool noResourcesAreLoaded();
|
bool noResourcesAreLoaded();
|
||||||
|
std::optional<int32_t> getLastReportedPointerDisplayId() { return latestPointerDisplayId; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType);
|
void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType);
|
||||||
@@ -66,6 +68,7 @@ private:
|
|||||||
bool pointerIconLoaded{false};
|
bool pointerIconLoaded{false};
|
||||||
bool pointerResourcesLoaded{false};
|
bool pointerResourcesLoaded{false};
|
||||||
bool additionalMouseResourcesLoaded{false};
|
bool additionalMouseResourcesLoaded{false};
|
||||||
|
std::optional<int32_t /*displayId*/> latestPointerDisplayId;
|
||||||
};
|
};
|
||||||
|
|
||||||
void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) {
|
void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) {
|
||||||
@@ -126,12 +129,19 @@ void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* ic
|
|||||||
icon->hotSpotX = hotSpot.first;
|
icon->hotSpotX = hotSpot.first;
|
||||||
icon->hotSpotY = hotSpot.second;
|
icon->hotSpotY = hotSpot.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MockPointerControllerPolicyInterface::onPointerDisplayIdChanged(int32_t displayId,
|
||||||
|
float /*xPos*/,
|
||||||
|
float /*yPos*/) {
|
||||||
|
latestPointerDisplayId = displayId;
|
||||||
|
}
|
||||||
|
|
||||||
class PointerControllerTest : public Test {
|
class PointerControllerTest : public Test {
|
||||||
protected:
|
protected:
|
||||||
PointerControllerTest();
|
PointerControllerTest();
|
||||||
~PointerControllerTest();
|
~PointerControllerTest();
|
||||||
|
|
||||||
void ensureDisplayViewportIsSet();
|
void ensureDisplayViewportIsSet(int32_t displayId = ADISPLAY_ID_DEFAULT);
|
||||||
|
|
||||||
sp<MockSprite> mPointerSprite;
|
sp<MockSprite> mPointerSprite;
|
||||||
sp<MockPointerControllerPolicyInterface> mPolicy;
|
sp<MockPointerControllerPolicyInterface> mPolicy;
|
||||||
@@ -168,9 +178,9 @@ PointerControllerTest::~PointerControllerTest() {
|
|||||||
mThread.join();
|
mThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointerControllerTest::ensureDisplayViewportIsSet() {
|
void PointerControllerTest::ensureDisplayViewportIsSet(int32_t displayId) {
|
||||||
DisplayViewport viewport;
|
DisplayViewport viewport;
|
||||||
viewport.displayId = ADISPLAY_ID_DEFAULT;
|
viewport.displayId = displayId;
|
||||||
viewport.logicalRight = 1600;
|
viewport.logicalRight = 1600;
|
||||||
viewport.logicalBottom = 1200;
|
viewport.logicalBottom = 1200;
|
||||||
viewport.physicalRight = 800;
|
viewport.physicalRight = 800;
|
||||||
@@ -255,6 +265,30 @@ TEST_F(PointerControllerTest, doesNotGetResourcesBeforeSettingViewport) {
|
|||||||
ensureDisplayViewportIsSet();
|
ensureDisplayViewportIsSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PointerControllerTest, notifiesPolicyWhenPointerDisplayChanges) {
|
||||||
|
EXPECT_FALSE(mPolicy->getLastReportedPointerDisplayId())
|
||||||
|
<< "A pointer display change does not occur when PointerController is created.";
|
||||||
|
|
||||||
|
ensureDisplayViewportIsSet(ADISPLAY_ID_DEFAULT);
|
||||||
|
|
||||||
|
const auto lastReportedPointerDisplayId = mPolicy->getLastReportedPointerDisplayId();
|
||||||
|
ASSERT_TRUE(lastReportedPointerDisplayId)
|
||||||
|
<< "The policy is notified of a pointer display change when the viewport is first set.";
|
||||||
|
EXPECT_EQ(ADISPLAY_ID_DEFAULT, *lastReportedPointerDisplayId)
|
||||||
|
<< "Incorrect pointer display notified.";
|
||||||
|
|
||||||
|
ensureDisplayViewportIsSet(42);
|
||||||
|
|
||||||
|
EXPECT_EQ(42, *mPolicy->getLastReportedPointerDisplayId())
|
||||||
|
<< "The policy is notified when the pointer display changes.";
|
||||||
|
|
||||||
|
// Release the PointerController.
|
||||||
|
mPointerController = nullptr;
|
||||||
|
|
||||||
|
EXPECT_EQ(ADISPLAY_ID_NONE, *mPolicy->getLastReportedPointerDisplayId())
|
||||||
|
<< "The pointer display changes to invalid when PointerController is destroyed.";
|
||||||
|
}
|
||||||
|
|
||||||
class PointerControllerWindowInfoListenerTest : public Test {};
|
class PointerControllerWindowInfoListenerTest : public Test {};
|
||||||
|
|
||||||
class TestPointerController : public PointerController {
|
class TestPointerController : public PointerController {
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
|
private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
|
||||||
private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
|
private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
|
||||||
private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
|
private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
|
||||||
|
private static final int MSG_POINTER_DISPLAY_ID_CHANGED = 7;
|
||||||
|
|
||||||
private static final int DEFAULT_VIBRATION_MAGNITUDE = 192;
|
private static final int DEFAULT_VIBRATION_MAGNITUDE = 192;
|
||||||
|
|
||||||
@@ -276,11 +277,24 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
@GuardedBy("mAssociationLock")
|
@GuardedBy("mAssociationLock")
|
||||||
private final Map<String, String> mUniqueIdAssociations = new ArrayMap<>();
|
private final Map<String, String> mUniqueIdAssociations = new ArrayMap<>();
|
||||||
|
|
||||||
|
// Guards per-display input properties and properties relating to the mouse pointer.
|
||||||
|
// Threads can wait on this lock to be notified the next time the display on which the mouse
|
||||||
|
// pointer is shown has changed.
|
||||||
private final Object mAdditionalDisplayInputPropertiesLock = new Object();
|
private final Object mAdditionalDisplayInputPropertiesLock = new Object();
|
||||||
|
|
||||||
// Forces the MouseCursorController to target a specific display id.
|
// Forces the PointerController to target a specific display id.
|
||||||
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
||||||
private int mOverriddenPointerDisplayId = Display.INVALID_DISPLAY;
|
private int mOverriddenPointerDisplayId = Display.INVALID_DISPLAY;
|
||||||
|
|
||||||
|
// PointerController is the source of truth of the pointer display. This is the value of the
|
||||||
|
// latest pointer display id reported by PointerController.
|
||||||
|
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
||||||
|
private int mAcknowledgedPointerDisplayId = Display.INVALID_DISPLAY;
|
||||||
|
// This is the latest display id that IMS has requested PointerController to use. If there are
|
||||||
|
// no devices that can control the pointer, PointerController may end up disregarding this
|
||||||
|
// value.
|
||||||
|
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
||||||
|
private int mRequestedPointerDisplayId = Display.INVALID_DISPLAY;
|
||||||
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
||||||
private final SparseArray<AdditionalDisplayInputProperties> mAdditionalDisplayInputProperties =
|
private final SparseArray<AdditionalDisplayInputProperties> mAdditionalDisplayInputProperties =
|
||||||
new SparseArray<>();
|
new SparseArray<>();
|
||||||
@@ -289,7 +303,6 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
@GuardedBy("mAdditionalDisplayInputPropertiesLock")
|
||||||
private PointerIcon mIcon;
|
private PointerIcon mIcon;
|
||||||
|
|
||||||
|
|
||||||
// Holds all the registered gesture monitors that are implemented as spy windows. The spy
|
// Holds all the registered gesture monitors that are implemented as spy windows. The spy
|
||||||
// windows are mapped by their InputChannel tokens.
|
// windows are mapped by their InputChannel tokens.
|
||||||
@GuardedBy("mInputMonitors")
|
@GuardedBy("mInputMonitors")
|
||||||
@@ -383,6 +396,10 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
NativeInputManagerService getNativeService(InputManagerService service) {
|
NativeInputManagerService getNativeService(InputManagerService service) {
|
||||||
return new NativeInputManagerService.NativeImpl(service, mContext, mLooper.getQueue());
|
return new NativeInputManagerService.NativeImpl(service, mContext, mLooper.getQueue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void registerLocalService(InputManagerInternal localService) {
|
||||||
|
LocalServices.addService(InputManagerInternal.class, localService);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputManagerService(Context context) {
|
public InputManagerService(Context context) {
|
||||||
@@ -409,7 +426,7 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
|
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
|
||||||
new File(doubleTouchGestureEnablePath);
|
new File(doubleTouchGestureEnablePath);
|
||||||
|
|
||||||
LocalServices.addService(InputManagerInternal.class, new LocalService());
|
injector.registerLocalService(new LocalService());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
|
public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
|
||||||
@@ -559,6 +576,8 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
vArray[i] = viewports.get(i);
|
vArray[i] = viewports.get(i);
|
||||||
}
|
}
|
||||||
mNative.setDisplayViewports(vArray);
|
mNative.setDisplayViewports(vArray);
|
||||||
|
// Always attempt to update the pointer display when viewports change.
|
||||||
|
updatePointerDisplayId();
|
||||||
|
|
||||||
if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
|
if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
|
||||||
final AdditionalDisplayInputProperties properties =
|
final AdditionalDisplayInputProperties properties =
|
||||||
@@ -1964,10 +1983,43 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setVirtualMousePointerDisplayId(int displayId) {
|
/**
|
||||||
|
* Update the display on which the mouse pointer is shown.
|
||||||
|
* If there is an overridden display for the mouse pointer, use that. Otherwise, query
|
||||||
|
* WindowManager for the pointer display.
|
||||||
|
*
|
||||||
|
* @return true if the pointer displayId changed, false otherwise.
|
||||||
|
*/
|
||||||
|
private boolean updatePointerDisplayId() {
|
||||||
|
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||||
|
final int pointerDisplayId = mOverriddenPointerDisplayId != Display.INVALID_DISPLAY
|
||||||
|
? mOverriddenPointerDisplayId : mWindowManagerCallbacks.getPointerDisplayId();
|
||||||
|
if (mRequestedPointerDisplayId == pointerDisplayId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mRequestedPointerDisplayId = pointerDisplayId;
|
||||||
|
mNative.setPointerDisplayId(pointerDisplayId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlePointerDisplayIdChanged(PointerDisplayIdChangedArgs args) {
|
||||||
|
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||||
|
mAcknowledgedPointerDisplayId = args.mPointerDisplayId;
|
||||||
|
// Notify waiting threads that the display of the mouse pointer has changed.
|
||||||
|
mAdditionalDisplayInputPropertiesLock.notifyAll();
|
||||||
|
}
|
||||||
|
mWindowManagerCallbacks.notifyPointerDisplayIdChanged(
|
||||||
|
args.mPointerDisplayId, args.mXPosition, args.mYPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean setVirtualMousePointerDisplayIdBlocking(int displayId) {
|
||||||
|
// Indicates whether this request is for removing the override.
|
||||||
|
final boolean removingOverride = displayId == Display.INVALID_DISPLAY;
|
||||||
|
|
||||||
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
||||||
mOverriddenPointerDisplayId = displayId;
|
mOverriddenPointerDisplayId = displayId;
|
||||||
if (displayId != Display.INVALID_DISPLAY) {
|
if (!removingOverride) {
|
||||||
final AdditionalDisplayInputProperties properties =
|
final AdditionalDisplayInputProperties properties =
|
||||||
mAdditionalDisplayInputProperties.get(displayId);
|
mAdditionalDisplayInputProperties.get(displayId);
|
||||||
if (properties != null) {
|
if (properties != null) {
|
||||||
@@ -1975,9 +2027,30 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
updatePointerIconVisibleLocked(properties.pointerIconVisible);
|
updatePointerIconVisibleLocked(properties.pointerIconVisible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!updatePointerDisplayId() && mAcknowledgedPointerDisplayId == displayId) {
|
||||||
|
// The requested pointer display is already set.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (removingOverride && mAcknowledgedPointerDisplayId == Display.INVALID_DISPLAY) {
|
||||||
|
// The pointer display override is being removed, but the current pointer display
|
||||||
|
// is already invalid. This can happen when the PointerController is destroyed as a
|
||||||
|
// result of the removal of all input devices that can control the pointer.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// The pointer display changed, so wait until the change has propagated.
|
||||||
|
mAdditionalDisplayInputPropertiesLock.wait(5_000 /*mills*/);
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
}
|
||||||
|
// This request succeeds in two cases:
|
||||||
|
// - This request was to remove the override, in which case the new pointer display
|
||||||
|
// could be anything that WM has set.
|
||||||
|
// - We are setting a new override, in which case the request only succeeds if the
|
||||||
|
// reported new displayId is the one we requested. This check ensures that if two
|
||||||
|
// competing overrides are requested in succession, the caller can be notified if one
|
||||||
|
// of them fails.
|
||||||
|
return removingOverride || mAcknowledgedPointerDisplayId == displayId;
|
||||||
}
|
}
|
||||||
// TODO(b/215597605): trigger MousePositionTracker update
|
|
||||||
mNative.notifyPointerDisplayIdChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getVirtualMousePointerDisplayId() {
|
private int getVirtualMousePointerDisplayId() {
|
||||||
@@ -3157,18 +3230,6 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
return mContext.createDisplayContext(display);
|
return mContext.createDisplayContext(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Native callback.
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private int getPointerDisplayId() {
|
|
||||||
synchronized (mAdditionalDisplayInputPropertiesLock) {
|
|
||||||
// Prefer the override to all other displays.
|
|
||||||
if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
|
|
||||||
return mOverriddenPointerDisplayId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mWindowManagerCallbacks.getPointerDisplayId();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Native callback.
|
// Native callback.
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
|
private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
|
||||||
@@ -3209,6 +3270,26 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class PointerDisplayIdChangedArgs {
|
||||||
|
final int mPointerDisplayId;
|
||||||
|
final float mXPosition;
|
||||||
|
final float mYPosition;
|
||||||
|
PointerDisplayIdChangedArgs(int pointerDisplayId, float xPosition, float yPosition) {
|
||||||
|
mPointerDisplayId = pointerDisplayId;
|
||||||
|
mXPosition = xPosition;
|
||||||
|
mYPosition = yPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native callback.
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@VisibleForTesting
|
||||||
|
void onPointerDisplayIdChanged(int pointerDisplayId, float xPosition, float yPosition) {
|
||||||
|
mHandler.obtainMessage(MSG_POINTER_DISPLAY_ID_CHANGED,
|
||||||
|
new PointerDisplayIdChangedArgs(pointerDisplayId, xPosition,
|
||||||
|
yPosition)).sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback interface implemented by the Window Manager.
|
* Callback interface implemented by the Window Manager.
|
||||||
*/
|
*/
|
||||||
@@ -3332,6 +3413,14 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
SurfaceControl createSurfaceForGestureMonitor(String name, int displayId);
|
SurfaceControl createSurfaceForGestureMonitor(String name, int displayId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify WindowManagerService when the display of the mouse pointer changes.
|
||||||
|
* @param displayId The display on which the mouse pointer is shown.
|
||||||
|
* @param x The x coordinate of the mouse pointer.
|
||||||
|
* @param y The y coordinate of the mouse pointer.
|
||||||
|
*/
|
||||||
|
void notifyPointerDisplayIdChanged(int displayId, float x, float y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3384,6 +3473,9 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
boolean inTabletMode = (boolean) args.arg1;
|
boolean inTabletMode = (boolean) args.arg1;
|
||||||
deliverTabletModeChanged(whenNanos, inTabletMode);
|
deliverTabletModeChanged(whenNanos, inTabletMode);
|
||||||
break;
|
break;
|
||||||
|
case MSG_POINTER_DISPLAY_ID_CHANGED:
|
||||||
|
handlePointerDisplayIdChanged((PointerDisplayIdChangedArgs) msg.obj);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3634,8 +3726,9 @@ public class InputManagerService extends IInputManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setVirtualMousePointerDisplayId(int pointerDisplayId) {
|
public boolean setVirtualMousePointerDisplayId(int pointerDisplayId) {
|
||||||
InputManagerService.this.setVirtualMousePointerDisplayId(pointerDisplayId);
|
return InputManagerService.this
|
||||||
|
.setVirtualMousePointerDisplayIdBlocking(pointerDisplayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -176,6 +176,9 @@ public interface NativeInputManagerService {
|
|||||||
|
|
||||||
void cancelCurrentTouch();
|
void cancelCurrentTouch();
|
||||||
|
|
||||||
|
/** Set the displayId on which the mouse cursor should be shown. */
|
||||||
|
void setPointerDisplayId(int displayId);
|
||||||
|
|
||||||
/** The native implementation of InputManagerService methods. */
|
/** The native implementation of InputManagerService methods. */
|
||||||
class NativeImpl implements NativeInputManagerService {
|
class NativeImpl implements NativeInputManagerService {
|
||||||
/** Pointer to native input manager service object, used by native code. */
|
/** Pointer to native input manager service object, used by native code. */
|
||||||
@@ -388,5 +391,8 @@ public interface NativeInputManagerService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public native void cancelCurrentTouch();
|
public native void cancelCurrentTouch();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public native void setPointerDisplayId(int displayId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -270,6 +270,22 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyPointerDisplayIdChanged(int displayId, float x, float y) {
|
||||||
|
synchronized (mService.mGlobalLock) {
|
||||||
|
mService.setMousePointerDisplayId(displayId);
|
||||||
|
if (displayId == Display.INVALID_DISPLAY) return;
|
||||||
|
|
||||||
|
final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
|
||||||
|
if (dc == null) {
|
||||||
|
Slog.wtf(TAG, "The mouse pointer was moved to display " + displayId
|
||||||
|
+ " that does not have a valid DisplayContent.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mService.restorePointerIconLocked(dc, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Waits until the built-in input devices have been configured. */
|
/** Waits until the built-in input devices have been configured. */
|
||||||
public boolean waitForInputDevicesReady(long timeoutMillis) {
|
public boolean waitForInputDevicesReady(long timeoutMillis) {
|
||||||
synchronized (mInputDevicesReadyMonitor) {
|
synchronized (mInputDevicesReadyMonitor) {
|
||||||
|
|||||||
@@ -7208,18 +7208,42 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
private float mLatestMouseX;
|
private float mLatestMouseX;
|
||||||
private float mLatestMouseY;
|
private float mLatestMouseY;
|
||||||
|
|
||||||
void updatePosition(float x, float y) {
|
/**
|
||||||
|
* The display that the pointer (mouse cursor) is currently shown on. This is updated
|
||||||
|
* directly by InputManagerService when the pointer display changes.
|
||||||
|
*/
|
||||||
|
private int mPointerDisplayId = INVALID_DISPLAY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the mouse cursor position as a result of a mouse movement.
|
||||||
|
* @return true if the position was successfully updated, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean updatePosition(int displayId, float x, float y) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
mLatestEventWasMouse = true;
|
mLatestEventWasMouse = true;
|
||||||
|
|
||||||
|
if (displayId != mPointerDisplayId) {
|
||||||
|
// The display of the position update does not match the display on which the
|
||||||
|
// mouse pointer is shown, so do not update the position.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
mLatestMouseX = x;
|
mLatestMouseX = x;
|
||||||
mLatestMouseY = y;
|
mLatestMouseY = y;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPointerDisplayId(int displayId) {
|
||||||
|
synchronized (this) {
|
||||||
|
mPointerDisplayId = displayId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPointerEvent(MotionEvent motionEvent) {
|
public void onPointerEvent(MotionEvent motionEvent) {
|
||||||
if (motionEvent.isFromSource(InputDevice.SOURCE_MOUSE)) {
|
if (motionEvent.isFromSource(InputDevice.SOURCE_MOUSE)) {
|
||||||
updatePosition(motionEvent.getRawX(), motionEvent.getRawY());
|
updatePosition(motionEvent.getDisplayId(), motionEvent.getRawX(),
|
||||||
|
motionEvent.getRawY());
|
||||||
} else {
|
} else {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
mLatestEventWasMouse = false;
|
mLatestEventWasMouse = false;
|
||||||
@@ -7229,6 +7253,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
};
|
};
|
||||||
|
|
||||||
void updatePointerIcon(IWindow client) {
|
void updatePointerIcon(IWindow client) {
|
||||||
|
int pointerDisplayId;
|
||||||
float mouseX, mouseY;
|
float mouseX, mouseY;
|
||||||
|
|
||||||
synchronized(mMousePositionTracker) {
|
synchronized(mMousePositionTracker) {
|
||||||
@@ -7237,6 +7262,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
}
|
}
|
||||||
mouseX = mMousePositionTracker.mLatestMouseX;
|
mouseX = mMousePositionTracker.mLatestMouseX;
|
||||||
mouseY = mMousePositionTracker.mLatestMouseY;
|
mouseY = mMousePositionTracker.mLatestMouseY;
|
||||||
|
pointerDisplayId = mMousePositionTracker.mPointerDisplayId;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (mGlobalLock) {
|
synchronized (mGlobalLock) {
|
||||||
@@ -7253,6 +7279,10 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
if (displayContent == null) {
|
if (displayContent == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (pointerDisplayId != displayContent.getDisplayId()) {
|
||||||
|
// Do not let the pointer icon be updated by a window on a different display.
|
||||||
|
return;
|
||||||
|
}
|
||||||
WindowState windowUnderPointer =
|
WindowState windowUnderPointer =
|
||||||
displayContent.getTouchableWinAtPointLocked(mouseX, mouseY);
|
displayContent.getTouchableWinAtPointLocked(mouseX, mouseY);
|
||||||
if (windowUnderPointer != callingWin) {
|
if (windowUnderPointer != callingWin) {
|
||||||
@@ -7270,7 +7300,11 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
|
|
||||||
void restorePointerIconLocked(DisplayContent displayContent, float latestX, float latestY) {
|
void restorePointerIconLocked(DisplayContent displayContent, float latestX, float latestY) {
|
||||||
// Mouse position tracker has not been getting updates while dragging, update it now.
|
// Mouse position tracker has not been getting updates while dragging, update it now.
|
||||||
mMousePositionTracker.updatePosition(latestX, latestY);
|
if (!mMousePositionTracker.updatePosition(
|
||||||
|
displayContent.getDisplayId(), latestX, latestY)) {
|
||||||
|
// The mouse position could not be updated, so ignore this request.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
WindowState windowUnderPointer =
|
WindowState windowUnderPointer =
|
||||||
displayContent.getTouchableWinAtPointLocked(latestX, latestY);
|
displayContent.getTouchableWinAtPointLocked(latestX, latestY);
|
||||||
@@ -7294,6 +7328,10 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setMousePointerDisplayId(int displayId) {
|
||||||
|
mMousePositionTracker.setPointerDisplayId(displayId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a tap exclude region in the window identified by the provided id. Touches down on this
|
* Update a tap exclude region in the window identified by the provided id. Touches down on this
|
||||||
* region will not:
|
* region will not:
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ static struct {
|
|||||||
jmethodID interceptKeyBeforeDispatching;
|
jmethodID interceptKeyBeforeDispatching;
|
||||||
jmethodID dispatchUnhandledKey;
|
jmethodID dispatchUnhandledKey;
|
||||||
jmethodID checkInjectEventsPermission;
|
jmethodID checkInjectEventsPermission;
|
||||||
|
jmethodID onPointerDisplayIdChanged;
|
||||||
jmethodID onPointerDownOutsideFocus;
|
jmethodID onPointerDownOutsideFocus;
|
||||||
jmethodID getVirtualKeyQuietTimeMillis;
|
jmethodID getVirtualKeyQuietTimeMillis;
|
||||||
jmethodID getExcludedDeviceNames;
|
jmethodID getExcludedDeviceNames;
|
||||||
@@ -120,7 +121,6 @@ static struct {
|
|||||||
jmethodID getLongPressTimeout;
|
jmethodID getLongPressTimeout;
|
||||||
jmethodID getPointerLayer;
|
jmethodID getPointerLayer;
|
||||||
jmethodID getPointerIcon;
|
jmethodID getPointerIcon;
|
||||||
jmethodID getPointerDisplayId;
|
|
||||||
jmethodID getKeyboardLayoutOverlay;
|
jmethodID getKeyboardLayoutOverlay;
|
||||||
jmethodID getDeviceAlias;
|
jmethodID getDeviceAlias;
|
||||||
jmethodID getTouchCalibrationForInputDevice;
|
jmethodID getTouchCalibrationForInputDevice;
|
||||||
@@ -277,6 +277,7 @@ public:
|
|||||||
void setFocusedDisplay(int32_t displayId);
|
void setFocusedDisplay(int32_t displayId);
|
||||||
void setInputDispatchMode(bool enabled, bool frozen);
|
void setInputDispatchMode(bool enabled, bool frozen);
|
||||||
void setSystemUiLightsOut(bool lightsOut);
|
void setSystemUiLightsOut(bool lightsOut);
|
||||||
|
void setPointerDisplayId(int32_t displayId);
|
||||||
void setPointerSpeed(int32_t speed);
|
void setPointerSpeed(int32_t speed);
|
||||||
void setPointerAcceleration(float acceleration);
|
void setPointerAcceleration(float acceleration);
|
||||||
void setInputDeviceEnabled(uint32_t deviceId, bool enabled);
|
void setInputDeviceEnabled(uint32_t deviceId, bool enabled);
|
||||||
@@ -288,7 +289,6 @@ public:
|
|||||||
void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled);
|
void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled);
|
||||||
void setCustomPointerIcon(const SpriteIcon& icon);
|
void setCustomPointerIcon(const SpriteIcon& icon);
|
||||||
void setMotionClassifierEnabled(bool enabled);
|
void setMotionClassifierEnabled(bool enabled);
|
||||||
void notifyPointerDisplayIdChanged();
|
|
||||||
|
|
||||||
/* --- InputReaderPolicyInterface implementation --- */
|
/* --- InputReaderPolicyInterface implementation --- */
|
||||||
|
|
||||||
@@ -346,6 +346,7 @@ public:
|
|||||||
std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId);
|
std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId);
|
||||||
virtual int32_t getDefaultPointerIconId();
|
virtual int32_t getDefaultPointerIconId();
|
||||||
virtual int32_t getCustomPointerIconId();
|
virtual int32_t getCustomPointerIconId();
|
||||||
|
virtual void onPointerDisplayIdChanged(int32_t displayId, float xPos, float yPos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sp<InputManagerInterface> mInputManager;
|
sp<InputManagerInterface> mInputManager;
|
||||||
@@ -394,7 +395,6 @@ private:
|
|||||||
void updateInactivityTimeoutLocked();
|
void updateInactivityTimeoutLocked();
|
||||||
void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
|
void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
|
||||||
void ensureSpriteControllerLocked();
|
void ensureSpriteControllerLocked();
|
||||||
int32_t getPointerDisplayId();
|
|
||||||
sp<SurfaceControl> getParentSurfaceForPointers(int displayId);
|
sp<SurfaceControl> getParentSurfaceForPointers(int displayId);
|
||||||
static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
|
static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
|
||||||
|
|
||||||
@@ -498,13 +498,9 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the preferred pointer controller displayId.
|
|
||||||
int32_t pointerDisplayId = getPointerDisplayId();
|
|
||||||
|
|
||||||
{ // acquire lock
|
{ // acquire lock
|
||||||
AutoMutex _l(mLock);
|
AutoMutex _l(mLock);
|
||||||
mLocked.viewports = viewports;
|
mLocked.viewports = viewports;
|
||||||
mLocked.pointerDisplayId = pointerDisplayId;
|
|
||||||
std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
|
std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
|
||||||
if (controller != nullptr) {
|
if (controller != nullptr) {
|
||||||
controller->onDisplayViewportsUpdated(mLocked.viewports);
|
controller->onDisplayViewportsUpdated(mLocked.viewports);
|
||||||
@@ -666,15 +662,12 @@ std::shared_ptr<PointerControllerInterface> NativeInputManager::obtainPointerCon
|
|||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t NativeInputManager::getPointerDisplayId() {
|
void NativeInputManager::onPointerDisplayIdChanged(int32_t pointerDisplayId, float xPos,
|
||||||
|
float yPos) {
|
||||||
JNIEnv* env = jniEnv();
|
JNIEnv* env = jniEnv();
|
||||||
jint pointerDisplayId = env->CallIntMethod(mServiceObj,
|
env->CallVoidMethod(mServiceObj, gServiceClassInfo.onPointerDisplayIdChanged, pointerDisplayId,
|
||||||
gServiceClassInfo.getPointerDisplayId);
|
xPos, yPos);
|
||||||
if (checkAndClearExceptionFromCallback(env, "getPointerDisplayId")) {
|
checkAndClearExceptionFromCallback(env, "onPointerDisplayIdChanged");
|
||||||
pointerDisplayId = ADISPLAY_ID_DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pointerDisplayId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<SurfaceControl> NativeInputManager::getParentSurfaceForPointers(int displayId) {
|
sp<SurfaceControl> NativeInputManager::getParentSurfaceForPointers(int displayId) {
|
||||||
@@ -1032,6 +1025,22 @@ void NativeInputManager::updateInactivityTimeoutLocked() REQUIRES(mLock) {
|
|||||||
: InactivityTimeout::NORMAL);
|
: InactivityTimeout::NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NativeInputManager::setPointerDisplayId(int32_t displayId) {
|
||||||
|
{ // acquire lock
|
||||||
|
AutoMutex _l(mLock);
|
||||||
|
|
||||||
|
if (mLocked.pointerDisplayId == displayId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALOGI("Setting pointer display id to %d.", displayId);
|
||||||
|
mLocked.pointerDisplayId = displayId;
|
||||||
|
} // release lock
|
||||||
|
|
||||||
|
mInputManager->getReader().requestRefreshConfiguration(
|
||||||
|
InputReaderConfiguration::CHANGE_DISPLAY_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
void NativeInputManager::setPointerSpeed(int32_t speed) {
|
void NativeInputManager::setPointerSpeed(int32_t speed) {
|
||||||
{ // acquire lock
|
{ // acquire lock
|
||||||
AutoMutex _l(mLock);
|
AutoMutex _l(mLock);
|
||||||
@@ -1494,18 +1503,6 @@ void NativeInputManager::setMotionClassifierEnabled(bool enabled) {
|
|||||||
mInputManager->getClassifier().setMotionClassifierEnabled(enabled);
|
mInputManager->getClassifier().setMotionClassifierEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeInputManager::notifyPointerDisplayIdChanged() {
|
|
||||||
int32_t pointerDisplayId = getPointerDisplayId();
|
|
||||||
|
|
||||||
{ // acquire lock
|
|
||||||
AutoMutex _l(mLock);
|
|
||||||
mLocked.pointerDisplayId = pointerDisplayId;
|
|
||||||
} // release lock
|
|
||||||
|
|
||||||
mInputManager->getReader().requestRefreshConfiguration(
|
|
||||||
InputReaderConfiguration::CHANGE_DISPLAY_INFO);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
static NativeInputManager* getNativeInputManager(JNIEnv* env, jobject clazz) {
|
static NativeInputManager* getNativeInputManager(JNIEnv* env, jobject clazz) {
|
||||||
@@ -2199,11 +2196,6 @@ static void nativeNotifyPortAssociationsChanged(JNIEnv* env, jobject nativeImplO
|
|||||||
InputReaderConfiguration::CHANGE_DISPLAY_INFO);
|
InputReaderConfiguration::CHANGE_DISPLAY_INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nativeNotifyPointerDisplayIdChanged(JNIEnv* env, jobject nativeImplObj) {
|
|
||||||
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
|
|
||||||
im->notifyPointerDisplayIdChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nativeSetDisplayEligibilityForPointerCapture(JNIEnv* env, jobject nativeImplObj,
|
static void nativeSetDisplayEligibilityForPointerCapture(JNIEnv* env, jobject nativeImplObj,
|
||||||
jint displayId, jboolean isEligible) {
|
jint displayId, jboolean isEligible) {
|
||||||
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
|
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
|
||||||
@@ -2321,6 +2313,11 @@ static void nativeCancelCurrentTouch(JNIEnv* env, jobject nativeImplObj) {
|
|||||||
im->getInputManager()->getDispatcher().cancelCurrentTouch();
|
im->getInputManager()->getDispatcher().cancelCurrentTouch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nativeSetPointerDisplayId(JNIEnv* env, jobject nativeImplObj, jint displayId) {
|
||||||
|
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
|
||||||
|
im->setPointerDisplayId(displayId);
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
static const JNINativeMethod gInputManagerMethods[] = {
|
static const JNINativeMethod gInputManagerMethods[] = {
|
||||||
@@ -2393,7 +2390,6 @@ static const JNINativeMethod gInputManagerMethods[] = {
|
|||||||
{"canDispatchToDisplay", "(II)Z", (void*)nativeCanDispatchToDisplay},
|
{"canDispatchToDisplay", "(II)Z", (void*)nativeCanDispatchToDisplay},
|
||||||
{"notifyPortAssociationsChanged", "()V", (void*)nativeNotifyPortAssociationsChanged},
|
{"notifyPortAssociationsChanged", "()V", (void*)nativeNotifyPortAssociationsChanged},
|
||||||
{"changeUniqueIdAssociation", "()V", (void*)nativeChangeUniqueIdAssociation},
|
{"changeUniqueIdAssociation", "()V", (void*)nativeChangeUniqueIdAssociation},
|
||||||
{"notifyPointerDisplayIdChanged", "()V", (void*)nativeNotifyPointerDisplayIdChanged},
|
|
||||||
{"setDisplayEligibilityForPointerCapture", "(IZ)V",
|
{"setDisplayEligibilityForPointerCapture", "(IZ)V",
|
||||||
(void*)nativeSetDisplayEligibilityForPointerCapture},
|
(void*)nativeSetDisplayEligibilityForPointerCapture},
|
||||||
{"setMotionClassifierEnabled", "(Z)V", (void*)nativeSetMotionClassifierEnabled},
|
{"setMotionClassifierEnabled", "(Z)V", (void*)nativeSetMotionClassifierEnabled},
|
||||||
@@ -2403,6 +2399,7 @@ static const JNINativeMethod gInputManagerMethods[] = {
|
|||||||
{"disableSensor", "(II)V", (void*)nativeDisableSensor},
|
{"disableSensor", "(II)V", (void*)nativeDisableSensor},
|
||||||
{"flushSensor", "(II)Z", (void*)nativeFlushSensor},
|
{"flushSensor", "(II)Z", (void*)nativeFlushSensor},
|
||||||
{"cancelCurrentTouch", "()V", (void*)nativeCancelCurrentTouch},
|
{"cancelCurrentTouch", "()V", (void*)nativeCancelCurrentTouch},
|
||||||
|
{"setPointerDisplayId", "(I)V", (void*)nativeSetPointerDisplayId},
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FIND_CLASS(var, className) \
|
#define FIND_CLASS(var, className) \
|
||||||
@@ -2498,6 +2495,9 @@ int register_android_server_InputManager(JNIEnv* env) {
|
|||||||
GET_METHOD_ID(gServiceClassInfo.checkInjectEventsPermission, clazz,
|
GET_METHOD_ID(gServiceClassInfo.checkInjectEventsPermission, clazz,
|
||||||
"checkInjectEventsPermission", "(II)Z");
|
"checkInjectEventsPermission", "(II)Z");
|
||||||
|
|
||||||
|
GET_METHOD_ID(gServiceClassInfo.onPointerDisplayIdChanged, clazz, "onPointerDisplayIdChanged",
|
||||||
|
"(IFF)V");
|
||||||
|
|
||||||
GET_METHOD_ID(gServiceClassInfo.onPointerDownOutsideFocus, clazz,
|
GET_METHOD_ID(gServiceClassInfo.onPointerDownOutsideFocus, clazz,
|
||||||
"onPointerDownOutsideFocus", "(Landroid/os/IBinder;)V");
|
"onPointerDownOutsideFocus", "(Landroid/os/IBinder;)V");
|
||||||
|
|
||||||
@@ -2537,9 +2537,6 @@ int register_android_server_InputManager(JNIEnv* env) {
|
|||||||
GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz,
|
GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz,
|
||||||
"getPointerIcon", "(I)Landroid/view/PointerIcon;");
|
"getPointerIcon", "(I)Landroid/view/PointerIcon;");
|
||||||
|
|
||||||
GET_METHOD_ID(gServiceClassInfo.getPointerDisplayId, clazz,
|
|
||||||
"getPointerDisplayId", "()I");
|
|
||||||
|
|
||||||
GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz,
|
GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz,
|
||||||
"getKeyboardLayoutOverlay",
|
"getKeyboardLayoutOverlay",
|
||||||
"(Landroid/hardware/input/InputDeviceIdentifier;)[Ljava/lang/String;");
|
"(Landroid/hardware/input/InputDeviceIdentifier;)[Ljava/lang/String;");
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package com.android.server.companion.virtual;
|
|||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doNothing;
|
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
@@ -67,7 +66,7 @@ public class InputControllerTest {
|
|||||||
mInputManagerMockHelper = new InputManagerMockHelper(
|
mInputManagerMockHelper = new InputManagerMockHelper(
|
||||||
TestableLooper.get(this), mNativeWrapperMock, mIInputManagerMock);
|
TestableLooper.get(this), mNativeWrapperMock, mIInputManagerMock);
|
||||||
|
|
||||||
doNothing().when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt());
|
doReturn(true).when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt());
|
||||||
LocalServices.removeServiceForTest(InputManagerInternal.class);
|
LocalServices.removeServiceForTest(InputManagerInternal.class);
|
||||||
LocalServices.addService(InputManagerInternal.class, mInputManagerInternalMock);
|
LocalServices.addService(InputManagerInternal.class, mInputManagerInternalMock);
|
||||||
|
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ public class VirtualDeviceManagerServiceTest {
|
|||||||
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
|
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
|
||||||
LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
|
LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
|
||||||
|
|
||||||
doNothing().when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt());
|
doReturn(true).when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt());
|
||||||
doNothing().when(mInputManagerInternalMock).setPointerAcceleration(anyFloat(), anyInt());
|
doNothing().when(mInputManagerInternalMock).setPointerAcceleration(anyFloat(), anyInt());
|
||||||
doNothing().when(mInputManagerInternalMock).setPointerIconVisible(anyBoolean(), anyInt());
|
doNothing().when(mInputManagerInternalMock).setPointerIconVisible(anyBoolean(), anyInt());
|
||||||
LocalServices.removeServiceForTest(InputManagerInternal.class);
|
LocalServices.removeServiceForTest(InputManagerInternal.class);
|
||||||
|
|||||||
@@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.input
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.ContextWrapper
|
||||||
|
import android.hardware.display.DisplayViewport
|
||||||
|
import android.hardware.input.InputManagerInternal
|
||||||
|
import android.os.test.TestLooper
|
||||||
|
import android.platform.test.annotations.Presubmit
|
||||||
|
import android.view.Display
|
||||||
|
import androidx.test.InstrumentationRegistry
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.ArgumentMatchers.any
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.`when`
|
||||||
|
import org.mockito.Mockito.doAnswer
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.spy
|
||||||
|
import org.mockito.Mockito.times
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.junit.MockitoJUnit
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link InputManagerService}.
|
||||||
|
*
|
||||||
|
* Build/Install/Run:
|
||||||
|
* atest FrameworksServicesTests:InputManagerServiceTests
|
||||||
|
*/
|
||||||
|
@Presubmit
|
||||||
|
class InputManagerServiceTests {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val rule = MockitoJUnit.rule()!!
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var native: NativeInputManagerService
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var wmCallbacks: InputManagerService.WindowManagerCallbacks
|
||||||
|
|
||||||
|
private lateinit var service: InputManagerService
|
||||||
|
private lateinit var localService: InputManagerInternal
|
||||||
|
private lateinit var context: Context
|
||||||
|
private lateinit var testLooper: TestLooper
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
context = spy(ContextWrapper(InstrumentationRegistry.getContext()))
|
||||||
|
testLooper = TestLooper()
|
||||||
|
service =
|
||||||
|
InputManagerService(object : InputManagerService.Injector(context, testLooper.looper) {
|
||||||
|
override fun getNativeService(
|
||||||
|
service: InputManagerService?
|
||||||
|
): NativeInputManagerService {
|
||||||
|
return native
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun registerLocalService(service: InputManagerInternal?) {
|
||||||
|
localService = service!!
|
||||||
|
}
|
||||||
|
})
|
||||||
|
assertTrue("Local service must be registered", this::localService.isInitialized)
|
||||||
|
service.setWindowManagerCallbacks(wmCallbacks)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPointerDisplayUpdatesWhenDisplayViewportsChanged() {
|
||||||
|
val displayId = 123
|
||||||
|
`when`(wmCallbacks.pointerDisplayId).thenReturn(displayId)
|
||||||
|
val viewports = listOf<DisplayViewport>()
|
||||||
|
localService.setDisplayViewports(viewports)
|
||||||
|
verify(native).setDisplayViewports(any(Array<DisplayViewport>::class.java))
|
||||||
|
verify(native).setPointerDisplayId(displayId)
|
||||||
|
|
||||||
|
val x = 42f
|
||||||
|
val y = 314f
|
||||||
|
service.onPointerDisplayIdChanged(displayId, x, y)
|
||||||
|
testLooper.dispatchNext()
|
||||||
|
verify(wmCallbacks).notifyPointerDisplayIdChanged(displayId, x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSetVirtualMousePointerDisplayId() {
|
||||||
|
// Set the virtual mouse pointer displayId, and ensure that the calling thread is blocked
|
||||||
|
// until the native callback happens.
|
||||||
|
var countDownLatch = CountDownLatch(1)
|
||||||
|
val overrideDisplayId = 123
|
||||||
|
Thread {
|
||||||
|
assertTrue("Setting virtual pointer display should succeed",
|
||||||
|
localService.setVirtualMousePointerDisplayId(overrideDisplayId))
|
||||||
|
countDownLatch.countDown()
|
||||||
|
}.start()
|
||||||
|
assertFalse("Setting virtual pointer display should block",
|
||||||
|
countDownLatch.await(100, TimeUnit.MILLISECONDS))
|
||||||
|
|
||||||
|
val x = 42f
|
||||||
|
val y = 314f
|
||||||
|
service.onPointerDisplayIdChanged(overrideDisplayId, x, y)
|
||||||
|
testLooper.dispatchNext()
|
||||||
|
verify(wmCallbacks).notifyPointerDisplayIdChanged(overrideDisplayId, x, y)
|
||||||
|
assertTrue("Native callback unblocks calling thread",
|
||||||
|
countDownLatch.await(100, TimeUnit.MILLISECONDS))
|
||||||
|
verify(native).setPointerDisplayId(overrideDisplayId)
|
||||||
|
|
||||||
|
// Ensure that setting the same override again succeeds immediately.
|
||||||
|
assertTrue("Setting the same virtual mouse pointer displayId again should succeed",
|
||||||
|
localService.setVirtualMousePointerDisplayId(overrideDisplayId))
|
||||||
|
|
||||||
|
// Ensure that we did not query WM for the pointerDisplayId when setting the override
|
||||||
|
verify(wmCallbacks, never()).pointerDisplayId
|
||||||
|
|
||||||
|
// Unset the virtual mouse pointer displayId, and ensure that we query WM for the new
|
||||||
|
// pointer displayId and the calling thread is blocked until the native callback happens.
|
||||||
|
countDownLatch = CountDownLatch(1)
|
||||||
|
val pointerDisplayId = 42
|
||||||
|
`when`(wmCallbacks.pointerDisplayId).thenReturn(pointerDisplayId)
|
||||||
|
Thread {
|
||||||
|
assertTrue("Unsetting virtual mouse pointer displayId should succeed",
|
||||||
|
localService.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY))
|
||||||
|
countDownLatch.countDown()
|
||||||
|
}.start()
|
||||||
|
assertFalse("Unsetting virtual mouse pointer displayId should block",
|
||||||
|
countDownLatch.await(100, TimeUnit.MILLISECONDS))
|
||||||
|
|
||||||
|
service.onPointerDisplayIdChanged(pointerDisplayId, x, y)
|
||||||
|
testLooper.dispatchNext()
|
||||||
|
verify(wmCallbacks).notifyPointerDisplayIdChanged(pointerDisplayId, x, y)
|
||||||
|
assertTrue("Native callback unblocks calling thread",
|
||||||
|
countDownLatch.await(100, TimeUnit.MILLISECONDS))
|
||||||
|
verify(native).setPointerDisplayId(pointerDisplayId)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSetVirtualMousePointerDisplayId_unsuccessfulUpdate() {
|
||||||
|
// Set the virtual mouse pointer displayId, and ensure that the calling thread is blocked
|
||||||
|
// until the native callback happens.
|
||||||
|
val countDownLatch = CountDownLatch(1)
|
||||||
|
val overrideDisplayId = 123
|
||||||
|
Thread {
|
||||||
|
assertFalse("Setting virtual pointer display should be unsuccessful",
|
||||||
|
localService.setVirtualMousePointerDisplayId(overrideDisplayId))
|
||||||
|
countDownLatch.countDown()
|
||||||
|
}.start()
|
||||||
|
assertFalse("Setting virtual pointer display should block",
|
||||||
|
countDownLatch.await(100, TimeUnit.MILLISECONDS))
|
||||||
|
|
||||||
|
val x = 42f
|
||||||
|
val y = 314f
|
||||||
|
// Assume the native callback updates the pointerDisplayId to the incorrect value.
|
||||||
|
service.onPointerDisplayIdChanged(Display.INVALID_DISPLAY, x, y)
|
||||||
|
testLooper.dispatchNext()
|
||||||
|
verify(wmCallbacks).notifyPointerDisplayIdChanged(Display.INVALID_DISPLAY, x, y)
|
||||||
|
assertTrue("Native callback unblocks calling thread",
|
||||||
|
countDownLatch.await(100, TimeUnit.MILLISECONDS))
|
||||||
|
verify(native).setPointerDisplayId(overrideDisplayId)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSetVirtualMousePointerDisplayId_competingRequests() {
|
||||||
|
val firstRequestSyncLatch = CountDownLatch(1)
|
||||||
|
doAnswer {
|
||||||
|
firstRequestSyncLatch.countDown()
|
||||||
|
}.`when`(native).setPointerDisplayId(anyInt())
|
||||||
|
|
||||||
|
val firstRequestLatch = CountDownLatch(1)
|
||||||
|
val firstOverride = 123
|
||||||
|
Thread {
|
||||||
|
assertFalse("Setting virtual pointer display from thread 1 should be unsuccessful",
|
||||||
|
localService.setVirtualMousePointerDisplayId(firstOverride))
|
||||||
|
firstRequestLatch.countDown()
|
||||||
|
}.start()
|
||||||
|
assertFalse("Setting virtual pointer display should block",
|
||||||
|
firstRequestLatch.await(100, TimeUnit.MILLISECONDS))
|
||||||
|
|
||||||
|
assertTrue("Wait for first thread's request should succeed",
|
||||||
|
firstRequestSyncLatch.await(100, TimeUnit.MILLISECONDS))
|
||||||
|
|
||||||
|
val secondRequestLatch = CountDownLatch(1)
|
||||||
|
val secondOverride = 42
|
||||||
|
Thread {
|
||||||
|
assertTrue("Setting virtual mouse pointer from thread 2 should be successful",
|
||||||
|
localService.setVirtualMousePointerDisplayId(secondOverride))
|
||||||
|
secondRequestLatch.countDown()
|
||||||
|
}.start()
|
||||||
|
assertFalse("Setting virtual mouse pointer should block",
|
||||||
|
secondRequestLatch.await(100, TimeUnit.MILLISECONDS))
|
||||||
|
|
||||||
|
val x = 42f
|
||||||
|
val y = 314f
|
||||||
|
// Assume the native callback updates directly to the second request.
|
||||||
|
service.onPointerDisplayIdChanged(secondOverride, x, y)
|
||||||
|
testLooper.dispatchNext()
|
||||||
|
verify(wmCallbacks).notifyPointerDisplayIdChanged(secondOverride, x, y)
|
||||||
|
assertTrue("Native callback unblocks first thread",
|
||||||
|
firstRequestLatch.await(100, TimeUnit.MILLISECONDS))
|
||||||
|
assertTrue("Native callback unblocks second thread",
|
||||||
|
secondRequestLatch.await(100, TimeUnit.MILLISECONDS))
|
||||||
|
verify(native, times(2)).setPointerDisplayId(anyInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user