• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "DebugConfig.h"
18 #include "input/Input.h"
19 #include "input/InputDevice.h"
20 #include "input/InputFlags.h"
21 
22 #include "InputState.h"
23 
24 #include <cinttypes>
25 #include "InputDispatcher.h"
26 
27 namespace android::inputdispatcher {
28 
InputState(const IdGenerator & idGenerator)29 InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {}
30 
~InputState()31 InputState::~InputState() {}
32 
isHovering(DeviceId deviceId,uint32_t source,ui::LogicalDisplayId displayId) const33 bool InputState::isHovering(DeviceId deviceId, uint32_t source,
34                             ui::LogicalDisplayId displayId) const {
35     for (const MotionMemento& memento : mMotionMementos) {
36         if (memento.deviceId == deviceId && memento.source == source &&
37             memento.displayId == displayId && memento.hovering) {
38             return true;
39         }
40     }
41     return false;
42 }
43 
trackKey(const KeyEntry & entry,int32_t flags)44 bool InputState::trackKey(const KeyEntry& entry, int32_t flags) {
45     switch (entry.action) {
46         case AKEY_EVENT_ACTION_UP: {
47             if (entry.flags & AKEY_EVENT_FLAG_FALLBACK) {
48                 std::erase_if(mFallbackKeys,
49                               [&entry](const auto& item) { return item.second == entry.keyCode; });
50             }
51             ssize_t index = findKeyMemento(entry);
52             if (index >= 0) {
53                 mKeyMementos.erase(mKeyMementos.begin() + index);
54                 return true;
55             }
56             /* FIXME: We can't just drop the key up event because that prevents creating
57              * popup windows that are automatically shown when a key is held and then
58              * dismissed when the key is released.  The problem is that the popup will
59              * not have received the original key down, so the key up will be considered
60              * to be inconsistent with its observed state.  We could perhaps handle this
61              * by synthesizing a key down but that will cause other problems.
62              *
63              * So for now, allow inconsistent key up events to be dispatched.
64              *
65     #if DEBUG_OUTBOUND_EVENT_DETAILS
66             ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
67                     "keyCode=%d, scanCode=%d",
68                     entry.deviceId, entry.source, entry.keyCode, entry.scanCode);
69     #endif
70             return false;
71             */
72             return true;
73         }
74 
75         case AKEY_EVENT_ACTION_DOWN: {
76             ssize_t index = findKeyMemento(entry);
77             if (index >= 0) {
78                 mKeyMementos.erase(mKeyMementos.begin() + index);
79             }
80             addKeyMemento(entry, flags);
81             return true;
82         }
83 
84         default:
85             return true;
86     }
87 }
88 
89 /**
90  * Return:
91  *  true if the incoming event was correctly tracked,
92  *  false if the incoming event should be dropped.
93  */
trackMotion(const MotionEntry & entry,int32_t flags)94 bool InputState::trackMotion(const MotionEntry& entry, int32_t flags) {
95     // Don't track non-pointer events
96     if (!isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) {
97         // This is a focus-dispatched event; we don't track its state.
98         return true;
99     }
100 
101     if (!input_flags::enable_multi_device_same_window_stream()) {
102         if (!mMotionMementos.empty()) {
103             const MotionMemento& lastMemento = mMotionMementos.back();
104             if (isStylusEvent(lastMemento.source, lastMemento.pointerProperties) &&
105                 !isStylusEvent(entry.source, entry.pointerProperties)) {
106                 // We already have a stylus stream, and the new event is not from stylus.
107                 return false;
108             }
109         }
110     }
111 
112     int32_t actionMasked = entry.action & AMOTION_EVENT_ACTION_MASK;
113     switch (actionMasked) {
114         case AMOTION_EVENT_ACTION_UP:
115         case AMOTION_EVENT_ACTION_CANCEL: {
116             ssize_t index = findMotionMemento(entry, /*hovering=*/false);
117             if (index >= 0) {
118                 mMotionMementos.erase(mMotionMementos.begin() + index);
119                 return true;
120             }
121 
122             return false;
123         }
124 
125         case AMOTION_EVENT_ACTION_DOWN: {
126             ssize_t index = findMotionMemento(entry, /*hovering=*/false);
127             if (index >= 0) {
128                 mMotionMementos.erase(mMotionMementos.begin() + index);
129             }
130             addMotionMemento(entry, flags, /*hovering=*/false);
131             return true;
132         }
133 
134         case AMOTION_EVENT_ACTION_POINTER_UP:
135         case AMOTION_EVENT_ACTION_POINTER_DOWN:
136         case AMOTION_EVENT_ACTION_MOVE: {
137             if (entry.source & AINPUT_SOURCE_CLASS_NAVIGATION) {
138                 // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need
139                 // to generate cancellation events for these since they're based in relative rather
140                 // than absolute units.
141                 return true;
142             }
143 
144             ssize_t index = findMotionMemento(entry, /*hovering=*/false);
145 
146             if (entry.source & AINPUT_SOURCE_CLASS_JOYSTICK) {
147                 // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all
148                 // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral.
149                 // Any other value and we need to track the motion so we can send cancellation
150                 // events for anything generating fallback events (e.g. DPad keys for joystick
151                 // movements).
152                 if (index >= 0) {
153                     if (entry.pointerCoords[0].isEmpty()) {
154                         mMotionMementos.erase(mMotionMementos.begin() + index);
155                     } else {
156                         MotionMemento& memento = mMotionMementos[index];
157                         memento.setPointers(entry);
158                     }
159                 } else if (!entry.pointerCoords[0].isEmpty()) {
160                     addMotionMemento(entry, flags, /*hovering=*/false);
161                 }
162 
163                 // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
164                 return true;
165             }
166 
167             if (index >= 0) {
168                 MotionMemento& memento = mMotionMementos[index];
169                 if (memento.firstNewPointerIdx < 0) {
170                     memento.setPointers(entry);
171                     return true;
172                 }
173             }
174 
175             return false;
176         }
177 
178         case AMOTION_EVENT_ACTION_HOVER_EXIT: {
179             ssize_t index = findMotionMemento(entry, /*hovering=*/true);
180             if (index >= 0) {
181                 mMotionMementos.erase(mMotionMementos.begin() + index);
182                 return true;
183             }
184 
185             return false;
186         }
187 
188         case AMOTION_EVENT_ACTION_HOVER_ENTER:
189         case AMOTION_EVENT_ACTION_HOVER_MOVE: {
190             ssize_t index = findMotionMemento(entry, /*hovering=*/true);
191             if (index >= 0) {
192                 mMotionMementos.erase(mMotionMementos.begin() + index);
193             }
194             addMotionMemento(entry, flags, /*hovering=*/true);
195             return true;
196         }
197 
198         default:
199             return true;
200     }
201 }
202 
203 std::optional<std::pair<std::vector<PointerProperties>, std::vector<PointerCoords>>>
getPointersOfLastEvent(const MotionEntry & entry,bool hovering) const204 InputState::getPointersOfLastEvent(const MotionEntry& entry, bool hovering) const {
205     ssize_t index = findMotionMemento(entry, hovering);
206     if (index == -1) {
207         return std::nullopt;
208     }
209     return std::make_pair(mMotionMementos[index].pointerProperties,
210                           mMotionMementos[index].pointerCoords);
211 }
212 
findKeyMemento(const KeyEntry & entry) const213 ssize_t InputState::findKeyMemento(const KeyEntry& entry) const {
214     for (size_t i = 0; i < mKeyMementos.size(); i++) {
215         const KeyMemento& memento = mKeyMementos[i];
216         if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
217             memento.displayId == entry.displayId && memento.keyCode == entry.keyCode &&
218             memento.scanCode == entry.scanCode) {
219             return i;
220         }
221     }
222     return -1;
223 }
224 
findMotionMemento(const MotionEntry & entry,bool hovering) const225 ssize_t InputState::findMotionMemento(const MotionEntry& entry, bool hovering) const {
226     // If we have connected displays a mouse can move between displays and displayId may change
227     // while a gesture is in-progress.
228     const bool skipDisplayCheck =
229             InputFlags::connectedDisplaysCursorEnabled() && isMouseOrTouchpad(entry.source);
230     for (size_t i = 0; i < mMotionMementos.size(); i++) {
231         const MotionMemento& memento = mMotionMementos[i];
232         if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
233             memento.hovering == hovering &&
234             (skipDisplayCheck || memento.displayId == entry.displayId)) {
235             return i;
236         }
237     }
238     return -1;
239 }
240 
addKeyMemento(const KeyEntry & entry,int32_t flags)241 void InputState::addKeyMemento(const KeyEntry& entry, int32_t flags) {
242     KeyMemento memento;
243     memento.deviceId = entry.deviceId;
244     memento.source = entry.source;
245     memento.displayId = entry.displayId;
246     memento.keyCode = entry.keyCode;
247     memento.scanCode = entry.scanCode;
248     memento.metaState = entry.metaState;
249     memento.flags = flags;
250     memento.downTime = entry.downTime;
251     memento.policyFlags = entry.policyFlags;
252     mKeyMementos.push_back(memento);
253 }
254 
addMotionMemento(const MotionEntry & entry,int32_t flags,bool hovering)255 void InputState::addMotionMemento(const MotionEntry& entry, int32_t flags, bool hovering) {
256     MotionMemento memento;
257     memento.deviceId = entry.deviceId;
258     memento.source = entry.source;
259     memento.displayId = entry.displayId;
260     memento.flags = flags;
261     memento.xPrecision = entry.xPrecision;
262     memento.yPrecision = entry.yPrecision;
263     memento.xCursorPosition = entry.xCursorPosition;
264     memento.yCursorPosition = entry.yCursorPosition;
265     memento.downTime = entry.downTime;
266     memento.setPointers(entry);
267     memento.hovering = hovering;
268     memento.policyFlags = entry.policyFlags;
269     mMotionMementos.push_back(memento);
270 }
271 
setPointers(const MotionEntry & entry)272 void InputState::MotionMemento::setPointers(const MotionEntry& entry) {
273     pointerProperties.clear();
274     pointerCoords.clear();
275 
276     for (uint32_t i = 0; i < entry.getPointerCount(); i++) {
277         if (MotionEvent::getActionMasked(entry.action) == AMOTION_EVENT_ACTION_POINTER_UP) {
278             // In POINTER_UP events, the pointer is leaving. Since the action is not stored,
279             // this departing pointer should not be recorded.
280             const uint8_t actionIndex = MotionEvent::getActionIndex(entry.action);
281             if (i == actionIndex) {
282                 continue;
283             }
284         }
285         pointerProperties.push_back(entry.pointerProperties[i]);
286         pointerCoords.push_back(entry.pointerCoords[i]);
287     }
288 }
289 
mergePointerStateTo(MotionMemento & other) const290 void InputState::MotionMemento::mergePointerStateTo(MotionMemento& other) const {
291     for (uint32_t i = 0; i < getPointerCount(); i++) {
292         if (other.firstNewPointerIdx < 0) {
293             other.firstNewPointerIdx = other.getPointerCount();
294         }
295         other.pointerProperties.push_back(pointerProperties[i]);
296         other.pointerCoords.push_back(pointerCoords[i]);
297     }
298 }
299 
getPointerCount() const300 size_t InputState::MotionMemento::getPointerCount() const {
301     return pointerProperties.size();
302 }
303 
shouldCancelPreviousStream(const MotionEntry & motionEntry) const304 bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry) const {
305     if (!isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER)) {
306         // This is a focus-dispatched event that should not affect the previous stream.
307         return false;
308     }
309 
310     // New MotionEntry pointer event is coming in.
311 
312     // If this is a new gesture, and it's from a different device, then, in general, we will cancel
313     // the current gesture.
314     // However, because stylus should be preferred over touch, we need to treat some cases in a
315     // special way.
316     if (mMotionMementos.empty()) {
317         // There is no ongoing pointer gesture, so there is nothing to cancel
318         return false;
319     }
320 
321     const MotionMemento& lastMemento = mMotionMementos.back();
322     const int32_t actionMasked = MotionEvent::getActionMasked(motionEntry.action);
323 
324     // For compatibility, only one input device can be active at a time in the same window.
325     if (lastMemento.deviceId == motionEntry.deviceId) {
326         // In general, the same device should produce self-consistent streams so nothing needs to
327         // be canceled. But there is one exception:
328         // Sometimes ACTION_DOWN is received without a corresponding HOVER_EXIT. To account for
329         // that, cancel the previous hovering stream
330         if (actionMasked == AMOTION_EVENT_ACTION_DOWN && lastMemento.hovering) {
331             return true;
332         }
333 
334         // If the stream changes its source, just cancel the current gesture to be safe. It's
335         // possible that the app isn't handling source changes properly
336         if (motionEntry.source != lastMemento.source) {
337             LOG(INFO) << "Canceling stream: last source was "
338                       << inputEventSourceToString(lastMemento.source) << " and new event is "
339                       << motionEntry;
340             return true;
341         }
342 
343         // If the injection is happening into two different displays, the same injected device id
344         // could be going into both. And at this time, if mirroring is active, the same connection
345         // would receive different events from each display. Since the TouchStates are per-display,
346         // it's unlikely that those two streams would be consistent with each other. Therefore,
347         // cancel the previous gesture if the display id changes.
348         // Except when we have connected-displays where a mouse may move across display boundaries.
349         const bool skipDisplayCheck = (InputFlags::connectedDisplaysCursorEnabled() &&
350                                        isMouseOrTouchpad(motionEntry.source));
351         if (!skipDisplayCheck && motionEntry.displayId != lastMemento.displayId) {
352             LOG(INFO) << "Canceling stream: last displayId was " << lastMemento.displayId
353                       << " and new event is " << motionEntry;
354             return true;
355         }
356 
357         return false;
358     }
359 
360     if (!input_flags::enable_multi_device_same_window_stream()) {
361         if (isStylusEvent(lastMemento.source, lastMemento.pointerProperties)) {
362             // A stylus is already active.
363             if (isStylusEvent(motionEntry.source, motionEntry.pointerProperties) &&
364                 actionMasked == AMOTION_EVENT_ACTION_DOWN) {
365                 // If this new event is from a different device, then cancel the old
366                 // stylus and allow the new stylus to take over, but only if it's going down.
367                 // Otherwise, they will start to race each other.
368                 return true;
369             }
370 
371             // Keep the current stylus gesture.
372             return false;
373         }
374 
375         // Cancel the current gesture if this is a start of a new gesture from a new device.
376         if (actionMasked == AMOTION_EVENT_ACTION_DOWN ||
377             actionMasked == AMOTION_EVENT_ACTION_HOVER_ENTER) {
378             return true;
379         }
380     }
381     // By default, don't cancel any events.
382     return false;
383 }
384 
cancelConflictingInputStream(const MotionEntry & motionEntry)385 std::unique_ptr<EventEntry> InputState::cancelConflictingInputStream(
386         const MotionEntry& motionEntry) {
387     if (!shouldCancelPreviousStream(motionEntry)) {
388         return {};
389     }
390 
391     const MotionMemento& memento = mMotionMementos.back();
392 
393     // Cancel the last device stream
394     std::unique_ptr<MotionEntry> cancelEntry =
395             createCancelEntryForMemento(memento, motionEntry.eventTime);
396 
397     if (!trackMotion(*cancelEntry, cancelEntry->flags)) {
398         LOG(FATAL) << "Generated inconsistent cancel event!";
399     }
400     return cancelEntry;
401 }
402 
createCancelEntryForMemento(const MotionMemento & memento,nsecs_t eventTime) const403 std::unique_ptr<MotionEntry> InputState::createCancelEntryForMemento(const MotionMemento& memento,
404                                                                      nsecs_t eventTime) const {
405     const int32_t action =
406             memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
407     int32_t flags = memento.flags;
408     if (action == AMOTION_EVENT_ACTION_CANCEL) {
409         flags |= AMOTION_EVENT_FLAG_CANCELED;
410     }
411     return std::make_unique<MotionEntry>(mIdGenerator.nextId(), /*injectionState=*/nullptr,
412                                          eventTime, memento.deviceId, memento.source,
413                                          memento.displayId, memento.policyFlags, action,
414                                          /*actionButton=*/0, flags, AMETA_NONE,
415                                          /*buttonState=*/0, MotionClassification::NONE,
416                                          AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
417                                          memento.yPrecision, memento.xCursorPosition,
418                                          memento.yCursorPosition, memento.downTime,
419                                          memento.pointerProperties, memento.pointerCoords);
420 }
421 
synthesizeCancelationEvents(nsecs_t currentTime,const CancelationOptions & options)422 std::vector<std::unique_ptr<EventEntry>> InputState::synthesizeCancelationEvents(
423         nsecs_t currentTime, const CancelationOptions& options) {
424     std::vector<std::unique_ptr<EventEntry>> events;
425     for (KeyMemento& memento : mKeyMementos) {
426         if (shouldCancelKey(memento, options)) {
427             events.push_back(
428                     std::make_unique<KeyEntry>(mIdGenerator.nextId(), /*injectionState=*/nullptr,
429                                                currentTime, memento.deviceId, memento.source,
430                                                memento.displayId, memento.policyFlags,
431                                                AKEY_EVENT_ACTION_UP,
432                                                memento.flags | AKEY_EVENT_FLAG_CANCELED,
433                                                memento.keyCode, memento.scanCode, memento.metaState,
434                                                /*repeatCount=*/0, memento.downTime));
435         }
436     }
437 
438     for (const MotionMemento& memento : mMotionMementos) {
439         if (shouldCancelMotion(memento, options)) {
440             if (options.pointerIds == std::nullopt) {
441                 events.push_back(createCancelEntryForMemento(memento, currentTime));
442             } else {
443                 std::vector<std::unique_ptr<MotionEntry>> pointerCancelEvents =
444                         synthesizeCancelationEventsForPointers(memento, options.pointerIds.value(),
445                                                                currentTime);
446                 events.insert(events.end(), std::make_move_iterator(pointerCancelEvents.begin()),
447                               std::make_move_iterator(pointerCancelEvents.end()));
448             }
449         }
450     }
451     return events;
452 }
453 
synthesizePointerDownEvents(nsecs_t currentTime)454 std::vector<std::unique_ptr<EventEntry>> InputState::synthesizePointerDownEvents(
455         nsecs_t currentTime) {
456     std::vector<std::unique_ptr<EventEntry>> events;
457     for (MotionMemento& memento : mMotionMementos) {
458         if (!isFromSource(memento.source, AINPUT_SOURCE_CLASS_POINTER)) {
459             continue;
460         }
461 
462         if (memento.firstNewPointerIdx < 0) {
463             continue;
464         }
465 
466         std::vector<PointerProperties> pointerProperties;
467         std::vector<PointerCoords> pointerCoords;
468 
469         // We will deliver all pointers the target already knows about
470         for (uint32_t i = 0; i < static_cast<uint32_t>(memento.firstNewPointerIdx); i++) {
471             pointerProperties.push_back(memento.pointerProperties[i]);
472             pointerCoords.push_back(memento.pointerCoords[i]);
473         }
474 
475         // We will send explicit events for all pointers the target doesn't know about
476         for (uint32_t i = static_cast<uint32_t>(memento.firstNewPointerIdx);
477              i < memento.getPointerCount(); i++) {
478             pointerProperties.push_back(memento.pointerProperties[i]);
479             pointerCoords.push_back(memento.pointerCoords[i]);
480 
481             const size_t pointerCount = pointerProperties.size();
482 
483             // Down only if the first pointer, pointer down otherwise
484             const int32_t action = (pointerCount <= 1)
485                     ? AMOTION_EVENT_ACTION_DOWN
486                     : AMOTION_EVENT_ACTION_POINTER_DOWN
487                             | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
488 
489             events.push_back(
490                     std::make_unique<MotionEntry>(mIdGenerator.nextId(), /*injectionState=*/nullptr,
491                                                   currentTime, memento.deviceId, memento.source,
492                                                   memento.displayId, memento.policyFlags, action,
493                                                   /*actionButton=*/0, memento.flags, AMETA_NONE,
494                                                   /*buttonState=*/0, MotionClassification::NONE,
495                                                   AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
496                                                   memento.yPrecision, memento.xCursorPosition,
497                                                   memento.yCursorPosition, memento.downTime,
498                                                   pointerProperties, pointerCoords));
499         }
500 
501         memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
502     }
503 
504     return events;
505 }
506 
synthesizeCancelationEventsForPointers(const MotionMemento & memento,std::bitset<MAX_POINTER_ID+1> pointerIds,nsecs_t currentTime)507 std::vector<std::unique_ptr<MotionEntry>> InputState::synthesizeCancelationEventsForPointers(
508         const MotionMemento& memento, std::bitset<MAX_POINTER_ID + 1> pointerIds,
509         nsecs_t currentTime) {
510     std::vector<std::unique_ptr<MotionEntry>> events;
511     std::vector<uint32_t> canceledPointerIndices;
512 
513     for (uint32_t pointerIdx = 0; pointerIdx < memento.getPointerCount(); pointerIdx++) {
514         uint32_t pointerId = uint32_t(memento.pointerProperties[pointerIdx].id);
515         if (pointerIds.test(pointerId)) {
516             canceledPointerIndices.push_back(pointerIdx);
517         }
518     }
519 
520     if (canceledPointerIndices.size() == memento.getPointerCount()) {
521         // We are cancelling all pointers.
522         events.emplace_back(createCancelEntryForMemento(memento, currentTime));
523         return events;
524     }
525 
526     // If we aren't canceling all pointers, we need to generate ACTION_POINTER_UP with
527     // FLAG_CANCELED for each of the canceled pointers. For each event, we must remove the
528     // previously canceled pointers from PointerProperties and PointerCoords, and update
529     // pointerCount appropriately. For convenience, sort the canceled pointer indices in
530     // descending order so that we can just slide the remaining pointers to the beginning of
531     // the array when a pointer is canceled.
532     std::sort(canceledPointerIndices.begin(), canceledPointerIndices.end(),
533               std::greater<uint32_t>());
534 
535     std::vector<PointerProperties> pointerProperties = memento.pointerProperties;
536     std::vector<PointerCoords> pointerCoords = memento.pointerCoords;
537     for (const uint32_t pointerIdx : canceledPointerIndices) {
538         if (pointerProperties.size() <= 1) {
539             LOG(FATAL) << "Unexpected code path for canceling all pointers!";
540         }
541         const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
542                 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
543         events.push_back(
544                 std::make_unique<MotionEntry>(mIdGenerator.nextId(), /*injectionState=*/nullptr,
545                                               currentTime, memento.deviceId, memento.source,
546                                               memento.displayId, memento.policyFlags, action,
547                                               /*actionButton=*/0,
548                                               memento.flags | AMOTION_EVENT_FLAG_CANCELED,
549                                               AMETA_NONE, /*buttonState=*/0,
550                                               MotionClassification::NONE,
551                                               AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
552                                               memento.yPrecision, memento.xCursorPosition,
553                                               memento.yCursorPosition, memento.downTime,
554                                               pointerProperties, pointerCoords));
555 
556         // Cleanup pointer information
557         pointerProperties.erase(pointerProperties.begin() + pointerIdx);
558         pointerCoords.erase(pointerCoords.begin() + pointerIdx);
559     }
560     return events;
561 }
562 
clear()563 void InputState::clear() {
564     mKeyMementos.clear();
565     mMotionMementos.clear();
566     mFallbackKeys.clear();
567 }
568 
mergePointerStateTo(InputState & other)569 void InputState::mergePointerStateTo(InputState& other) {
570     for (size_t i = 0; i < mMotionMementos.size(); i++) {
571         MotionMemento& memento = mMotionMementos[i];
572         // Since we support split pointers we need to merge touch events
573         // from the same source + device + screen.
574         if (isFromSource(memento.source, AINPUT_SOURCE_CLASS_POINTER)) {
575             bool merged = false;
576             for (size_t j = 0; j < other.mMotionMementos.size(); j++) {
577                 MotionMemento& otherMemento = other.mMotionMementos[j];
578                 if (memento.deviceId == otherMemento.deviceId &&
579                     memento.source == otherMemento.source &&
580                     memento.displayId == otherMemento.displayId) {
581                     memento.mergePointerStateTo(otherMemento);
582                     merged = true;
583                     break;
584                 }
585             }
586             if (!merged) {
587                 memento.firstNewPointerIdx = 0;
588                 other.mMotionMementos.push_back(memento);
589             }
590         }
591     }
592 }
593 
getFallbackKey(int32_t originalKeyCode)594 std::optional<int32_t> InputState::getFallbackKey(int32_t originalKeyCode) {
595     auto it = mFallbackKeys.find(originalKeyCode);
596     if (it == mFallbackKeys.end()) {
597         return {};
598     }
599     return it->second;
600 }
601 
setFallbackKey(int32_t originalKeyCode,int32_t fallbackKeyCode)602 void InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) {
603     mFallbackKeys.insert_or_assign(originalKeyCode, fallbackKeyCode);
604 }
605 
removeFallbackKey(int32_t originalKeyCode)606 void InputState::removeFallbackKey(int32_t originalKeyCode) {
607     mFallbackKeys.erase(originalKeyCode);
608 }
609 
shouldCancelKey(const KeyMemento & memento,const CancelationOptions & options)610 bool InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) {
611     if (options.keyCode && memento.keyCode != options.keyCode.value()) {
612         return false;
613     }
614 
615     if (options.deviceId && memento.deviceId != options.deviceId.value()) {
616         return false;
617     }
618 
619     if (options.displayId && memento.displayId != options.displayId.value()) {
620         return false;
621     }
622 
623     switch (options.mode) {
624         case CancelationOptions::Mode::CANCEL_ALL_EVENTS:
625         case CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS:
626             return true;
627         case CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS:
628             return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
629         default:
630             return false;
631     }
632 }
633 
shouldCancelMotion(const MotionMemento & memento,const CancelationOptions & options)634 bool InputState::shouldCancelMotion(const MotionMemento& memento,
635                                     const CancelationOptions& options) {
636     if (options.deviceId && memento.deviceId != options.deviceId.value()) {
637         return false;
638     }
639 
640     if (options.displayId && memento.displayId != options.displayId.value()) {
641         return false;
642     }
643 
644     switch (options.mode) {
645         case CancelationOptions::Mode::CANCEL_ALL_EVENTS:
646             return true;
647         case CancelationOptions::Mode::CANCEL_POINTER_EVENTS:
648             return memento.source & AINPUT_SOURCE_CLASS_POINTER;
649         case CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS:
650             return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
651         case CancelationOptions::Mode::CANCEL_HOVER_EVENTS:
652             return memento.hovering;
653         default:
654             return false;
655     }
656 }
657 
operator <<(std::ostream & out,const InputState & state)658 std::ostream& operator<<(std::ostream& out, const InputState& state) {
659     if (!state.mMotionMementos.empty()) {
660         out << "mMotionMementos: ";
661         for (const InputState::MotionMemento& memento : state.mMotionMementos) {
662             out << "{deviceId=" << memento.deviceId
663                 << ", hovering=" << std::to_string(memento.hovering)
664                 << ", downTime=" << memento.downTime << "}, ";
665         }
666     }
667     return out;
668 }
669 
670 } // namespace android::inputdispatcher
671