summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Prabir Pradhan <prabirmsp@google.com> 2021-11-18 07:29:25 -0800
committer Prabir Pradhan <prabirmsp@google.com> 2021-11-19 04:10:38 -0800
commitf155b3ed59455b0fd301a4e8412164576e540995 (patch)
tree724c88da6281ceb4225f8105bc14e56b0d591464
parent20ca662583aec7a67562b5589e5114fdebf6ca95 (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.cpp55
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h4
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp27
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();