Reland "Input injection: Assume transformed values are i..."
Revert submission 16306432-revert-16295572-ORWQJPYRMQ
Reason for revert: The broken test was fixed in ag/16365181, so
this should be safe to re-land now.
Reverted Changes:
Iab395d41d:Revert "Remove x/y offset from MotionEntry"
I7beca684d:Revert "Input injection: Assume transformed values...
Change-Id: I68b5619bf52d999a653bb246e1acb02f5d07991e
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 7f68d1b..3fd1c8a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -506,12 +506,6 @@
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 @@
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 @@
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::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);
+ // 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];
- // 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);
+ 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 8a551cf..6f05670 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -280,7 +280,9 @@
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 515a01e..eaea4e2 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2079,6 +2079,33 @@
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();