blob: da578395500ef6870cd77d11cf33b86d787d2ab3 [file] [log] [blame]
Jeff Brown46b9ac0a2010-04-22 18:58:52 -07001//
2// Copyright 2010 The Android Open Source Project
3//
4// Provides a pipe-based transport for native events in the NDK.
5//
6#define LOG_TAG "Input"
7
8//#define LOG_NDEBUG 0
9
Jeff Brownace13b12011-03-09 17:39:48 -080010// Log debug messages about keymap probing.
Jeff Brown47e6b1b2010-11-29 17:37:49 -080011#define DEBUG_PROBE 0
12
Jeff Brownace13b12011-03-09 17:39:48 -080013// Log debug messages about velocity tracking.
14#define DEBUG_VELOCITY 0
15
Jeff Brownb59ab9f2011-09-14 10:53:18 -070016// Log debug messages about least squares fitting.
17#define DEBUG_LEAST_SQUARES 0
18
Jeff Brown19c97d462011-06-01 12:33:19 -070019// Log debug messages about acceleration.
20#define DEBUG_ACCELERATION 0
21
22
Jeff Brown47e6b1b2010-11-29 17:37:49 -080023#include <stdlib.h>
24#include <unistd.h>
Jeff Brown90655042010-12-02 13:50:46 -080025#include <ctype.h>
Jeff Brown47e6b1b2010-11-29 17:37:49 -080026
Mathias Agopianb93a03f82012-02-17 15:34:57 -080027#include <androidfw/Input.h>
Jeff Brown46b9ac0a2010-04-22 18:58:52 -070028
Jeff Brown91c69ab2011-02-14 17:03:18 -080029#include <math.h>
Jeff Brown19c97d462011-06-01 12:33:19 -070030#include <limits.h>
Jeff Brown91c69ab2011-02-14 17:03:18 -080031
32#ifdef HAVE_ANDROID_OS
33#include <binder/Parcel.h>
34
35#include "SkPoint.h"
36#include "SkMatrix.h"
37#include "SkScalar.h"
38#endif
39
Jeff Brown46b9ac0a2010-04-22 18:58:52 -070040namespace android {
41
Jeff Brown47e6b1b2010-11-29 17:37:49 -080042static const char* CONFIGURATION_FILE_DIR[] = {
43 "idc/",
44 "keylayout/",
45 "keychars/",
46};
47
48static const char* CONFIGURATION_FILE_EXTENSION[] = {
49 ".idc",
50 ".kl",
51 ".kcm",
52};
53
Jeff Brown90655042010-12-02 13:50:46 -080054static bool isValidNameChar(char ch) {
55 return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
56}
57
Jeff Brown47e6b1b2010-11-29 17:37:49 -080058static void appendInputDeviceConfigurationFileRelativePath(String8& path,
59 const String8& name, InputDeviceConfigurationFileType type) {
60 path.append(CONFIGURATION_FILE_DIR[type]);
61 for (size_t i = 0; i < name.length(); i++) {
62 char ch = name[i];
Jeff Brown90655042010-12-02 13:50:46 -080063 if (!isValidNameChar(ch)) {
Jeff Brown47e6b1b2010-11-29 17:37:49 -080064 ch = '_';
65 }
66 path.append(&ch, 1);
67 }
68 path.append(CONFIGURATION_FILE_EXTENSION[type]);
69}
70
Jeff Brown90655042010-12-02 13:50:46 -080071String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
72 const InputDeviceIdentifier& deviceIdentifier,
73 InputDeviceConfigurationFileType type) {
74 if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
75 if (deviceIdentifier.version != 0) {
76 // Try vendor product version.
77 String8 versionPath(getInputDeviceConfigurationFilePathByName(
78 String8::format("Vendor_%04x_Product_%04x_Version_%04x",
79 deviceIdentifier.vendor, deviceIdentifier.product,
80 deviceIdentifier.version),
81 type));
82 if (!versionPath.isEmpty()) {
83 return versionPath;
84 }
85 }
86
87 // Try vendor product.
88 String8 productPath(getInputDeviceConfigurationFilePathByName(
89 String8::format("Vendor_%04x_Product_%04x",
90 deviceIdentifier.vendor, deviceIdentifier.product),
91 type));
92 if (!productPath.isEmpty()) {
93 return productPath;
94 }
95 }
96
97 // Try device name.
98 return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
99}
100
101String8 getInputDeviceConfigurationFilePathByName(
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800102 const String8& name, InputDeviceConfigurationFileType type) {
103 // Search system repository.
104 String8 path;
105 path.setTo(getenv("ANDROID_ROOT"));
106 path.append("/usr/");
107 appendInputDeviceConfigurationFileRelativePath(path, name, type);
108#if DEBUG_PROBE
Steve Block5baa3a62011-12-20 16:23:08 +0000109 ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800110#endif
111 if (!access(path.string(), R_OK)) {
112#if DEBUG_PROBE
Steve Block5baa3a62011-12-20 16:23:08 +0000113 ALOGD("Found");
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800114#endif
115 return path;
116 }
117
118 // Search user repository.
119 // TODO Should only look here if not in safe mode.
120 path.setTo(getenv("ANDROID_DATA"));
121 path.append("/system/devices/");
122 appendInputDeviceConfigurationFileRelativePath(path, name, type);
123#if DEBUG_PROBE
Steve Block5baa3a62011-12-20 16:23:08 +0000124 ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800125#endif
126 if (!access(path.string(), R_OK)) {
127#if DEBUG_PROBE
Steve Block5baa3a62011-12-20 16:23:08 +0000128 ALOGD("Found");
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800129#endif
130 return path;
131 }
132
133 // Not found.
134#if DEBUG_PROBE
Steve Block5baa3a62011-12-20 16:23:08 +0000135 ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800136 name.string(), type);
137#endif
138 return String8();
139}
140
141
142// --- InputEvent ---
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700143
Jeff Brownc5ed5912010-07-14 18:48:53 -0700144void InputEvent::initialize(int32_t deviceId, int32_t source) {
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700145 mDeviceId = deviceId;
Jeff Brownc5ed5912010-07-14 18:48:53 -0700146 mSource = source;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700147}
148
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700149void InputEvent::initialize(const InputEvent& from) {
150 mDeviceId = from.mDeviceId;
151 mSource = from.mSource;
152}
153
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800154// --- KeyEvent ---
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700155
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700156bool KeyEvent::hasDefaultAction(int32_t keyCode) {
157 switch (keyCode) {
Jeff Brownfd0358292010-06-30 16:10:35 -0700158 case AKEYCODE_HOME:
159 case AKEYCODE_BACK:
160 case AKEYCODE_CALL:
161 case AKEYCODE_ENDCALL:
162 case AKEYCODE_VOLUME_UP:
163 case AKEYCODE_VOLUME_DOWN:
Jeff Brownb0418da2010-11-01 15:24:01 -0700164 case AKEYCODE_VOLUME_MUTE:
Jeff Brownfd0358292010-06-30 16:10:35 -0700165 case AKEYCODE_POWER:
166 case AKEYCODE_CAMERA:
167 case AKEYCODE_HEADSETHOOK:
168 case AKEYCODE_MENU:
169 case AKEYCODE_NOTIFICATION:
170 case AKEYCODE_FOCUS:
171 case AKEYCODE_SEARCH:
Jeff Brownb0418da2010-11-01 15:24:01 -0700172 case AKEYCODE_MEDIA_PLAY:
173 case AKEYCODE_MEDIA_PAUSE:
Jeff Brownfd0358292010-06-30 16:10:35 -0700174 case AKEYCODE_MEDIA_PLAY_PAUSE:
175 case AKEYCODE_MEDIA_STOP:
176 case AKEYCODE_MEDIA_NEXT:
177 case AKEYCODE_MEDIA_PREVIOUS:
178 case AKEYCODE_MEDIA_REWIND:
Jeff Brownb0418da2010-11-01 15:24:01 -0700179 case AKEYCODE_MEDIA_RECORD:
Jeff Brownfd0358292010-06-30 16:10:35 -0700180 case AKEYCODE_MEDIA_FAST_FORWARD:
181 case AKEYCODE_MUTE:
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700182 return true;
183 }
184
185 return false;
186}
187
188bool KeyEvent::hasDefaultAction() const {
189 return hasDefaultAction(getKeyCode());
190}
191
192bool KeyEvent::isSystemKey(int32_t keyCode) {
193 switch (keyCode) {
Jeff Brownfd0358292010-06-30 16:10:35 -0700194 case AKEYCODE_MENU:
195 case AKEYCODE_SOFT_RIGHT:
196 case AKEYCODE_HOME:
197 case AKEYCODE_BACK:
198 case AKEYCODE_CALL:
199 case AKEYCODE_ENDCALL:
200 case AKEYCODE_VOLUME_UP:
201 case AKEYCODE_VOLUME_DOWN:
Jeff Brownb0418da2010-11-01 15:24:01 -0700202 case AKEYCODE_VOLUME_MUTE:
Jeff Brownfd0358292010-06-30 16:10:35 -0700203 case AKEYCODE_MUTE:
204 case AKEYCODE_POWER:
205 case AKEYCODE_HEADSETHOOK:
Jeff Brownb0418da2010-11-01 15:24:01 -0700206 case AKEYCODE_MEDIA_PLAY:
207 case AKEYCODE_MEDIA_PAUSE:
Jeff Brownfd0358292010-06-30 16:10:35 -0700208 case AKEYCODE_MEDIA_PLAY_PAUSE:
209 case AKEYCODE_MEDIA_STOP:
210 case AKEYCODE_MEDIA_NEXT:
211 case AKEYCODE_MEDIA_PREVIOUS:
212 case AKEYCODE_MEDIA_REWIND:
Jeff Brownb0418da2010-11-01 15:24:01 -0700213 case AKEYCODE_MEDIA_RECORD:
Jeff Brownfd0358292010-06-30 16:10:35 -0700214 case AKEYCODE_MEDIA_FAST_FORWARD:
215 case AKEYCODE_CAMERA:
216 case AKEYCODE_FOCUS:
217 case AKEYCODE_SEARCH:
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700218 return true;
219 }
220
221 return false;
222}
223
224bool KeyEvent::isSystemKey() const {
225 return isSystemKey(getKeyCode());
226}
227
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700228void KeyEvent::initialize(
229 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700230 int32_t source,
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700231 int32_t action,
232 int32_t flags,
233 int32_t keyCode,
234 int32_t scanCode,
235 int32_t metaState,
236 int32_t repeatCount,
237 nsecs_t downTime,
238 nsecs_t eventTime) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700239 InputEvent::initialize(deviceId, source);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700240 mAction = action;
241 mFlags = flags;
242 mKeyCode = keyCode;
243 mScanCode = scanCode;
244 mMetaState = metaState;
245 mRepeatCount = repeatCount;
246 mDownTime = downTime;
247 mEventTime = eventTime;
248}
249
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700250void KeyEvent::initialize(const KeyEvent& from) {
251 InputEvent::initialize(from);
252 mAction = from.mAction;
253 mFlags = from.mFlags;
254 mKeyCode = from.mKeyCode;
255 mScanCode = from.mScanCode;
256 mMetaState = from.mMetaState;
257 mRepeatCount = from.mRepeatCount;
258 mDownTime = from.mDownTime;
259 mEventTime = from.mEventTime;
260}
261
Jeff Brown91c69ab2011-02-14 17:03:18 -0800262
263// --- PointerCoords ---
264
Jeff Brown6f2fba42011-02-19 01:08:02 -0800265float PointerCoords::getAxisValue(int32_t axis) const {
266 if (axis < 0 || axis > 63) {
267 return 0;
268 }
269
270 uint64_t axisBit = 1LL << axis;
271 if (!(bits & axisBit)) {
272 return 0;
273 }
274 uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
275 return values[index];
276}
277
278status_t PointerCoords::setAxisValue(int32_t axis, float value) {
279 if (axis < 0 || axis > 63) {
280 return NAME_NOT_FOUND;
281 }
282
283 uint64_t axisBit = 1LL << axis;
284 uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
285 if (!(bits & axisBit)) {
Jeff Brownbe1aa822011-07-27 16:04:54 -0700286 if (value == 0) {
287 return OK; // axes with value 0 do not need to be stored
288 }
Jeff Brown6f2fba42011-02-19 01:08:02 -0800289 uint32_t count = __builtin_popcountll(bits);
290 if (count >= MAX_AXES) {
291 tooManyAxes(axis);
292 return NO_MEMORY;
293 }
294 bits |= axisBit;
295 for (uint32_t i = count; i > index; i--) {
296 values[i] = values[i - 1];
297 }
298 }
299 values[index] = value;
300 return OK;
301}
302
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400303static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
Jeff Brownbe1aa822011-07-27 16:04:54 -0700304 float value = c.getAxisValue(axis);
305 if (value != 0) {
306 c.setAxisValue(axis, value * scaleFactor);
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400307 }
308}
309
310void PointerCoords::scale(float scaleFactor) {
311 // No need to scale pressure or size since they are normalized.
312 // No need to scale orientation since it is meaningless to do so.
313 scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor);
314 scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor);
315 scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
316 scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
317 scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
318 scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
319}
320
Jeff Brown91c69ab2011-02-14 17:03:18 -0800321#ifdef HAVE_ANDROID_OS
322status_t PointerCoords::readFromParcel(Parcel* parcel) {
Jeff Brown6f2fba42011-02-19 01:08:02 -0800323 bits = parcel->readInt64();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800324
Jeff Brown6f2fba42011-02-19 01:08:02 -0800325 uint32_t count = __builtin_popcountll(bits);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800326 if (count > MAX_AXES) {
327 return BAD_VALUE;
328 }
329
330 for (uint32_t i = 0; i < count; i++) {
331 values[i] = parcel->readInt32();
332 }
333 return OK;
334}
335
336status_t PointerCoords::writeToParcel(Parcel* parcel) const {
Jeff Brown6f2fba42011-02-19 01:08:02 -0800337 parcel->writeInt64(bits);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800338
Jeff Brown6f2fba42011-02-19 01:08:02 -0800339 uint32_t count = __builtin_popcountll(bits);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800340 for (uint32_t i = 0; i < count; i++) {
341 parcel->writeInt32(values[i]);
342 }
343 return OK;
344}
345#endif
346
347void PointerCoords::tooManyAxes(int axis) {
Steve Block8564c8d2012-01-05 23:22:43 +0000348 ALOGW("Could not set value for axis %d because the PointerCoords structure is full and "
Jeff Brown91c69ab2011-02-14 17:03:18 -0800349 "cannot contain more than %d axis values.", axis, int(MAX_AXES));
350}
351
Jeff Brownace13b12011-03-09 17:39:48 -0800352bool PointerCoords::operator==(const PointerCoords& other) const {
353 if (bits != other.bits) {
354 return false;
355 }
356 uint32_t count = __builtin_popcountll(bits);
357 for (uint32_t i = 0; i < count; i++) {
358 if (values[i] != other.values[i]) {
359 return false;
360 }
361 }
362 return true;
363}
364
365void PointerCoords::copyFrom(const PointerCoords& other) {
366 bits = other.bits;
367 uint32_t count = __builtin_popcountll(bits);
368 for (uint32_t i = 0; i < count; i++) {
369 values[i] = other.values[i];
370 }
371}
372
Jeff Brown91c69ab2011-02-14 17:03:18 -0800373
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700374// --- PointerProperties ---
375
376bool PointerProperties::operator==(const PointerProperties& other) const {
377 return id == other.id
378 && toolType == other.toolType;
379}
380
381void PointerProperties::copyFrom(const PointerProperties& other) {
382 id = other.id;
383 toolType = other.toolType;
384}
385
386
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800387// --- MotionEvent ---
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700388
389void MotionEvent::initialize(
390 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700391 int32_t source,
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700392 int32_t action,
Jeff Brown85a31762010-09-01 17:01:00 -0700393 int32_t flags,
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700394 int32_t edgeFlags,
395 int32_t metaState,
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700396 int32_t buttonState,
Jeff Brown5c225b12010-06-16 01:53:36 -0700397 float xOffset,
398 float yOffset,
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700399 float xPrecision,
400 float yPrecision,
401 nsecs_t downTime,
402 nsecs_t eventTime,
403 size_t pointerCount,
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700404 const PointerProperties* pointerProperties,
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700405 const PointerCoords* pointerCoords) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700406 InputEvent::initialize(deviceId, source);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700407 mAction = action;
Jeff Brown85a31762010-09-01 17:01:00 -0700408 mFlags = flags;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700409 mEdgeFlags = edgeFlags;
410 mMetaState = metaState;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700411 mButtonState = buttonState;
Jeff Brown5c225b12010-06-16 01:53:36 -0700412 mXOffset = xOffset;
413 mYOffset = yOffset;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700414 mXPrecision = xPrecision;
415 mYPrecision = yPrecision;
416 mDownTime = downTime;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700417 mPointerProperties.clear();
418 mPointerProperties.appendArray(pointerProperties, pointerCount);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700419 mSampleEventTimes.clear();
420 mSamplePointerCoords.clear();
421 addSample(eventTime, pointerCoords);
422}
423
Jeff Brown91c69ab2011-02-14 17:03:18 -0800424void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
425 InputEvent::initialize(other->mDeviceId, other->mSource);
426 mAction = other->mAction;
427 mFlags = other->mFlags;
428 mEdgeFlags = other->mEdgeFlags;
429 mMetaState = other->mMetaState;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700430 mButtonState = other->mButtonState;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800431 mXOffset = other->mXOffset;
432 mYOffset = other->mYOffset;
433 mXPrecision = other->mXPrecision;
434 mYPrecision = other->mYPrecision;
435 mDownTime = other->mDownTime;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700436 mPointerProperties = other->mPointerProperties;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800437
438 if (keepHistory) {
439 mSampleEventTimes = other->mSampleEventTimes;
440 mSamplePointerCoords = other->mSamplePointerCoords;
441 } else {
442 mSampleEventTimes.clear();
443 mSampleEventTimes.push(other->getEventTime());
444 mSamplePointerCoords.clear();
445 size_t pointerCount = other->getPointerCount();
446 size_t historySize = other->getHistorySize();
447 mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array()
448 + (historySize * pointerCount), pointerCount);
449 }
450}
451
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700452void MotionEvent::addSample(
453 int64_t eventTime,
454 const PointerCoords* pointerCoords) {
455 mSampleEventTimes.push(eventTime);
456 mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
457}
458
Jeff Brown91c69ab2011-02-14 17:03:18 -0800459const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
460 return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
461}
462
463float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
464 return getRawPointerCoords(pointerIndex)->getAxisValue(axis);
465}
466
467float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
468 float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
469 switch (axis) {
Jeff Brownebbd5d12011-02-17 13:01:34 -0800470 case AMOTION_EVENT_AXIS_X:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400471 return value + mXOffset;
Jeff Brownebbd5d12011-02-17 13:01:34 -0800472 case AMOTION_EVENT_AXIS_Y:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400473 return value + mYOffset;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800474 }
475 return value;
476}
477
478const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
479 size_t pointerIndex, size_t historicalIndex) const {
480 return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
481}
482
483float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
484 size_t historicalIndex) const {
485 return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
486}
487
488float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
489 size_t historicalIndex) const {
490 float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
491 switch (axis) {
Jeff Brownebbd5d12011-02-17 13:01:34 -0800492 case AMOTION_EVENT_AXIS_X:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400493 return value + mXOffset;
Jeff Brownebbd5d12011-02-17 13:01:34 -0800494 case AMOTION_EVENT_AXIS_Y:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400495 return value + mYOffset;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800496 }
497 return value;
498}
499
Jeff Brown2ed24622011-03-14 19:39:54 -0700500ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700501 size_t pointerCount = mPointerProperties.size();
Jeff Brown2ed24622011-03-14 19:39:54 -0700502 for (size_t i = 0; i < pointerCount; i++) {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700503 if (mPointerProperties.itemAt(i).id == pointerId) {
Jeff Brown2ed24622011-03-14 19:39:54 -0700504 return i;
505 }
506 }
507 return -1;
508}
509
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700510void MotionEvent::offsetLocation(float xOffset, float yOffset) {
Jeff Brown5c225b12010-06-16 01:53:36 -0700511 mXOffset += xOffset;
512 mYOffset += yOffset;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700513}
514
Jeff Brown91c69ab2011-02-14 17:03:18 -0800515void MotionEvent::scale(float scaleFactor) {
516 mXOffset *= scaleFactor;
517 mYOffset *= scaleFactor;
518 mXPrecision *= scaleFactor;
519 mYPrecision *= scaleFactor;
520
521 size_t numSamples = mSamplePointerCoords.size();
522 for (size_t i = 0; i < numSamples; i++) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400523 mSamplePointerCoords.editItemAt(i).scale(scaleFactor);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800524 }
525}
526
527#ifdef HAVE_ANDROID_OS
528static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
529 // Construct and transform a vector oriented at the specified clockwise angle from vertical.
530 // Coordinate system: down is increasing Y, right is increasing X.
531 SkPoint vector;
532 vector.fX = SkFloatToScalar(sinf(angleRadians));
533 vector.fY = SkFloatToScalar(-cosf(angleRadians));
534 matrix->mapVectors(& vector, 1);
535
536 // Derive the transformed vector's clockwise angle from vertical.
537 float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY));
538 if (result < - M_PI_2) {
539 result += M_PI;
540 } else if (result > M_PI_2) {
541 result -= M_PI;
542 }
543 return result;
544}
545
546void MotionEvent::transform(const SkMatrix* matrix) {
547 float oldXOffset = mXOffset;
548 float oldYOffset = mYOffset;
549
550 // The tricky part of this implementation is to preserve the value of
551 // rawX and rawY. So we apply the transformation to the first point
552 // then derive an appropriate new X/Y offset that will preserve rawX and rawY.
553 SkPoint point;
554 float rawX = getRawX(0);
555 float rawY = getRawY(0);
556 matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset),
557 & point);
558 float newX = SkScalarToFloat(point.fX);
559 float newY = SkScalarToFloat(point.fY);
560 float newXOffset = newX - rawX;
561 float newYOffset = newY - rawY;
562
563 mXOffset = newXOffset;
564 mYOffset = newYOffset;
565
566 // Apply the transformation to all samples.
567 size_t numSamples = mSamplePointerCoords.size();
568 for (size_t i = 0; i < numSamples; i++) {
569 PointerCoords& c = mSamplePointerCoords.editItemAt(i);
Jeff Brownbe1aa822011-07-27 16:04:54 -0700570 float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
571 float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
572 matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point);
573 c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset);
574 c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800575
Jeff Brownbe1aa822011-07-27 16:04:54 -0700576 float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
577 c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation));
Jeff Brown91c69ab2011-02-14 17:03:18 -0800578 }
579}
580
581status_t MotionEvent::readFromParcel(Parcel* parcel) {
582 size_t pointerCount = parcel->readInt32();
583 size_t sampleCount = parcel->readInt32();
584 if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) {
585 return BAD_VALUE;
586 }
587
588 mDeviceId = parcel->readInt32();
589 mSource = parcel->readInt32();
590 mAction = parcel->readInt32();
591 mFlags = parcel->readInt32();
592 mEdgeFlags = parcel->readInt32();
593 mMetaState = parcel->readInt32();
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700594 mButtonState = parcel->readInt32();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800595 mXOffset = parcel->readFloat();
596 mYOffset = parcel->readFloat();
597 mXPrecision = parcel->readFloat();
598 mYPrecision = parcel->readFloat();
599 mDownTime = parcel->readInt64();
600
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700601 mPointerProperties.clear();
602 mPointerProperties.setCapacity(pointerCount);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800603 mSampleEventTimes.clear();
604 mSampleEventTimes.setCapacity(sampleCount);
605 mSamplePointerCoords.clear();
606 mSamplePointerCoords.setCapacity(sampleCount * pointerCount);
607
608 for (size_t i = 0; i < pointerCount; i++) {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700609 mPointerProperties.push();
610 PointerProperties& properties = mPointerProperties.editTop();
611 properties.id = parcel->readInt32();
612 properties.toolType = parcel->readInt32();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800613 }
614
615 while (sampleCount-- > 0) {
616 mSampleEventTimes.push(parcel->readInt64());
617 for (size_t i = 0; i < pointerCount; i++) {
618 mSamplePointerCoords.push();
619 status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel);
Jeff Brownebbd5d12011-02-17 13:01:34 -0800620 if (status) {
Jeff Brown91c69ab2011-02-14 17:03:18 -0800621 return status;
622 }
623 }
624 }
625 return OK;
626}
627
628status_t MotionEvent::writeToParcel(Parcel* parcel) const {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700629 size_t pointerCount = mPointerProperties.size();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800630 size_t sampleCount = mSampleEventTimes.size();
631
632 parcel->writeInt32(pointerCount);
633 parcel->writeInt32(sampleCount);
634
635 parcel->writeInt32(mDeviceId);
636 parcel->writeInt32(mSource);
637 parcel->writeInt32(mAction);
638 parcel->writeInt32(mFlags);
639 parcel->writeInt32(mEdgeFlags);
640 parcel->writeInt32(mMetaState);
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700641 parcel->writeInt32(mButtonState);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800642 parcel->writeFloat(mXOffset);
643 parcel->writeFloat(mYOffset);
644 parcel->writeFloat(mXPrecision);
645 parcel->writeFloat(mYPrecision);
646 parcel->writeInt64(mDownTime);
647
648 for (size_t i = 0; i < pointerCount; i++) {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700649 const PointerProperties& properties = mPointerProperties.itemAt(i);
650 parcel->writeInt32(properties.id);
651 parcel->writeInt32(properties.toolType);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800652 }
653
654 const PointerCoords* pc = mSamplePointerCoords.array();
655 for (size_t h = 0; h < sampleCount; h++) {
656 parcel->writeInt64(mSampleEventTimes.itemAt(h));
657 for (size_t i = 0; i < pointerCount; i++) {
658 status_t status = (pc++)->writeToParcel(parcel);
Jeff Brownebbd5d12011-02-17 13:01:34 -0800659 if (status) {
Jeff Brown91c69ab2011-02-14 17:03:18 -0800660 return status;
661 }
662 }
663 }
664 return OK;
665}
666#endif
667
Jeff Brown56194eb2011-03-02 19:23:13 -0800668bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
669 if (source & AINPUT_SOURCE_CLASS_POINTER) {
670 // Specifically excludes HOVER_MOVE and SCROLL.
671 switch (action & AMOTION_EVENT_ACTION_MASK) {
672 case AMOTION_EVENT_ACTION_DOWN:
673 case AMOTION_EVENT_ACTION_MOVE:
674 case AMOTION_EVENT_ACTION_UP:
675 case AMOTION_EVENT_ACTION_POINTER_DOWN:
676 case AMOTION_EVENT_ACTION_POINTER_UP:
677 case AMOTION_EVENT_ACTION_CANCEL:
678 case AMOTION_EVENT_ACTION_OUTSIDE:
679 return true;
680 }
681 }
682 return false;
683}
684
Jeff Brown91c69ab2011-02-14 17:03:18 -0800685
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700686// --- PooledInputEventFactory ---
687
688PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) :
689 mMaxPoolSize(maxPoolSize) {
690}
691
692PooledInputEventFactory::~PooledInputEventFactory() {
693 for (size_t i = 0; i < mKeyEventPool.size(); i++) {
694 delete mKeyEventPool.itemAt(i);
695 }
696 for (size_t i = 0; i < mMotionEventPool.size(); i++) {
697 delete mMotionEventPool.itemAt(i);
698 }
699}
700
701KeyEvent* PooledInputEventFactory::createKeyEvent() {
702 if (!mKeyEventPool.isEmpty()) {
703 KeyEvent* event = mKeyEventPool.top();
704 mKeyEventPool.pop();
705 return event;
706 }
707 return new KeyEvent();
708}
709
710MotionEvent* PooledInputEventFactory::createMotionEvent() {
711 if (!mMotionEventPool.isEmpty()) {
712 MotionEvent* event = mMotionEventPool.top();
713 mMotionEventPool.pop();
714 return event;
715 }
716 return new MotionEvent();
717}
718
719void PooledInputEventFactory::recycle(InputEvent* event) {
720 switch (event->getType()) {
721 case AINPUT_EVENT_TYPE_KEY:
722 if (mKeyEventPool.size() < mMaxPoolSize) {
723 mKeyEventPool.push(static_cast<KeyEvent*>(event));
724 return;
725 }
726 break;
727 case AINPUT_EVENT_TYPE_MOTION:
728 if (mMotionEventPool.size() < mMaxPoolSize) {
729 mMotionEventPool.push(static_cast<MotionEvent*>(event));
730 return;
731 }
732 break;
733 }
734 delete event;
735}
736
737
Jeff Brownace13b12011-03-09 17:39:48 -0800738// --- VelocityTracker ---
739
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700740const uint32_t VelocityTracker::DEFAULT_DEGREE;
741const nsecs_t VelocityTracker::DEFAULT_HORIZON;
Jeff Brown19c97d462011-06-01 12:33:19 -0700742const uint32_t VelocityTracker::HISTORY_SIZE;
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700743
744static inline float vectorDot(const float* a, const float* b, uint32_t m) {
745 float r = 0;
746 while (m--) {
747 r += *(a++) * *(b++);
748 }
749 return r;
750}
751
752static inline float vectorNorm(const float* a, uint32_t m) {
753 float r = 0;
754 while (m--) {
755 float t = *(a++);
756 r += t * t;
757 }
758 return sqrtf(r);
759}
760
761#if DEBUG_LEAST_SQUARES || DEBUG_VELOCITY
762static String8 vectorToString(const float* a, uint32_t m) {
763 String8 str;
764 str.append("[");
765 while (m--) {
766 str.appendFormat(" %f", *(a++));
767 if (m) {
768 str.append(",");
769 }
770 }
771 str.append(" ]");
772 return str;
773}
774
775static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
776 String8 str;
777 str.append("[");
778 for (size_t i = 0; i < m; i++) {
779 if (i) {
780 str.append(",");
781 }
782 str.append(" [");
783 for (size_t j = 0; j < n; j++) {
784 if (j) {
785 str.append(",");
786 }
787 str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]);
788 }
789 str.append(" ]");
790 }
791 str.append(" ]");
792 return str;
793}
794#endif
Jeff Brown19c97d462011-06-01 12:33:19 -0700795
Jeff Brownace13b12011-03-09 17:39:48 -0800796VelocityTracker::VelocityTracker() {
797 clear();
798}
799
800void VelocityTracker::clear() {
801 mIndex = 0;
802 mMovements[0].idBits.clear();
Jeff Brown2ed24622011-03-14 19:39:54 -0700803 mActivePointerId = -1;
804}
805
806void VelocityTracker::clearPointers(BitSet32 idBits) {
807 BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
808 mMovements[mIndex].idBits = remainingIdBits;
809
810 if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) {
811 mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
812 }
Jeff Brownace13b12011-03-09 17:39:48 -0800813}
814
815void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
816 if (++mIndex == HISTORY_SIZE) {
817 mIndex = 0;
818 }
Jeff Brown2ed24622011-03-14 19:39:54 -0700819
820 while (idBits.count() > MAX_POINTERS) {
Jeff Brownbe1aa822011-07-27 16:04:54 -0700821 idBits.clearLastMarkedBit();
Jeff Brown2ed24622011-03-14 19:39:54 -0700822 }
823
Jeff Brownace13b12011-03-09 17:39:48 -0800824 Movement& movement = mMovements[mIndex];
825 movement.eventTime = eventTime;
826 movement.idBits = idBits;
827 uint32_t count = idBits.count();
828 for (uint32_t i = 0; i < count; i++) {
829 movement.positions[i] = positions[i];
830 }
831
Jeff Brown2ed24622011-03-14 19:39:54 -0700832 if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
833 mActivePointerId = count != 0 ? idBits.firstMarkedBit() : -1;
834 }
835
Jeff Brownace13b12011-03-09 17:39:48 -0800836#if DEBUG_VELOCITY
Steve Block5baa3a62011-12-20 16:23:08 +0000837 ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d",
Jeff Brown2ed24622011-03-14 19:39:54 -0700838 eventTime, idBits.value, mActivePointerId);
Jeff Brownace13b12011-03-09 17:39:48 -0800839 for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
840 uint32_t id = iterBits.firstMarkedBit();
841 uint32_t index = idBits.getIndexOfBit(id);
842 iterBits.clearBit(id);
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700843 Estimator estimator;
844 getEstimator(id, DEFAULT_DEGREE, DEFAULT_HORIZON, &estimator);
Steve Block5baa3a62011-12-20 16:23:08 +0000845 ALOGD(" %d: position (%0.3f, %0.3f), "
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700846 "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
847 id, positions[index].x, positions[index].y,
848 int(estimator.degree),
849 vectorToString(estimator.xCoeff, estimator.degree).string(),
850 vectorToString(estimator.yCoeff, estimator.degree).string(),
851 estimator.confidence);
Jeff Brownace13b12011-03-09 17:39:48 -0800852 }
853#endif
854}
855
Jeff Brown2ed24622011-03-14 19:39:54 -0700856void VelocityTracker::addMovement(const MotionEvent* event) {
857 int32_t actionMasked = event->getActionMasked();
858
859 switch (actionMasked) {
860 case AMOTION_EVENT_ACTION_DOWN:
Jeff Brown581761d2011-09-09 15:39:35 -0700861 case AMOTION_EVENT_ACTION_HOVER_ENTER:
Jeff Brown2ed24622011-03-14 19:39:54 -0700862 // Clear all pointers on down before adding the new movement.
863 clear();
864 break;
865 case AMOTION_EVENT_ACTION_POINTER_DOWN: {
866 // Start a new movement trace for a pointer that just went down.
867 // We do this on down instead of on up because the client may want to query the
868 // final velocity for a pointer that just went up.
869 BitSet32 downIdBits;
Jeff Brownbe1aa822011-07-27 16:04:54 -0700870 downIdBits.markBit(event->getPointerId(event->getActionIndex()));
Jeff Brown2ed24622011-03-14 19:39:54 -0700871 clearPointers(downIdBits);
872 break;
873 }
Jeff Brown581761d2011-09-09 15:39:35 -0700874 case AMOTION_EVENT_ACTION_MOVE:
875 case AMOTION_EVENT_ACTION_HOVER_MOVE:
876 break;
877 default:
878 // Ignore all other actions because they do not convey any new information about
Jeff Brown2ed24622011-03-14 19:39:54 -0700879 // pointer movement. We also want to preserve the last known velocity of the pointers.
880 // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
881 // of the pointers that went up. ACTION_POINTER_UP does include the new position of
882 // pointers that remained down but we will also receive an ACTION_MOVE with this
883 // information if any of them actually moved. Since we don't know how many pointers
884 // will be going up at once it makes sense to just wait for the following ACTION_MOVE
885 // before adding the movement.
886 return;
887 }
888
889 size_t pointerCount = event->getPointerCount();
890 if (pointerCount > MAX_POINTERS) {
891 pointerCount = MAX_POINTERS;
892 }
893
894 BitSet32 idBits;
895 for (size_t i = 0; i < pointerCount; i++) {
896 idBits.markBit(event->getPointerId(i));
897 }
898
899 nsecs_t eventTime;
900 Position positions[pointerCount];
901
902 size_t historySize = event->getHistorySize();
903 for (size_t h = 0; h < historySize; h++) {
904 eventTime = event->getHistoricalEventTime(h);
905 for (size_t i = 0; i < pointerCount; i++) {
906 positions[i].x = event->getHistoricalX(i, h);
907 positions[i].y = event->getHistoricalY(i, h);
908 }
909 addMovement(eventTime, idBits, positions);
910 }
911
912 eventTime = event->getEventTime();
913 for (size_t i = 0; i < pointerCount; i++) {
914 positions[i].x = event->getX(i);
915 positions[i].y = event->getY(i);
916 }
917 addMovement(eventTime, idBits, positions);
918}
919
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700920/**
921 * Solves a linear least squares problem to obtain a N degree polynomial that fits
922 * the specified input data as nearly as possible.
923 *
924 * Returns true if a solution is found, false otherwise.
925 *
926 * The input consists of two vectors of data points X and Y with indices 0..m-1.
927 * The output is a vector B with indices 0..n-1 that describes a polynomial
928 * that fits the data, such the sum of abs(Y[i] - (B[0] + B[1] X[i] + B[2] X[i]^2 ... B[n] X[i]^n))
929 * for all i between 0 and m-1 is minimized.
930 *
931 * That is to say, the function that generated the input data can be approximated
932 * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n.
933 *
934 * The coefficient of determination (R^2) is also returned to describe the goodness
935 * of fit of the model for the given data. It is a value between 0 and 1, where 1
936 * indicates perfect correspondence.
937 *
938 * This function first expands the X vector to a m by n matrix A such that
939 * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n.
940 *
941 * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q
942 * and an m by n upper triangular matrix R. Because R is upper triangular (lower
943 * part is all zeroes), we can simplify the decomposition into an m by n matrix
944 * Q1 and a n by n matrix R1 such that A = Q1 R1.
945 *
946 * Finally we solve the system of linear equations given by R1 B = (Qtranspose Y)
947 * to find B.
948 *
949 * For efficiency, we lay out A and Q column-wise in memory because we frequently
950 * operate on the column vectors. Conversely, we lay out R row-wise.
951 *
952 * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares
953 * http://en.wikipedia.org/wiki/Gram-Schmidt
954 */
955static bool solveLeastSquares(const float* x, const float* y, uint32_t m, uint32_t n,
956 float* outB, float* outDet) {
957#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000958 ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s", int(m), int(n),
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700959 vectorToString(x, m).string(), vectorToString(y, m).string());
960#endif
961
962 // Expand the X vector to a matrix A.
963 float a[n][m]; // column-major order
964 for (uint32_t h = 0; h < m; h++) {
965 a[0][h] = 1;
966 for (uint32_t i = 1; i < n; i++) {
967 a[i][h] = a[i - 1][h] * x[h];
968 }
969 }
970#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000971 ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700972#endif
973
974 // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
975 float q[n][m]; // orthonormal basis, column-major order
976 float r[n][n]; // upper triangular matrix, row-major order
977 for (uint32_t j = 0; j < n; j++) {
978 for (uint32_t h = 0; h < m; h++) {
979 q[j][h] = a[j][h];
980 }
981 for (uint32_t i = 0; i < j; i++) {
982 float dot = vectorDot(&q[j][0], &q[i][0], m);
983 for (uint32_t h = 0; h < m; h++) {
984 q[j][h] -= dot * q[i][h];
985 }
986 }
987
988 float norm = vectorNorm(&q[j][0], m);
989 if (norm < 0.000001f) {
990 // vectors are linearly dependent or zero so no solution
991#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000992 ALOGD(" - no solution, norm=%f", norm);
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700993#endif
994 return false;
995 }
996
997 float invNorm = 1.0f / norm;
998 for (uint32_t h = 0; h < m; h++) {
999 q[j][h] *= invNorm;
1000 }
1001 for (uint32_t i = 0; i < n; i++) {
1002 r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m);
1003 }
1004 }
1005#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +00001006 ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string());
1007 ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001008
1009 // calculate QR, if we factored A correctly then QR should equal A
1010 float qr[n][m];
1011 for (uint32_t h = 0; h < m; h++) {
1012 for (uint32_t i = 0; i < n; i++) {
1013 qr[i][h] = 0;
1014 for (uint32_t j = 0; j < n; j++) {
1015 qr[i][h] += q[j][h] * r[j][i];
1016 }
1017 }
1018 }
Steve Block5baa3a62011-12-20 16:23:08 +00001019 ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001020#endif
1021
1022 // Solve R B = Qt Y to find B. This is easy because R is upper triangular.
1023 // We just work from bottom-right to top-left calculating B's coefficients.
1024 for (uint32_t i = n; i-- != 0; ) {
1025 outB[i] = vectorDot(&q[i][0], y, m);
1026 for (uint32_t j = n - 1; j > i; j--) {
1027 outB[i] -= r[i][j] * outB[j];
1028 }
1029 outB[i] /= r[i][i];
1030 }
1031#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +00001032 ALOGD(" - b=%s", vectorToString(outB, n).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001033#endif
1034
1035 // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
1036 // SSerr is the residual sum of squares (squared variance of the error),
1037 // and SStot is the total sum of squares (squared variance of the data).
1038 float ymean = 0;
1039 for (uint32_t h = 0; h < m; h++) {
1040 ymean += y[h];
1041 }
1042 ymean /= m;
1043
1044 float sserr = 0;
1045 float sstot = 0;
1046 for (uint32_t h = 0; h < m; h++) {
1047 float err = y[h] - outB[0];
1048 float term = 1;
1049 for (uint32_t i = 1; i < n; i++) {
1050 term *= x[h];
1051 err -= term * outB[i];
1052 }
1053 sserr += err * err;
1054 float var = y[h] - ymean;
1055 sstot += var * var;
1056 }
1057 *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
1058#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +00001059 ALOGD(" - sserr=%f", sserr);
1060 ALOGD(" - sstot=%f", sstot);
1061 ALOGD(" - det=%f", *outDet);
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001062#endif
1063 return true;
1064}
1065
Jeff Brownace13b12011-03-09 17:39:48 -08001066bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001067 Estimator estimator;
1068 if (getEstimator(id, DEFAULT_DEGREE, DEFAULT_HORIZON, &estimator)) {
1069 if (estimator.degree >= 1) {
1070 *outVx = estimator.xCoeff[1];
1071 *outVy = estimator.yCoeff[1];
1072 return true;
1073 }
1074 }
Jeff Brownb0c71eb2011-09-16 21:40:49 -07001075 *outVx = 0;
1076 *outVy = 0;
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001077 return false;
1078}
1079
1080bool VelocityTracker::getEstimator(uint32_t id, uint32_t degree, nsecs_t horizon,
1081 Estimator* outEstimator) const {
1082 outEstimator->clear();
1083
1084 // Iterate over movement samples in reverse time order and collect samples.
1085 float x[HISTORY_SIZE];
1086 float y[HISTORY_SIZE];
1087 float time[HISTORY_SIZE];
1088 uint32_t m = 0;
1089 uint32_t index = mIndex;
Jeff Brownace13b12011-03-09 17:39:48 -08001090 const Movement& newestMovement = mMovements[mIndex];
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001091 do {
1092 const Movement& movement = mMovements[index];
1093 if (!movement.idBits.hasBit(id)) {
1094 break;
1095 }
Jeff Brown2352b972011-04-12 22:39:53 -07001096
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001097 nsecs_t age = newestMovement.eventTime - movement.eventTime;
1098 if (age > horizon) {
1099 break;
1100 }
Jeff Brown581761d2011-09-09 15:39:35 -07001101
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001102 const Position& position = movement.getPosition(id);
1103 x[m] = position.x;
1104 y[m] = position.y;
1105 time[m] = -age * 0.000000001f;
1106 index = (index == 0 ? HISTORY_SIZE : index) - 1;
1107 } while (++m < HISTORY_SIZE);
Jeff Brown581761d2011-09-09 15:39:35 -07001108
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001109 if (m == 0) {
1110 return false; // no data
1111 }
Jeff Brownace13b12011-03-09 17:39:48 -08001112
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001113 // Calculate a least squares polynomial fit.
1114 if (degree > Estimator::MAX_DEGREE) {
1115 degree = Estimator::MAX_DEGREE;
1116 }
1117 if (degree > m - 1) {
1118 degree = m - 1;
1119 }
1120 if (degree >= 1) {
1121 float xdet, ydet;
1122 uint32_t n = degree + 1;
1123 if (solveLeastSquares(time, x, m, n, outEstimator->xCoeff, &xdet)
1124 && solveLeastSquares(time, y, m, n, outEstimator->yCoeff, &ydet)) {
1125 outEstimator->degree = degree;
1126 outEstimator->confidence = xdet * ydet;
1127#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +00001128 ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001129 int(outEstimator->degree),
1130 vectorToString(outEstimator->xCoeff, n).string(),
1131 vectorToString(outEstimator->yCoeff, n).string(),
1132 outEstimator->confidence);
1133#endif
Jeff Brownace13b12011-03-09 17:39:48 -08001134 return true;
1135 }
1136 }
1137
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001138 // No velocity data available for this pointer, but we do have its current position.
1139 outEstimator->xCoeff[0] = x[0];
1140 outEstimator->yCoeff[0] = y[0];
1141 outEstimator->degree = 0;
1142 outEstimator->confidence = 1;
1143 return true;
Jeff Brownace13b12011-03-09 17:39:48 -08001144}
1145
1146
Jeff Brown19c97d462011-06-01 12:33:19 -07001147// --- VelocityControl ---
1148
1149const nsecs_t VelocityControl::STOP_TIME;
1150
1151VelocityControl::VelocityControl() {
1152 reset();
1153}
1154
1155void VelocityControl::setParameters(const VelocityControlParameters& parameters) {
1156 mParameters = parameters;
1157 reset();
1158}
1159
1160void VelocityControl::reset() {
1161 mLastMovementTime = LLONG_MIN;
1162 mRawPosition.x = 0;
1163 mRawPosition.y = 0;
1164 mVelocityTracker.clear();
1165}
1166
1167void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
1168 if ((deltaX && *deltaX) || (deltaY && *deltaY)) {
1169 if (eventTime >= mLastMovementTime + STOP_TIME) {
1170#if DEBUG_ACCELERATION
Steve Block5baa3a62011-12-20 16:23:08 +00001171 ALOGD("VelocityControl: stopped, last movement was %0.3fms ago",
Jeff Brown19c97d462011-06-01 12:33:19 -07001172 (eventTime - mLastMovementTime) * 0.000001f);
1173#endif
1174 reset();
1175 }
1176
1177 mLastMovementTime = eventTime;
1178 if (deltaX) {
1179 mRawPosition.x += *deltaX;
1180 }
1181 if (deltaY) {
1182 mRawPosition.y += *deltaY;
1183 }
1184 mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition);
1185
1186 float vx, vy;
1187 float scale = mParameters.scale;
1188 if (mVelocityTracker.getVelocity(0, &vx, &vy)) {
1189 float speed = hypotf(vx, vy) * scale;
1190 if (speed >= mParameters.highThreshold) {
1191 // Apply full acceleration above the high speed threshold.
1192 scale *= mParameters.acceleration;
1193 } else if (speed > mParameters.lowThreshold) {
1194 // Linearly interpolate the acceleration to apply between the low and high
1195 // speed thresholds.
1196 scale *= 1 + (speed - mParameters.lowThreshold)
1197 / (mParameters.highThreshold - mParameters.lowThreshold)
1198 * (mParameters.acceleration - 1);
1199 }
1200
1201#if DEBUG_ACCELERATION
Steve Block5baa3a62011-12-20 16:23:08 +00001202 ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
Jeff Brown19c97d462011-06-01 12:33:19 -07001203 "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
1204 mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
1205 mParameters.acceleration,
1206 vx, vy, speed, scale / mParameters.scale);
1207#endif
1208 } else {
1209#if DEBUG_ACCELERATION
Steve Block5baa3a62011-12-20 16:23:08 +00001210 ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
Jeff Brown19c97d462011-06-01 12:33:19 -07001211 mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
1212 mParameters.acceleration);
1213#endif
1214 }
1215
1216 if (deltaX) {
1217 *deltaX *= scale;
1218 }
1219 if (deltaY) {
1220 *deltaY *= scale;
1221 }
1222 }
1223}
1224
1225
Jeff Brown47e6b1b2010-11-29 17:37:49 -08001226// --- InputDeviceInfo ---
Jeff Brown6d0fec22010-07-23 21:28:06 -07001227
1228InputDeviceInfo::InputDeviceInfo() {
1229 initialize(-1, String8("uninitialized device info"));
1230}
1231
1232InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
1233 mId(other.mId), mName(other.mName), mSources(other.mSources),
1234 mKeyboardType(other.mKeyboardType),
1235 mMotionRanges(other.mMotionRanges) {
1236}
1237
1238InputDeviceInfo::~InputDeviceInfo() {
1239}
1240
1241void InputDeviceInfo::initialize(int32_t id, const String8& name) {
1242 mId = id;
1243 mName = name;
1244 mSources = 0;
1245 mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
1246 mMotionRanges.clear();
1247}
1248
Jeff Brownefd32662011-03-08 15:13:06 -08001249const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
1250 int32_t axis, uint32_t source) const {
1251 size_t numRanges = mMotionRanges.size();
1252 for (size_t i = 0; i < numRanges; i++) {
1253 const MotionRange& range = mMotionRanges.itemAt(i);
1254 if (range.axis == axis && range.source == source) {
1255 return &range;
1256 }
1257 }
1258 return NULL;
Jeff Brown6d0fec22010-07-23 21:28:06 -07001259}
1260
1261void InputDeviceInfo::addSource(uint32_t source) {
1262 mSources |= source;
1263}
1264
Jeff Brownefd32662011-03-08 15:13:06 -08001265void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
Jeff Brown6d0fec22010-07-23 21:28:06 -07001266 float flat, float fuzz) {
Jeff Brownefd32662011-03-08 15:13:06 -08001267 MotionRange range = { axis, source, min, max, flat, fuzz };
1268 mMotionRanges.add(range);
Jeff Brown6d0fec22010-07-23 21:28:06 -07001269}
1270
Jeff Brownefd32662011-03-08 15:13:06 -08001271void InputDeviceInfo::addMotionRange(const MotionRange& range) {
1272 mMotionRanges.add(range);
Jeff Brown6d0fec22010-07-23 21:28:06 -07001273}
1274
Jeff Brown46b9ac0a2010-04-22 18:58:52 -07001275} // namespace android