blob: 1617a3f36dc98dd531390a2fcb866614928eecc2 [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 Brown46b9ac0a2010-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 Brown46b9ac0a2010-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 Brown46b9ac0a2010-04-22 18:58:52 -070051namespace android {
52
Jeff Brown47e6b1b2010-11-29 17:37:49 -080053// --- InputEvent ---
Jeff Brown46b9ac0a2010-04-22 18:58:52 -070054
Jeff Brownc5ed5912010-07-14 18:48:53 -070055void InputEvent::initialize(int32_t deviceId, int32_t source) {
Jeff Brown46b9ac0a2010-04-22 18:58:52 -070056 mDeviceId = deviceId;
Jeff Brownc5ed5912010-07-14 18:48:53 -070057 mSource = source;
Jeff Brown46b9ac0a2010-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 Brown46b9ac0a2010-04-22 18:58:52 -070066
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070067bool KeyEvent::hasDefaultAction(int32_t keyCode) {
68 switch (keyCode) {
Jeff Brownfd0358292010-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 Brownfd0358292010-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 Brownfd0358292010-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 Brownfd0358292010-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 Brownfd0358292010-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 Brownfd0358292010-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 Brownfd0358292010-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 Brownfd0358292010-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 Brown46b9ac0a2010-04-22 18:58:52 -0700139void KeyEvent::initialize(
140 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700141 int32_t source,
Jeff Brown46b9ac0a2010-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 Brown46b9ac0a2010-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 Brown91c69ab2011-02-14 17:03:18 -0800232#ifdef HAVE_ANDROID_OS
233status_t PointerCoords::readFromParcel(Parcel* parcel) {
Jeff Brown6f2fba42011-02-19 01:08:02 -0800234 bits = parcel->readInt64();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800235
Jeff Brown6f2fba42011-02-19 01:08:02 -0800236 uint32_t count = __builtin_popcountll(bits);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800237 if (count > MAX_AXES) {
238 return BAD_VALUE;
239 }
240
241 for (uint32_t i = 0; i < count; i++) {
242 values[i] = parcel->readInt32();
243 }
244 return OK;
245}
246
247status_t PointerCoords::writeToParcel(Parcel* parcel) const {
Jeff Brown6f2fba42011-02-19 01:08:02 -0800248 parcel->writeInt64(bits);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800249
Jeff Brown6f2fba42011-02-19 01:08:02 -0800250 uint32_t count = __builtin_popcountll(bits);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800251 for (uint32_t i = 0; i < count; i++) {
252 parcel->writeInt32(values[i]);
253 }
254 return OK;
255}
256#endif
257
258void PointerCoords::tooManyAxes(int axis) {
Steve Block8564c8d2012-01-05 23:22:43 +0000259 ALOGW("Could not set value for axis %d because the PointerCoords structure is full and "
Jeff Brown91c69ab2011-02-14 17:03:18 -0800260 "cannot contain more than %d axis values.", axis, int(MAX_AXES));
261}
262
Jeff Brownace13b12011-03-09 17:39:48 -0800263bool PointerCoords::operator==(const PointerCoords& other) const {
264 if (bits != other.bits) {
265 return false;
266 }
267 uint32_t count = __builtin_popcountll(bits);
268 for (uint32_t i = 0; i < count; i++) {
269 if (values[i] != other.values[i]) {
270 return false;
271 }
272 }
273 return true;
274}
275
276void PointerCoords::copyFrom(const PointerCoords& other) {
277 bits = other.bits;
278 uint32_t count = __builtin_popcountll(bits);
279 for (uint32_t i = 0; i < count; i++) {
280 values[i] = other.values[i];
281 }
282}
283
Jeff Brown91c69ab2011-02-14 17:03:18 -0800284
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700285// --- PointerProperties ---
286
287bool PointerProperties::operator==(const PointerProperties& other) const {
288 return id == other.id
289 && toolType == other.toolType;
290}
291
292void PointerProperties::copyFrom(const PointerProperties& other) {
293 id = other.id;
294 toolType = other.toolType;
295}
296
297
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800298// --- MotionEvent ---
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700299
300void MotionEvent::initialize(
301 int32_t deviceId,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700302 int32_t source,
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700303 int32_t action,
Jeff Brown85a31762010-09-01 17:01:00 -0700304 int32_t flags,
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700305 int32_t edgeFlags,
306 int32_t metaState,
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700307 int32_t buttonState,
Jeff Brown5c225b12010-06-16 01:53:36 -0700308 float xOffset,
309 float yOffset,
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700310 float xPrecision,
311 float yPrecision,
312 nsecs_t downTime,
313 nsecs_t eventTime,
314 size_t pointerCount,
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700315 const PointerProperties* pointerProperties,
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700316 const PointerCoords* pointerCoords) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700317 InputEvent::initialize(deviceId, source);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700318 mAction = action;
Jeff Brown85a31762010-09-01 17:01:00 -0700319 mFlags = flags;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700320 mEdgeFlags = edgeFlags;
321 mMetaState = metaState;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700322 mButtonState = buttonState;
Jeff Brown5c225b12010-06-16 01:53:36 -0700323 mXOffset = xOffset;
324 mYOffset = yOffset;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700325 mXPrecision = xPrecision;
326 mYPrecision = yPrecision;
327 mDownTime = downTime;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700328 mPointerProperties.clear();
329 mPointerProperties.appendArray(pointerProperties, pointerCount);
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700330 mSampleEventTimes.clear();
331 mSamplePointerCoords.clear();
332 addSample(eventTime, pointerCoords);
333}
334
Jeff Brown91c69ab2011-02-14 17:03:18 -0800335void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
336 InputEvent::initialize(other->mDeviceId, other->mSource);
337 mAction = other->mAction;
338 mFlags = other->mFlags;
339 mEdgeFlags = other->mEdgeFlags;
340 mMetaState = other->mMetaState;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700341 mButtonState = other->mButtonState;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800342 mXOffset = other->mXOffset;
343 mYOffset = other->mYOffset;
344 mXPrecision = other->mXPrecision;
345 mYPrecision = other->mYPrecision;
346 mDownTime = other->mDownTime;
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700347 mPointerProperties = other->mPointerProperties;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800348
349 if (keepHistory) {
350 mSampleEventTimes = other->mSampleEventTimes;
351 mSamplePointerCoords = other->mSamplePointerCoords;
352 } else {
353 mSampleEventTimes.clear();
354 mSampleEventTimes.push(other->getEventTime());
355 mSamplePointerCoords.clear();
356 size_t pointerCount = other->getPointerCount();
357 size_t historySize = other->getHistorySize();
358 mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array()
359 + (historySize * pointerCount), pointerCount);
360 }
361}
362
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700363void MotionEvent::addSample(
364 int64_t eventTime,
365 const PointerCoords* pointerCoords) {
366 mSampleEventTimes.push(eventTime);
367 mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
368}
369
Jeff Brown91c69ab2011-02-14 17:03:18 -0800370const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
371 return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
372}
373
374float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
375 return getRawPointerCoords(pointerIndex)->getAxisValue(axis);
376}
377
378float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
379 float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
380 switch (axis) {
Jeff Brownebbd5d12011-02-17 13:01:34 -0800381 case AMOTION_EVENT_AXIS_X:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400382 return value + mXOffset;
Jeff Brownebbd5d12011-02-17 13:01:34 -0800383 case AMOTION_EVENT_AXIS_Y:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400384 return value + mYOffset;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800385 }
386 return value;
387}
388
389const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
390 size_t pointerIndex, size_t historicalIndex) const {
391 return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
392}
393
394float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
395 size_t historicalIndex) const {
396 return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
397}
398
399float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
400 size_t historicalIndex) const {
401 float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
402 switch (axis) {
Jeff Brownebbd5d12011-02-17 13:01:34 -0800403 case AMOTION_EVENT_AXIS_X:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400404 return value + mXOffset;
Jeff Brownebbd5d12011-02-17 13:01:34 -0800405 case AMOTION_EVENT_AXIS_Y:
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400406 return value + mYOffset;
Jeff Brown91c69ab2011-02-14 17:03:18 -0800407 }
408 return value;
409}
410
Jeff Brown2ed24622011-03-14 19:39:54 -0700411ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700412 size_t pointerCount = mPointerProperties.size();
Jeff Brown2ed24622011-03-14 19:39:54 -0700413 for (size_t i = 0; i < pointerCount; i++) {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700414 if (mPointerProperties.itemAt(i).id == pointerId) {
Jeff Brown2ed24622011-03-14 19:39:54 -0700415 return i;
416 }
417 }
418 return -1;
419}
420
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700421void MotionEvent::offsetLocation(float xOffset, float yOffset) {
Jeff Brown5c225b12010-06-16 01:53:36 -0700422 mXOffset += xOffset;
423 mYOffset += yOffset;
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700424}
425
Jeff Brown91c69ab2011-02-14 17:03:18 -0800426void MotionEvent::scale(float scaleFactor) {
427 mXOffset *= scaleFactor;
428 mYOffset *= scaleFactor;
429 mXPrecision *= scaleFactor;
430 mYPrecision *= scaleFactor;
431
432 size_t numSamples = mSamplePointerCoords.size();
433 for (size_t i = 0; i < numSamples; i++) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400434 mSamplePointerCoords.editItemAt(i).scale(scaleFactor);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800435 }
436}
437
438#ifdef HAVE_ANDROID_OS
439static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
440 // Construct and transform a vector oriented at the specified clockwise angle from vertical.
441 // Coordinate system: down is increasing Y, right is increasing X.
442 SkPoint vector;
443 vector.fX = SkFloatToScalar(sinf(angleRadians));
444 vector.fY = SkFloatToScalar(-cosf(angleRadians));
445 matrix->mapVectors(& vector, 1);
446
447 // Derive the transformed vector's clockwise angle from vertical.
448 float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY));
449 if (result < - M_PI_2) {
450 result += M_PI;
451 } else if (result > M_PI_2) {
452 result -= M_PI;
453 }
454 return result;
455}
456
457void MotionEvent::transform(const SkMatrix* matrix) {
458 float oldXOffset = mXOffset;
459 float oldYOffset = mYOffset;
460
461 // The tricky part of this implementation is to preserve the value of
462 // rawX and rawY. So we apply the transformation to the first point
463 // then derive an appropriate new X/Y offset that will preserve rawX and rawY.
464 SkPoint point;
465 float rawX = getRawX(0);
466 float rawY = getRawY(0);
467 matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset),
468 & point);
469 float newX = SkScalarToFloat(point.fX);
470 float newY = SkScalarToFloat(point.fY);
471 float newXOffset = newX - rawX;
472 float newYOffset = newY - rawY;
473
474 mXOffset = newXOffset;
475 mYOffset = newYOffset;
476
477 // Apply the transformation to all samples.
478 size_t numSamples = mSamplePointerCoords.size();
479 for (size_t i = 0; i < numSamples; i++) {
480 PointerCoords& c = mSamplePointerCoords.editItemAt(i);
Jeff Brownbe1aa822011-07-27 16:04:54 -0700481 float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
482 float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
483 matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point);
484 c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset);
485 c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800486
Jeff Brownbe1aa822011-07-27 16:04:54 -0700487 float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
488 c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation));
Jeff Brown91c69ab2011-02-14 17:03:18 -0800489 }
490}
491
492status_t MotionEvent::readFromParcel(Parcel* parcel) {
493 size_t pointerCount = parcel->readInt32();
494 size_t sampleCount = parcel->readInt32();
495 if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) {
496 return BAD_VALUE;
497 }
498
499 mDeviceId = parcel->readInt32();
500 mSource = parcel->readInt32();
501 mAction = parcel->readInt32();
502 mFlags = parcel->readInt32();
503 mEdgeFlags = parcel->readInt32();
504 mMetaState = parcel->readInt32();
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700505 mButtonState = parcel->readInt32();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800506 mXOffset = parcel->readFloat();
507 mYOffset = parcel->readFloat();
508 mXPrecision = parcel->readFloat();
509 mYPrecision = parcel->readFloat();
510 mDownTime = parcel->readInt64();
511
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700512 mPointerProperties.clear();
513 mPointerProperties.setCapacity(pointerCount);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800514 mSampleEventTimes.clear();
515 mSampleEventTimes.setCapacity(sampleCount);
516 mSamplePointerCoords.clear();
517 mSamplePointerCoords.setCapacity(sampleCount * pointerCount);
518
519 for (size_t i = 0; i < pointerCount; i++) {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700520 mPointerProperties.push();
521 PointerProperties& properties = mPointerProperties.editTop();
522 properties.id = parcel->readInt32();
523 properties.toolType = parcel->readInt32();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800524 }
525
526 while (sampleCount-- > 0) {
527 mSampleEventTimes.push(parcel->readInt64());
528 for (size_t i = 0; i < pointerCount; i++) {
529 mSamplePointerCoords.push();
530 status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel);
Jeff Brownebbd5d12011-02-17 13:01:34 -0800531 if (status) {
Jeff Brown91c69ab2011-02-14 17:03:18 -0800532 return status;
533 }
534 }
535 }
536 return OK;
537}
538
539status_t MotionEvent::writeToParcel(Parcel* parcel) const {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700540 size_t pointerCount = mPointerProperties.size();
Jeff Brown91c69ab2011-02-14 17:03:18 -0800541 size_t sampleCount = mSampleEventTimes.size();
542
543 parcel->writeInt32(pointerCount);
544 parcel->writeInt32(sampleCount);
545
546 parcel->writeInt32(mDeviceId);
547 parcel->writeInt32(mSource);
548 parcel->writeInt32(mAction);
549 parcel->writeInt32(mFlags);
550 parcel->writeInt32(mEdgeFlags);
551 parcel->writeInt32(mMetaState);
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700552 parcel->writeInt32(mButtonState);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800553 parcel->writeFloat(mXOffset);
554 parcel->writeFloat(mYOffset);
555 parcel->writeFloat(mXPrecision);
556 parcel->writeFloat(mYPrecision);
557 parcel->writeInt64(mDownTime);
558
559 for (size_t i = 0; i < pointerCount; i++) {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -0700560 const PointerProperties& properties = mPointerProperties.itemAt(i);
561 parcel->writeInt32(properties.id);
562 parcel->writeInt32(properties.toolType);
Jeff Brown91c69ab2011-02-14 17:03:18 -0800563 }
564
565 const PointerCoords* pc = mSamplePointerCoords.array();
566 for (size_t h = 0; h < sampleCount; h++) {
567 parcel->writeInt64(mSampleEventTimes.itemAt(h));
568 for (size_t i = 0; i < pointerCount; i++) {
569 status_t status = (pc++)->writeToParcel(parcel);
Jeff Brownebbd5d12011-02-17 13:01:34 -0800570 if (status) {
Jeff Brown91c69ab2011-02-14 17:03:18 -0800571 return status;
572 }
573 }
574 }
575 return OK;
576}
577#endif
578
Jeff Brown56194eb2011-03-02 19:23:13 -0800579bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
580 if (source & AINPUT_SOURCE_CLASS_POINTER) {
581 // Specifically excludes HOVER_MOVE and SCROLL.
582 switch (action & AMOTION_EVENT_ACTION_MASK) {
583 case AMOTION_EVENT_ACTION_DOWN:
584 case AMOTION_EVENT_ACTION_MOVE:
585 case AMOTION_EVENT_ACTION_UP:
586 case AMOTION_EVENT_ACTION_POINTER_DOWN:
587 case AMOTION_EVENT_ACTION_POINTER_UP:
588 case AMOTION_EVENT_ACTION_CANCEL:
589 case AMOTION_EVENT_ACTION_OUTSIDE:
590 return true;
591 }
592 }
593 return false;
594}
595
Jeff Brown91c69ab2011-02-14 17:03:18 -0800596
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700597// --- PooledInputEventFactory ---
598
599PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) :
600 mMaxPoolSize(maxPoolSize) {
601}
602
603PooledInputEventFactory::~PooledInputEventFactory() {
604 for (size_t i = 0; i < mKeyEventPool.size(); i++) {
605 delete mKeyEventPool.itemAt(i);
606 }
607 for (size_t i = 0; i < mMotionEventPool.size(); i++) {
608 delete mMotionEventPool.itemAt(i);
609 }
610}
611
612KeyEvent* PooledInputEventFactory::createKeyEvent() {
613 if (!mKeyEventPool.isEmpty()) {
614 KeyEvent* event = mKeyEventPool.top();
615 mKeyEventPool.pop();
616 return event;
617 }
618 return new KeyEvent();
619}
620
621MotionEvent* PooledInputEventFactory::createMotionEvent() {
622 if (!mMotionEventPool.isEmpty()) {
623 MotionEvent* event = mMotionEventPool.top();
624 mMotionEventPool.pop();
625 return event;
626 }
627 return new MotionEvent();
628}
629
630void PooledInputEventFactory::recycle(InputEvent* event) {
631 switch (event->getType()) {
632 case AINPUT_EVENT_TYPE_KEY:
633 if (mKeyEventPool.size() < mMaxPoolSize) {
634 mKeyEventPool.push(static_cast<KeyEvent*>(event));
635 return;
636 }
637 break;
638 case AINPUT_EVENT_TYPE_MOTION:
639 if (mMotionEventPool.size() < mMaxPoolSize) {
640 mMotionEventPool.push(static_cast<MotionEvent*>(event));
641 return;
642 }
643 break;
644 }
645 delete event;
646}
647
648
Jeff Brownace13b12011-03-09 17:39:48 -0800649// --- VelocityTracker ---
650
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700651const uint32_t VelocityTracker::DEFAULT_DEGREE;
652const nsecs_t VelocityTracker::DEFAULT_HORIZON;
Jeff Brown19c97d462011-06-01 12:33:19 -0700653const uint32_t VelocityTracker::HISTORY_SIZE;
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700654
655static inline float vectorDot(const float* a, const float* b, uint32_t m) {
656 float r = 0;
657 while (m--) {
658 r += *(a++) * *(b++);
659 }
660 return r;
661}
662
663static inline float vectorNorm(const float* a, uint32_t m) {
664 float r = 0;
665 while (m--) {
666 float t = *(a++);
667 r += t * t;
668 }
669 return sqrtf(r);
670}
671
672#if DEBUG_LEAST_SQUARES || DEBUG_VELOCITY
673static String8 vectorToString(const float* a, uint32_t m) {
674 String8 str;
675 str.append("[");
676 while (m--) {
677 str.appendFormat(" %f", *(a++));
678 if (m) {
679 str.append(",");
680 }
681 }
682 str.append(" ]");
683 return str;
684}
685
686static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
687 String8 str;
688 str.append("[");
689 for (size_t i = 0; i < m; i++) {
690 if (i) {
691 str.append(",");
692 }
693 str.append(" [");
694 for (size_t j = 0; j < n; j++) {
695 if (j) {
696 str.append(",");
697 }
698 str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]);
699 }
700 str.append(" ]");
701 }
702 str.append(" ]");
703 return str;
704}
705#endif
Jeff Brown19c97d462011-06-01 12:33:19 -0700706
Jeff Brownace13b12011-03-09 17:39:48 -0800707VelocityTracker::VelocityTracker() {
708 clear();
709}
710
711void VelocityTracker::clear() {
712 mIndex = 0;
713 mMovements[0].idBits.clear();
Jeff Brown2ed24622011-03-14 19:39:54 -0700714 mActivePointerId = -1;
715}
716
717void VelocityTracker::clearPointers(BitSet32 idBits) {
718 BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
719 mMovements[mIndex].idBits = remainingIdBits;
720
721 if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) {
722 mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
723 }
Jeff Brownace13b12011-03-09 17:39:48 -0800724}
725
726void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
727 if (++mIndex == HISTORY_SIZE) {
728 mIndex = 0;
729 }
Jeff Brown2ed24622011-03-14 19:39:54 -0700730
731 while (idBits.count() > MAX_POINTERS) {
Jeff Brownbe1aa822011-07-27 16:04:54 -0700732 idBits.clearLastMarkedBit();
Jeff Brown2ed24622011-03-14 19:39:54 -0700733 }
734
Jeff Brownace13b12011-03-09 17:39:48 -0800735 Movement& movement = mMovements[mIndex];
736 movement.eventTime = eventTime;
737 movement.idBits = idBits;
738 uint32_t count = idBits.count();
739 for (uint32_t i = 0; i < count; i++) {
740 movement.positions[i] = positions[i];
741 }
742
Jeff Brown2ed24622011-03-14 19:39:54 -0700743 if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
744 mActivePointerId = count != 0 ? idBits.firstMarkedBit() : -1;
745 }
746
Jeff Brownace13b12011-03-09 17:39:48 -0800747#if DEBUG_VELOCITY
Steve Block5baa3a62011-12-20 16:23:08 +0000748 ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d",
Jeff Brown2ed24622011-03-14 19:39:54 -0700749 eventTime, idBits.value, mActivePointerId);
Jeff Brownace13b12011-03-09 17:39:48 -0800750 for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
751 uint32_t id = iterBits.firstMarkedBit();
752 uint32_t index = idBits.getIndexOfBit(id);
753 iterBits.clearBit(id);
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700754 Estimator estimator;
755 getEstimator(id, DEFAULT_DEGREE, DEFAULT_HORIZON, &estimator);
Steve Block5baa3a62011-12-20 16:23:08 +0000756 ALOGD(" %d: position (%0.3f, %0.3f), "
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700757 "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
758 id, positions[index].x, positions[index].y,
759 int(estimator.degree),
760 vectorToString(estimator.xCoeff, estimator.degree).string(),
761 vectorToString(estimator.yCoeff, estimator.degree).string(),
762 estimator.confidence);
Jeff Brownace13b12011-03-09 17:39:48 -0800763 }
764#endif
765}
766
Jeff Brown2ed24622011-03-14 19:39:54 -0700767void VelocityTracker::addMovement(const MotionEvent* event) {
768 int32_t actionMasked = event->getActionMasked();
769
770 switch (actionMasked) {
771 case AMOTION_EVENT_ACTION_DOWN:
Jeff Brown581761d2011-09-09 15:39:35 -0700772 case AMOTION_EVENT_ACTION_HOVER_ENTER:
Jeff Brown2ed24622011-03-14 19:39:54 -0700773 // Clear all pointers on down before adding the new movement.
774 clear();
775 break;
776 case AMOTION_EVENT_ACTION_POINTER_DOWN: {
777 // Start a new movement trace for a pointer that just went down.
778 // We do this on down instead of on up because the client may want to query the
779 // final velocity for a pointer that just went up.
780 BitSet32 downIdBits;
Jeff Brownbe1aa822011-07-27 16:04:54 -0700781 downIdBits.markBit(event->getPointerId(event->getActionIndex()));
Jeff Brown2ed24622011-03-14 19:39:54 -0700782 clearPointers(downIdBits);
783 break;
784 }
Jeff Brown581761d2011-09-09 15:39:35 -0700785 case AMOTION_EVENT_ACTION_MOVE:
786 case AMOTION_EVENT_ACTION_HOVER_MOVE:
787 break;
788 default:
789 // Ignore all other actions because they do not convey any new information about
Jeff Brown2ed24622011-03-14 19:39:54 -0700790 // pointer movement. We also want to preserve the last known velocity of the pointers.
791 // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
792 // of the pointers that went up. ACTION_POINTER_UP does include the new position of
793 // pointers that remained down but we will also receive an ACTION_MOVE with this
794 // information if any of them actually moved. Since we don't know how many pointers
795 // will be going up at once it makes sense to just wait for the following ACTION_MOVE
796 // before adding the movement.
797 return;
798 }
799
800 size_t pointerCount = event->getPointerCount();
801 if (pointerCount > MAX_POINTERS) {
802 pointerCount = MAX_POINTERS;
803 }
804
805 BitSet32 idBits;
806 for (size_t i = 0; i < pointerCount; i++) {
807 idBits.markBit(event->getPointerId(i));
808 }
809
810 nsecs_t eventTime;
811 Position positions[pointerCount];
812
813 size_t historySize = event->getHistorySize();
814 for (size_t h = 0; h < historySize; h++) {
815 eventTime = event->getHistoricalEventTime(h);
816 for (size_t i = 0; i < pointerCount; i++) {
817 positions[i].x = event->getHistoricalX(i, h);
818 positions[i].y = event->getHistoricalY(i, h);
819 }
820 addMovement(eventTime, idBits, positions);
821 }
822
823 eventTime = event->getEventTime();
824 for (size_t i = 0; i < pointerCount; i++) {
825 positions[i].x = event->getX(i);
826 positions[i].y = event->getY(i);
827 }
828 addMovement(eventTime, idBits, positions);
829}
830
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700831/**
832 * Solves a linear least squares problem to obtain a N degree polynomial that fits
833 * the specified input data as nearly as possible.
834 *
835 * Returns true if a solution is found, false otherwise.
836 *
837 * The input consists of two vectors of data points X and Y with indices 0..m-1.
838 * The output is a vector B with indices 0..n-1 that describes a polynomial
839 * 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))
840 * for all i between 0 and m-1 is minimized.
841 *
842 * That is to say, the function that generated the input data can be approximated
843 * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n.
844 *
845 * The coefficient of determination (R^2) is also returned to describe the goodness
846 * of fit of the model for the given data. It is a value between 0 and 1, where 1
847 * indicates perfect correspondence.
848 *
849 * This function first expands the X vector to a m by n matrix A such that
850 * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n.
851 *
852 * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q
853 * and an m by n upper triangular matrix R. Because R is upper triangular (lower
854 * part is all zeroes), we can simplify the decomposition into an m by n matrix
855 * Q1 and a n by n matrix R1 such that A = Q1 R1.
856 *
857 * Finally we solve the system of linear equations given by R1 B = (Qtranspose Y)
858 * to find B.
859 *
860 * For efficiency, we lay out A and Q column-wise in memory because we frequently
861 * operate on the column vectors. Conversely, we lay out R row-wise.
862 *
863 * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares
864 * http://en.wikipedia.org/wiki/Gram-Schmidt
865 */
866static bool solveLeastSquares(const float* x, const float* y, uint32_t m, uint32_t n,
867 float* outB, float* outDet) {
868#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000869 ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s", int(m), int(n),
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700870 vectorToString(x, m).string(), vectorToString(y, m).string());
871#endif
872
873 // Expand the X vector to a matrix A.
874 float a[n][m]; // column-major order
875 for (uint32_t h = 0; h < m; h++) {
876 a[0][h] = 1;
877 for (uint32_t i = 1; i < n; i++) {
878 a[i][h] = a[i - 1][h] * x[h];
879 }
880 }
881#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000882 ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700883#endif
884
885 // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
886 float q[n][m]; // orthonormal basis, column-major order
887 float r[n][n]; // upper triangular matrix, row-major order
888 for (uint32_t j = 0; j < n; j++) {
889 for (uint32_t h = 0; h < m; h++) {
890 q[j][h] = a[j][h];
891 }
892 for (uint32_t i = 0; i < j; i++) {
893 float dot = vectorDot(&q[j][0], &q[i][0], m);
894 for (uint32_t h = 0; h < m; h++) {
895 q[j][h] -= dot * q[i][h];
896 }
897 }
898
899 float norm = vectorNorm(&q[j][0], m);
900 if (norm < 0.000001f) {
901 // vectors are linearly dependent or zero so no solution
902#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000903 ALOGD(" - no solution, norm=%f", norm);
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700904#endif
905 return false;
906 }
907
908 float invNorm = 1.0f / norm;
909 for (uint32_t h = 0; h < m; h++) {
910 q[j][h] *= invNorm;
911 }
912 for (uint32_t i = 0; i < n; i++) {
913 r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m);
914 }
915 }
916#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000917 ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string());
918 ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700919
920 // calculate QR, if we factored A correctly then QR should equal A
921 float qr[n][m];
922 for (uint32_t h = 0; h < m; h++) {
923 for (uint32_t i = 0; i < n; i++) {
924 qr[i][h] = 0;
925 for (uint32_t j = 0; j < n; j++) {
926 qr[i][h] += q[j][h] * r[j][i];
927 }
928 }
929 }
Steve Block5baa3a62011-12-20 16:23:08 +0000930 ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700931#endif
932
933 // Solve R B = Qt Y to find B. This is easy because R is upper triangular.
934 // We just work from bottom-right to top-left calculating B's coefficients.
935 for (uint32_t i = n; i-- != 0; ) {
936 outB[i] = vectorDot(&q[i][0], y, m);
937 for (uint32_t j = n - 1; j > i; j--) {
938 outB[i] -= r[i][j] * outB[j];
939 }
940 outB[i] /= r[i][i];
941 }
942#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000943 ALOGD(" - b=%s", vectorToString(outB, n).string());
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700944#endif
945
946 // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
947 // SSerr is the residual sum of squares (squared variance of the error),
948 // and SStot is the total sum of squares (squared variance of the data).
949 float ymean = 0;
950 for (uint32_t h = 0; h < m; h++) {
951 ymean += y[h];
952 }
953 ymean /= m;
954
955 float sserr = 0;
956 float sstot = 0;
957 for (uint32_t h = 0; h < m; h++) {
958 float err = y[h] - outB[0];
959 float term = 1;
960 for (uint32_t i = 1; i < n; i++) {
961 term *= x[h];
962 err -= term * outB[i];
963 }
964 sserr += err * err;
965 float var = y[h] - ymean;
966 sstot += var * var;
967 }
968 *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
969#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +0000970 ALOGD(" - sserr=%f", sserr);
971 ALOGD(" - sstot=%f", sstot);
972 ALOGD(" - det=%f", *outDet);
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700973#endif
974 return true;
975}
976
Jeff Brownace13b12011-03-09 17:39:48 -0800977bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700978 Estimator estimator;
979 if (getEstimator(id, DEFAULT_DEGREE, DEFAULT_HORIZON, &estimator)) {
980 if (estimator.degree >= 1) {
981 *outVx = estimator.xCoeff[1];
982 *outVy = estimator.yCoeff[1];
983 return true;
984 }
985 }
Jeff Brownb0c71eb2011-09-16 21:40:49 -0700986 *outVx = 0;
987 *outVy = 0;
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700988 return false;
989}
990
991bool VelocityTracker::getEstimator(uint32_t id, uint32_t degree, nsecs_t horizon,
992 Estimator* outEstimator) const {
993 outEstimator->clear();
994
995 // Iterate over movement samples in reverse time order and collect samples.
996 float x[HISTORY_SIZE];
997 float y[HISTORY_SIZE];
998 float time[HISTORY_SIZE];
999 uint32_t m = 0;
1000 uint32_t index = mIndex;
Jeff Brownace13b12011-03-09 17:39:48 -08001001 const Movement& newestMovement = mMovements[mIndex];
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001002 do {
1003 const Movement& movement = mMovements[index];
1004 if (!movement.idBits.hasBit(id)) {
1005 break;
1006 }
Jeff Brown2352b972011-04-12 22:39:53 -07001007
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001008 nsecs_t age = newestMovement.eventTime - movement.eventTime;
1009 if (age > horizon) {
1010 break;
1011 }
Jeff Brown581761d2011-09-09 15:39:35 -07001012
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001013 const Position& position = movement.getPosition(id);
1014 x[m] = position.x;
1015 y[m] = position.y;
1016 time[m] = -age * 0.000000001f;
1017 index = (index == 0 ? HISTORY_SIZE : index) - 1;
1018 } while (++m < HISTORY_SIZE);
Jeff Brown581761d2011-09-09 15:39:35 -07001019
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001020 if (m == 0) {
1021 return false; // no data
1022 }
Jeff Brownace13b12011-03-09 17:39:48 -08001023
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001024 // Calculate a least squares polynomial fit.
1025 if (degree > Estimator::MAX_DEGREE) {
1026 degree = Estimator::MAX_DEGREE;
1027 }
1028 if (degree > m - 1) {
1029 degree = m - 1;
1030 }
1031 if (degree >= 1) {
1032 float xdet, ydet;
1033 uint32_t n = degree + 1;
1034 if (solveLeastSquares(time, x, m, n, outEstimator->xCoeff, &xdet)
1035 && solveLeastSquares(time, y, m, n, outEstimator->yCoeff, &ydet)) {
1036 outEstimator->degree = degree;
1037 outEstimator->confidence = xdet * ydet;
1038#if DEBUG_LEAST_SQUARES
Steve Block5baa3a62011-12-20 16:23:08 +00001039 ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001040 int(outEstimator->degree),
1041 vectorToString(outEstimator->xCoeff, n).string(),
1042 vectorToString(outEstimator->yCoeff, n).string(),
1043 outEstimator->confidence);
1044#endif
Jeff Brownace13b12011-03-09 17:39:48 -08001045 return true;
1046 }
1047 }
1048
Jeff Brownb59ab9f2011-09-14 10:53:18 -07001049 // No velocity data available for this pointer, but we do have its current position.
1050 outEstimator->xCoeff[0] = x[0];
1051 outEstimator->yCoeff[0] = y[0];
1052 outEstimator->degree = 0;
1053 outEstimator->confidence = 1;
1054 return true;
Jeff Brownace13b12011-03-09 17:39:48 -08001055}
1056
1057
Jeff Brown19c97d462011-06-01 12:33:19 -07001058// --- VelocityControl ---
1059
1060const nsecs_t VelocityControl::STOP_TIME;
1061
1062VelocityControl::VelocityControl() {
1063 reset();
1064}
1065
1066void VelocityControl::setParameters(const VelocityControlParameters& parameters) {
1067 mParameters = parameters;
1068 reset();
1069}
1070
1071void VelocityControl::reset() {
1072 mLastMovementTime = LLONG_MIN;
1073 mRawPosition.x = 0;
1074 mRawPosition.y = 0;
1075 mVelocityTracker.clear();
1076}
1077
1078void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
1079 if ((deltaX && *deltaX) || (deltaY && *deltaY)) {
1080 if (eventTime >= mLastMovementTime + STOP_TIME) {
1081#if DEBUG_ACCELERATION
Steve Block5baa3a62011-12-20 16:23:08 +00001082 ALOGD("VelocityControl: stopped, last movement was %0.3fms ago",
Jeff Brown19c97d462011-06-01 12:33:19 -07001083 (eventTime - mLastMovementTime) * 0.000001f);
1084#endif
1085 reset();
1086 }
1087
1088 mLastMovementTime = eventTime;
1089 if (deltaX) {
1090 mRawPosition.x += *deltaX;
1091 }
1092 if (deltaY) {
1093 mRawPosition.y += *deltaY;
1094 }
1095 mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition);
1096
1097 float vx, vy;
1098 float scale = mParameters.scale;
1099 if (mVelocityTracker.getVelocity(0, &vx, &vy)) {
1100 float speed = hypotf(vx, vy) * scale;
1101 if (speed >= mParameters.highThreshold) {
1102 // Apply full acceleration above the high speed threshold.
1103 scale *= mParameters.acceleration;
1104 } else if (speed > mParameters.lowThreshold) {
1105 // Linearly interpolate the acceleration to apply between the low and high
1106 // speed thresholds.
1107 scale *= 1 + (speed - mParameters.lowThreshold)
1108 / (mParameters.highThreshold - mParameters.lowThreshold)
1109 * (mParameters.acceleration - 1);
1110 }
1111
1112#if DEBUG_ACCELERATION
Steve Block5baa3a62011-12-20 16:23:08 +00001113 ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
Jeff Brown19c97d462011-06-01 12:33:19 -07001114 "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
1115 mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
1116 mParameters.acceleration,
1117 vx, vy, speed, scale / mParameters.scale);
1118#endif
1119 } else {
1120#if DEBUG_ACCELERATION
Steve Block5baa3a62011-12-20 16:23:08 +00001121 ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
Jeff Brown19c97d462011-06-01 12:33:19 -07001122 mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
1123 mParameters.acceleration);
1124#endif
1125 }
1126
1127 if (deltaX) {
1128 *deltaX *= scale;
1129 }
1130 if (deltaY) {
1131 *deltaY *= scale;
1132 }
1133 }
1134}
1135
Jeff Brown46b9ac0a2010-04-22 18:58:52 -07001136} // namespace android