blob: 09b5186a6929b736e3d9a37839426f556faafc31 [file] [log] [blame]
Garfield Tane84e6f92019-08-29 17:28:41 -07001/*
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
Arthur Hung1a1007b2022-05-11 07:15:01 +000017#include "DebugConfig.h"
Chris Yef59a2f42020-10-16 12:55:26 -070018#include "input/InputDevice.h"
19
Garfield Tane84e6f92019-08-29 17:28:41 -070020#include "InputState.h"
21
Arthur Hung1a1007b2022-05-11 07:15:01 +000022#include <cinttypes>
Garfield Tanff1f1bb2020-01-28 13:24:04 -080023#include "InputDispatcher.h"
24
Garfield Tane84e6f92019-08-29 17:28:41 -070025namespace android::inputdispatcher {
26
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070027namespace {
28bool isHoverAction(int32_t action) {
29 switch (MotionEvent::getActionMasked(action)) {
30 case AMOTION_EVENT_ACTION_HOVER_ENTER:
31 case AMOTION_EVENT_ACTION_HOVER_MOVE:
32 case AMOTION_EVENT_ACTION_HOVER_EXIT: {
33 return true;
34 }
35 }
36 return false;
37}
38} // namespace
39
Garfield Tanff1f1bb2020-01-28 13:24:04 -080040InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {}
Garfield Tane84e6f92019-08-29 17:28:41 -070041
42InputState::~InputState() {}
43
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070044bool InputState::isHovering(DeviceId deviceId, uint32_t source, int32_t displayId) const {
Garfield Tane84e6f92019-08-29 17:28:41 -070045 for (const MotionMemento& memento : mMotionMementos) {
46 if (memento.deviceId == deviceId && memento.source == source &&
47 memento.displayId == displayId && memento.hovering) {
48 return true;
49 }
50 }
51 return false;
52}
53
Siarhei Vishniakoud2770042019-10-29 11:08:14 -070054bool InputState::trackKey(const KeyEntry& entry, int32_t action, int32_t flags) {
Garfield Tane84e6f92019-08-29 17:28:41 -070055 switch (action) {
56 case AKEY_EVENT_ACTION_UP: {
Siarhei Vishniakoud2770042019-10-29 11:08:14 -070057 if (entry.flags & AKEY_EVENT_FLAG_FALLBACK) {
Siarhei Vishniakou0fe01262023-04-17 08:11:37 -070058 std::erase_if(mFallbackKeys,
59 [&entry](const auto& item) { return item.second == entry.keyCode; });
Garfield Tane84e6f92019-08-29 17:28:41 -070060 }
61 ssize_t index = findKeyMemento(entry);
62 if (index >= 0) {
63 mKeyMementos.erase(mKeyMementos.begin() + index);
64 return true;
65 }
66 /* FIXME: We can't just drop the key up event because that prevents creating
67 * popup windows that are automatically shown when a key is held and then
68 * dismissed when the key is released. The problem is that the popup will
69 * not have received the original key down, so the key up will be considered
70 * to be inconsistent with its observed state. We could perhaps handle this
71 * by synthesizing a key down but that will cause other problems.
72 *
73 * So for now, allow inconsistent key up events to be dispatched.
74 *
75 #if DEBUG_OUTBOUND_EVENT_DETAILS
76 ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
77 "keyCode=%d, scanCode=%d",
Siarhei Vishniakoud2770042019-10-29 11:08:14 -070078 entry.deviceId, entry.source, entry.keyCode, entry.scanCode);
Garfield Tane84e6f92019-08-29 17:28:41 -070079 #endif
80 return false;
81 */
82 return true;
83 }
84
85 case AKEY_EVENT_ACTION_DOWN: {
86 ssize_t index = findKeyMemento(entry);
87 if (index >= 0) {
88 mKeyMementos.erase(mKeyMementos.begin() + index);
89 }
90 addKeyMemento(entry, flags);
91 return true;
92 }
93
94 default:
95 return true;
96 }
97}
98
Siarhei Vishniakouf4043212023-09-18 19:33:03 -070099/**
100 * Return:
101 * true if the incoming event was correctly tracked,
102 * false if the incoming event should be dropped.
103 */
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700104bool InputState::trackMotion(const MotionEntry& entry, int32_t action, int32_t flags) {
Siarhei Vishniakou2899c552023-07-10 18:20:46 -0700105 // Don't track non-pointer events
106 if (!isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) {
107 // This is a focus-dispatched event; we don't track its state.
108 return true;
109 }
110
111 if (!mMotionMementos.empty()) {
112 const MotionMemento& lastMemento = mMotionMementos.back();
113 if (isStylusEvent(lastMemento.source, lastMemento.pointerProperties) &&
114 !isStylusEvent(entry.source, entry.pointerProperties)) {
115 // We already have a stylus stream, and the new event is not from stylus.
116 if (!lastMemento.hovering) {
117 // If stylus is currently down, reject the new event unconditionally.
118 return false;
119 }
120 }
121 if (!lastMemento.hovering && isHoverAction(action)) {
122 // Reject hovers if already down
123 return false;
124 }
125 }
126
Garfield Tane84e6f92019-08-29 17:28:41 -0700127 int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
128 switch (actionMasked) {
129 case AMOTION_EVENT_ACTION_UP:
130 case AMOTION_EVENT_ACTION_CANCEL: {
Harry Cutts33476232023-01-30 19:57:29 +0000131 ssize_t index = findMotionMemento(entry, /*hovering=*/false);
Garfield Tane84e6f92019-08-29 17:28:41 -0700132 if (index >= 0) {
133 mMotionMementos.erase(mMotionMementos.begin() + index);
134 return true;
135 }
Siarhei Vishniakouc94dafe2023-05-26 10:24:19 -0700136
Garfield Tane84e6f92019-08-29 17:28:41 -0700137 return false;
138 }
139
140 case AMOTION_EVENT_ACTION_DOWN: {
Harry Cutts33476232023-01-30 19:57:29 +0000141 ssize_t index = findMotionMemento(entry, /*hovering=*/false);
Garfield Tane84e6f92019-08-29 17:28:41 -0700142 if (index >= 0) {
143 mMotionMementos.erase(mMotionMementos.begin() + index);
144 }
Harry Cutts33476232023-01-30 19:57:29 +0000145 addMotionMemento(entry, flags, /*hovering=*/false);
Garfield Tane84e6f92019-08-29 17:28:41 -0700146 return true;
147 }
148
149 case AMOTION_EVENT_ACTION_POINTER_UP:
150 case AMOTION_EVENT_ACTION_POINTER_DOWN:
151 case AMOTION_EVENT_ACTION_MOVE: {
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700152 if (entry.source & AINPUT_SOURCE_CLASS_NAVIGATION) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700153 // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need
154 // to generate cancellation events for these since they're based in relative rather
155 // than absolute units.
156 return true;
157 }
158
Harry Cutts33476232023-01-30 19:57:29 +0000159 ssize_t index = findMotionMemento(entry, /*hovering=*/false);
Garfield Tane84e6f92019-08-29 17:28:41 -0700160
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700161 if (entry.source & AINPUT_SOURCE_CLASS_JOYSTICK) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700162 // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all
163 // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral.
164 // Any other value and we need to track the motion so we can send cancellation
165 // events for anything generating fallback events (e.g. DPad keys for joystick
166 // movements).
167 if (index >= 0) {
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700168 if (entry.pointerCoords[0].isEmpty()) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700169 mMotionMementos.erase(mMotionMementos.begin() + index);
170 } else {
171 MotionMemento& memento = mMotionMementos[index];
172 memento.setPointers(entry);
173 }
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700174 } else if (!entry.pointerCoords[0].isEmpty()) {
Harry Cutts33476232023-01-30 19:57:29 +0000175 addMotionMemento(entry, flags, /*hovering=*/false);
Garfield Tane84e6f92019-08-29 17:28:41 -0700176 }
177
178 // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
179 return true;
180 }
Svet Ganov5d3bc372020-01-26 23:11:07 -0800181
Garfield Tane84e6f92019-08-29 17:28:41 -0700182 if (index >= 0) {
183 MotionMemento& memento = mMotionMementos[index];
Svet Ganov5d3bc372020-01-26 23:11:07 -0800184 if (memento.firstNewPointerIdx < 0) {
185 memento.setPointers(entry);
186 return true;
187 }
Garfield Tane84e6f92019-08-29 17:28:41 -0700188 }
Siarhei Vishniakouc94dafe2023-05-26 10:24:19 -0700189
Garfield Tane84e6f92019-08-29 17:28:41 -0700190 return false;
191 }
192
193 case AMOTION_EVENT_ACTION_HOVER_EXIT: {
Harry Cutts33476232023-01-30 19:57:29 +0000194 ssize_t index = findMotionMemento(entry, /*hovering=*/true);
Garfield Tane84e6f92019-08-29 17:28:41 -0700195 if (index >= 0) {
196 mMotionMementos.erase(mMotionMementos.begin() + index);
197 return true;
198 }
Siarhei Vishniakouc94dafe2023-05-26 10:24:19 -0700199
Garfield Tane84e6f92019-08-29 17:28:41 -0700200 return false;
201 }
202
203 case AMOTION_EVENT_ACTION_HOVER_ENTER:
204 case AMOTION_EVENT_ACTION_HOVER_MOVE: {
Harry Cutts33476232023-01-30 19:57:29 +0000205 ssize_t index = findMotionMemento(entry, /*hovering=*/true);
Garfield Tane84e6f92019-08-29 17:28:41 -0700206 if (index >= 0) {
207 mMotionMementos.erase(mMotionMementos.begin() + index);
208 }
Harry Cutts33476232023-01-30 19:57:29 +0000209 addMotionMemento(entry, flags, /*hovering=*/true);
Garfield Tane84e6f92019-08-29 17:28:41 -0700210 return true;
211 }
212
213 default:
214 return true;
215 }
216}
217
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700218ssize_t InputState::findKeyMemento(const KeyEntry& entry) const {
Garfield Tane84e6f92019-08-29 17:28:41 -0700219 for (size_t i = 0; i < mKeyMementos.size(); i++) {
220 const KeyMemento& memento = mKeyMementos[i];
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700221 if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
222 memento.displayId == entry.displayId && memento.keyCode == entry.keyCode &&
223 memento.scanCode == entry.scanCode) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700224 return i;
225 }
226 }
227 return -1;
228}
229
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700230ssize_t InputState::findMotionMemento(const MotionEntry& entry, bool hovering) const {
Garfield Tane84e6f92019-08-29 17:28:41 -0700231 for (size_t i = 0; i < mMotionMementos.size(); i++) {
232 const MotionMemento& memento = mMotionMementos[i];
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700233 if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
234 memento.displayId == entry.displayId && memento.hovering == hovering) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700235 return i;
236 }
237 }
238 return -1;
239}
240
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700241void InputState::addKeyMemento(const KeyEntry& entry, int32_t flags) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700242 KeyMemento memento;
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700243 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;
Garfield Tane84e6f92019-08-29 17:28:41 -0700249 memento.flags = flags;
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700250 memento.downTime = entry.downTime;
251 memento.policyFlags = entry.policyFlags;
Garfield Tane84e6f92019-08-29 17:28:41 -0700252 mKeyMementos.push_back(memento);
253}
254
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700255void InputState::addMotionMemento(const MotionEntry& entry, int32_t flags, bool hovering) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700256 MotionMemento memento;
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700257 memento.deviceId = entry.deviceId;
258 memento.source = entry.source;
259 memento.displayId = entry.displayId;
Garfield Tane84e6f92019-08-29 17:28:41 -0700260 memento.flags = flags;
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700261 memento.xPrecision = entry.xPrecision;
262 memento.yPrecision = entry.yPrecision;
263 memento.xCursorPosition = entry.xCursorPosition;
264 memento.yCursorPosition = entry.yCursorPosition;
265 memento.downTime = entry.downTime;
Garfield Tane84e6f92019-08-29 17:28:41 -0700266 memento.setPointers(entry);
267 memento.hovering = hovering;
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700268 memento.policyFlags = entry.policyFlags;
Garfield Tane84e6f92019-08-29 17:28:41 -0700269 mMotionMementos.push_back(memento);
270}
271
Siarhei Vishniakoud2770042019-10-29 11:08:14 -0700272void InputState::MotionMemento::setPointers(const MotionEntry& entry) {
Siarhei Vishniakou47a02a12023-10-18 09:56:00 -0700273 pointerProperties.clear();
274 pointerCoords.clear();
275
Siarhei Vishniakouedd61202023-10-18 11:22:40 -0700276 for (uint32_t i = 0; i < entry.getPointerCount(); i++) {
Siarhei Vishniakou82dc0422023-02-17 23:12:52 -0800277 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 }
Siarhei Vishniakou47a02a12023-10-18 09:56:00 -0700285 pointerProperties.push_back(entry.pointerProperties[i]);
286 pointerCoords.push_back(entry.pointerCoords[i]);
Garfield Tane84e6f92019-08-29 17:28:41 -0700287 }
288}
289
Svet Ganov5d3bc372020-01-26 23:11:07 -0800290void InputState::MotionMemento::mergePointerStateTo(MotionMemento& other) const {
Siarhei Vishniakou47a02a12023-10-18 09:56:00 -0700291 for (uint32_t i = 0; i < getPointerCount(); i++) {
Svet Ganov5d3bc372020-01-26 23:11:07 -0800292 if (other.firstNewPointerIdx < 0) {
Siarhei Vishniakou47a02a12023-10-18 09:56:00 -0700293 other.firstNewPointerIdx = other.getPointerCount();
Svet Ganov5d3bc372020-01-26 23:11:07 -0800294 }
Siarhei Vishniakou47a02a12023-10-18 09:56:00 -0700295 other.pointerProperties.push_back(pointerProperties[i]);
296 other.pointerCoords.push_back(pointerCoords[i]);
Svet Ganov5d3bc372020-01-26 23:11:07 -0800297 }
298}
299
Siarhei Vishniakou47a02a12023-10-18 09:56:00 -0700300size_t InputState::MotionMemento::getPointerCount() const {
301 return pointerProperties.size();
302}
303
Siarhei Vishniakou2899c552023-07-10 18:20:46 -0700304bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry,
305 int32_t resolvedAction) const {
306 if (!isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER)) {
307 // This is a focus-dispatched event that should not affect the previous stream.
308 return false;
309 }
310
311 // New MotionEntry pointer event is coming in.
312
313 // If this is a new gesture, and it's from a different device, then, in general, we will cancel
314 // the current gesture.
315 // However, because stylus should be preferred over touch, we need to treat some cases in a
316 // special way.
317 if (mMotionMementos.empty()) {
318 // There is no ongoing pointer gesture, so there is nothing to cancel
319 return false;
320 }
321
322 const MotionMemento& lastMemento = mMotionMementos.back();
323 const int32_t actionMasked = MotionEvent::getActionMasked(resolvedAction);
324
325 // For compatibility, only one input device can be active at a time in the same window.
326 if (lastMemento.deviceId == motionEntry.deviceId) {
327 // In general, the same device should produce self-consistent streams so nothing needs to
328 // be canceled. But there is one exception:
329 // Sometimes ACTION_DOWN is received without a corresponding HOVER_EXIT. To account for
330 // that, cancel the previous hovering stream
331 if (actionMasked == AMOTION_EVENT_ACTION_DOWN && lastMemento.hovering) {
332 return true;
333 }
334
335 // Use the previous stream cancellation logic to generate all HOVER_EXIT events.
336 // If this hover event was generated as a result of the pointer leaving the window,
337 // the HOVER_EXIT event should have the same coordinates as the previous
338 // HOVER_MOVE event in this stream. Ensure that all HOVER_EXITs have the same
339 // coordinates as the previous event by cancelling the stream here. With this approach, the
340 // HOVER_EXIT event is generated from the previous event.
341 if (actionMasked == AMOTION_EVENT_ACTION_HOVER_EXIT && lastMemento.hovering) {
342 return true;
343 }
344
345 // If the stream changes its source, just cancel the current gesture to be safe. It's
346 // possible that the app isn't handling source changes properly
347 if (motionEntry.source != lastMemento.source) {
348 LOG(INFO) << "Canceling stream: last source was "
349 << inputEventSourceToString(lastMemento.source) << " and new event is "
350 << motionEntry;
351 return true;
352 }
353
354 // If the injection is happening into two different displays, the same injected device id
355 // could be going into both. And at this time, if mirroring is active, the same connection
356 // would receive different events from each display. Since the TouchStates are per-display,
357 // it's unlikely that those two streams would be consistent with each other. Therefore,
358 // cancel the previous gesture if the display id changes.
359 if (motionEntry.displayId != lastMemento.displayId) {
360 LOG(INFO) << "Canceling stream: last displayId was "
361 << inputEventSourceToString(lastMemento.displayId) << " and new event is "
362 << motionEntry;
363 return true;
364 }
365
366 return false;
367 }
368
369 // We want stylus down to block touch and other source types, but stylus hover should not
370 // have such an effect.
371 if (isHoverAction(motionEntry.action) && !lastMemento.hovering) {
372 // New event is a hover. Keep the current non-hovering gesture instead
373 return false;
374 }
375
376 if (isStylusEvent(lastMemento.source, lastMemento.pointerProperties) && !lastMemento.hovering) {
377 // We have non-hovering stylus already active.
378 if (isStylusEvent(motionEntry.source, motionEntry.pointerProperties) &&
379 actionMasked == AMOTION_EVENT_ACTION_DOWN) {
380 // If this new event is a stylus from a different device going down, then cancel the old
381 // stylus and allow the new stylus to take over
382 return true;
383 }
384
385 // Keep the current stylus gesture.
386 return false;
387 }
388
389 // Cancel the current gesture if this is a start of a new gesture from a new device.
390 if (actionMasked == AMOTION_EVENT_ACTION_DOWN ||
391 actionMasked == AMOTION_EVENT_ACTION_HOVER_ENTER) {
392 return true;
393 }
394 // By default, don't cancel any events.
395 return false;
396}
397
398std::unique_ptr<EventEntry> InputState::cancelConflictingInputStream(const MotionEntry& motionEntry,
399 int32_t resolvedAction) {
400 if (!shouldCancelPreviousStream(motionEntry, resolvedAction)) {
401 return {};
402 }
403
404 const MotionMemento& memento = mMotionMementos.back();
405
406 // Cancel the last device stream
407 std::unique_ptr<MotionEntry> cancelEntry =
408 createCancelEntryForMemento(memento, motionEntry.eventTime);
409
410 if (!trackMotion(*cancelEntry, cancelEntry->action, cancelEntry->flags)) {
411 LOG(FATAL) << "Generated inconsistent cancel event!";
412 }
413 return cancelEntry;
414}
415
416std::unique_ptr<MotionEntry> InputState::createCancelEntryForMemento(const MotionMemento& memento,
417 nsecs_t eventTime) const {
418 const int32_t action =
419 memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
420 int32_t flags = memento.flags;
421 if (action == AMOTION_EVENT_ACTION_CANCEL) {
422 flags |= AMOTION_EVENT_FLAG_CANCELED;
423 }
424 return std::make_unique<MotionEntry>(mIdGenerator.nextId(), eventTime, memento.deviceId,
425 memento.source, memento.displayId, memento.policyFlags,
426 action, /*actionButton=*/0, flags, AMETA_NONE,
427 /*buttonState=*/0, MotionClassification::NONE,
428 AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
429 memento.yPrecision, memento.xCursorPosition,
430 memento.yCursorPosition, memento.downTime,
431 memento.pointerProperties, memento.pointerCoords);
432}
433
Siarhei Vishniakoua9a7ee82019-10-14 16:28:19 -0700434std::vector<std::unique_ptr<EventEntry>> InputState::synthesizeCancelationEvents(
Siarhei Vishniakou00fca7c2019-10-29 13:05:57 -0700435 nsecs_t currentTime, const CancelationOptions& options) {
Siarhei Vishniakoua9a7ee82019-10-14 16:28:19 -0700436 std::vector<std::unique_ptr<EventEntry>> events;
Garfield Tane84e6f92019-08-29 17:28:41 -0700437 for (KeyMemento& memento : mKeyMementos) {
438 if (shouldCancelKey(memento, options)) {
Siarhei Vishniakoua9a7ee82019-10-14 16:28:19 -0700439 events.push_back(
440 std::make_unique<KeyEntry>(mIdGenerator.nextId(), currentTime, memento.deviceId,
441 memento.source, memento.displayId,
442 memento.policyFlags, AKEY_EVENT_ACTION_UP,
443 memento.flags | AKEY_EVENT_FLAG_CANCELED,
444 memento.keyCode, memento.scanCode, memento.metaState,
Harry Cutts33476232023-01-30 19:57:29 +0000445 /*repeatCount=*/0, memento.downTime));
Garfield Tane84e6f92019-08-29 17:28:41 -0700446 }
447 }
448
449 for (const MotionMemento& memento : mMotionMementos) {
450 if (shouldCancelMotion(memento, options)) {
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000451 if (options.pointerIds == std::nullopt) {
Siarhei Vishniakou2899c552023-07-10 18:20:46 -0700452 events.push_back(createCancelEntryForMemento(memento, currentTime));
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000453 } else {
454 std::vector<std::unique_ptr<MotionEntry>> pointerCancelEvents =
455 synthesizeCancelationEventsForPointers(memento, options.pointerIds.value(),
456 currentTime);
457 events.insert(events.end(), std::make_move_iterator(pointerCancelEvents.begin()),
458 std::make_move_iterator(pointerCancelEvents.end()));
459 }
Garfield Tane84e6f92019-08-29 17:28:41 -0700460 }
461 }
Siarhei Vishniakou00fca7c2019-10-29 13:05:57 -0700462 return events;
Garfield Tane84e6f92019-08-29 17:28:41 -0700463}
464
Siarhei Vishniakoua9a7ee82019-10-14 16:28:19 -0700465std::vector<std::unique_ptr<EventEntry>> InputState::synthesizePointerDownEvents(
466 nsecs_t currentTime) {
467 std::vector<std::unique_ptr<EventEntry>> events;
Svet Ganov5d3bc372020-01-26 23:11:07 -0800468 for (MotionMemento& memento : mMotionMementos) {
Siarhei Vishniakouf4043212023-09-18 19:33:03 -0700469 if (!isFromSource(memento.source, AINPUT_SOURCE_CLASS_POINTER)) {
Svet Ganov5d3bc372020-01-26 23:11:07 -0800470 continue;
471 }
472
473 if (memento.firstNewPointerIdx < 0) {
474 continue;
475 }
476
Siarhei Vishniakouedd61202023-10-18 11:22:40 -0700477 std::vector<PointerProperties> pointerProperties;
478 std::vector<PointerCoords> pointerCoords;
Svet Ganov5d3bc372020-01-26 23:11:07 -0800479
480 // We will deliver all pointers the target already knows about
481 for (uint32_t i = 0; i < static_cast<uint32_t>(memento.firstNewPointerIdx); i++) {
Siarhei Vishniakouedd61202023-10-18 11:22:40 -0700482 pointerProperties.push_back(memento.pointerProperties[i]);
483 pointerCoords.push_back(memento.pointerCoords[i]);
Svet Ganov5d3bc372020-01-26 23:11:07 -0800484 }
485
486 // We will send explicit events for all pointers the target doesn't know about
487 for (uint32_t i = static_cast<uint32_t>(memento.firstNewPointerIdx);
Siarhei Vishniakou47a02a12023-10-18 09:56:00 -0700488 i < memento.getPointerCount(); i++) {
Siarhei Vishniakouedd61202023-10-18 11:22:40 -0700489 pointerProperties.push_back(memento.pointerProperties[i]);
490 pointerCoords.push_back(memento.pointerCoords[i]);
491
492 const size_t pointerCount = pointerProperties.size();
Svet Ganov5d3bc372020-01-26 23:11:07 -0800493
494 // Down only if the first pointer, pointer down otherwise
495 const int32_t action = (pointerCount <= 1)
496 ? AMOTION_EVENT_ACTION_DOWN
497 : AMOTION_EVENT_ACTION_POINTER_DOWN
498 | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
499
Siarhei Vishniakoua9a7ee82019-10-14 16:28:19 -0700500 events.push_back(
501 std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
502 memento.deviceId, memento.source,
503 memento.displayId, memento.policyFlags, action,
Harry Cutts33476232023-01-30 19:57:29 +0000504 /*actionButton=*/0, memento.flags, AMETA_NONE,
505 /*buttonState=*/0, MotionClassification::NONE,
Siarhei Vishniakoua9a7ee82019-10-14 16:28:19 -0700506 AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
507 memento.yPrecision, memento.xCursorPosition,
508 memento.yCursorPosition, memento.downTime,
Siarhei Vishniakouedd61202023-10-18 11:22:40 -0700509 pointerProperties, pointerCoords));
Svet Ganov5d3bc372020-01-26 23:11:07 -0800510 }
511
512 memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
513 }
514
515 return events;
516}
517
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000518std::vector<std::unique_ptr<MotionEntry>> InputState::synthesizeCancelationEventsForPointers(
Siarhei Vishniakou8a878352023-01-30 14:05:01 -0800519 const MotionMemento& memento, std::bitset<MAX_POINTER_ID + 1> pointerIds,
520 nsecs_t currentTime) {
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000521 std::vector<std::unique_ptr<MotionEntry>> events;
522 std::vector<uint32_t> canceledPointerIndices;
523 std::vector<PointerProperties> pointerProperties(MAX_POINTERS);
524 std::vector<PointerCoords> pointerCoords(MAX_POINTERS);
Siarhei Vishniakou47a02a12023-10-18 09:56:00 -0700525 for (uint32_t pointerIdx = 0; pointerIdx < memento.getPointerCount(); pointerIdx++) {
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000526 uint32_t pointerId = uint32_t(memento.pointerProperties[pointerIdx].id);
Siarhei Vishniakou73e6d372023-07-06 18:07:21 -0700527 pointerProperties[pointerIdx] = memento.pointerProperties[pointerIdx];
528 pointerCoords[pointerIdx] = memento.pointerCoords[pointerIdx];
Siarhei Vishniakou8a878352023-01-30 14:05:01 -0800529 if (pointerIds.test(pointerId)) {
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000530 canceledPointerIndices.push_back(pointerIdx);
531 }
532 }
533
Siarhei Vishniakou47a02a12023-10-18 09:56:00 -0700534 if (canceledPointerIndices.size() == memento.getPointerCount()) {
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000535 const int32_t action =
536 memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -0800537 int32_t flags = memento.flags;
538 if (action == AMOTION_EVENT_ACTION_CANCEL) {
539 flags |= AMOTION_EVENT_FLAG_CANCELED;
540 }
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000541 events.push_back(
542 std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime, memento.deviceId,
543 memento.source, memento.displayId,
Harry Cutts33476232023-01-30 19:57:29 +0000544 memento.policyFlags, action, /*actionButton=*/0,
545 flags, AMETA_NONE, /*buttonState=*/0,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000546 MotionClassification::NONE,
547 AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
548 memento.yPrecision, memento.xCursorPosition,
549 memento.yCursorPosition, memento.downTime,
Siarhei Vishniakouedd61202023-10-18 11:22:40 -0700550 memento.pointerProperties, memento.pointerCoords));
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000551 } else {
Siarhei Vishniakou1ae72f12023-01-29 12:55:30 -0800552 // If we aren't canceling all pointers, we need to generate ACTION_POINTER_UP with
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000553 // FLAG_CANCELED for each of the canceled pointers. For each event, we must remove the
554 // previously canceled pointers from PointerProperties and PointerCoords, and update
555 // pointerCount appropriately. For convenience, sort the canceled pointer indices so that we
556 // can just slide the remaining pointers to the beginning of the array when a pointer is
557 // canceled.
558 std::sort(canceledPointerIndices.begin(), canceledPointerIndices.end(),
559 std::greater<uint32_t>());
560
Siarhei Vishniakou47a02a12023-10-18 09:56:00 -0700561 uint32_t pointerCount = memento.getPointerCount();
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000562 for (const uint32_t pointerIdx : canceledPointerIndices) {
563 const int32_t action = pointerCount == 1 ? AMOTION_EVENT_ACTION_CANCEL
564 : AMOTION_EVENT_ACTION_POINTER_UP |
565 (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
566 events.push_back(
567 std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
568 memento.deviceId, memento.source,
569 memento.displayId, memento.policyFlags, action,
Harry Cutts33476232023-01-30 19:57:29 +0000570 /*actionButton=*/0,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000571 memento.flags | AMOTION_EVENT_FLAG_CANCELED,
Harry Cutts33476232023-01-30 19:57:29 +0000572 AMETA_NONE, /*buttonState=*/0,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000573 MotionClassification::NONE,
574 AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
575 memento.yPrecision, memento.xCursorPosition,
576 memento.yCursorPosition, memento.downTime,
Siarhei Vishniakouedd61202023-10-18 11:22:40 -0700577 pointerProperties, pointerCoords));
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000578
579 // Cleanup pointer information
580 pointerProperties.erase(pointerProperties.begin() + pointerIdx);
581 pointerCoords.erase(pointerCoords.begin() + pointerIdx);
582 pointerCount--;
583 }
584 }
585 return events;
586}
587
Garfield Tane84e6f92019-08-29 17:28:41 -0700588void InputState::clear() {
589 mKeyMementos.clear();
590 mMotionMementos.clear();
591 mFallbackKeys.clear();
592}
593
Svet Ganov5d3bc372020-01-26 23:11:07 -0800594void InputState::mergePointerStateTo(InputState& other) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700595 for (size_t i = 0; i < mMotionMementos.size(); i++) {
Svet Ganov5d3bc372020-01-26 23:11:07 -0800596 MotionMemento& memento = mMotionMementos[i];
597 // Since we support split pointers we need to merge touch events
598 // from the same source + device + screen.
Siarhei Vishniakouf4043212023-09-18 19:33:03 -0700599 if (isFromSource(memento.source, AINPUT_SOURCE_CLASS_POINTER)) {
Svet Ganov5d3bc372020-01-26 23:11:07 -0800600 bool merged = false;
601 for (size_t j = 0; j < other.mMotionMementos.size(); j++) {
602 MotionMemento& otherMemento = other.mMotionMementos[j];
Garfield Tane84e6f92019-08-29 17:28:41 -0700603 if (memento.deviceId == otherMemento.deviceId &&
604 memento.source == otherMemento.source &&
605 memento.displayId == otherMemento.displayId) {
Svet Ganov5d3bc372020-01-26 23:11:07 -0800606 memento.mergePointerStateTo(otherMemento);
607 merged = true;
608 break;
Garfield Tane84e6f92019-08-29 17:28:41 -0700609 }
610 }
Svet Ganov5d3bc372020-01-26 23:11:07 -0800611 if (!merged) {
612 memento.firstNewPointerIdx = 0;
613 other.mMotionMementos.push_back(memento);
614 }
Garfield Tane84e6f92019-08-29 17:28:41 -0700615 }
616 }
617}
618
Siarhei Vishniakou0fe01262023-04-17 08:11:37 -0700619std::optional<int32_t> InputState::getFallbackKey(int32_t originalKeyCode) {
620 auto it = mFallbackKeys.find(originalKeyCode);
621 if (it == mFallbackKeys.end()) {
622 return {};
623 }
624 return it->second;
Garfield Tane84e6f92019-08-29 17:28:41 -0700625}
626
627void InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) {
Siarhei Vishniakou0fe01262023-04-17 08:11:37 -0700628 mFallbackKeys.insert_or_assign(originalKeyCode, fallbackKeyCode);
Garfield Tane84e6f92019-08-29 17:28:41 -0700629}
630
631void InputState::removeFallbackKey(int32_t originalKeyCode) {
Siarhei Vishniakou0fe01262023-04-17 08:11:37 -0700632 mFallbackKeys.erase(originalKeyCode);
Garfield Tane84e6f92019-08-29 17:28:41 -0700633}
634
635bool InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) {
636 if (options.keyCode && memento.keyCode != options.keyCode.value()) {
637 return false;
638 }
639
640 if (options.deviceId && memento.deviceId != options.deviceId.value()) {
641 return false;
642 }
643
644 if (options.displayId && memento.displayId != options.displayId.value()) {
645 return false;
646 }
647
648 switch (options.mode) {
Michael Wrightfb04fd52022-11-24 22:31:11 +0000649 case CancelationOptions::Mode::CANCEL_ALL_EVENTS:
650 case CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS:
Garfield Tane84e6f92019-08-29 17:28:41 -0700651 return true;
Michael Wrightfb04fd52022-11-24 22:31:11 +0000652 case CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS:
Garfield Tane84e6f92019-08-29 17:28:41 -0700653 return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
654 default:
655 return false;
656 }
657}
658
659bool InputState::shouldCancelMotion(const MotionMemento& memento,
660 const CancelationOptions& options) {
661 if (options.deviceId && memento.deviceId != options.deviceId.value()) {
662 return false;
663 }
664
665 if (options.displayId && memento.displayId != options.displayId.value()) {
666 return false;
667 }
668
669 switch (options.mode) {
Michael Wrightfb04fd52022-11-24 22:31:11 +0000670 case CancelationOptions::Mode::CANCEL_ALL_EVENTS:
Garfield Tane84e6f92019-08-29 17:28:41 -0700671 return true;
Michael Wrightfb04fd52022-11-24 22:31:11 +0000672 case CancelationOptions::Mode::CANCEL_POINTER_EVENTS:
Garfield Tane84e6f92019-08-29 17:28:41 -0700673 return memento.source & AINPUT_SOURCE_CLASS_POINTER;
Michael Wrightfb04fd52022-11-24 22:31:11 +0000674 case CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS:
Garfield Tane84e6f92019-08-29 17:28:41 -0700675 return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
676 default:
677 return false;
678 }
679}
680
Siarhei Vishniakoud38a1e02023-07-18 11:55:17 -0700681std::ostream& operator<<(std::ostream& out, const InputState& state) {
682 if (!state.mMotionMementos.empty()) {
683 out << "mMotionMementos: ";
684 for (const InputState::MotionMemento& memento : state.mMotionMementos) {
685 out << "{deviceId= " << memento.deviceId << ", hovering=" << memento.hovering << "}, ";
686 }
687 }
688 return out;
689}
690
Garfield Tane84e6f92019-08-29 17:28:41 -0700691} // namespace android::inputdispatcher