Loading include/input/Input.h +8 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,14 @@ enum { */ AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE = 0x8, /** * This flag indicates that the event will not cause a focus change if it is directed to an * unfocused window, even if it an ACTION_DOWN. This is typically used with pointer * gestures to allow the user to direct gestures to an unfocused window without bringing it * into focus. */ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40, /* Motion event is inconsistent with previously sent motion events. */ AMOTION_EVENT_FLAG_TAINTED = 0x80000000, }; Loading services/inputflinger/dispatcher/InputDispatcher.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -2886,6 +2886,12 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connectio ATRACE_NAME(message.c_str()); } if ((motionEntry.flags & AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) && (motionEntry.policyFlags & POLICY_FLAG_TRUSTED)) { // Skip reporting pointer down outside focus to the policy. break; } dispatchPointerDownOutsideFocus(motionEntry.source, dispatchEntry->resolvedAction, inputTarget.inputChannel->getConnectionToken()); Loading services/inputflinger/reader/mapper/TouchInputMapper.cpp +14 −8 Original line number Diff line number Diff line Loading @@ -2456,6 +2456,12 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentCookedState.buttonState; uint32_t flags = 0; if (!PointerGesture::canGestureAffectWindowFocus(mPointerGesture.currentGestureMode)) { flags |= AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE; } // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. bool down = mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP || Loading Loading @@ -2485,8 +2491,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); if (!dispatchedGestureIdBits.isEmpty()) { if (cancelPreviousGesture) { dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, mPointerGesture.downTime); Loading @@ -2504,7 +2510,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u uint32_t id = upGestureIdBits.clearFirstMarkedBit(); dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, AMOTION_EVENT_ACTION_POINTER_UP, 0, flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, 0, Loading @@ -2517,7 +2523,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u // Send motion events for all pointers that moved. if (moveNeeded) { dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, Loading @@ -2538,7 +2544,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u } dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, 0, flags, metaState, buttonState, 0, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, 0, Loading @@ -2548,8 +2554,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u // Send motion events for hover. if (mPointerGesture.currentGestureMode == PointerGesture::Mode::HOVER) { dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, Loading @@ -2573,7 +2579,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u const int32_t displayId = mPointerController->getDisplayId(); NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, flags, metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, x, y, mPointerGesture.downTime, /* videoFrames */ {}); Loading services/inputflinger/reader/mapper/TouchInputMapper.h +21 −0 Original line number Diff line number Diff line Loading @@ -590,6 +590,27 @@ private: QUIET, }; // When a gesture is sent to an unfocused window, return true if it can bring that window // into focus, false otherwise. static bool canGestureAffectWindowFocus(Mode mode) { switch (mode) { case Mode::TAP: case Mode::TAP_DRAG: case Mode::BUTTON_CLICK_OR_DRAG: // Taps can affect window focus. return true; case Mode::FREEFORM: case Mode::HOVER: case Mode::NEUTRAL: case Mode::PRESS: case Mode::QUIET: case Mode::SWIPE: // Most gestures can be performed on an unfocused window, so they should not // not affect window focus. return false; } } // Time the first finger went down. nsecs_t firstTouchTime; Loading services/inputflinger/tests/InputDispatcher_test.cpp +26 −1 Original line number Diff line number Diff line Loading @@ -1225,6 +1225,11 @@ public: return *this; } MotionEventBuilder& addFlag(uint32_t flags) { mFlags |= flags; return *this; } MotionEvent build() { std::vector<PointerProperties> pointerProperties; std::vector<PointerCoords> pointerCoords; Loading @@ -1244,7 +1249,7 @@ public: MotionEvent event; ui::Transform identityTransform; event.initialize(InputEvent::nextId(), DEVICE_ID, mSource, mDisplayId, INVALID_HMAC, mAction, mActionButton, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, mAction, mActionButton, mFlags, /* edgeFlags */ 0, AMETA_NONE, mButtonState, MotionClassification::NONE, identityTransform, /* xPrecision */ 0, /* yPrecision */ 0, mRawXCursorPosition, mRawYCursorPosition, mDisplayWidth, mDisplayHeight, mEventTime, mEventTime, Loading @@ -1260,6 +1265,7 @@ private: int32_t mDisplayId{ADISPLAY_ID_DEFAULT}; int32_t mActionButton{0}; int32_t mButtonState{0}; int32_t mFlags{0}; float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; int32_t mDisplayWidth{AMOTION_EVENT_INVALID_DISPLAY_SIZE}; Loading Loading @@ -3105,6 +3111,25 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlr mFakePolicy->assertOnPointerDownWasNotCalled(); } // Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag // NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) { const MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(20).y(20)) .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, event)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); ASSERT_TRUE(mDispatcher->waitForIdle()); mFakePolicy->assertOnPointerDownWasNotCalled(); // Ensure that the unfocused window did not receive any FOCUS events. mUnfocusedWindow->assertNoEvents(); } // These tests ensures we can send touch events to a single client when there are multiple input // windows that point to the same client token. class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { Loading Loading
include/input/Input.h +8 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,14 @@ enum { */ AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE = 0x8, /** * This flag indicates that the event will not cause a focus change if it is directed to an * unfocused window, even if it an ACTION_DOWN. This is typically used with pointer * gestures to allow the user to direct gestures to an unfocused window without bringing it * into focus. */ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40, /* Motion event is inconsistent with previously sent motion events. */ AMOTION_EVENT_FLAG_TAINTED = 0x80000000, }; Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -2886,6 +2886,12 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connectio ATRACE_NAME(message.c_str()); } if ((motionEntry.flags & AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) && (motionEntry.policyFlags & POLICY_FLAG_TRUSTED)) { // Skip reporting pointer down outside focus to the policy. break; } dispatchPointerDownOutsideFocus(motionEntry.source, dispatchEntry->resolvedAction, inputTarget.inputChannel->getConnectionToken()); Loading
services/inputflinger/reader/mapper/TouchInputMapper.cpp +14 −8 Original line number Diff line number Diff line Loading @@ -2456,6 +2456,12 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentCookedState.buttonState; uint32_t flags = 0; if (!PointerGesture::canGestureAffectWindowFocus(mPointerGesture.currentGestureMode)) { flags |= AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE; } // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. bool down = mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP || Loading Loading @@ -2485,8 +2491,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); if (!dispatchedGestureIdBits.isEmpty()) { if (cancelPreviousGesture) { dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, mPointerGesture.downTime); Loading @@ -2504,7 +2510,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u uint32_t id = upGestureIdBits.clearFirstMarkedBit(); dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, AMOTION_EVENT_ACTION_POINTER_UP, 0, flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, 0, Loading @@ -2517,7 +2523,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u // Send motion events for all pointers that moved. if (moveNeeded) { dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, Loading @@ -2538,7 +2544,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u } dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, 0, flags, metaState, buttonState, 0, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, 0, Loading @@ -2548,8 +2554,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u // Send motion events for hover. if (mPointerGesture.currentGestureMode == PointerGesture::Mode::HOVER) { dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, Loading @@ -2573,7 +2579,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime, u const int32_t displayId = mPointerController->getDisplayId(); NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, flags, metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, x, y, mPointerGesture.downTime, /* videoFrames */ {}); Loading
services/inputflinger/reader/mapper/TouchInputMapper.h +21 −0 Original line number Diff line number Diff line Loading @@ -590,6 +590,27 @@ private: QUIET, }; // When a gesture is sent to an unfocused window, return true if it can bring that window // into focus, false otherwise. static bool canGestureAffectWindowFocus(Mode mode) { switch (mode) { case Mode::TAP: case Mode::TAP_DRAG: case Mode::BUTTON_CLICK_OR_DRAG: // Taps can affect window focus. return true; case Mode::FREEFORM: case Mode::HOVER: case Mode::NEUTRAL: case Mode::PRESS: case Mode::QUIET: case Mode::SWIPE: // Most gestures can be performed on an unfocused window, so they should not // not affect window focus. return false; } } // Time the first finger went down. nsecs_t firstTouchTime; Loading
services/inputflinger/tests/InputDispatcher_test.cpp +26 −1 Original line number Diff line number Diff line Loading @@ -1225,6 +1225,11 @@ public: return *this; } MotionEventBuilder& addFlag(uint32_t flags) { mFlags |= flags; return *this; } MotionEvent build() { std::vector<PointerProperties> pointerProperties; std::vector<PointerCoords> pointerCoords; Loading @@ -1244,7 +1249,7 @@ public: MotionEvent event; ui::Transform identityTransform; event.initialize(InputEvent::nextId(), DEVICE_ID, mSource, mDisplayId, INVALID_HMAC, mAction, mActionButton, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, mAction, mActionButton, mFlags, /* edgeFlags */ 0, AMETA_NONE, mButtonState, MotionClassification::NONE, identityTransform, /* xPrecision */ 0, /* yPrecision */ 0, mRawXCursorPosition, mRawYCursorPosition, mDisplayWidth, mDisplayHeight, mEventTime, mEventTime, Loading @@ -1260,6 +1265,7 @@ private: int32_t mDisplayId{ADISPLAY_ID_DEFAULT}; int32_t mActionButton{0}; int32_t mButtonState{0}; int32_t mFlags{0}; float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; int32_t mDisplayWidth{AMOTION_EVENT_INVALID_DISPLAY_SIZE}; Loading Loading @@ -3105,6 +3111,25 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlr mFakePolicy->assertOnPointerDownWasNotCalled(); } // Have two windows, one with focus. Injecting a trusted DOWN MotionEvent with the flag // NO_FOCUS_CHANGE on the unfocused window should not call the onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) { const MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(20).y(20)) .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, event)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); ASSERT_TRUE(mDispatcher->waitForIdle()); mFakePolicy->assertOnPointerDownWasNotCalled(); // Ensure that the unfocused window did not receive any FOCUS events. mUnfocusedWindow->assertNoEvents(); } // These tests ensures we can send touch events to a single client when there are multiple input // windows that point to the same client token. class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { Loading