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 "input/InputDevice.h"
18 
19 #include "InputState.h"
20 
21 #include "InputDispatcher.h"
22 
23 namespace android::inputdispatcher {
24 
InputState(const IdGenerator & idGenerator)25 InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {}
26 
~InputState()27 InputState::~InputState() {}
28 
isNeutral() const29 bool InputState::isNeutral() const {
30     return mKeyMementos.empty() && mMotionMementos.empty();
31 }
32 
isHovering(int32_t deviceId,uint32_t source,int32_t displayId) const33 bool InputState::isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const {
34     for (const MotionMemento& memento : mMotionMementos) {
35         if (memento.deviceId == deviceId && memento.source == source &&
36             memento.displayId == displayId && memento.hovering) {
37             return true;
38         }
39     }
40     return false;
41 }
42 
trackKey(const KeyEntry & entry,int32_t action,int32_t flags)43 bool InputState::trackKey(const KeyEntry& entry, int32_t action, int32_t flags) {
44     switch (action) {
45         case AKEY_EVENT_ACTION_UP: {
46             if (entry.flags & AKEY_EVENT_FLAG_FALLBACK) {
47                 for (size_t i = 0; i < mFallbackKeys.size();) {
48                     if (mFallbackKeys.valueAt(i) == entry.keyCode) {
49                         mFallbackKeys.removeItemsAt(i);
50                     } else {
51                         i += 1;
52                     }
53                 }
54             }
55             ssize_t index = findKeyMemento(entry);
56             if (index >= 0) {
57                 mKeyMementos.erase(mKeyMementos.begin() + index);
58                 return true;
59             }
60             /* FIXME: We can't just drop the key up event because that prevents creating
61              * popup windows that are automatically shown when a key is held and then
62              * dismissed when the key is released.  The problem is that the popup will
63              * not have received the original key down, so the key up will be considered
64              * to be inconsistent with its observed state.  We could perhaps handle this
65              * by synthesizing a key down but that will cause other problems.
66              *
67              * So for now, allow inconsistent key up events to be dispatched.
68              *
69     #if DEBUG_OUTBOUND_EVENT_DETAILS
70             ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
71                     "keyCode=%d, scanCode=%d",
72                     entry.deviceId, entry.source, entry.keyCode, entry.scanCode);
73     #endif
74             return false;
75             */
76             return true;
77         }
78 
79         case AKEY_EVENT_ACTION_DOWN: {
80             ssize_t index = findKeyMemento(entry);
81             if (index >= 0) {
82                 mKeyMementos.erase(mKeyMementos.begin() + index);
83             }
84             addKeyMemento(entry, flags);
85             return true;
86         }
87 
88         default:
89             return true;
90     }
91 }
92 
trackMotion(const MotionEntry & entry,int32_t action,int32_t flags)93 bool InputState::trackMotion(const MotionEntry& entry, int32_t action, int32_t flags) {
94     int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
95     switch (actionMasked) {
96         case AMOTION_EVENT_ACTION_UP:
97         case AMOTION_EVENT_ACTION_CANCEL: {
98             ssize_t index = findMotionMemento(entry, false /*hovering*/);
99             if (index >= 0) {
100                 mMotionMementos.erase(mMotionMementos.begin() + index);
101                 return true;
102             }
103 #if DEBUG_OUTBOUND_EVENT_DETAILS
104             ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
105                   "displayId=%" PRId32 ", actionMasked=%d",
106                   entry.deviceId, entry.source, entry.displayId, actionMasked);
107 #endif
108             return false;
109         }
110 
111         case AMOTION_EVENT_ACTION_DOWN: {
112             ssize_t index = findMotionMemento(entry, false /*hovering*/);
113             if (index >= 0) {
114                 mMotionMementos.erase(mMotionMementos.begin() + index);
115             }
116             addMotionMemento(entry, flags, false /*hovering*/);
117             return true;
118         }
119 
120         case AMOTION_EVENT_ACTION_POINTER_UP:
121         case AMOTION_EVENT_ACTION_POINTER_DOWN:
122         case AMOTION_EVENT_ACTION_MOVE: {
123             if (entry.source & AINPUT_SOURCE_CLASS_NAVIGATION) {
124                 // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need
125                 // to generate cancellation events for these since they're based in relative rather
126                 // than absolute units.
127                 return true;
128             }
129 
130             ssize_t index = findMotionMemento(entry, false /*hovering*/);
131 
132             if (entry.source & AINPUT_SOURCE_CLASS_JOYSTICK) {
133                 // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all
134                 // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral.
135                 // Any other value and we need to track the motion so we can send cancellation
136                 // events for anything generating fallback events (e.g. DPad keys for joystick
137                 // movements).
138                 if (index >= 0) {
139                     if (entry.pointerCoords[0].isEmpty()) {
140                         mMotionMementos.erase(mMotionMementos.begin() + index);
141                     } else {
142                         MotionMemento& memento = mMotionMementos[index];
143                         memento.setPointers(entry);
144                     }
145                 } else if (!entry.pointerCoords[0].isEmpty()) {
146                     addMotionMemento(entry, flags, false /*hovering*/);
147                 }
148 
149                 // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
150                 return true;
151             }
152 
153             if (index >= 0) {
154                 MotionMemento& memento = mMotionMementos[index];
155                 if (memento.firstNewPointerIdx < 0) {
156                     memento.setPointers(entry);
157                     return true;
158                 }
159             }
160 #if DEBUG_OUTBOUND_EVENT_DETAILS
161             ALOGD("Dropping inconsistent motion pointer up/down or move event: "
162                   "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
163                   entry.deviceId, entry.source, entry.displayId, actionMasked);
164 #endif
165             return false;
166         }
167 
168         case AMOTION_EVENT_ACTION_HOVER_EXIT: {
169             ssize_t index = findMotionMemento(entry, true /*hovering*/);
170             if (index >= 0) {
171                 mMotionMementos.erase(mMotionMementos.begin() + index);
172                 return true;
173             }
174 #if DEBUG_OUTBOUND_EVENT_DETAILS
175             ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
176                   "displayId=%" PRId32,
177                   entry.deviceId, entry.source, entry.displayId);
178 #endif
179             return false;
180         }
181 
182         case AMOTION_EVENT_ACTION_HOVER_ENTER:
183         case AMOTION_EVENT_ACTION_HOVER_MOVE: {
184             ssize_t index = findMotionMemento(entry, true /*hovering*/);
185             if (index >= 0) {
186                 mMotionMementos.erase(mMotionMementos.begin() + index);
187             }
188             addMotionMemento(entry, flags, true /*hovering*/);
189             return true;
190         }
191 
192         default:
193             return true;
194     }
195 }
196 
findKeyMemento(const KeyEntry & entry) const197 ssize_t InputState::findKeyMemento(const KeyEntry& entry) const {
198     for (size_t i = 0; i < mKeyMementos.size(); i++) {
199         const KeyMemento& memento = mKeyMementos[i];
200         if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
201             memento.displayId == entry.displayId && memento.keyCode == entry.keyCode &&
202             memento.scanCode == entry.scanCode) {
203             return i;
204         }
205     }
206     return -1;
207 }
208 
findMotionMemento(const MotionEntry & entry,bool hovering) const209 ssize_t InputState::findMotionMemento(const MotionEntry& entry, bool hovering) const {
210     for (size_t i = 0; i < mMotionMementos.size(); i++) {
211         const MotionMemento& memento = mMotionMementos[i];
212         if (memento.deviceId == entry.deviceId && memento.source == entry.source &&
213             memento.displayId == entry.displayId && memento.hovering == hovering) {
214             return i;
215         }
216     }
217     return -1;
218 }
219 
addKeyMemento(const KeyEntry & entry,int32_t flags)220 void InputState::addKeyMemento(const KeyEntry& entry, int32_t flags) {
221     KeyMemento memento;
222     memento.deviceId = entry.deviceId;
223     memento.source = entry.source;
224     memento.displayId = entry.displayId;
225     memento.keyCode = entry.keyCode;
226     memento.scanCode = entry.scanCode;
227     memento.metaState = entry.metaState;
228     memento.flags = flags;
229     memento.downTime = entry.downTime;
230     memento.policyFlags = entry.policyFlags;
231     mKeyMementos.push_back(memento);
232 }
233 
addMotionMemento(const MotionEntry & entry,int32_t flags,bool hovering)234 void InputState::addMotionMemento(const MotionEntry& entry, int32_t flags, bool hovering) {
235     MotionMemento memento;
236     memento.deviceId = entry.deviceId;
237     memento.source = entry.source;
238     memento.displayId = entry.displayId;
239     memento.flags = flags;
240     memento.xPrecision = entry.xPrecision;
241     memento.yPrecision = entry.yPrecision;
242     memento.xCursorPosition = entry.xCursorPosition;
243     memento.yCursorPosition = entry.yCursorPosition;
244     memento.downTime = entry.downTime;
245     memento.setPointers(entry);
246     memento.hovering = hovering;
247     memento.policyFlags = entry.policyFlags;
248     mMotionMementos.push_back(memento);
249 }
250 
setPointers(const MotionEntry & entry)251 void InputState::MotionMemento::setPointers(const MotionEntry& entry) {
252     pointerCount = entry.pointerCount;
253     for (uint32_t i = 0; i < entry.pointerCount; i++) {
254         pointerProperties[i].copyFrom(entry.pointerProperties[i]);
255         pointerCoords[i].copyFrom(entry.pointerCoords[i]);
256     }
257 }
258 
mergePointerStateTo(MotionMemento & other) const259 void InputState::MotionMemento::mergePointerStateTo(MotionMemento& other) const {
260     for (uint32_t i = 0; i < pointerCount; i++) {
261         if (other.firstNewPointerIdx < 0) {
262             other.firstNewPointerIdx = other.pointerCount;
263         }
264         other.pointerProperties[other.pointerCount].copyFrom(pointerProperties[i]);
265         other.pointerCoords[other.pointerCount].copyFrom(pointerCoords[i]);
266         other.pointerCount++;
267     }
268 }
269 
synthesizeCancelationEvents(nsecs_t currentTime,const CancelationOptions & options)270 std::vector<std::unique_ptr<EventEntry>> InputState::synthesizeCancelationEvents(
271         nsecs_t currentTime, const CancelationOptions& options) {
272     std::vector<std::unique_ptr<EventEntry>> events;
273     for (KeyMemento& memento : mKeyMementos) {
274         if (shouldCancelKey(memento, options)) {
275             events.push_back(
276                     std::make_unique<KeyEntry>(mIdGenerator.nextId(), currentTime, memento.deviceId,
277                                                memento.source, memento.displayId,
278                                                memento.policyFlags, AKEY_EVENT_ACTION_UP,
279                                                memento.flags | AKEY_EVENT_FLAG_CANCELED,
280                                                memento.keyCode, memento.scanCode, memento.metaState,
281                                                0 /*repeatCount*/, memento.downTime));
282         }
283     }
284 
285     for (const MotionMemento& memento : mMotionMementos) {
286         if (shouldCancelMotion(memento, options)) {
287             const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
288                                                     : AMOTION_EVENT_ACTION_CANCEL;
289             events.push_back(
290                     std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
291                                                   memento.deviceId, memento.source,
292                                                   memento.displayId, memento.policyFlags, action,
293                                                   0 /*actionButton*/, memento.flags, AMETA_NONE,
294                                                   0 /*buttonState*/, MotionClassification::NONE,
295                                                   AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
296                                                   memento.yPrecision, memento.xCursorPosition,
297                                                   memento.yCursorPosition, memento.downTime,
298                                                   memento.pointerCount, memento.pointerProperties,
299                                                   memento.pointerCoords, 0 /*xOffset*/,
300                                                   0 /*yOffset*/));
301         }
302     }
303     return events;
304 }
305 
synthesizePointerDownEvents(nsecs_t currentTime)306 std::vector<std::unique_ptr<EventEntry>> InputState::synthesizePointerDownEvents(
307         nsecs_t currentTime) {
308     std::vector<std::unique_ptr<EventEntry>> events;
309     for (MotionMemento& memento : mMotionMementos) {
310         if (!(memento.source & AINPUT_SOURCE_CLASS_POINTER)) {
311             continue;
312         }
313 
314         if (memento.firstNewPointerIdx < 0) {
315             continue;
316         }
317 
318         uint32_t pointerCount = 0;
319         PointerProperties pointerProperties[MAX_POINTERS];
320         PointerCoords pointerCoords[MAX_POINTERS];
321 
322         // We will deliver all pointers the target already knows about
323         for (uint32_t i = 0; i < static_cast<uint32_t>(memento.firstNewPointerIdx); i++) {
324             pointerProperties[i].copyFrom(memento.pointerProperties[i]);
325             pointerCoords[i].copyFrom(memento.pointerCoords[i]);
326             pointerCount++;
327         }
328 
329         // We will send explicit events for all pointers the target doesn't know about
330         for (uint32_t i = static_cast<uint32_t>(memento.firstNewPointerIdx);
331                 i < memento.pointerCount; i++) {
332 
333             pointerProperties[i].copyFrom(memento.pointerProperties[i]);
334             pointerCoords[i].copyFrom(memento.pointerCoords[i]);
335             pointerCount++;
336 
337             // Down only if the first pointer, pointer down otherwise
338             const int32_t action = (pointerCount <= 1)
339                     ? AMOTION_EVENT_ACTION_DOWN
340                     : AMOTION_EVENT_ACTION_POINTER_DOWN
341                             | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
342 
343             events.push_back(
344                     std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
345                                                   memento.deviceId, memento.source,
346                                                   memento.displayId, memento.policyFlags, action,
347                                                   0 /*actionButton*/, memento.flags, AMETA_NONE,
348                                                   0 /*buttonState*/, MotionClassification::NONE,
349                                                   AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
350                                                   memento.yPrecision, memento.xCursorPosition,
351                                                   memento.yCursorPosition, memento.downTime,
352                                                   pointerCount, pointerProperties, pointerCoords,
353                                                   0 /*xOffset*/, 0 /*yOffset*/));
354         }
355 
356         memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
357     }
358 
359     return events;
360 }
361 
clear()362 void InputState::clear() {
363     mKeyMementos.clear();
364     mMotionMementos.clear();
365     mFallbackKeys.clear();
366 }
367 
mergePointerStateTo(InputState & other)368 void InputState::mergePointerStateTo(InputState& other) {
369     for (size_t i = 0; i < mMotionMementos.size(); i++) {
370         MotionMemento& memento = mMotionMementos[i];
371         // Since we support split pointers we need to merge touch events
372         // from the same source + device + screen.
373         if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
374             bool merged = false;
375             for (size_t j = 0; j < other.mMotionMementos.size(); j++) {
376                 MotionMemento& otherMemento = other.mMotionMementos[j];
377                 if (memento.deviceId == otherMemento.deviceId &&
378                     memento.source == otherMemento.source &&
379                     memento.displayId == otherMemento.displayId) {
380                     memento.mergePointerStateTo(otherMemento);
381                     merged = true;
382                     break;
383                 }
384             }
385             if (!merged) {
386                 memento.firstNewPointerIdx = 0;
387                 other.mMotionMementos.push_back(memento);
388             }
389         }
390     }
391 }
392 
getFallbackKey(int32_t originalKeyCode)393 int32_t InputState::getFallbackKey(int32_t originalKeyCode) {
394     ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
395     return index >= 0 ? mFallbackKeys.valueAt(index) : -1;
396 }
397 
setFallbackKey(int32_t originalKeyCode,int32_t fallbackKeyCode)398 void InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) {
399     ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
400     if (index >= 0) {
401         mFallbackKeys.replaceValueAt(index, fallbackKeyCode);
402     } else {
403         mFallbackKeys.add(originalKeyCode, fallbackKeyCode);
404     }
405 }
406 
removeFallbackKey(int32_t originalKeyCode)407 void InputState::removeFallbackKey(int32_t originalKeyCode) {
408     mFallbackKeys.removeItem(originalKeyCode);
409 }
410 
shouldCancelKey(const KeyMemento & memento,const CancelationOptions & options)411 bool InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) {
412     if (options.keyCode && memento.keyCode != options.keyCode.value()) {
413         return false;
414     }
415 
416     if (options.deviceId && memento.deviceId != options.deviceId.value()) {
417         return false;
418     }
419 
420     if (options.displayId && memento.displayId != options.displayId.value()) {
421         return false;
422     }
423 
424     switch (options.mode) {
425         case CancelationOptions::CANCEL_ALL_EVENTS:
426         case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
427             return true;
428         case CancelationOptions::CANCEL_FALLBACK_EVENTS:
429             return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
430         default:
431             return false;
432     }
433 }
434 
shouldCancelMotion(const MotionMemento & memento,const CancelationOptions & options)435 bool InputState::shouldCancelMotion(const MotionMemento& memento,
436                                     const CancelationOptions& options) {
437     if (options.deviceId && memento.deviceId != options.deviceId.value()) {
438         return false;
439     }
440 
441     if (options.displayId && memento.displayId != options.displayId.value()) {
442         return false;
443     }
444 
445     switch (options.mode) {
446         case CancelationOptions::CANCEL_ALL_EVENTS:
447             return true;
448         case CancelationOptions::CANCEL_POINTER_EVENTS:
449             return memento.source & AINPUT_SOURCE_CLASS_POINTER;
450         case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
451             return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
452         default:
453             return false;
454     }
455 }
456 
457 } // namespace android::inputdispatcher
458