diff options
| author | 2021-11-18 07:29:25 -0800 | |
|---|---|---|
| committer | 2021-11-19 04:10:38 -0800 | |
| commit | f155b3ed59455b0fd301a4e8412164576e540995 (patch) | |
| tree | 724c88da6281ceb4225f8105bc14e56b0d591464 | |
| parent | 20ca662583aec7a67562b5589e5114fdebf6ca95 (diff) | |
Input injection: Assume transformed values are in logical display space
Previously, we assumed that, for injected MotionEvents, the values in
the PointerCoords were in logical display space. This is not always
true, as the PointerCoords for events generated by dispatcher are in the
display space, and are only in the logical display space once their
transform is applied.
In this CL we assume that the transformed PointerCoords values are in
the logical display space before converting it to the display space.
Additionally, we set the offset values to 0, because they are now
already included in the transform.
Bug: 206842332
Test: atest inputflinger_tests
Test: manual with accessibility over (e.g. Magnification) in different
orientations
Change-Id: I65c284e5e00ed7c1b60b31269e16ba6f045071c2
| -rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 55 | ||||
| -rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.h | 4 | ||||
| -rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 27 |
3 files changed, 50 insertions, 36 deletions
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7f68d1b8b1..3fd1c8aa27 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -506,12 +506,6 @@ bool isConnectionResponsive(const Connection& connection) { return true; } -vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { - const vec2 transformedXy = transform.transform(x, y); - const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; -} - // Returns true if the event type passed as argument represents a user activity. bool isUserActivityEvent(const EventEntry& eventEntry) { switch (eventEntry.type) { @@ -4214,10 +4208,8 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords, - motionEvent.getXOffset(), - motionEvent.getYOffset()); - transformMotionEntryForInjectionLocked(*injectedEntry); + pointerProperties, samplePointerCoords, 0, 0); + transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { sampleEventTimes += 1; @@ -4236,9 +4228,9 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), uint32_t(pointerCount), pointerProperties, - samplePointerCoords, motionEvent.getXOffset(), - motionEvent.getYOffset()); - transformMotionEntryForInjectionLocked(*nextInjectedEntry); + samplePointerCoords, 0, 0); + transformMotionEntryForInjectionLocked(*nextInjectedEntry, + motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); } break; @@ -4402,35 +4394,28 @@ void InputDispatcher::setInjectionResult(EventEntry& entry, } } -void InputDispatcher::transformMotionEntryForInjectionLocked(MotionEntry& entry) const { - const bool isRelativeMouseEvent = isFromSource(entry.source, AINPUT_SOURCE_MOUSE_RELATIVE); - if (!isRelativeMouseEvent && !isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) { - return; - } - +void InputDispatcher::transformMotionEntryForInjectionLocked( + MotionEntry& entry, const ui::Transform& injectedTransform) const { // Input injection works in the logical display coordinate space, but the input pipeline works // display space, so we need to transform the injected events accordingly. const auto it = mDisplayInfos.find(entry.displayId); if (it == mDisplayInfos.end()) return; - const auto& transformToDisplay = it->second.transform.inverse(); + const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform; for (uint32_t i = 0; i < entry.pointerCount; i++) { PointerCoords& pc = entry.pointerCoords[i]; - const auto xy = isRelativeMouseEvent - ? transformWithoutTranslation(transformToDisplay, pc.getX(), pc.getY()) - : transformToDisplay.transform(pc.getXYValue()); - pc.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); - pc.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); - - // Axes with relative values never represent points on a screen, so they should never have - // translation applied. If a device does not report relative values, these values are always - // 0, and will remain unaffected by the following operation. - const auto rel = - transformWithoutTranslation(transformToDisplay, - pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), - pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); - pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, rel.x); - pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, rel.y); + // Make a copy of the injected coords. We cannot change them in place because some of them + // are interdependent (for example, X coordinate might depend on the Y coordinate). + PointerCoords injectedCoords = entry.pointerCoords[i]; + + BitSet64 bits(injectedCoords.bits); + while (!bits.isEmpty()) { + const auto axis = static_cast<int32_t>(bits.clearFirstMarkedBit()); + const float value = + MotionEvent::calculateTransformedAxisValue(axis, entry.source, + transformToDisplay, injectedCoords); + pc.setAxisValue(axis, value); + } } } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 8a551cfca1..6f05670943 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -280,7 +280,9 @@ private: bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); void setInjectionResult(EventEntry& entry, android::os::InputEventInjectionResult injectionResult); - void transformMotionEntryForInjectionLocked(MotionEntry&) const REQUIRES(mLock); + void transformMotionEntryForInjectionLocked(MotionEntry&, + const ui::Transform& injectedTransform) const + REQUIRES(mLock); std::condition_variable mInjectionSyncFinished; void incrementPendingForegroundDispatches(EventEntry& entry); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 515a01e137..eaea4e26c4 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2079,6 +2079,33 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) { secondWindow->assertNoEvents(); } +// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed +// event should be treated as being in the logical display space. +TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) { + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + + const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; + ui::Transform injectedEventTransform; + injectedEventTransform.set(matrix); + const vec2 expectedPoint{75, 55}; // The injected point in the logical display space. + const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint); + + MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(untransformedPoint.x) + .y(untransformedPoint.y)) + .build(); + event.transform(matrix); + + injectMotionEvent(mDispatcher, event, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT); + + firstWindow->consumeMotionDown(); + secondWindow->assertNoEvents(); +} + TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) { auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); |