From 670b33dd9068490e5a177ffa999639e774453b9e Mon Sep 17 00:00:00 2001 From: Seunghwan Choi Date: Fri, 13 Jan 2023 21:12:59 +0900 Subject: [PATCH 1/2] Separate default pointer for mouse and stylus (frameworks/base part) PointerIcon.TYPE_NOT_SPECIFIED will be used for requesting default pointer. For the type, MouseCursorController will decide whether to show mouse or stylus icon, based on the active source. Need complement: the resource for default stylus icon should be added. Test: Manual Test(hover pointer on handwriting area) Bug: b/215436642 Change-Id: I6a337cb69bea57427f676e561900802270d206ae --- core/java/android/view/ViewRootImpl.java | 17 ++++++---- libs/input/MouseCursorController.cpp | 33 +++++++++++++++---- libs/input/MouseCursorController.h | 3 ++ libs/input/PointerController.cpp | 12 +++++-- libs/input/PointerControllerContext.h | 1 + libs/input/tests/PointerController_test.cpp | 26 +++++++++++++++ ...droid_server_input_InputManagerService.cpp | 6 ++++ 7 files changed, 83 insertions(+), 15 deletions(-) diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 125960f0575f3..308248cbf7353 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -772,7 +772,12 @@ public final class ViewRootImpl implements ViewParent, private long mFpsPrevTime = -1; private int mFpsNumFrames; - private int mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED; + /** + * The resolved pointer icon type requested by this window. + * A null value indicates the resolved pointer icon has not yet been calculated. + */ + @Nullable + private Integer mPointerIconType = null; private PointerIcon mCustomPointerIcon = null; /** @@ -6905,13 +6910,13 @@ public final class ViewRootImpl implements ViewParent, || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) { // Other apps or the window manager may change the icon type outside of // this app, therefore the icon type has to be reset on enter/exit event. - mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED; + mPointerIconType = null; } if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) { if (!updatePointerIcon(event) && event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) { - mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED; + mPointerIconType = null; } } } @@ -6950,7 +6955,7 @@ public final class ViewRootImpl implements ViewParent, } private void resetPointerIcon(MotionEvent event) { - mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED; + mPointerIconType = null; updatePointerIcon(event); } @@ -6980,9 +6985,9 @@ public final class ViewRootImpl implements ViewParent, } final int pointerType = (pointerIcon != null) ? - pointerIcon.getType() : PointerIcon.TYPE_DEFAULT; + pointerIcon.getType() : PointerIcon.TYPE_NOT_SPECIFIED; - if (mPointerIconType != pointerType) { + if (mPointerIconType == null || mPointerIconType != pointerType) { mPointerIconType = pointerType; mCustomPointerIcon = null; if (mPointerIconType != PointerIcon.TYPE_CUSTOM) { diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp index a83516791f332..24cfc9d70c9b4 100644 --- a/libs/input/MouseCursorController.cpp +++ b/libs/input/MouseCursorController.cpp @@ -38,6 +38,8 @@ MouseCursorController::MouseCursorController(PointerControllerContext& context) : mContext(context) { std::scoped_lock lock(mLock); + mLocked.stylusHoverMode = false; + mLocked.animationFrameIndex = 0; mLocked.lastFrameUpdatedTime = 0; @@ -47,7 +49,8 @@ MouseCursorController::MouseCursorController(PointerControllerContext& context) mLocked.pointerAlpha = 0.0f; // pointer is initially faded mLocked.pointerSprite = mContext.getSpriteController()->createSprite(); mLocked.updatePointerIcon = false; - mLocked.requestedPointerType = mContext.getPolicy()->getDefaultPointerIconId(); + mLocked.requestedPointerType = PointerIconStyle::TYPE_NOT_SPECIFIED; + mLocked.resolvedPointerType = PointerIconStyle::TYPE_NOT_SPECIFIED; mLocked.resourcesLoaded = false; @@ -184,6 +187,15 @@ void MouseCursorController::unfade(PointerControllerInterface::Transition transi } } +void MouseCursorController::setStylusHoverMode(bool stylusHoverMode) { + std::scoped_lock lock(mLock); + + if (mLocked.stylusHoverMode != stylusHoverMode) { + mLocked.stylusHoverMode = stylusHoverMode; + mLocked.updatePointerIcon = true; + } +} + void MouseCursorController::reloadPointerResources(bool getAdditionalMouseResources) { std::scoped_lock lock(mLock); @@ -339,7 +351,7 @@ bool MouseCursorController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES( bool MouseCursorController::doBitmapAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) { std::map::const_iterator iter = - mLocked.animationResources.find(mLocked.requestedPointerType); + mLocked.animationResources.find(mLocked.resolvedPointerType); if (iter == mLocked.animationResources.end()) { return false; } @@ -381,14 +393,23 @@ void MouseCursorController::updatePointerLocked() REQUIRES(mLock) { } if (mLocked.updatePointerIcon) { - if (mLocked.requestedPointerType == mContext.getPolicy()->getDefaultPointerIconId()) { + mLocked.resolvedPointerType = mLocked.requestedPointerType; + const PointerIconStyle defaultPointerIconId = + mContext.getPolicy()->getDefaultPointerIconId(); + if (mLocked.resolvedPointerType == PointerIconStyle::TYPE_NOT_SPECIFIED) { + mLocked.resolvedPointerType = mLocked.stylusHoverMode + ? mContext.getPolicy()->getDefaultStylusIconId() + : defaultPointerIconId; + } + + if (mLocked.resolvedPointerType == defaultPointerIconId) { mLocked.pointerSprite->setIcon(mLocked.pointerIcon); } else { std::map::const_iterator iter = - mLocked.additionalMouseResources.find(mLocked.requestedPointerType); + mLocked.additionalMouseResources.find(mLocked.resolvedPointerType); if (iter != mLocked.additionalMouseResources.end()) { std::map::const_iterator anim_iter = - mLocked.animationResources.find(mLocked.requestedPointerType); + mLocked.animationResources.find(mLocked.resolvedPointerType); if (anim_iter != mLocked.animationResources.end()) { mLocked.animationFrameIndex = 0; mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC); @@ -396,7 +417,7 @@ void MouseCursorController::updatePointerLocked() REQUIRES(mLock) { } mLocked.pointerSprite->setIcon(iter->second); } else { - ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerType); + ALOGW("Can't find the resource for icon id %d", mLocked.resolvedPointerType); mLocked.pointerSprite->setIcon(mLocked.pointerIcon); } } diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h index 208d33d7c717d..db0ab56429b21 100644 --- a/libs/input/MouseCursorController.h +++ b/libs/input/MouseCursorController.h @@ -53,6 +53,7 @@ public: void fade(PointerControllerInterface::Transition transition); void unfade(PointerControllerInterface::Transition transition); void setDisplayViewport(const DisplayViewport& viewport, bool getAdditionalMouseResources); + void setStylusHoverMode(bool stylusHoverMode); void updatePointerIcon(PointerIconStyle iconId); void setCustomPointerIcon(const SpriteIcon& icon); @@ -74,6 +75,7 @@ private: struct Locked { DisplayViewport viewport; + bool stylusHoverMode; size_t animationFrameIndex; nsecs_t lastFrameUpdatedTime; @@ -92,6 +94,7 @@ private: std::map animationResources; PointerIconStyle requestedPointerType; + PointerIconStyle resolvedPointerType; int32_t buttonState; diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index 099efd3a1a2fa..fedf58d7c6d07 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -195,7 +195,11 @@ void PointerController::setPresentation(Presentation presentation) { return; } - if (presentation == Presentation::POINTER) { + if (presentation == Presentation::POINTER || presentation == Presentation::STYLUS_HOVER) { + // For now, we support stylus hover using the mouse cursor implementation. + // TODO: Add proper support for stylus hover icons. + mCursorController.setStylusHoverMode(presentation == Presentation::STYLUS_HOVER); + mCursorController.getAdditionalMouseResources(); clearSpotsLocked(); } @@ -249,7 +253,8 @@ void PointerController::reloadPointerResources() { if (mCursorController.resourcesLoaded()) { bool getAdditionalMouseResources = false; - if (mLocked.presentation == PointerController::Presentation::POINTER) { + if (mLocked.presentation == PointerController::Presentation::POINTER || + mLocked.presentation == PointerController::Presentation::STYLUS_HOVER) { getAdditionalMouseResources = true; } mCursorController.reloadPointerResources(getAdditionalMouseResources); @@ -260,7 +265,8 @@ void PointerController::setDisplayViewport(const DisplayViewport& viewport) { std::scoped_lock lock(getLock()); bool getAdditionalMouseResources = false; - if (mLocked.presentation == PointerController::Presentation::POINTER) { + if (mLocked.presentation == PointerController::Presentation::POINTER || + mLocked.presentation == PointerController::Presentation::STYLUS_HOVER) { getAdditionalMouseResources = true; } mCursorController.setDisplayViewport(viewport, getAdditionalMouseResources); diff --git a/libs/input/PointerControllerContext.h b/libs/input/PointerControllerContext.h index 1797428b343f6..96d83a5f0d15f 100644 --- a/libs/input/PointerControllerContext.h +++ b/libs/input/PointerControllerContext.h @@ -79,6 +79,7 @@ public: std::map* outAnimationResources, int32_t displayId) = 0; virtual PointerIconStyle getDefaultPointerIconId() = 0; + virtual PointerIconStyle getDefaultStylusIconId() = 0; virtual PointerIconStyle getCustomPointerIconId() = 0; virtual void onPointerDisplayIdChanged(int32_t displayId, float xPos, float yPos) = 0; }; diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp index a6a4115476df4..c820d0007a4bb 100644 --- a/libs/input/tests/PointerController_test.cpp +++ b/libs/input/tests/PointerController_test.cpp @@ -35,6 +35,7 @@ enum TestCursorType { CURSOR_TYPE_ANCHOR, CURSOR_TYPE_ADDITIONAL, CURSOR_TYPE_ADDITIONAL_ANIM, + CURSOR_TYPE_STYLUS, CURSOR_TYPE_CUSTOM = -1, }; @@ -57,6 +58,7 @@ public: std::map* outAnimationResources, int32_t displayId) override; virtual PointerIconStyle getDefaultPointerIconId() override; + virtual PointerIconStyle getDefaultStylusIconId() override; virtual PointerIconStyle getCustomPointerIconId() override; virtual void onPointerDisplayIdChanged(int32_t displayId, float xPos, float yPos) override; @@ -105,6 +107,11 @@ void MockPointerControllerPolicyInterface::loadAdditionalMouseResources( (*outResources)[static_cast(cursorType)] = icon; (*outAnimationResources)[static_cast(cursorType)] = anim; + // CURSOR_TYPE_STYLUS doesn't have animation resource. + cursorType = CURSOR_TYPE_STYLUS; + loadPointerIconForType(&icon, cursorType); + (*outResources)[static_cast(cursorType)] = icon; + additionalMouseResourcesLoaded = true; } @@ -112,6 +119,10 @@ PointerIconStyle MockPointerControllerPolicyInterface::getDefaultPointerIconId() return static_cast(CURSOR_TYPE_DEFAULT); } +PointerIconStyle MockPointerControllerPolicyInterface::getDefaultStylusIconId() { + return static_cast(CURSOR_TYPE_STYLUS); +} + PointerIconStyle MockPointerControllerPolicyInterface::getCustomPointerIconId() { return static_cast(CURSOR_TYPE_CUSTOM); } @@ -214,6 +225,21 @@ TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) { mPointerController->reloadPointerResources(); } +TEST_F(PointerControllerTest, useStylusTypeForStylusHover) { + ensureDisplayViewportIsSet(); + mPointerController->setPresentation(PointerController::Presentation::STYLUS_HOVER); + mPointerController->unfade(PointerController::Transition::IMMEDIATE); + std::pair hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_STYLUS); + EXPECT_CALL(*mPointerSprite, setVisible(true)); + EXPECT_CALL(*mPointerSprite, setAlpha(1.0f)); + EXPECT_CALL(*mPointerSprite, + setIcon(AllOf(Field(&SpriteIcon::style, + static_cast(CURSOR_TYPE_STYLUS)), + Field(&SpriteIcon::hotSpotX, hotspot.first), + Field(&SpriteIcon::hotSpotY, hotspot.second)))); + mPointerController->reloadPointerResources(); +} + TEST_F(PointerControllerTest, updatePointerIcon) { ensureDisplayViewportIsSet(); mPointerController->setPresentation(PointerController::Presentation::POINTER); diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index f4d1d1ef88d18..56ccf872d2f63 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -363,6 +363,7 @@ public: std::map* outResources, std::map* outAnimationResources, int32_t displayId); virtual PointerIconStyle getDefaultPointerIconId(); + virtual PointerIconStyle getDefaultStylusIconId(); virtual PointerIconStyle getCustomPointerIconId(); virtual void onPointerDisplayIdChanged(int32_t displayId, float xPos, float yPos); @@ -1605,6 +1606,11 @@ PointerIconStyle NativeInputManager::getDefaultPointerIconId() { return PointerIconStyle::TYPE_ARROW; } +PointerIconStyle NativeInputManager::getDefaultStylusIconId() { + // TODO: add resource for default stylus icon and change this + return PointerIconStyle::TYPE_CROSSHAIR; +} + PointerIconStyle NativeInputManager::getCustomPointerIconId() { return PointerIconStyle::TYPE_CUSTOM; } From 492922a6e815faa2da02bc27883f4195aceb2b8a Mon Sep 17 00:00:00 2001 From: Seunghwan Choi Date: Tue, 17 Jan 2023 20:47:47 +0900 Subject: [PATCH 2/2] check config for showing a stylus pointer (frameworks/base part) On InputReader, get the configuration from config.xml to decide whether to show a stylus pointer. Test: Manual Test(hover pointer on handwriting area) Bug: b/215436642 Change-Id: Ia08052f97e027c48d3bbc76ad03988722a7d9e2f --- .../com/android/server/input/InputManagerService.java | 7 +++++++ .../com_android_server_input_InputManagerService.cpp | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index e2caeec114d0a..a752c15921832 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -2974,6 +2974,13 @@ public class InputManagerService extends IInputManager.Stub return null; } + // Native callback. + @SuppressWarnings("unused") + private boolean isStylusPointerIconEnabled() { + return Objects.requireNonNull(mContext.getSystemService(InputManager.class)) + .isStylusPointerIconEnabled(); + } + private static class PointerDisplayIdChangedArgs { final int mPointerDisplayId; final float mXPosition; diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 56ccf872d2f63..b4e2fb6ca3e3f 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -137,6 +137,7 @@ static struct { jmethodID notifyDropWindow; jmethodID getParentSurfaceForPointers; jmethodID isPerDisplayTouchModeEnabled; + jmethodID isStylusPointerIconEnabled; } gServiceClassInfo; static struct { @@ -660,6 +661,12 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon outConfig->pointerGestureTapSlop = hoverTapSlop; } + jboolean stylusPointerIconEnabled = + env->CallBooleanMethod(mServiceObj, gServiceClassInfo.isStylusPointerIconEnabled); + if (!checkAndClearExceptionFromCallback(env, "isStylusPointerIconEnabled")) { + outConfig->stylusPointerIconEnabled = stylusPointerIconEnabled; + } + { // acquire lock AutoMutex _l(mLock); @@ -2793,6 +2800,9 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gServiceClassInfo.isPerDisplayTouchModeEnabled, clazz, "isPerDisplayTouchModeEnabled", "()Z"); + GET_METHOD_ID(gServiceClassInfo.isStylusPointerIconEnabled, clazz, "isStylusPointerIconEnabled", + "()Z"); + // InputDevice FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");