blob: fbe19268e4fbbda3031fff047d7aa2d3bd0b7633 [file] [log] [blame]
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001/*
2 * Copyright (C) 2010 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
Jeff Brown46b9ac02010-04-22 18:58:52 -070017#define LOG_TAG "Input"
18
19//#define LOG_NDEBUG 0
20
Jeff Brownace13b12011-03-09 17:39:48 -080021// Log debug messages about keymap probing.
Jeff Brown47e6b1b2010-11-29 17:37:49 -080022#define DEBUG_PROBE 0
23
Jeff Brownace13b12011-03-09 17:39:48 -080024// Log debug messages about velocity tracking.
25#define DEBUG_VELOCITY 0
26
Jeff Brownb59ab9f2011-09-14 10:53:18 -070027// Log debug messages about least squares fitting.
28#define DEBUG_LEAST_SQUARES 0
29
Jeff Brown19c97d462011-06-01 12:33:19 -070030// Log debug messages about acceleration.
31#define DEBUG_ACCELERATION 0
32
33
Jeff Brown47e6b1b2010-11-29 17:37:49 -080034#include <stdlib.h>
35#include <unistd.h>
Jeff Brown90655042010-12-02 13:50:46 -080036#include <ctype.h>
Jeff Brown47e6b1b2010-11-29 17:37:49 -080037
Mathias Agopianb93a03f82012-02-17 15:34:57 -080038#include <androidfw/Input.h>
Jeff Brown46b9ac02010-04-22 18:58:52 -070039
Jeff Brown91c69ab2011-02-14 17:03:18 -080040#include <math.h>
Jeff Brown19c97d462011-06-01 12:33:19 -070041#include <limits.h>
Jeff Brown91c69ab2011-02-14 17:03:18 -080042
43#ifdef HAVE_ANDROID_OS
44#include <binder/Parcel.h>
45
46#include "SkPoint.h"
47#include "SkMatrix.h"
48#include "SkScalar.h"
49#endif
50
Jeff Brown46b9ac02010-04-22 18:58:52 -070051namespace android {
52
Jeff Brown47e6b1b2010-11-29 17:37:49 -080053// --- InputEvent ---
Jeff Brown46b9ac02010-04-22 18:58:52 -070054
Jeff Brownc5ed5912010-07-14 18:48:53 -070055void InputEvent::initialize(int32_t deviceId, int32_t source) {
Jeff Brown46b9ac02010-04-22 18:58:52 -070056 mDeviceId = deviceId;
Jeff Brownc5ed5912010-07-14 18:48:53 -070057 mSource = source;
Jeff Brown46b9ac02010-04-22 18:58:52 -070058}
59
Dianne Hackborn2c6081c2010-07-15 17:44:53 -070060void InputEvent::initialize(const InputEvent& from) {
61 mDeviceId = from.mDeviceId;
62 mSource = from.mSource;
63}
64
Jeff Brown47e6b1b2010-11-29 17:37:49 -080065// --- KeyEvent ---
Jeff Brown46b9ac02010-04-22 18:58:52 -070066
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070067bool KeyEvent::hasDefaultAction(int32_t keyCode) {
68 switch (keyCode) {
Jeff Brownfd035822010-06-30 16:10:35 -070069 case AKEYCODE_HOME:
70 case AKEYCODE_BACK:
71 case AKEYCODE_CALL:
72 case AKEYCODE_ENDCALL:
73 case AKEYCODE_VOLUME_UP:
74 case AKEYCODE_VOLUME_DOWN:
Jeff Brownb0418da2010-11-01 15:24:01 -070075 case AKEYCODE_VOLUME_MUTE:
Jeff Brownfd035822010-06-30 16:10:35 -070076 case AKEYCODE_POWER:
77 case AKEYCODE_CAMERA:
78 case AKEYCODE_HEADSETHOOK:
79 case AKEYCODE_MENU:
80 case AKEYCODE_NOTIFICATION:
81 case AKEYCODE_FOCUS:
82 case AKEYCODE_SEARCH:
Jeff Brownb0418da2010-11-01 15:24:01 -070083 case AKEYCODE_MEDIA_PLAY:
84 case AKEYCODE_MEDIA_PAUSE:
Jeff Brownfd035822010-06-30 16:10:35 -070085 case AKEYCODE_MEDIA_PLAY_PAUSE:
86 case AKEYCODE_MEDIA_STOP:
87 case AKEYCODE_MEDIA_NEXT:
88 case AKEYCODE_MEDIA_PREVIOUS:
89 case AKEYCODE_MEDIA_REWIND:
Jeff Brownb0418da2010-11-01 15:24:01 -070090 case AKEYCODE_MEDIA_RECORD:
Jeff Brownfd035822010-06-30 16:10:35 -070091 case AKEYCODE_MEDIA_FAST_FORWARD:
92 case AKEYCODE_MUTE:
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070093 return true;
94 }
95
96 return false;
97}
98
99bool KeyEvent::hasDefaultAction() const {
100 return hasDefaultAction(getKeyCode());
101}
102
103bool KeyEvent::isSystemKey(int32_t keyCode) {
104 switch (keyCode) {
Jeff Brownfd035822010-06-30 16:10:35 -0700105 case AKEYCODE_MENU:
106 case AKEYCODE_SOFT_RIGHT:
107 case AKEYCODE_HOME:
108 case AKEYCODE_BACK:
109 case AKEYCODE_CALL:
110 case AKEYCODE_ENDCALL:
111 case AKEYCODE_VOLUME_UP:
112 case AKEYCODE_VOLUME_DOWN:
Jeff Brownb0418da2010-11-01 15:24:01 -0700113 case AKEYCODE_VOLUME_MUTE:
Jeff Brownfd035822010-06-30 16:10:35 -0700114 case AKEYCODE_MUTE:
115 case AKEYCODE_POWER:
116 case AKEYCODE_HEADSETHOOK:
Jeff Brownb0418da2010-11-01 15:24:01 -0700117 case AKEYCODE_MEDIA_PLAY:
118 case AKEYCODE_MEDIA_PAUSE:
Jeff Brownfd035822010-06-30 16:10:35 -0700119 case AKEYCODE_MEDIA_PLAY_PAUSE:
120 case AKEYCODE_MEDIA_STOP:
121 case AKEYCODE_MEDIA_NEXT:
122 case AKEYCODE_MEDIA_PREVIOUS:
123 case AKEYCODE_MEDIA_REWIND:
Jeff Brownb0418da2010-11-01 15:24:01 -0700124 case AKEYCODE_MEDIA_RECORD:
Jeff Brownfd035822010-06-30 16:10:35 -0700125 case AKEYCODE_MEDIA_FAST_FORWARD:
126 case AKEYCODE_CAMERA:
127 case AKEYCODE_FOCUS:
128 case AKEYCODE_SEARCH:
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700129 return true;
130 }
131
132 return false;
133}
134
135bool KeyEvent::isSystemKey() const {
136 return isSystemKey(getKeyCode());
137}
138
Jeff Brown46b9ac02010-04-22 18:58:52 -0700139void KeyEvent::initialize(
140 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700141 int32_t source,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700142 int32_t action,
143 int32_t flags,
144 int32_t keyCode,
145 int32_t scanCode,
146 int32_t metaState,
147 int32_t repeatCount,
148 nsecs_t downTime,
149 nsecs_t eventTime) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700150 InputEvent::initialize(deviceId, source);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700151 mAction = action;
152 mFlags = flags;
153 mKeyCode = keyCode;
154 mScanCode = scanCode;
155 mMetaState = metaState;
156 mRepeatCount = repeatCount;
157 mDownTime = downTime;
158 mEventTime = eventTime;
159}
160
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700161void KeyEvent::initialize(const KeyEvent& from) {
162 InputEvent::initialize(from);
163 mAction = from.mAction;
164 mFlags = from.mFlags;
165 mKeyCode = from.mKeyCode;
166 mScanCode = from.mScanCode;
167 mMetaState = from.mMetaState;
168 mRepeatCount = from.mRepeatCount;
169 mDownTime = from.mDownTime;
170 mEventTime = from.mEventTime;
171}
172
Jeff Brown91c69ab2011-02-14 17:03:18 -0800173
174// --- PointerCoords ---
175
Jeff Brown6f2fba42011-02-19 01:08:02 -0800176float PointerCoords::getAxisValue(int32_t axis) const {
177 if (axis < 0 || axis > 63) {
178 return 0;
179 }
180
181 uint64_t axisBit = 1LL << axis;
182 if (!(bits & axisBit)) {
183 return 0;
184 }
185 uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
186 return values[index];
187}
188
189status_t PointerCoords::setAxisValue(int32_t axis, float value) {
190 if (axis < 0 || axis > 63) {
191 return NAME_NOT_FOUND;
192 }
193
194 uint64_t axisBit = 1LL << axis;
195 uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
196 if (!(bits & axisBit)) {
Jeff Brownbe1aa822011-07-27 16:04:54 -0700197 if (value == 0) {
198 return OK; // axes with value 0 do not need to be stored
199 }
Jeff Brown6f2fba42011-02-19 01:08:02 -0800200 uint32_t count = __builtin_popcountll(bits);
201 if (count >= MAX_AXES) {
202 tooManyAxes(axis);
203 return NO_MEMORY;
204 }
205 bits |= axisBit;
206 for (uint32_t i = count; i > index; i--) {
207 values[i] = values[i - 1];
208 }
209 }
210 values[index] = value;
211 return OK;
212}
213
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400214static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
Jeff Brownbe1aa822011-07-27 16:04:54 -0700215 float value = c.getAxisValue(axis);
216 if (value != 0) {
217 c.setAxisValue(axis, value * scaleFactor);
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400218 }
219}
220
221void PointerCoords::scale(float scaleFactor) {
222 // No need to scale pressure or size since they are normalized.
223 // No need to scale orientation since it is meaningless to do so.
224 scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor);
225 scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor);
226 scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
227 scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
228 scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
229 scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
230}
231
Jeff Brown771526c2012-04-27 15:13:25 -0700232void PointerCoords::lerp(const PointerCoords& a, const PointerCoords& b, float alpha) {
233 bits = 0;
234 for (uint64_t bitsRemaining = a.bits | b.bits; bitsRemaining; ) {
235 int32_t axis = __builtin_ctz(bitsRemaining);
236 uint64_t axisBit = 1LL << axis;
237 bitsRemaining &= ~axisBit;
238 if (a.bits & axisBit) {
239 if (b.bits & axisBit) {
240 float aval = a.getAxisValue(axis);
241 float bval = b.getAxisValue(axis);
242 setAxisValue(axis, aval + alpha * (bval - aval));
243 } else {
244 setAxisValue(axis, a.getAxisValue(axis));
245 }
246 } else {
247 setAxisValue(axis, b.getAxisValue(axis));
248 }
249 }
250}
251
Jeff Brown91c69ab2011-02-14 17:03:18 -0800252#ifdef HAVE_ANDROID_OS
253status_t PointerCoords::readFromParcel(Parcel* parcel) {
Jeff Brown6f2fba42011-02-19 01:08:02 -0800254 bits = parcel->readInt64();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800255
Jeff Brown6f2fba42011-02-19 01:08:02 -0800256 uint32_t count = __builtin_popcountll(bits);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800257 if (count > MAX_AXES) {
258 return BAD_VALUE;
259 }
260
261 for (uint32_t i = 0; i < count; i++) {
262 values[i] = parcel->readInt32();
263 }
264 return OK;
265}
266
267status_t PointerCoords::writeToParcel(Parcel* parcel) const {
Jeff Brown6f2fba42011-02-19 01:08:02 -0800268 parcel->writeInt64(bits);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800269
Jeff Brown6f2fba42011-02-19 01:08:02 -0800270 uint32_t count = __builtin_popcountll(bits);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800271 for (uint32_t i = 0; i < count; i++) {
272 parcel->writeInt32(values[i]);
273 }
274 return OK;
275}
276#endif
277
278void PointerCoords::tooManyAxes(int axis) {
Steve Block8564c8d2012-01-05 23:22:43 +0000279 ALOGW("Could not set value for axis %d because the PointerCoords structure is full and "
Jeff Brown91c69ab2011-02-14 17:03:18 -0800280 "cannot contain more than %d axis values.", axis, int(MAX_AXES));
281}
282
Jeff Brownace13b12011-03-09 17:39:48 -0800283bool PointerCoords::operator==(const PointerCoords& other) const {
284 if (bits != other.bits) {
285 return false;
286 }
287 uint32_t count = __builtin_popcountll(bits);
288 for (uint32_t i = 0; i < count; i++) {
289 if (values[i] != other.values[i]) {
290 return false;
291 }
292 }
293 return true;
294}
295
296void PointerCoords::copyFrom(const PointerCoords& other) {
297 bits = other.bits;
298 uint32_t count = __builtin_popcountll(bits);
299 for (uint32_t i = 0; i < count; i++) {
300 values[i] = other.values[i];
301 }
302}
303
Jeff Brown91c69ab2011-02-14 17:03:18 -0800304
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700305// --- PointerProperties ---
306
307bool PointerProperties::operator==(const PointerProperties& other) const {
308 return id == other.id
309 && toolType == other.toolType;
310}
311
312void PointerProperties::copyFrom(const PointerProperties& other) {
313 id = other.id;
314 toolType = other.toolType;
315}
316
317
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800318// --- MotionEvent ---
Jeff Brown46b9ac02010-04-22 18:58:52 -0700319
320void MotionEvent::initialize(
321 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700322 int32_t source,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700323 int32_t action,
Jeff Brown85a31762010-09-01 17:01:00 -0700324 int32_t flags,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700325 int32_t edgeFlags,
326 int32_t metaState,
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700327 int32_t buttonState,
Jeff Brown5c225b12010-06-16 01:53:36 -0700328 float xOffset,
329 float yOffset,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700330 float xPrecision,
331 float yPrecision,
332 nsecs_t downTime,
333 nsecs_t eventTime,
334 size_t pointerCount,
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700335 const PointerProperties* pointerProperties,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700336 const PointerCoords* pointerCoords) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700337 InputEvent::initialize(deviceId, source);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700338 mAction = action;
Jeff Brown85a31762010-09-01 17:01:00 -0700339 mFlags = flags;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700340 mEdgeFlags = edgeFlags;
341 mMetaState = metaState;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700342 mButtonState = buttonState;
Jeff Brown5c225b12010-06-16 01:53:36 -0700343 mXOffset = xOffset;
344 mYOffset = yOffset;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700345 mXPrecision = xPrecision;
346 mYPrecision = yPrecision;
347 mDownTime = downTime;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700348 mPointerProperties.clear();
349 mPointerProperties.appendArray(pointerProperties, pointerCount);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700350 mSampleEventTimes.clear();
351 mSamplePointerCoords.clear();
352 addSample(eventTime, pointerCoords);
353}
354
Jeff Brown91c69ab2011-02-14 17:03:18 -0800355void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
356 InputEvent::initialize(other->mDeviceId, other->mSource);
357 mAction = other->mAction;
358 mFlags = other->mFlags;
359 mEdgeFlags = other->mEdgeFlags;
360 mMetaState = other->mMetaState;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700361 mButtonState = other->mButtonState;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800362 mXOffset = other->mXOffset;
363 mYOffset = other->mYOffset;
364 mXPrecision = other->mXPrecision;
365 mYPrecision = other->mYPrecision;
366 mDownTime = other->mDownTime;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700367 mPointerProperties = other->mPointerProperties;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800368
369 if (keepHistory) {
370 mSampleEventTimes = other->mSampleEventTimes;
371 mSamplePointerCoords = other->mSamplePointerCoords;
372 } else {
373 mSampleEventTimes.clear();
374 mSampleEventTimes.push(other->getEventTime());
375 mSamplePointerCoords.clear();
376 size_t pointerCount = other->getPointerCount();
377 size_t historySize = other->getHistorySize();
378 mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array()
379 + (historySize * pointerCount), pointerCount);
380 }
381}
382
Jeff Brown46b9ac02010-04-22 18:58:52 -0700383void MotionEvent::addSample(
384 int64_t eventTime,
385 const PointerCoords* pointerCoords) {
386 mSampleEventTimes.push(eventTime);
387 mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
388}
389
Jeff Brown91c69ab2011-02-14 17:03:18 -0800390const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
391 return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
392}
393
394float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
395 return getRawPointerCoords(pointerIndex)->getAxisValue(axis);
396}
397
398float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
399 float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
400 switch (axis) {
Jeff Brownebbd5d12011-02-17 13:01:34 -0800401 case AMOTION_EVENT_AXIS_X:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400402 return value + mXOffset;
Jeff Brownebbd5d12011-02-17 13:01:34 -0800403 case AMOTION_EVENT_AXIS_Y:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400404 return value + mYOffset;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800405 }
406 return value;
407}
408
409const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
410 size_t pointerIndex, size_t historicalIndex) const {
411 return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
412}
413
414float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
415 size_t historicalIndex) const {
416 return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
417}
418
419float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
420 size_t historicalIndex) const {
421 float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
422 switch (axis) {
Jeff Brownebbd5d12011-02-17 13:01:34 -0800423 case AMOTION_EVENT_AXIS_X:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400424 return value + mXOffset;
Jeff Brownebbd5d12011-02-17 13:01:34 -0800425 case AMOTION_EVENT_AXIS_Y:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400426 return value + mYOffset;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800427 }
428 return value;
429}
430
Jeff Brown2ed24622011-03-14 19:39:54 -0700431ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700432 size_t pointerCount = mPointerProperties.size();
Jeff Brown2ed24622011-03-14 19:39:54 -0700433 for (size_t i = 0; i < pointerCount; i++) {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700434 if (mPointerProperties.itemAt(i).id == pointerId) {
Jeff Brown2ed24622011-03-14 19:39:54 -0700435 return i;
436 }
437 }
438 return -1;
439}
440
Jeff Brown46b9ac02010-04-22 18:58:52 -0700441void MotionEvent::offsetLocation(float xOffset, float yOffset) {
Jeff Brown5c225b12010-06-16 01:53:36 -0700442 mXOffset += xOffset;
443 mYOffset += yOffset;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700444}
445
Jeff Brown91c69ab2011-02-14 17:03:18 -0800446void MotionEvent::scale(float scaleFactor) {
447 mXOffset *= scaleFactor;
448 mYOffset *= scaleFactor;
449 mXPrecision *= scaleFactor;
450 mYPrecision *= scaleFactor;
451
452 size_t numSamples = mSamplePointerCoords.size();
453 for (size_t i = 0; i < numSamples; i++) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400454 mSamplePointerCoords.editItemAt(i).scale(scaleFactor);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800455 }
456}
457
458#ifdef HAVE_ANDROID_OS
459static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
460 // Construct and transform a vector oriented at the specified clockwise angle from vertical.
461 // Coordinate system: down is increasing Y, right is increasing X.
462 SkPoint vector;
463 vector.fX = SkFloatToScalar(sinf(angleRadians));
464 vector.fY = SkFloatToScalar(-cosf(angleRadians));
465 matrix->mapVectors(& vector, 1);
466
467 // Derive the transformed vector's clockwise angle from vertical.
468 float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY));
469 if (result < - M_PI_2) {
470 result += M_PI;
471 } else if (result > M_PI_2) {
472 result -= M_PI;
473 }
474 return result;
475}
476
477void MotionEvent::transform(const SkMatrix* matrix) {
478 float oldXOffset = mXOffset;
479 float oldYOffset = mYOffset;
480
481 // The tricky part of this implementation is to preserve the value of
482 // rawX and rawY. So we apply the transformation to the first point
483 // then derive an appropriate new X/Y offset that will preserve rawX and rawY.
484 SkPoint point;
485 float rawX = getRawX(0);
486 float rawY = getRawY(0);
487 matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset),
488 & point);
489 float newX = SkScalarToFloat(point.fX);
490 float newY = SkScalarToFloat(point.fY);
491 float newXOffset = newX - rawX;
492 float newYOffset = newY - rawY;
493
494 mXOffset = newXOffset;
495 mYOffset = newYOffset;
496
497 // Apply the transformation to all samples.
498 size_t numSamples = mSamplePointerCoords.size();
499 for (size_t i = 0; i < numSamples; i++) {
500 PointerCoords& c = mSamplePointerCoords.editItemAt(i);
Jeff Brownbe1aa822011-07-27 16:04:54 -0700501 float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
502 float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
503 matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point);
504 c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset);
505 c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800506
Jeff Brownbe1aa822011-07-27 16:04:54 -0700507 float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
508 c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation));
Jeff Brown91c69ab2011-02-14 17:03:18 -0800509 }
510}
511
512status_t MotionEvent::readFromParcel(Parcel* parcel) {
513 size_t pointerCount = parcel->readInt32();
514 size_t sampleCount = parcel->readInt32();
515 if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) {
516 return BAD_VALUE;
517 }
518
519 mDeviceId = parcel->readInt32();
520 mSource = parcel->readInt32();
521 mAction = parcel->readInt32();
522 mFlags = parcel->readInt32();
523 mEdgeFlags = parcel->readInt32();
524 mMetaState = parcel->readInt32();
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700525 mButtonState = parcel->readInt32();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800526 mXOffset = parcel->readFloat();
527 mYOffset = parcel->readFloat();
528 mXPrecision = parcel->readFloat();
529 mYPrecision = parcel->readFloat();
530 mDownTime = parcel->readInt64();
531
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700532 mPointerProperties.clear();
533 mPointerProperties.setCapacity(pointerCount);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800534 mSampleEventTimes.clear();
535 mSampleEventTimes.setCapacity(sampleCount);
536 mSamplePointerCoords.clear();
537 mSamplePointerCoords.setCapacity(sampleCount * pointerCount);
538
539 for (size_t i = 0; i < pointerCount; i++) {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700540 mPointerProperties.push();
541 PointerProperties& properties = mPointerProperties.editTop();
542 properties.id = parcel->readInt32();
543 properties.toolType = parcel->readInt32();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800544 }
545
546 while (sampleCount-- > 0) {
547 mSampleEventTimes.push(parcel->readInt64());
548 for (size_t i = 0; i < pointerCount; i++) {
549 mSamplePointerCoords.push();
550 status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel);
Jeff Brownebbd5d12011-02-17 13:01:34 -0800551 if (status) {
Jeff Brown91c69ab2011-02-14 17:03:18 -0800552 return status;
553 }
554 }
555 }
556 return OK;
557}
558
559status_t MotionEvent::writeToParcel(Parcel* parcel) const {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700560 size_t pointerCount = mPointerProperties.size();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800561 size_t sampleCount = mSampleEventTimes.size();
562
563 parcel->writeInt32(pointerCount);
564 parcel->writeInt32(sampleCount);
565
566 parcel->writeInt32(mDeviceId);
567 parcel->writeInt32(mSource);
568 parcel->writeInt32(mAction);
569 parcel->writeInt32(mFlags);
570 parcel->writeInt32(mEdgeFlags);
571 parcel->writeInt32(mMetaState);
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700572 parcel->writeInt32(mButtonState);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800573 parcel->writeFloat(mXOffset);
574 parcel->writeFloat(mYOffset);
575 parcel->writeFloat(mXPrecision);
576 parcel->writeFloat(mYPrecision);
577 parcel->writeInt64(mDownTime);
578
579 for (size_t i = 0; i < pointerCount; i++) {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700580 const PointerProperties& properties = mPointerProperties.itemAt(i);
581 parcel->writeInt32(properties.id);
582 parcel->writeInt32(properties.toolType);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800583 }
584
585 const PointerCoords* pc = mSamplePointerCoords.array();
586 for (size_t h = 0; h < sampleCount; h++) {
587 parcel->writeInt64(mSampleEventTimes.itemAt(h));
588 for (size_t i = 0; i < pointerCount; i++) {
589 status_t status = (pc++)->writeToParcel(parcel);
Jeff Brownebbd5d12011-02-17 13:01:34 -0800590 if (status) {
Jeff Brown91c69ab2011-02-14 17:03:18 -0800591 return status;
592 }
593 }
594 }
595 return OK;
596}
597#endif
598
Jeff Brown56194eb2011-03-02 19:23:13 -0800599bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
600 if (source & AINPUT_SOURCE_CLASS_POINTER) {
601 // Specifically excludes HOVER_MOVE and SCROLL.
602 switch (action & AMOTION_EVENT_ACTION_MASK) {
603 case AMOTION_EVENT_ACTION_DOWN:
604 case AMOTION_EVENT_ACTION_MOVE:
605 case AMOTION_EVENT_ACTION_UP:
606 case AMOTION_EVENT_ACTION_POINTER_DOWN:
607 case AMOTION_EVENT_ACTION_POINTER_UP:
608 case AMOTION_EVENT_ACTION_CANCEL:
609 case AMOTION_EVENT_ACTION_OUTSIDE:
610 return true;
611 }
612 }
613 return false;
614}
615
Jeff Brown91c69ab2011-02-14 17:03:18 -0800616
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700617// --- PooledInputEventFactory ---
618
619PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) :
620 mMaxPoolSize(maxPoolSize) {
621}
622
623PooledInputEventFactory::~PooledInputEventFactory() {
624 for (size_t i = 0; i < mKeyEventPool.size(); i++) {
625 delete mKeyEventPool.itemAt(i);
626 }
627 for (size_t i = 0; i < mMotionEventPool.size(); i++) {
628 delete mMotionEventPool.itemAt(i);
629 }
630}
631
632KeyEvent* PooledInputEventFactory::createKeyEvent() {
633 if (!mKeyEventPool.isEmpty()) {
634 KeyEvent* event = mKeyEventPool.top();
635 mKeyEventPool.pop();
636 return event;
637 }
638 return new KeyEvent();
639}
640
641MotionEvent* PooledInputEventFactory::createMotionEvent() {
642 if (!mMotionEventPool.isEmpty()) {
643 MotionEvent* event = mMotionEventPool.top();
644 mMotionEventPool.pop();
645 return event;
646 }
647 return new MotionEvent();
648}
649
650void PooledInputEventFactory::recycle(InputEvent* event) {
651 switch (event->getType()) {
652 case AINPUT_EVENT_TYPE_KEY:
653 if (mKeyEventPool.size() < mMaxPoolSize) {
654 mKeyEventPool.push(static_cast<KeyEvent*>(event));
655 return;
656 }
657 break;
658 case AINPUT_EVENT_TYPE_MOTION:
659 if (mMotionEventPool.size() < mMaxPoolSize) {
660 mMotionEventPool.push(static_cast<MotionEvent*>(event));
661 return;
662 }
663 break;
664 }
665 delete event;
666}
667
668
Jeff Brownace13b12011-03-09 17:39:48 -0800669// --- VelocityTracker ---
670
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700671const uint32_t VelocityTracker::DEFAULT_DEGREE;
672const nsecs_t VelocityTracker::DEFAULT_HORIZON;
Jeff Brown19c97d462011-06-01 12:33:19 -0700673const uint32_t VelocityTracker::HISTORY_SIZE;
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700674
675static inline float vectorDot(const float* a, const float* b, uint32_t m) {
676 float r = 0;
677 while (m--) {
678 r += *(a++) * *(b++);
679 }
680 return r;
681}
682
683static inline float vectorNorm(const float* a, uint32_t m) {
684 float r = 0;
685 while (m--) {
686 float t = *(a++);
687 r += t * t;
688 }
689 return sqrtf(r);
690}
691
692#if DEBUG_LEAST_SQUARES || DEBUG_VELOCITY
693static String8 vectorToString(const float* a, uint32_t m) {
694 String8 str;
695 str.append("[");
696 while (m--) {
697 str.appendFormat(" %f", *(a++));
698 if (m) {
699 str.append(",");
700 }
701 }
702 str.append(" ]");
703 return str;
704}
705
706static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
707 String8 str;
708 str.append("[");
709 for (size_t i = 0; i < m; i++) {
710 if (i) {
711 str.append(",");
712 }
713 str.append(" [");
714 for (size_t j = 0; j < n; j++) {
715 if (j) {
716 str.append(",");
717 }
718 str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]);
719 }
720 str.append(" ]");
721 }
722 str.append(" ]");
723 return str;
724}
725#endif
Jeff Brown19c97d462011-06-01 12:33:19 -0700726
Jeff Brownace13b12011-03-09 17:39:48 -0800727VelocityTracker::VelocityTracker() {
728 clear();
729}
730
731void VelocityTracker::clear() {
732 mIndex = 0;
733 mMovements[0].idBits.clear();
Jeff Brown2ed24622011-03-14 19:39:54 -0700734 mActivePointerId = -1;
735}
736
737void VelocityTracker::clearPointers(BitSet32 idBits) {
738 BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
739 mMovements[mIndex].idBits = remainingIdBits;
740
741 if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) {
742 mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
743 }
Jeff Brownace13b12011-03-09 17:39:48 -0800744}
745
746void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
747 if (++mIndex == HISTORY_SIZE) {
748 mIndex = 0;
749 }
Jeff Brown2ed24622011-03-14 19:39:54 -0700750
751 while (idBits.count() > MAX_POINTERS) {
Jeff Brownbe1aa822011-07-27 16:04:54 -0700752 idBits.clearLastMarkedBit();
Jeff Brown2ed24622011-03-14 19:39:54 -0700753 }
754
Jeff Brownace13b12011-03-09 17:39:48 -0800755 Movement& movement = mMovements[mIndex];
756 movement.eventTime = eventTime;
757 movement.idBits = idBits;
758 uint32_t count = idBits.count();
759 for (uint32_t i = 0; i < count; i++) {
760 movement.positions[i] = positions[i];
761 }
762
Jeff Brown2ed24622011-03-14 19:39:54 -0700763 if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
764 mActivePointerId = count != 0 ? idBits.firstMarkedBit() : -1;
765 }
766
Jeff Brownace13b12011-03-09 17:39:48 -0800767#if DEBUG_VELOCITY
Steve Block5baa3a62011-12-20 16:23:08 +0000768 ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d",
Jeff Brown2ed24622011-03-14 19:39:54 -0700769 eventTime, idBits.value, mActivePointerId);
Jeff Brownace13b12011-03-09 17:39:48 -0800770 for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
771 uint32_t id = iterBits.firstMarkedBit();
772 uint32_t index = idBits.getIndexOfBit(id);
773 iterBits.clearBit(id);
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700774 Estimator estimator;
775 getEstimator(id, DEFAULT_DEGREE, DEFAULT_HORIZON, &estimator);
Steve Block5baa3a62011-12-20 16:23:08 +0000776 ALOGD(" %d: position (%0.3f, %0.3f), "
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700777 "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
778 id, positions[index].x, positions[index].y,
779 int(estimator.degree),
780 vectorToString(estimator.xCoeff, estimator.degree).string(),
781 vectorToString(estimator.yCoeff, estimator.degree).string(),
782 estimator.confidence);
Jeff Brownace13b12011-03-09 17:39:48 -0800783 }
784#endif
785}
786
Jeff Brown2ed24622011-03-14 19:39:54 -0700787void VelocityTracker::addMovement(const MotionEvent* event) {
788 int32_t actionMasked = event->getActionMasked();
789
790 switch (actionMasked) {
791 case AMOTION_EVENT_ACTION_DOWN:
Jeff Brown581761d2011-09-09 15:39:35 -0700792 case AMOTION_EVENT_ACTION_HOVER_ENTER:
Jeff Brown2ed24622011-03-14 19:39:54 -0700793 // Clear all pointers on down before adding the new movement.
794 clear();
795 break;
796 case AMOTION_EVENT_ACTION_POINTER_DOWN: {
797 // Start a new movement trace for a pointer that just went down.
798 // We do this on down instead of on up because the client may want to query the
799 // final velocity for a pointer that just went up.
800 BitSet32 downIdBits;
Jeff Brownbe1aa822011-07-27 16:04:54 -0700801 downIdBits.markBit(event->getPointerId(event->getActionIndex()));
Jeff Brown2ed24622011-03-14 19:39:54 -0700802 clearPointers(downIdBits);
803 break;
804 }
Jeff Brown581761d2011-09-09 15:39:35 -0700805 case AMOTION_EVENT_ACTION_MOVE:
806 case AMOTION_EVENT_ACTION_HOVER_MOVE:
807 break;
808 default:
809 // Ignore all other actions because they do not convey any new information about
Jeff Brown2ed24622011-03-14 19:39:54 -0700810 // pointer movement. We also want to preserve the last known velocity of the pointers.
811 // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
812 // of the pointers that went up. ACTION_POINTER_UP does include the new position of
813 // pointers that remained down but we will also receive an ACTION_MOVE with this
814 // information if any of them actually moved. Since we don't know how many pointers
815 // will be going up at once it makes sense to just wait for the following ACTION_MOVE
816 // before adding the movement.
817 return;
818 }
819
820 size_t pointerCount = event->getPointerCount();
821 if (pointerCount > MAX_POINTERS) {
822 pointerCount = MAX_POINTERS;
823 }
824
825 BitSet32 idBits;
826 for (size_t i = 0; i < pointerCount; i++) {
827 idBits.markBit(event->getPointerId(i));
828 }
829
830 nsecs_t eventTime;
831 Position positions[pointerCount];
832
833 size_t historySize = event->getHistorySize();
834 for (size_t h = 0; h < historySize; h++) {
835 eventTime = event->getHistoricalEventTime(h);
836 for (size_t i = 0; i < pointerCount; i++) {
837 positions[i].x = event->getHistoricalX(i, h);
838 positions[i].y = event->getHistoricalY(i, h);
839 }
840 addMovement(eventTime, idBits, positions);
841 }
842
843 eventTime = event->getEventTime();
844 for (size_t i = 0; i < pointerCount; i++) {
845 positions[i].x = event->getX(i);
846 positions[i].y = event->getY(i);
847 }
848 addMovement(eventTime, idBits, positions);
849}
850
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700851/**
852 * Solves a linear least squares problem to obtain a N degree polynomial that fits
853 * the specified input data as nearly as possible.
854 *
855 * Returns true if a solution is found, false otherwise.
856 *
857 * The input consists of two vectors of data points X and Y with indices 0..m-1.
858 * The output is a vector B with indices 0..n-1 that describes a polynomial
859 * 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))
860 * for all i between 0 and m-1 is minimized.
861 *
862 * That is to say, the function that generated the input data can be approximated
863 * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n.
864 *
865 * The coefficient of determination (R^2) is also returned to describe the goodness
866 * of fit of the model for the given data. It is a value between 0 and 1, where 1
867 * indicates perfect correspondence.
868 *
869 * This function first expands the X vector to a m by n matrix A such that
870 * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n.
871 *
872 * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q
873 * and an m by n upper triangular matrix R. Because R is upper triangular (lower
874 * part is all zeroes), we can simplify the decomposition into an m by n matrix
875 * Q1 and a n by n matrix R1 such that A = Q1 R1.
876 *
877 * Finally we solve the system of linear equations given by R1 B = (Qtranspose Y)
878 * to find B.
879 *
880 * For efficiency, we lay out A and Q column-wise in memory because we frequently
881 * operate on the column vectors. Conversely, we lay out R row-wise.
882 *
883 * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares
884 * http://en.wikipedia.org/wiki/Gram-Schmidt
885 */
886static bool solveLeastSquares(const float* x, const float* y, uint32_t m, uint32_t n,
887 float* outB, float* outDet) {
888#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000889 ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s", int(m), int(n),
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700890 vectorToString(x, m).string(), vectorToString(y, m).string());
891#endif
892
893 // Expand the X vector to a matrix A.
894 float a[n][m]; // column-major order
895 for (uint32_t h = 0; h < m; h++) {
896 a[0][h] = 1;
897 for (uint32_t i = 1; i < n; i++) {
898 a[i][h] = a[i - 1][h] * x[h];
899 }
900 }
901#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000902 ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700903#endif
904
905 // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
906 float q[n][m]; // orthonormal basis, column-major order
907 float r[n][n]; // upper triangular matrix, row-major order
908 for (uint32_t j = 0; j < n; j++) {
909 for (uint32_t h = 0; h < m; h++) {
910 q[j][h] = a[j][h];
911 }
912 for (uint32_t i = 0; i < j; i++) {
913 float dot = vectorDot(&q[j][0], &q[i][0], m);
914 for (uint32_t h = 0; h < m; h++) {
915 q[j][h] -= dot * q[i][h];
916 }
917 }
918
919 float norm = vectorNorm(&q[j][0], m);
920 if (norm < 0.000001f) {
921 // vectors are linearly dependent or zero so no solution
922#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000923 ALOGD(" - no solution, norm=%f", norm);
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700924#endif
925 return false;
926 }
927
928 float invNorm = 1.0f / norm;
929 for (uint32_t h = 0; h < m; h++) {
930 q[j][h] *= invNorm;
931 }
932 for (uint32_t i = 0; i < n; i++) {
933 r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m);
934 }
935 }
936#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000937 ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string());
938 ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700939
940 // calculate QR, if we factored A correctly then QR should equal A
941 float qr[n][m];
942 for (uint32_t h = 0; h < m; h++) {
943 for (uint32_t i = 0; i < n; i++) {
944 qr[i][h] = 0;
945 for (uint32_t j = 0; j < n; j++) {
946 qr[i][h] += q[j][h] * r[j][i];
947 }
948 }
949 }
Steve Block5baa3a62011-12-20 16:23:08 +0000950 ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700951#endif
952
953 // Solve R B = Qt Y to find B. This is easy because R is upper triangular.
954 // We just work from bottom-right to top-left calculating B's coefficients.
955 for (uint32_t i = n; i-- != 0; ) {
956 outB[i] = vectorDot(&q[i][0], y, m);
957 for (uint32_t j = n - 1; j > i; j--) {
958 outB[i] -= r[i][j] * outB[j];
959 }
960 outB[i] /= r[i][i];
961 }
962#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000963 ALOGD(" - b=%s", vectorToString(outB, n).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700964#endif
965
966 // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
967 // SSerr is the residual sum of squares (squared variance of the error),
968 // and SStot is the total sum of squares (squared variance of the data).
969 float ymean = 0;
970 for (uint32_t h = 0; h < m; h++) {
971 ymean += y[h];
972 }
973 ymean /= m;
974
975 float sserr = 0;
976 float sstot = 0;
977 for (uint32_t h = 0; h < m; h++) {
978 float err = y[h] - outB[0];
979 float term = 1;
980 for (uint32_t i = 1; i < n; i++) {
981 term *= x[h];
982 err -= term * outB[i];
983 }
984 sserr += err * err;
985 float var = y[h] - ymean;
986 sstot += var * var;
987 }
988 *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
989#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000990 ALOGD(" - sserr=%f", sserr);
991 ALOGD(" - sstot=%f", sstot);
992 ALOGD(" - det=%f", *outDet);
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700993#endif
994 return true;
995}
996
Jeff Brownace13b12011-03-09 17:39:48 -0800997bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700998 Estimator estimator;
999 if (getEstimator(id, DEFAULT_DEGREE, DEFAULT_HORIZON, &estimator)) {
1000 if (estimator.degree >= 1) {
1001 *outVx = estimator.xCoeff[1];
1002 *outVy = estimator.yCoeff[1];
1003 return true;
1004 }
1005 }
Jeff Brownb0c71eb2011-09-16 21:40:49 -07001006 *outVx = 0;
1007 *outVy = 0;
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001008 return false;
1009}
1010
1011bool VelocityTracker::getEstimator(uint32_t id, uint32_t degree, nsecs_t horizon,
1012 Estimator* outEstimator) const {
1013 outEstimator->clear();
1014
1015 // Iterate over movement samples in reverse time order and collect samples.
1016 float x[HISTORY_SIZE];
1017 float y[HISTORY_SIZE];
1018 float time[HISTORY_SIZE];
1019 uint32_t m = 0;
1020 uint32_t index = mIndex;
Jeff Brownace13b12011-03-09 17:39:48 -08001021 const Movement& newestMovement = mMovements[mIndex];
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001022 do {
1023 const Movement& movement = mMovements[index];
1024 if (!movement.idBits.hasBit(id)) {
1025 break;
1026 }
Jeff Brown2352b972011-04-12 22:39:53 -07001027
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001028 nsecs_t age = newestMovement.eventTime - movement.eventTime;
1029 if (age > horizon) {
1030 break;
1031 }
Jeff Brown581761d2011-09-09 15:39:35 -07001032
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001033 const Position& position = movement.getPosition(id);
1034 x[m] = position.x;
1035 y[m] = position.y;
1036 time[m] = -age * 0.000000001f;
1037 index = (index == 0 ? HISTORY_SIZE : index) - 1;
1038 } while (++m < HISTORY_SIZE);
Jeff Brown581761d2011-09-09 15:39:35 -07001039
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001040 if (m == 0) {
1041 return false; // no data
1042 }
Jeff Brownace13b12011-03-09 17:39:48 -08001043
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001044 // Calculate a least squares polynomial fit.
1045 if (degree > Estimator::MAX_DEGREE) {
1046 degree = Estimator::MAX_DEGREE;
1047 }
1048 if (degree > m - 1) {
1049 degree = m - 1;
1050 }
1051 if (degree >= 1) {
1052 float xdet, ydet;
1053 uint32_t n = degree + 1;
1054 if (solveLeastSquares(time, x, m, n, outEstimator->xCoeff, &xdet)
1055 && solveLeastSquares(time, y, m, n, outEstimator->yCoeff, &ydet)) {
1056 outEstimator->degree = degree;
1057 outEstimator->confidence = xdet * ydet;
1058#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +00001059 ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001060 int(outEstimator->degree),
1061 vectorToString(outEstimator->xCoeff, n).string(),
1062 vectorToString(outEstimator->yCoeff, n).string(),
1063 outEstimator->confidence);
1064#endif
Jeff Brownace13b12011-03-09 17:39:48 -08001065 return true;
1066 }
1067 }
1068
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001069 // No velocity data available for this pointer, but we do have its current position.
1070 outEstimator->xCoeff[0] = x[0];
1071 outEstimator->yCoeff[0] = y[0];
1072 outEstimator->degree = 0;
1073 outEstimator->confidence = 1;
1074 return true;
Jeff Brownace13b12011-03-09 17:39:48 -08001075}
1076
1077
Jeff Brown19c97d462011-06-01 12:33:19 -07001078// --- VelocityControl ---
1079
1080const nsecs_t VelocityControl::STOP_TIME;
1081
1082VelocityControl::VelocityControl() {
1083 reset();
1084}
1085
1086void VelocityControl::setParameters(const VelocityControlParameters& parameters) {
1087 mParameters = parameters;
1088 reset();
1089}
1090
1091void VelocityControl::reset() {
1092 mLastMovementTime = LLONG_MIN;
1093 mRawPosition.x = 0;
1094 mRawPosition.y = 0;
1095 mVelocityTracker.clear();
1096}
1097
1098void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
1099 if ((deltaX && *deltaX) || (deltaY && *deltaY)) {
1100 if (eventTime >= mLastMovementTime + STOP_TIME) {
1101#if DEBUG_ACCELERATION
Steve Block5baa3a62011-12-20 16:23:08 +00001102 ALOGD("VelocityControl: stopped, last movement was %0.3fms ago",
Jeff Brown19c97d462011-06-01 12:33:19 -07001103 (eventTime - mLastMovementTime) * 0.000001f);
1104#endif
1105 reset();
1106 }
1107
1108 mLastMovementTime = eventTime;
1109 if (deltaX) {
1110 mRawPosition.x += *deltaX;
1111 }
1112 if (deltaY) {
1113 mRawPosition.y += *deltaY;
1114 }
1115 mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition);
1116
1117 float vx, vy;
1118 float scale = mParameters.scale;
1119 if (mVelocityTracker.getVelocity(0, &vx, &vy)) {
1120 float speed = hypotf(vx, vy) * scale;
1121 if (speed >= mParameters.highThreshold) {
1122 // Apply full acceleration above the high speed threshold.
1123 scale *= mParameters.acceleration;
1124 } else if (speed > mParameters.lowThreshold) {
1125 // Linearly interpolate the acceleration to apply between the low and high
1126 // speed thresholds.
1127 scale *= 1 + (speed - mParameters.lowThreshold)
1128 / (mParameters.highThreshold - mParameters.lowThreshold)
1129 * (mParameters.acceleration - 1);
1130 }
1131
1132#if DEBUG_ACCELERATION
Steve Block5baa3a62011-12-20 16:23:08 +00001133 ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
Jeff Brown19c97d462011-06-01 12:33:19 -07001134 "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
1135 mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
1136 mParameters.acceleration,
1137 vx, vy, speed, scale / mParameters.scale);
1138#endif
1139 } else {
1140#if DEBUG_ACCELERATION
Steve Block5baa3a62011-12-20 16:23:08 +00001141 ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
Jeff Brown19c97d462011-06-01 12:33:19 -07001142 mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
1143 mParameters.acceleration);
1144#endif
1145 }
1146
1147 if (deltaX) {
1148 *deltaX *= scale;
1149 }
1150 if (deltaY) {
1151 *deltaY *= scale;
1152 }
1153 }
1154}
1155
Jeff Brown46b9ac02010-04-22 18:58:52 -07001156} // namespace android