blob: 6f207e0ff8b93cee4f8c8945464b53541130f3ed [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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
17package com.android.server;
18
19import android.util.Log;
20import android.view.Display;
21import android.view.MotionEvent;
22import android.view.Surface;
23import android.view.WindowManagerPolicy;
24
25public class InputDevice {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070026 static final boolean DEBUG_POINTERS = false;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -070027 static final boolean DEBUG_HACKS = false;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029 /** Amount that trackball needs to move in order to generate a key event. */
30 static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
31
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070032 /** Maximum number of pointers we will track and report. */
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070033 static final int MAX_POINTERS = 10;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 final int id;
36 final int classes;
37 final String name;
38 final AbsoluteInfo absX;
39 final AbsoluteInfo absY;
40 final AbsoluteInfo absPressure;
41 final AbsoluteInfo absSize;
42
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070043 long mKeyDownTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 int mMetaKeysState = 0;
45
Dianne Hackborn2a2b34432009-08-12 17:13:55 -070046 // For use by KeyInputQueue for keeping track of the current touch
47 // data in the old non-multi-touch protocol.
48 final int[] curTouchVals = new int[MotionEvent.NUM_SAMPLE_DATA * 2];
49
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 final MotionState mAbs = new MotionState(0, 0);
51 final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD,
52 TRACKBALL_MOVEMENT_THRESHOLD);
53
54 static class MotionState {
55 int xPrecision;
56 int yPrecision;
57 float xMoveScale;
58 float yMoveScale;
59 MotionEvent currentMove = null;
60 boolean changed = false;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070061 long mDownTime = 0;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070062
63 // The currently assigned pointer IDs, corresponding to the last data.
64 int[] mPointerIds = new int[MAX_POINTERS];
65
66 // This is the last generated pointer data, ordered to match
67 // mPointerIds.
Dianne Hackborndc953722009-10-19 11:24:39 -070068 boolean mSkipLastPointers;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070069 int mLastNumPointers = 0;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070070 final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070071
72 // This is the next set of pointer data being generated. It is not
73 // in any known order, and will be propagated in to mLastData
74 // as part of mapping it to the appropriate pointer IDs.
75 // Note that we have one extra sample of data here, to help clients
76 // avoid doing bounds checking.
77 int mNextNumPointers = 0;
78 final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
79 + MotionEvent.NUM_SAMPLE_DATA];
80
Dianne Hackborn1411d1c2009-10-12 23:21:18 -070081 // Used to determine whether we dropped bad data, to avoid doing
82 // it repeatedly.
83 final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS];
84
85 // Used to perform averaging of reported coordinates, to smooth
86 // the data and filter out transients during a release.
87 static final int HISTORY_SIZE = 5;
88 int[] mHistoryDataStart = new int[MAX_POINTERS];
89 int[] mHistoryDataEnd = new int[MAX_POINTERS];
90 final int[] mHistoryData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
91 * HISTORY_SIZE];
92 final int[] mAveragedData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
93
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070094 // Temporary data structures for doing the pointer ID mapping.
95 final int[] mLast2Next = new int[MAX_POINTERS];
96 final int[] mNext2Last = new int[MAX_POINTERS];
97 final long[] mNext2LastDistance = new long[MAX_POINTERS];
98
99 // Temporary data structure for generating the final motion data.
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700100 final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700102 // This is not used here, but can be used by callers for state tracking.
103 int mAddingPointerOffset = 0;
104 final boolean[] mDown = new boolean[MAX_POINTERS];
105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 MotionState(int mx, int my) {
107 xPrecision = mx;
108 yPrecision = my;
109 xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f;
110 yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700111 for (int i=0; i<MAX_POINTERS; i++) {
112 mPointerIds[i] = i;
113 }
114 }
115
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700116 /**
117 * Special hack for devices that have bad screen data: if one of the
118 * points has moved more than a screen height from the last position,
119 * then drop it.
120 */
121 void dropBadPoint(InputDevice dev) {
122 // We should always have absY, but let's be paranoid.
123 if (dev.absY == null) {
124 return;
125 }
126 // Don't do anything if a finger is going down or up. We run
127 // here before assigning pointer IDs, so there isn't a good
128 // way to do per-finger matching.
129 if (mNextNumPointers != mLastNumPointers) {
130 return;
131 }
132
133 // We consider a single movement across more than a 7/16 of
134 // the long size of the screen to be bad. This was a magic value
135 // determined by looking at the maximum distance it is feasible
136 // to actually move in one sample.
137 final int maxDy = ((dev.absY.maxValue-dev.absY.minValue)*7)/16;
138
139 // Look through all new points and see if any are farther than
140 // acceptable from all previous points.
141 for (int i=mNextNumPointers-1; i>=0; i--) {
142 final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
143 //final int x = mNextData[ioff + MotionEvent.SAMPLE_X];
144 final int y = mNextData[ioff + MotionEvent.SAMPLE_Y];
145 if (DEBUG_HACKS) Log.v("InputDevice", "Looking at next point #" + i + ": y=" + y);
146 boolean dropped = false;
147 if (!mDroppedBadPoint[i] && mLastNumPointers > 0) {
148 dropped = true;
149 int closestDy = -1;
150 int closestY = -1;
151 // We will drop this new point if it is sufficiently
152 // far away from -all- last points.
153 for (int j=mLastNumPointers-1; j>=0; j--) {
154 final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
155 //int dx = x - mLastData[joff + MotionEvent.SAMPLE_X];
156 int dy = y - mLastData[joff + MotionEvent.SAMPLE_Y];
157 //if (dx < 0) dx = -dx;
158 if (dy < 0) dy = -dy;
159 if (DEBUG_HACKS) Log.v("InputDevice", "Comparing with last point #" + j
160 + ": y=" + mLastData[joff] + " dy=" + dy);
161 if (dy < maxDy) {
162 dropped = false;
163 break;
164 } else if (closestDy < 0 || dy < closestDy) {
165 closestDy = dy;
166 closestY = mLastData[joff + MotionEvent.SAMPLE_Y];
167 }
168 }
169 if (dropped) {
170 dropped = true;
171 Log.i("InputDevice", "Dropping bad point #" + i
172 + ": newY=" + y + " closestDy=" + closestDy
173 + " maxDy=" + maxDy);
174 mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY;
175 break;
176 }
177 }
178 mDroppedBadPoint[i] = dropped;
179 }
180 }
181
182 /**
183 * Special hack for devices that have bad screen data: aggregate and
184 * compute averages of the coordinate data, to reduce the amount of
185 * jitter seen by applications.
186 */
187 int[] generateAveragedData(int upOrDownPointer, int lastNumPointers,
188 int nextNumPointers) {
189 final int numPointers = mLastNumPointers;
190 final int[] rawData = mLastData;
191 if (DEBUG_HACKS) Log.v("InputDevice", "lastNumPointers=" + lastNumPointers
192 + " nextNumPointers=" + nextNumPointers
193 + " numPointers=" + numPointers);
194 for (int i=0; i<numPointers; i++) {
195 final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
196 // We keep the average data in offsets based on the pointer
197 // ID, so we don't need to move it around as fingers are
198 // pressed and released.
199 final int p = mPointerIds[i];
200 final int poff = p * MotionEvent.NUM_SAMPLE_DATA * HISTORY_SIZE;
201 if (i == upOrDownPointer && lastNumPointers != nextNumPointers) {
202 if (lastNumPointers < nextNumPointers) {
203 // This pointer is going down. Clear its history
204 // and start fresh.
205 if (DEBUG_HACKS) Log.v("InputDevice", "Pointer down @ index "
206 + upOrDownPointer + " id " + mPointerIds[i]);
207 mHistoryDataStart[i] = 0;
208 mHistoryDataEnd[i] = 0;
209 System.arraycopy(rawData, ioff, mHistoryData, poff,
210 MotionEvent.NUM_SAMPLE_DATA);
211 System.arraycopy(rawData, ioff, mAveragedData, ioff,
212 MotionEvent.NUM_SAMPLE_DATA);
213 continue;
214 } else {
215 // The pointer is going up. Just fall through to
216 // recompute the last averaged point (and don't add
217 // it as a new point to include in the average).
218 if (DEBUG_HACKS) Log.v("InputDevice", "Pointer up @ index "
219 + upOrDownPointer + " id " + mPointerIds[i]);
220 }
221 } else {
222 int end = mHistoryDataEnd[i];
223 int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
224 int oldX = mHistoryData[eoff + MotionEvent.SAMPLE_X];
225 int oldY = mHistoryData[eoff + MotionEvent.SAMPLE_Y];
226 int newX = rawData[ioff + MotionEvent.SAMPLE_X];
227 int newY = rawData[ioff + MotionEvent.SAMPLE_Y];
228 int dx = newX-oldX;
229 int dy = newY-oldY;
230 int delta = dx*dx + dy*dy;
231 if (DEBUG_HACKS) Log.v("InputDevice", "Delta from last: " + delta);
232 if (delta >= (75*75)) {
233 // Magic number, if moving farther than this, turn
234 // off filtering to avoid lag in response.
235 mHistoryDataStart[i] = 0;
236 mHistoryDataEnd[i] = 0;
237 System.arraycopy(rawData, ioff, mHistoryData, poff,
238 MotionEvent.NUM_SAMPLE_DATA);
239 System.arraycopy(rawData, ioff, mAveragedData, ioff,
240 MotionEvent.NUM_SAMPLE_DATA);
241 continue;
242 } else {
243 end++;
244 if (end >= HISTORY_SIZE) {
245 end -= HISTORY_SIZE;
246 }
247 mHistoryDataEnd[i] = end;
248 int noff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
249 mHistoryData[noff + MotionEvent.SAMPLE_X] = newX;
250 mHistoryData[noff + MotionEvent.SAMPLE_Y] = newY;
251 mHistoryData[noff + MotionEvent.SAMPLE_PRESSURE]
252 = rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
253 int start = mHistoryDataStart[i];
254 if (end == start) {
255 start++;
256 if (start >= HISTORY_SIZE) {
257 start -= HISTORY_SIZE;
258 }
259 mHistoryDataStart[i] = start;
260 }
261 }
262 }
263
264 // Now compute the average.
265 int start = mHistoryDataStart[i];
266 int end = mHistoryDataEnd[i];
267 int x=0, y=0;
268 int totalPressure = 0;
269 while (start != end) {
270 int soff = poff + (start*MotionEvent.NUM_SAMPLE_DATA);
271 int pressure = mHistoryData[soff + MotionEvent.SAMPLE_PRESSURE];
Dianne Hackborn53cd5792009-10-13 19:50:51 -0700272 if (pressure <= 0) pressure = 1;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700273 x += mHistoryData[soff + MotionEvent.SAMPLE_X] * pressure;
274 y += mHistoryData[soff + MotionEvent.SAMPLE_Y] * pressure;
275 totalPressure += pressure;
276 start++;
277 if (start >= HISTORY_SIZE) start = 0;
278 }
279 int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
280 int pressure = mHistoryData[eoff + MotionEvent.SAMPLE_PRESSURE];
Dianne Hackborn53cd5792009-10-13 19:50:51 -0700281 if (pressure <= 0) pressure = 1;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700282 x += mHistoryData[eoff + MotionEvent.SAMPLE_X] * pressure;
283 y += mHistoryData[eoff + MotionEvent.SAMPLE_Y] * pressure;
284 totalPressure += pressure;
285 x /= totalPressure;
286 y /= totalPressure;
287 if (DEBUG_HACKS) Log.v("InputDevice", "Averaging " + totalPressure
288 + " weight: (" + x + "," + y + ")");
289 mAveragedData[ioff + MotionEvent.SAMPLE_X] = x;
290 mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y;
Dianne Hackborn05799982009-11-23 13:08:14 -0800291 mAveragedData[ioff + MotionEvent.SAMPLE_PRESSURE] =
292 rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
293 mAveragedData[ioff + MotionEvent.SAMPLE_SIZE] =
294 rawData[ioff + MotionEvent.SAMPLE_SIZE];
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700295 }
296 return mAveragedData;
297 }
298
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700299 private boolean assignPointer(int nextIndex, boolean allowOverlap) {
300 final int lastNumPointers = mLastNumPointers;
301 final int[] next2Last = mNext2Last;
302 final long[] next2LastDistance = mNext2LastDistance;
303 final int[] last2Next = mLast2Next;
304 final int[] lastData = mLastData;
305 final int[] nextData = mNextData;
306 final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
307
308 if (DEBUG_POINTERS) Log.v("InputDevice", "assignPointer: nextIndex="
309 + nextIndex + " dataOff=" + id);
310 final int x1 = nextData[id + MotionEvent.SAMPLE_X];
311 final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
312
313 long bestDistance = -1;
314 int bestIndex = -1;
315 for (int j=0; j<lastNumPointers; j++) {
Dianne Hackborn709d6db2009-12-02 18:42:39 -0800316 // If we are not allowing multiple new points to be assigned
317 // to the same old pointer, then skip this one if it is already
318 // detected as a conflict (-2).
319 if (!allowOverlap && last2Next[j] < -1) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700320 continue;
321 }
322 final int jd = j * MotionEvent.NUM_SAMPLE_DATA;
323 final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1;
324 final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1;
325 final long distance = xd*(long)xd + yd*(long)yd;
Dianne Hackborn709d6db2009-12-02 18:42:39 -0800326 if (bestDistance == -1 || distance < bestDistance) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700327 bestDistance = distance;
328 bestIndex = j;
329 }
330 }
331
332 if (DEBUG_POINTERS) Log.v("InputDevice", "New index " + nextIndex
333 + " best old index=" + bestIndex + " (distance="
334 + bestDistance + ")");
335 next2Last[nextIndex] = bestIndex;
336 next2LastDistance[nextIndex] = bestDistance;
337
338 if (bestIndex < 0) {
339 return true;
340 }
341
342 if (last2Next[bestIndex] == -1) {
343 last2Next[bestIndex] = nextIndex;
344 return false;
345 }
346
347 if (DEBUG_POINTERS) Log.v("InputDevice", "Old index " + bestIndex
348 + " has multiple best new pointers!");
349
350 last2Next[bestIndex] = -2;
351 return true;
352 }
353
354 private int updatePointerIdentifiers() {
355 final int[] lastData = mLastData;
356 final int[] nextData = mNextData;
357 final int nextNumPointers = mNextNumPointers;
358 final int lastNumPointers = mLastNumPointers;
359
360 if (nextNumPointers == 1 && lastNumPointers == 1) {
361 System.arraycopy(nextData, 0, lastData, 0,
362 MotionEvent.NUM_SAMPLE_DATA);
363 return -1;
364 }
365
366 // Clear our old state.
367 final int[] last2Next = mLast2Next;
368 for (int i=0; i<lastNumPointers; i++) {
369 last2Next[i] = -1;
370 }
371
372 if (DEBUG_POINTERS) Log.v("InputDevice",
373 "Update pointers: lastNumPointers=" + lastNumPointers
374 + " nextNumPointers=" + nextNumPointers);
375
376 // Figure out the closes new points to the previous points.
377 final int[] next2Last = mNext2Last;
378 final long[] next2LastDistance = mNext2LastDistance;
379 boolean conflicts = false;
380 for (int i=0; i<nextNumPointers; i++) {
381 conflicts |= assignPointer(i, true);
382 }
383
384 // Resolve ambiguities in pointer mappings, when two or more
385 // new pointer locations find their best previous location is
386 // the same.
387 if (conflicts) {
388 if (DEBUG_POINTERS) Log.v("InputDevice", "Resolving conflicts");
389
390 for (int i=0; i<lastNumPointers; i++) {
391 if (last2Next[i] != -2) {
392 continue;
393 }
394
395 // Note that this algorithm is far from perfect. Ideally
396 // we should do something like the one described at
397 // http://portal.acm.org/citation.cfm?id=997856
398
399 if (DEBUG_POINTERS) Log.v("InputDevice",
400 "Resolving last index #" + i);
401
402 int numFound;
403 do {
404 numFound = 0;
405 long worstDistance = 0;
406 int worstJ = -1;
407 for (int j=0; j<nextNumPointers; j++) {
408 if (next2Last[j] != i) {
409 continue;
410 }
411 numFound++;
412 if (worstDistance < next2LastDistance[j]) {
413 worstDistance = next2LastDistance[j];
414 worstJ = j;
415 }
416 }
417
418 if (worstJ >= 0) {
419 if (DEBUG_POINTERS) Log.v("InputDevice",
420 "Worst new pointer: " + worstJ
421 + " (distance=" + worstDistance + ")");
422 if (assignPointer(worstJ, false)) {
423 // In this case there is no last pointer
424 // remaining for this new one!
425 next2Last[worstJ] = -1;
426 }
427 }
428 } while (numFound > 2);
429 }
430 }
431
432 int retIndex = -1;
433
434 if (lastNumPointers < nextNumPointers) {
435 // We have one or more new pointers that are down. Create a
436 // new pointer identifier for one of them.
437 if (DEBUG_POINTERS) Log.v("InputDevice", "Adding new pointer");
438 int nextId = 0;
439 int i=0;
440 while (i < lastNumPointers) {
441 if (mPointerIds[i] > nextId) {
442 // Found a hole, insert the pointer here.
443 if (DEBUG_POINTERS) Log.v("InputDevice",
444 "Inserting new pointer at hole " + i);
445 System.arraycopy(mPointerIds, i, mPointerIds,
446 i+1, lastNumPointers-i);
447 System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA,
448 lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA,
449 (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA);
450 break;
451 }
452 i++;
453 nextId++;
454 }
455
456 if (DEBUG_POINTERS) Log.v("InputDevice",
457 "New pointer id " + nextId + " at index " + i);
458
459 mLastNumPointers++;
460 retIndex = i;
461 mPointerIds[i] = nextId;
462
463 // And assign this identifier to the first new pointer.
464 for (int j=0; j<nextNumPointers; j++) {
465 if (next2Last[j] < 0) {
466 if (DEBUG_POINTERS) Log.v("InputDevice",
467 "Assigning new id to new pointer index " + j);
468 next2Last[j] = i;
469 break;
470 }
471 }
472 }
473
474 // Propagate all of the current data into the appropriate
475 // location in the old data to match the pointer ID that was
476 // assigned to it.
477 for (int i=0; i<nextNumPointers; i++) {
478 int lastIndex = next2Last[i];
479 if (lastIndex >= 0) {
480 if (DEBUG_POINTERS) Log.v("InputDevice",
481 "Copying next pointer index " + i
482 + " to last index " + lastIndex);
483 System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
484 lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA,
485 MotionEvent.NUM_SAMPLE_DATA);
486 }
487 }
488
489 if (lastNumPointers > nextNumPointers) {
490 // One or more pointers has gone up. Find the first one,
491 // and adjust accordingly.
492 if (DEBUG_POINTERS) Log.v("InputDevice", "Removing old pointer");
493 for (int i=0; i<lastNumPointers; i++) {
494 if (last2Next[i] == -1) {
495 if (DEBUG_POINTERS) Log.v("InputDevice",
496 "Removing old pointer at index " + i);
497 retIndex = i;
498 break;
499 }
500 }
501 }
502
503 return retIndex;
504 }
505
506 void removeOldPointer(int index) {
507 final int lastNumPointers = mLastNumPointers;
508 if (index >= 0 && index < lastNumPointers) {
509 System.arraycopy(mPointerIds, index+1, mPointerIds,
510 index, lastNumPointers-index-1);
511 System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA,
512 mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA,
513 (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA);
514 mLastNumPointers--;
515 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 }
517
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700518 MotionEvent generateAbsMotion(InputDevice device, long curTime,
519 long curTimeNano, Display display, int orientation,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 int metaState) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700521
Dianne Hackborndc953722009-10-19 11:24:39 -0700522 if (mSkipLastPointers) {
523 mSkipLastPointers = false;
524 mLastNumPointers = 0;
525 }
526
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700527 if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
528 return null;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700529 }
530
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700531 final int lastNumPointers = mLastNumPointers;
532 final int nextNumPointers = mNextNumPointers;
533 if (mNextNumPointers > MAX_POINTERS) {
534 Log.w("InputDevice", "Number of pointers " + mNextNumPointers
535 + " exceeded maximum of " + MAX_POINTERS);
536 mNextNumPointers = MAX_POINTERS;
537 }
538
539 int upOrDownPointer = updatePointerIdentifiers();
540
541 final float[] reportData = mReportData;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700542 final int[] rawData;
543 if (KeyInputQueue.BAD_TOUCH_HACK) {
544 rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
545 nextNumPointers);
546 } else {
547 rawData = mLastData;
548 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700549
550 final int numPointers = mLastNumPointers;
551
552 if (DEBUG_POINTERS) Log.v("InputDevice", "Processing "
553 + numPointers + " pointers (going from " + lastNumPointers
554 + " to " + nextNumPointers + ")");
555
556 for (int i=0; i<numPointers; i++) {
557 final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
558 reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
559 reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];
560 reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
561 reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700562 }
563
564 int action;
565 int edgeFlags = 0;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700566 if (nextNumPointers != lastNumPointers) {
567 if (nextNumPointers > lastNumPointers) {
568 if (lastNumPointers == 0) {
569 action = MotionEvent.ACTION_DOWN;
570 mDownTime = curTime;
571 } else {
572 action = MotionEvent.ACTION_POINTER_DOWN
573 | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700574 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700575 } else {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700576 if (numPointers == 1) {
577 action = MotionEvent.ACTION_UP;
578 } else {
579 action = MotionEvent.ACTION_POINTER_UP
580 | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
581 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700582 }
583 currentMove = null;
584 } else {
585 action = MotionEvent.ACTION_MOVE;
586 }
587
588 final int dispW = display.getWidth()-1;
589 final int dispH = display.getHeight()-1;
590 int w = dispW;
591 int h = dispH;
592 if (orientation == Surface.ROTATION_90
593 || orientation == Surface.ROTATION_270) {
594 int tmp = w;
595 w = h;
596 h = tmp;
597 }
598
599 final AbsoluteInfo absX = device.absX;
600 final AbsoluteInfo absY = device.absY;
601 final AbsoluteInfo absPressure = device.absPressure;
602 final AbsoluteInfo absSize = device.absSize;
603 for (int i=0; i<numPointers; i++) {
604 final int j = i * MotionEvent.NUM_SAMPLE_DATA;
605
606 if (absX != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700607 reportData[j + MotionEvent.SAMPLE_X] =
608 ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700609 / absX.range) * w;
610 }
611 if (absY != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700612 reportData[j + MotionEvent.SAMPLE_Y] =
613 ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700614 / absY.range) * h;
615 }
616 if (absPressure != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700617 reportData[j + MotionEvent.SAMPLE_PRESSURE] =
618 ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700619 / (float)absPressure.range);
620 }
621 if (absSize != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700622 reportData[j + MotionEvent.SAMPLE_SIZE] =
623 ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700624 / (float)absSize.range);
625 }
626
627 switch (orientation) {
628 case Surface.ROTATION_90: {
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700629 final float temp = reportData[j + MotionEvent.SAMPLE_X];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700630 reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y];
631 reportData[j + MotionEvent.SAMPLE_Y] = w-temp;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700632 break;
633 }
634 case Surface.ROTATION_180: {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700635 reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X];
636 reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700637 break;
638 }
639 case Surface.ROTATION_270: {
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700640 final float temp = reportData[j + MotionEvent.SAMPLE_X];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700641 reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y];
642 reportData[j + MotionEvent.SAMPLE_Y] = temp;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700643 break;
644 }
645 }
646 }
647
648 // We only consider the first pointer when computing the edge
649 // flags, since they are global to the event.
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700650 if (action == MotionEvent.ACTION_DOWN) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700651 if (reportData[MotionEvent.SAMPLE_X] <= 0) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700652 edgeFlags |= MotionEvent.EDGE_LEFT;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700653 } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700654 edgeFlags |= MotionEvent.EDGE_RIGHT;
655 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700656 if (reportData[MotionEvent.SAMPLE_Y] <= 0) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700657 edgeFlags |= MotionEvent.EDGE_TOP;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700658 } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700659 edgeFlags |= MotionEvent.EDGE_BOTTOM;
660 }
661 }
662
663 if (currentMove != null) {
664 if (false) Log.i("InputDevice", "Adding batch x="
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700665 + reportData[MotionEvent.SAMPLE_X]
666 + " y=" + reportData[MotionEvent.SAMPLE_Y]
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700667 + " to " + currentMove);
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700668 currentMove.addBatch(curTime, reportData, metaState);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700669 if (WindowManagerPolicy.WATCH_POINTER) {
670 Log.i("KeyInputQueue", "Updating: " + currentMove);
671 }
672 return null;
673 }
674
675 MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700676 curTimeNano, action, numPointers, mPointerIds, reportData,
677 metaState, xPrecision, yPrecision, device.id, edgeFlags);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700678 if (action == MotionEvent.ACTION_MOVE) {
679 currentMove = me;
680 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700681
682 if (nextNumPointers < lastNumPointers) {
683 removeOldPointer(upOrDownPointer);
684 }
685
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700686 return me;
687 }
688
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700689 boolean hasMore() {
690 return mLastNumPointers != mNextNumPointers;
691 }
692
693 void finish() {
694 mNextNumPointers = mAddingPointerOffset = 0;
695 mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;
696 }
697
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700698 MotionEvent generateRelMotion(InputDevice device, long curTime,
699 long curTimeNano, int orientation, int metaState) {
700
701 final float[] scaled = mReportData;
702
703 // For now we only support 1 pointer with relative motions.
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700704 scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X];
705 scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700706 scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f;
707 scaled[MotionEvent.SAMPLE_SIZE] = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 int edgeFlags = 0;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700709
710 int action;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700711 if (mNextNumPointers != mLastNumPointers) {
712 mNextData[MotionEvent.SAMPLE_X] =
713 mNextData[MotionEvent.SAMPLE_Y] = 0;
714 if (mNextNumPointers > 0 && mLastNumPointers == 0) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700715 action = MotionEvent.ACTION_DOWN;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700716 mDownTime = curTime;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700717 } else if (mNextNumPointers == 0) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700718 action = MotionEvent.ACTION_UP;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700719 } else {
720 action = MotionEvent.ACTION_MOVE;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700721 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700722 mLastNumPointers = mNextNumPointers;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700723 currentMove = null;
724 } else {
725 action = MotionEvent.ACTION_MOVE;
726 }
727
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700728 scaled[MotionEvent.SAMPLE_X] *= xMoveScale;
729 scaled[MotionEvent.SAMPLE_Y] *= yMoveScale;
730 switch (orientation) {
731 case Surface.ROTATION_90: {
732 final float temp = scaled[MotionEvent.SAMPLE_X];
733 scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y];
734 scaled[MotionEvent.SAMPLE_Y] = -temp;
735 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700737 case Surface.ROTATION_180: {
738 scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X];
739 scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y];
740 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700742 case Surface.ROTATION_270: {
743 final float temp = scaled[MotionEvent.SAMPLE_X];
744 scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y];
745 scaled[MotionEvent.SAMPLE_Y] = temp;
746 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 }
748 }
749
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700750 if (currentMove != null) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700751 if (false) Log.i("InputDevice", "Adding batch x="
752 + scaled[MotionEvent.SAMPLE_X]
753 + " y=" + scaled[MotionEvent.SAMPLE_Y]
754 + " to " + currentMove);
755 currentMove.addBatch(curTime, scaled, metaState);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700756 if (WindowManagerPolicy.WATCH_POINTER) {
757 Log.i("KeyInputQueue", "Updating: " + currentMove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700759 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700761
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700762 MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700763 curTimeNano, action, 1, mPointerIds, scaled, metaState,
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700764 xPrecision, yPrecision, device.id, edgeFlags);
765 if (action == MotionEvent.ACTION_MOVE) {
766 currentMove = me;
767 }
768 return me;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 }
770 }
771
772 static class AbsoluteInfo {
773 int minValue;
774 int maxValue;
775 int range;
776 int flat;
777 int fuzz;
778 };
779
780 InputDevice(int _id, int _classes, String _name,
781 AbsoluteInfo _absX, AbsoluteInfo _absY,
782 AbsoluteInfo _absPressure, AbsoluteInfo _absSize) {
783 id = _id;
784 classes = _classes;
785 name = _name;
786 absX = _absX;
787 absY = _absY;
788 absPressure = _absPressure;
789 absSize = _absSize;
790 }
791};