Handle different scale and offset for pointers in InputTarget.
This change allows an InputTarget to have multiple pointers in different
scale and offsets. This was done by using an array to store each
pointerId to PointerInfo. PointerInfo contains the information that's
unique to each pointer, scale and offset.
Once the dispatcher is ready to queue the event, the dispatcher will
request the InputTarget to gather all it's pointer information and
normalize them to a single offset and scale. It will generate a new
DispatcherEntry with a new MotionEvent that has all the coordinates in a
single offset and scale. It will also set that offset and scale in the
MotionEvent so it can be handled properly when sent to the client.
This is the 3rd attempt since it was breaking tests
Change-Id: Ic75c7df06cf4a881da6ac0c57013e29a84533d1e
Test: InputDispatcherMultiWindowSameTokenTests
Test: manually with magnification
Test: NexusLauncherOutOfProcTests:TaplTestsLauncher3
Test: NexusLauncherOutOfProcTests:TaplTestsQuickstep
Fixes: 140756730
Fixes: 147371357
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index 80fa2cb..0588374 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -42,4 +42,63 @@
return StringPrintf("%" PRId32, dispatchMode);
}
+void InputTarget::addPointers(BitSet32 newPointerIds, float xOffset, float yOffset,
+ float windowXScale, float windowYScale) {
+ // The pointerIds can be empty, but still a valid InputTarget. This can happen for Monitors
+ // and non splittable windows since we will just use all the pointers from the input event.
+ if (newPointerIds.isEmpty()) {
+ setDefaultPointerInfo(xOffset, yOffset, windowXScale, windowYScale);
+ return;
+ }
+
+ // Ensure that the new set of pointers doesn't overlap with the current set of pointers.
+ ALOG_ASSERT((pointerIds & newPointerIds) == 0);
+
+ pointerIds |= newPointerIds;
+ while (!newPointerIds.isEmpty()) {
+ int32_t pointerId = newPointerIds.clearFirstMarkedBit();
+ pointerInfos[pointerId].xOffset = xOffset;
+ pointerInfos[pointerId].yOffset = yOffset;
+ pointerInfos[pointerId].windowXScale = windowXScale;
+ pointerInfos[pointerId].windowYScale = windowYScale;
+ }
+}
+
+void InputTarget::setDefaultPointerInfo(float xOffset, float yOffset, float windowXScale,
+ float windowYScale) {
+ pointerIds.clear();
+ pointerInfos[0].xOffset = xOffset;
+ pointerInfos[0].yOffset = yOffset;
+ pointerInfos[0].windowXScale = windowXScale;
+ pointerInfos[0].windowYScale = windowYScale;
+}
+
+bool InputTarget::useDefaultPointerInfo() const {
+ return pointerIds.isEmpty();
+}
+
+const PointerInfo& InputTarget::getDefaultPointerInfo() const {
+ return pointerInfos[0];
+}
+
+std::string InputTarget::getPointerInfoString() const {
+ if (useDefaultPointerInfo()) {
+ const PointerInfo& pointerInfo = getDefaultPointerInfo();
+ return StringPrintf("xOffset=%.1f, yOffset=%.1f windowScaleFactor=(%.1f, %.1f)",
+ pointerInfo.xOffset, pointerInfo.yOffset, pointerInfo.windowXScale,
+ pointerInfo.windowYScale);
+ }
+
+ std::string out;
+ for (uint32_t i = pointerIds.firstMarkedBit(); i <= pointerIds.lastMarkedBit(); i++) {
+ if (!pointerIds.hasBit(i)) {
+ continue;
+ }
+ out += StringPrintf("\n pointerId %d: xOffset=%.1f, yOffset=%.1f "
+ "windowScaleFactor=(%.1f, %.1f)",
+ i, pointerInfos[i].xOffset, pointerInfos[i].yOffset,
+ pointerInfos[i].windowXScale, pointerInfos[i].windowYScale);
+ }
+ return out;
+}
} // namespace android::inputdispatcher