blob: 7fed61f09d5c406e2347e5dea73a40d9c2102056 [file] [log] [blame]
Prabir Pradhanbaa5c822019-08-30 15:27:05 -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
17#include "Macros.h"
18
19#include "InputDevice.h"
20
21#include "InputMapper.h"
22
23namespace android {
24
25InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
26 int32_t controllerNumber, const InputDeviceIdentifier& identifier,
27 uint32_t classes)
28 : mContext(context),
29 mId(id),
30 mGeneration(generation),
31 mControllerNumber(controllerNumber),
32 mIdentifier(identifier),
33 mClasses(classes),
34 mSources(0),
35 mIsExternal(false),
36 mHasMic(false),
37 mDropUntilNextSync(false) {}
38
39InputDevice::~InputDevice() {
40 size_t numMappers = mMappers.size();
41 for (size_t i = 0; i < numMappers; i++) {
42 delete mMappers[i];
43 }
44 mMappers.clear();
45}
46
47bool InputDevice::isEnabled() {
48 return getEventHub()->isDeviceEnabled(mId);
49}
50
51void InputDevice::setEnabled(bool enabled, nsecs_t when) {
52 if (enabled && mAssociatedDisplayPort && !mAssociatedViewport) {
53 ALOGW("Cannot enable input device %s because it is associated with port %" PRIu8 ", "
54 "but the corresponding viewport is not found",
55 getName().c_str(), *mAssociatedDisplayPort);
56 enabled = false;
57 }
58
59 if (isEnabled() == enabled) {
60 return;
61 }
62
63 if (enabled) {
64 getEventHub()->enableDevice(mId);
65 reset(when);
66 } else {
67 reset(when);
68 getEventHub()->disableDevice(mId);
69 }
70 // Must change generation to flag this device as changed
71 bumpGeneration();
72}
73
74void InputDevice::dump(std::string& dump) {
75 InputDeviceInfo deviceInfo;
76 getDeviceInfo(&deviceInfo);
77
78 dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(),
79 deviceInfo.getDisplayName().c_str());
80 dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration);
81 dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
82 dump += StringPrintf(INDENT2 "AssociatedDisplayPort: ");
83 if (mAssociatedDisplayPort) {
84 dump += StringPrintf("%" PRIu8 "\n", *mAssociatedDisplayPort);
85 } else {
86 dump += "<none>\n";
87 }
88 dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic));
89 dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
90 dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
91
92 const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
93 if (!ranges.empty()) {
94 dump += INDENT2 "Motion Ranges:\n";
95 for (size_t i = 0; i < ranges.size(); i++) {
96 const InputDeviceInfo::MotionRange& range = ranges[i];
97 const char* label = getAxisLabel(range.axis);
98 char name[32];
99 if (label) {
100 strncpy(name, label, sizeof(name));
101 name[sizeof(name) - 1] = '\0';
102 } else {
103 snprintf(name, sizeof(name), "%d", range.axis);
104 }
105 dump += StringPrintf(INDENT3
106 "%s: source=0x%08x, "
107 "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n",
108 name, range.source, range.min, range.max, range.flat, range.fuzz,
109 range.resolution);
110 }
111 }
112
113 size_t numMappers = mMappers.size();
114 for (size_t i = 0; i < numMappers; i++) {
115 InputMapper* mapper = mMappers[i];
116 mapper->dump(dump);
117 }
118}
119
120void InputDevice::addMapper(InputMapper* mapper) {
121 mMappers.push_back(mapper);
122}
123
124void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config,
125 uint32_t changes) {
126 mSources = 0;
127
128 if (!isIgnored()) {
129 if (!changes) { // first time only
130 mContext->getEventHub()->getConfiguration(mId, &mConfiguration);
131 }
132
133 if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) {
134 if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
135 sp<KeyCharacterMap> keyboardLayout =
136 mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier);
137 if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) {
138 bumpGeneration();
139 }
140 }
141 }
142
143 if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) {
144 if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
145 std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
146 if (mAlias != alias) {
147 mAlias = alias;
148 bumpGeneration();
149 }
150 }
151 }
152
153 if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) {
154 auto it = config->disabledDevices.find(mId);
155 bool enabled = it == config->disabledDevices.end();
156 setEnabled(enabled, when);
157 }
158
159 if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
160 // In most situations, no port will be specified.
161 mAssociatedDisplayPort = std::nullopt;
162 mAssociatedViewport = std::nullopt;
163 // Find the display port that corresponds to the current input port.
164 const std::string& inputPort = mIdentifier.location;
165 if (!inputPort.empty()) {
166 const std::unordered_map<std::string, uint8_t>& ports = config->portAssociations;
167 const auto& displayPort = ports.find(inputPort);
168 if (displayPort != ports.end()) {
169 mAssociatedDisplayPort = std::make_optional(displayPort->second);
170 }
171 }
172
173 // If the device was explicitly disabled by the user, it would be present in the
174 // "disabledDevices" list. If it is associated with a specific display, and it was not
175 // explicitly disabled, then enable/disable the device based on whether we can find the
176 // corresponding viewport.
177 bool enabled = (config->disabledDevices.find(mId) == config->disabledDevices.end());
178 if (mAssociatedDisplayPort) {
179 mAssociatedViewport = config->getDisplayViewportByPort(*mAssociatedDisplayPort);
180 if (!mAssociatedViewport) {
181 ALOGW("Input device %s should be associated with display on port %" PRIu8 ", "
182 "but the corresponding viewport is not found.",
183 getName().c_str(), *mAssociatedDisplayPort);
184 enabled = false;
185 }
186 }
187
188 if (changes) {
189 // For first-time configuration, only allow device to be disabled after mappers have
190 // finished configuring. This is because we need to read some of the properties from
191 // the device's open fd.
192 setEnabled(enabled, when);
193 }
194 }
195
196 for (InputMapper* mapper : mMappers) {
197 mapper->configure(when, config, changes);
198 mSources |= mapper->getSources();
199 }
200
201 // If a device is just plugged but it might be disabled, we need to update some info like
202 // axis range of touch from each InputMapper first, then disable it.
203 if (!changes) {
204 setEnabled(config->disabledDevices.find(mId) == config->disabledDevices.end(), when);
205 }
206 }
207}
208
209void InputDevice::reset(nsecs_t when) {
210 for (InputMapper* mapper : mMappers) {
211 mapper->reset(when);
212 }
213
214 mContext->updateGlobalMetaState();
215
216 notifyReset(when);
217}
218
219void InputDevice::process(const RawEvent* rawEvents, size_t count) {
220 // Process all of the events in order for each mapper.
221 // We cannot simply ask each mapper to process them in bulk because mappers may
222 // have side-effects that must be interleaved. For example, joystick movement events and
223 // gamepad button presses are handled by different mappers but they should be dispatched
224 // in the order received.
225 for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
226#if DEBUG_RAW_EVENTS
227 ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
228 rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, rawEvent->when);
229#endif
230
231 if (mDropUntilNextSync) {
232 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
233 mDropUntilNextSync = false;
234#if DEBUG_RAW_EVENTS
235 ALOGD("Recovered from input event buffer overrun.");
236#endif
237 } else {
238#if DEBUG_RAW_EVENTS
239 ALOGD("Dropped input event while waiting for next input sync.");
240#endif
241 }
242 } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
243 ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
244 mDropUntilNextSync = true;
245 reset(rawEvent->when);
246 } else {
247 for (InputMapper* mapper : mMappers) {
248 mapper->process(rawEvent);
249 }
250 }
251 --count;
252 }
253}
254
255void InputDevice::timeoutExpired(nsecs_t when) {
256 for (InputMapper* mapper : mMappers) {
257 mapper->timeoutExpired(when);
258 }
259}
260
261void InputDevice::updateExternalStylusState(const StylusState& state) {
262 for (InputMapper* mapper : mMappers) {
263 mapper->updateExternalStylusState(state);
264 }
265}
266
267void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
268 outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal,
269 mHasMic);
270 for (InputMapper* mapper : mMappers) {
271 mapper->populateDeviceInfo(outDeviceInfo);
272 }
273}
274
275int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
276 return getState(sourceMask, keyCode, &InputMapper::getKeyCodeState);
277}
278
279int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
280 return getState(sourceMask, scanCode, &InputMapper::getScanCodeState);
281}
282
283int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
284 return getState(sourceMask, switchCode, &InputMapper::getSwitchState);
285}
286
287int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) {
288 int32_t result = AKEY_STATE_UNKNOWN;
289 for (InputMapper* mapper : mMappers) {
290 if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
291 // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
292 // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it.
293 int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code);
294 if (currentResult >= AKEY_STATE_DOWN) {
295 return currentResult;
296 } else if (currentResult == AKEY_STATE_UP) {
297 result = currentResult;
298 }
299 }
300 }
301 return result;
302}
303
304bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
305 const int32_t* keyCodes, uint8_t* outFlags) {
306 bool result = false;
307 for (InputMapper* mapper : mMappers) {
308 if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
309 result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
310 }
311 }
312 return result;
313}
314
315void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
316 int32_t token) {
317 for (InputMapper* mapper : mMappers) {
318 mapper->vibrate(pattern, patternSize, repeat, token);
319 }
320}
321
322void InputDevice::cancelVibrate(int32_t token) {
323 for (InputMapper* mapper : mMappers) {
324 mapper->cancelVibrate(token);
325 }
326}
327
328void InputDevice::cancelTouch(nsecs_t when) {
329 for (InputMapper* mapper : mMappers) {
330 mapper->cancelTouch(when);
331 }
332}
333
334int32_t InputDevice::getMetaState() {
335 int32_t result = 0;
336 for (InputMapper* mapper : mMappers) {
337 result |= mapper->getMetaState();
338 }
339 return result;
340}
341
342void InputDevice::updateMetaState(int32_t keyCode) {
343 for (InputMapper* mapper : mMappers) {
344 mapper->updateMetaState(keyCode);
345 }
346}
347
348void InputDevice::fadePointer() {
349 for (InputMapper* mapper : mMappers) {
350 mapper->fadePointer();
351 }
352}
353
354void InputDevice::bumpGeneration() {
355 mGeneration = mContext->bumpGeneration();
356}
357
358void InputDevice::notifyReset(nsecs_t when) {
359 NotifyDeviceResetArgs args(mContext->getNextSequenceNum(), when, mId);
360 mContext->getListener()->notifyDeviceReset(&args);
361}
362
363std::optional<int32_t> InputDevice::getAssociatedDisplayId() {
364 // Check if we had associated to the specific display.
365 if (mAssociatedViewport) {
366 return mAssociatedViewport->displayId;
367 }
368
369 // No associated display port, check if some InputMapper is associated.
370 for (InputMapper* mapper : mMappers) {
371 std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplayId();
372 if (associatedDisplayId) {
373 return associatedDisplayId;
374 }
375 }
376
377 return std::nullopt;
378}
379
380} // namespace android