Generate down events when transferring touch focus
When we transfer touch focus to another window we are
now sending down events for all pointers that would
be delivered tot his window to ensure it sees a consistent
event stream.
Bug:146535667
Test: atest CtsAutofillTestCases
atest inputflinger_tests
atest com.android.server.wm.DragDropControllerTests
atest android.server.wm.DragDropTest
atest android.server.wm.CrossAppDragAndDropTests
added dedicated tests to inputflinger_tests
Change-Id: Ic745df966dbd873da94bb6d8061552ce1a5b27b0
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index c43e304..053598a 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -145,10 +145,13 @@
// Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
return true;
}
+
if (index >= 0) {
MotionMemento& memento = mMotionMementos[index];
- memento.setPointers(entry);
- return true;
+ if (memento.firstNewPointerIdx < 0) {
+ memento.setPointers(entry);
+ return true;
+ }
}
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("Dropping inconsistent motion pointer up/down or move event: "
@@ -249,6 +252,17 @@
}
}
+void InputState::MotionMemento::mergePointerStateTo(MotionMemento& other) const {
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ if (other.firstNewPointerIdx < 0) {
+ other.firstNewPointerIdx = other.pointerCount;
+ }
+ other.pointerProperties[other.pointerCount].copyFrom(pointerProperties[i]);
+ other.pointerCoords[other.pointerCount].copyFrom(pointerCoords[i]);
+ other.pointerCount++;
+ }
+}
+
std::vector<EventEntry*> InputState::synthesizeCancelationEvents(
nsecs_t currentTime, const CancelationOptions& options) {
std::vector<EventEntry*> events;
@@ -282,27 +296,87 @@
return events;
}
+std::vector<EventEntry*> InputState::synthesizePointerDownEvents(nsecs_t currentTime) {
+ std::vector<EventEntry*> events;
+ for (MotionMemento& memento : mMotionMementos) {
+ if (!(memento.source & AINPUT_SOURCE_CLASS_POINTER)) {
+ continue;
+ }
+
+ if (memento.firstNewPointerIdx < 0) {
+ continue;
+ }
+
+ uint32_t pointerCount = 0;
+ PointerProperties pointerProperties[MAX_POINTERS];
+ PointerCoords pointerCoords[MAX_POINTERS];
+
+ // We will deliver all pointers the target already knows about
+ for (uint32_t i = 0; i < static_cast<uint32_t>(memento.firstNewPointerIdx); i++) {
+ pointerProperties[i].copyFrom(memento.pointerProperties[i]);
+ pointerCoords[i].copyFrom(memento.pointerCoords[i]);
+ pointerCount++;
+ }
+
+ // We will send explicit events for all pointers the target doesn't know about
+ for (uint32_t i = static_cast<uint32_t>(memento.firstNewPointerIdx);
+ i < memento.pointerCount; i++) {
+
+ pointerProperties[i].copyFrom(memento.pointerProperties[i]);
+ pointerCoords[i].copyFrom(memento.pointerCoords[i]);
+ pointerCount++;
+
+ // Down only if the first pointer, pointer down otherwise
+ const int32_t action = (pointerCount <= 1)
+ ? AMOTION_EVENT_ACTION_DOWN
+ : AMOTION_EVENT_ACTION_POINTER_DOWN
+ | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
+ events.push_back(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
+ memento.deviceId, memento.source, memento.displayId,
+ memento.policyFlags, action, 0 /*actionButton*/,
+ memento.flags, AMETA_NONE, 0 /*buttonState*/,
+ MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+ memento.yPrecision, memento.xCursorPosition,
+ memento.yCursorPosition, memento.downTime,
+ pointerCount, pointerProperties,
+ pointerCoords, 0 /*xOffset*/, 0 /*yOffset*/));
+ }
+
+ memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
+ }
+
+ return events;
+}
+
void InputState::clear() {
mKeyMementos.clear();
mMotionMementos.clear();
mFallbackKeys.clear();
}
-void InputState::copyPointerStateTo(InputState& other) const {
+void InputState::mergePointerStateTo(InputState& other) {
for (size_t i = 0; i < mMotionMementos.size(); i++) {
- const MotionMemento& memento = mMotionMementos[i];
+ MotionMemento& memento = mMotionMementos[i];
+ // Since we support split pointers we need to merge touch events
+ // from the same source + device + screen.
if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
- for (size_t j = 0; j < other.mMotionMementos.size();) {
- const MotionMemento& otherMemento = other.mMotionMementos[j];
+ bool merged = false;
+ for (size_t j = 0; j < other.mMotionMementos.size(); j++) {
+ MotionMemento& otherMemento = other.mMotionMementos[j];
if (memento.deviceId == otherMemento.deviceId &&
memento.source == otherMemento.source &&
memento.displayId == otherMemento.displayId) {
- other.mMotionMementos.erase(other.mMotionMementos.begin() + j);
- } else {
- j += 1;
+ memento.mergePointerStateTo(otherMemento);
+ merged = true;
+ break;
}
}
- other.mMotionMementos.push_back(memento);
+ if (!merged) {
+ memento.firstNewPointerIdx = 0;
+ other.mMotionMementos.push_back(memento);
+ }
}
}
}