blob: eaad3b7990cc5fd8adc301d85c0649ae30833cc0 [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.
68 int mLastNumPointers = 0;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070069 final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070070
71 // This is the next set of pointer data being generated. It is not
72 // in any known order, and will be propagated in to mLastData
73 // as part of mapping it to the appropriate pointer IDs.
74 // Note that we have one extra sample of data here, to help clients
75 // avoid doing bounds checking.
76 int mNextNumPointers = 0;
77 final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
78 + MotionEvent.NUM_SAMPLE_DATA];
79
Dianne Hackborn1411d1c2009-10-12 23:21:18 -070080 // Used to determine whether we dropped bad data, to avoid doing
81 // it repeatedly.
82 final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS];
83
84 // Used to perform averaging of reported coordinates, to smooth
85 // the data and filter out transients during a release.
86 static final int HISTORY_SIZE = 5;
87 int[] mHistoryDataStart = new int[MAX_POINTERS];
88 int[] mHistoryDataEnd = new int[MAX_POINTERS];
89 final int[] mHistoryData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
90 * HISTORY_SIZE];
91 final int[] mAveragedData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
92
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070093 // Temporary data structures for doing the pointer ID mapping.
94 final int[] mLast2Next = new int[MAX_POINTERS];
95 final int[] mNext2Last = new int[MAX_POINTERS];
96 final long[] mNext2LastDistance = new long[MAX_POINTERS];
97
98 // Temporary data structure for generating the final motion data.
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070099 final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700101 // This is not used here, but can be used by callers for state tracking.
102 int mAddingPointerOffset = 0;
103 final boolean[] mDown = new boolean[MAX_POINTERS];
104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 MotionState(int mx, int my) {
106 xPrecision = mx;
107 yPrecision = my;
108 xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f;
109 yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700110 for (int i=0; i<MAX_POINTERS; i++) {
111 mPointerIds[i] = i;
112 }
113 }
114
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700115 /**
116 * Special hack for devices that have bad screen data: if one of the
117 * points has moved more than a screen height from the last position,
118 * then drop it.
119 */
120 void dropBadPoint(InputDevice dev) {
121 // We should always have absY, but let's be paranoid.
122 if (dev.absY == null) {
123 return;
124 }
125 // Don't do anything if a finger is going down or up. We run
126 // here before assigning pointer IDs, so there isn't a good
127 // way to do per-finger matching.
128 if (mNextNumPointers != mLastNumPointers) {
129 return;
130 }
131
132 // We consider a single movement across more than a 7/16 of
133 // the long size of the screen to be bad. This was a magic value
134 // determined by looking at the maximum distance it is feasible
135 // to actually move in one sample.
136 final int maxDy = ((dev.absY.maxValue-dev.absY.minValue)*7)/16;
137
138 // Look through all new points and see if any are farther than
139 // acceptable from all previous points.
140 for (int i=mNextNumPointers-1; i>=0; i--) {
141 final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
142 //final int x = mNextData[ioff + MotionEvent.SAMPLE_X];
143 final int y = mNextData[ioff + MotionEvent.SAMPLE_Y];
144 if (DEBUG_HACKS) Log.v("InputDevice", "Looking at next point #" + i + ": y=" + y);
145 boolean dropped = false;
146 if (!mDroppedBadPoint[i] && mLastNumPointers > 0) {
147 dropped = true;
148 int closestDy = -1;
149 int closestY = -1;
150 // We will drop this new point if it is sufficiently
151 // far away from -all- last points.
152 for (int j=mLastNumPointers-1; j>=0; j--) {
153 final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
154 //int dx = x - mLastData[joff + MotionEvent.SAMPLE_X];
155 int dy = y - mLastData[joff + MotionEvent.SAMPLE_Y];
156 //if (dx < 0) dx = -dx;
157 if (dy < 0) dy = -dy;
158 if (DEBUG_HACKS) Log.v("InputDevice", "Comparing with last point #" + j
159 + ": y=" + mLastData[joff] + " dy=" + dy);
160 if (dy < maxDy) {
161 dropped = false;
162 break;
163 } else if (closestDy < 0 || dy < closestDy) {
164 closestDy = dy;
165 closestY = mLastData[joff + MotionEvent.SAMPLE_Y];
166 }
167 }
168 if (dropped) {
169 dropped = true;
170 Log.i("InputDevice", "Dropping bad point #" + i
171 + ": newY=" + y + " closestDy=" + closestDy
172 + " maxDy=" + maxDy);
173 mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY;
174 break;
175 }
176 }
177 mDroppedBadPoint[i] = dropped;
178 }
179 }
180
181 /**
182 * Special hack for devices that have bad screen data: aggregate and
183 * compute averages of the coordinate data, to reduce the amount of
184 * jitter seen by applications.
185 */
186 int[] generateAveragedData(int upOrDownPointer, int lastNumPointers,
187 int nextNumPointers) {
188 final int numPointers = mLastNumPointers;
189 final int[] rawData = mLastData;
190 if (DEBUG_HACKS) Log.v("InputDevice", "lastNumPointers=" + lastNumPointers
191 + " nextNumPointers=" + nextNumPointers
192 + " numPointers=" + numPointers);
193 for (int i=0; i<numPointers; i++) {
194 final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
195 // We keep the average data in offsets based on the pointer
196 // ID, so we don't need to move it around as fingers are
197 // pressed and released.
198 final int p = mPointerIds[i];
199 final int poff = p * MotionEvent.NUM_SAMPLE_DATA * HISTORY_SIZE;
200 if (i == upOrDownPointer && lastNumPointers != nextNumPointers) {
201 if (lastNumPointers < nextNumPointers) {
202 // This pointer is going down. Clear its history
203 // and start fresh.
204 if (DEBUG_HACKS) Log.v("InputDevice", "Pointer down @ index "
205 + upOrDownPointer + " id " + mPointerIds[i]);
206 mHistoryDataStart[i] = 0;
207 mHistoryDataEnd[i] = 0;
208 System.arraycopy(rawData, ioff, mHistoryData, poff,
209 MotionEvent.NUM_SAMPLE_DATA);
210 System.arraycopy(rawData, ioff, mAveragedData, ioff,
211 MotionEvent.NUM_SAMPLE_DATA);
212 continue;
213 } else {
214 // The pointer is going up. Just fall through to
215 // recompute the last averaged point (and don't add
216 // it as a new point to include in the average).
217 if (DEBUG_HACKS) Log.v("InputDevice", "Pointer up @ index "
218 + upOrDownPointer + " id " + mPointerIds[i]);
219 }
220 } else {
221 int end = mHistoryDataEnd[i];
222 int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
223 int oldX = mHistoryData[eoff + MotionEvent.SAMPLE_X];
224 int oldY = mHistoryData[eoff + MotionEvent.SAMPLE_Y];
225 int newX = rawData[ioff + MotionEvent.SAMPLE_X];
226 int newY = rawData[ioff + MotionEvent.SAMPLE_Y];
227 int dx = newX-oldX;
228 int dy = newY-oldY;
229 int delta = dx*dx + dy*dy;
230 if (DEBUG_HACKS) Log.v("InputDevice", "Delta from last: " + delta);
231 if (delta >= (75*75)) {
232 // Magic number, if moving farther than this, turn
233 // off filtering to avoid lag in response.
234 mHistoryDataStart[i] = 0;
235 mHistoryDataEnd[i] = 0;
236 System.arraycopy(rawData, ioff, mHistoryData, poff,
237 MotionEvent.NUM_SAMPLE_DATA);
238 System.arraycopy(rawData, ioff, mAveragedData, ioff,
239 MotionEvent.NUM_SAMPLE_DATA);
240 continue;
241 } else {
242 end++;
243 if (end >= HISTORY_SIZE) {
244 end -= HISTORY_SIZE;
245 }
246 mHistoryDataEnd[i] = end;
247 int noff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
248 mHistoryData[noff + MotionEvent.SAMPLE_X] = newX;
249 mHistoryData[noff + MotionEvent.SAMPLE_Y] = newY;
250 mHistoryData[noff + MotionEvent.SAMPLE_PRESSURE]
251 = rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
252 int start = mHistoryDataStart[i];
253 if (end == start) {
254 start++;
255 if (start >= HISTORY_SIZE) {
256 start -= HISTORY_SIZE;
257 }
258 mHistoryDataStart[i] = start;
259 }
260 }
261 }
262
263 // Now compute the average.
264 int start = mHistoryDataStart[i];
265 int end = mHistoryDataEnd[i];
266 int x=0, y=0;
267 int totalPressure = 0;
268 while (start != end) {
269 int soff = poff + (start*MotionEvent.NUM_SAMPLE_DATA);
270 int pressure = mHistoryData[soff + MotionEvent.SAMPLE_PRESSURE];
Dianne Hackborn53cd5792009-10-13 19:50:51 -0700271 if (pressure <= 0) pressure = 1;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700272 x += mHistoryData[soff + MotionEvent.SAMPLE_X] * pressure;
273 y += mHistoryData[soff + MotionEvent.SAMPLE_Y] * pressure;
274 totalPressure += pressure;
275 start++;
276 if (start >= HISTORY_SIZE) start = 0;
277 }
278 int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
279 int pressure = mHistoryData[eoff + MotionEvent.SAMPLE_PRESSURE];
Dianne Hackborn53cd5792009-10-13 19:50:51 -0700280 if (pressure <= 0) pressure = 1;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700281 x += mHistoryData[eoff + MotionEvent.SAMPLE_X] * pressure;
282 y += mHistoryData[eoff + MotionEvent.SAMPLE_Y] * pressure;
283 totalPressure += pressure;
284 x /= totalPressure;
285 y /= totalPressure;
286 if (DEBUG_HACKS) Log.v("InputDevice", "Averaging " + totalPressure
287 + " weight: (" + x + "," + y + ")");
288 mAveragedData[ioff + MotionEvent.SAMPLE_X] = x;
289 mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y;
290 }
291 return mAveragedData;
292 }
293
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700294 private boolean assignPointer(int nextIndex, boolean allowOverlap) {
295 final int lastNumPointers = mLastNumPointers;
296 final int[] next2Last = mNext2Last;
297 final long[] next2LastDistance = mNext2LastDistance;
298 final int[] last2Next = mLast2Next;
299 final int[] lastData = mLastData;
300 final int[] nextData = mNextData;
301 final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
302
303 if (DEBUG_POINTERS) Log.v("InputDevice", "assignPointer: nextIndex="
304 + nextIndex + " dataOff=" + id);
305 final int x1 = nextData[id + MotionEvent.SAMPLE_X];
306 final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
307
308 long bestDistance = -1;
309 int bestIndex = -1;
310 for (int j=0; j<lastNumPointers; j++) {
311 if (!allowOverlap && last2Next[j] < 0) {
312 continue;
313 }
314 final int jd = j * MotionEvent.NUM_SAMPLE_DATA;
315 final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1;
316 final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1;
317 final long distance = xd*(long)xd + yd*(long)yd;
318 if (j == 0 || distance < bestDistance) {
319 bestDistance = distance;
320 bestIndex = j;
321 }
322 }
323
324 if (DEBUG_POINTERS) Log.v("InputDevice", "New index " + nextIndex
325 + " best old index=" + bestIndex + " (distance="
326 + bestDistance + ")");
327 next2Last[nextIndex] = bestIndex;
328 next2LastDistance[nextIndex] = bestDistance;
329
330 if (bestIndex < 0) {
331 return true;
332 }
333
334 if (last2Next[bestIndex] == -1) {
335 last2Next[bestIndex] = nextIndex;
336 return false;
337 }
338
339 if (DEBUG_POINTERS) Log.v("InputDevice", "Old index " + bestIndex
340 + " has multiple best new pointers!");
341
342 last2Next[bestIndex] = -2;
343 return true;
344 }
345
346 private int updatePointerIdentifiers() {
347 final int[] lastData = mLastData;
348 final int[] nextData = mNextData;
349 final int nextNumPointers = mNextNumPointers;
350 final int lastNumPointers = mLastNumPointers;
351
352 if (nextNumPointers == 1 && lastNumPointers == 1) {
353 System.arraycopy(nextData, 0, lastData, 0,
354 MotionEvent.NUM_SAMPLE_DATA);
355 return -1;
356 }
357
358 // Clear our old state.
359 final int[] last2Next = mLast2Next;
360 for (int i=0; i<lastNumPointers; i++) {
361 last2Next[i] = -1;
362 }
363
364 if (DEBUG_POINTERS) Log.v("InputDevice",
365 "Update pointers: lastNumPointers=" + lastNumPointers
366 + " nextNumPointers=" + nextNumPointers);
367
368 // Figure out the closes new points to the previous points.
369 final int[] next2Last = mNext2Last;
370 final long[] next2LastDistance = mNext2LastDistance;
371 boolean conflicts = false;
372 for (int i=0; i<nextNumPointers; i++) {
373 conflicts |= assignPointer(i, true);
374 }
375
376 // Resolve ambiguities in pointer mappings, when two or more
377 // new pointer locations find their best previous location is
378 // the same.
379 if (conflicts) {
380 if (DEBUG_POINTERS) Log.v("InputDevice", "Resolving conflicts");
381
382 for (int i=0; i<lastNumPointers; i++) {
383 if (last2Next[i] != -2) {
384 continue;
385 }
386
387 // Note that this algorithm is far from perfect. Ideally
388 // we should do something like the one described at
389 // http://portal.acm.org/citation.cfm?id=997856
390
391 if (DEBUG_POINTERS) Log.v("InputDevice",
392 "Resolving last index #" + i);
393
394 int numFound;
395 do {
396 numFound = 0;
397 long worstDistance = 0;
398 int worstJ = -1;
399 for (int j=0; j<nextNumPointers; j++) {
400 if (next2Last[j] != i) {
401 continue;
402 }
403 numFound++;
404 if (worstDistance < next2LastDistance[j]) {
405 worstDistance = next2LastDistance[j];
406 worstJ = j;
407 }
408 }
409
410 if (worstJ >= 0) {
411 if (DEBUG_POINTERS) Log.v("InputDevice",
412 "Worst new pointer: " + worstJ
413 + " (distance=" + worstDistance + ")");
414 if (assignPointer(worstJ, false)) {
415 // In this case there is no last pointer
416 // remaining for this new one!
417 next2Last[worstJ] = -1;
418 }
419 }
420 } while (numFound > 2);
421 }
422 }
423
424 int retIndex = -1;
425
426 if (lastNumPointers < nextNumPointers) {
427 // We have one or more new pointers that are down. Create a
428 // new pointer identifier for one of them.
429 if (DEBUG_POINTERS) Log.v("InputDevice", "Adding new pointer");
430 int nextId = 0;
431 int i=0;
432 while (i < lastNumPointers) {
433 if (mPointerIds[i] > nextId) {
434 // Found a hole, insert the pointer here.
435 if (DEBUG_POINTERS) Log.v("InputDevice",
436 "Inserting new pointer at hole " + i);
437 System.arraycopy(mPointerIds, i, mPointerIds,
438 i+1, lastNumPointers-i);
439 System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA,
440 lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA,
441 (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA);
442 break;
443 }
444 i++;
445 nextId++;
446 }
447
448 if (DEBUG_POINTERS) Log.v("InputDevice",
449 "New pointer id " + nextId + " at index " + i);
450
451 mLastNumPointers++;
452 retIndex = i;
453 mPointerIds[i] = nextId;
454
455 // And assign this identifier to the first new pointer.
456 for (int j=0; j<nextNumPointers; j++) {
457 if (next2Last[j] < 0) {
458 if (DEBUG_POINTERS) Log.v("InputDevice",
459 "Assigning new id to new pointer index " + j);
460 next2Last[j] = i;
461 break;
462 }
463 }
464 }
465
466 // Propagate all of the current data into the appropriate
467 // location in the old data to match the pointer ID that was
468 // assigned to it.
469 for (int i=0; i<nextNumPointers; i++) {
470 int lastIndex = next2Last[i];
471 if (lastIndex >= 0) {
472 if (DEBUG_POINTERS) Log.v("InputDevice",
473 "Copying next pointer index " + i
474 + " to last index " + lastIndex);
475 System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
476 lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA,
477 MotionEvent.NUM_SAMPLE_DATA);
478 }
479 }
480
481 if (lastNumPointers > nextNumPointers) {
482 // One or more pointers has gone up. Find the first one,
483 // and adjust accordingly.
484 if (DEBUG_POINTERS) Log.v("InputDevice", "Removing old pointer");
485 for (int i=0; i<lastNumPointers; i++) {
486 if (last2Next[i] == -1) {
487 if (DEBUG_POINTERS) Log.v("InputDevice",
488 "Removing old pointer at index " + i);
489 retIndex = i;
490 break;
491 }
492 }
493 }
494
495 return retIndex;
496 }
497
498 void removeOldPointer(int index) {
499 final int lastNumPointers = mLastNumPointers;
500 if (index >= 0 && index < lastNumPointers) {
501 System.arraycopy(mPointerIds, index+1, mPointerIds,
502 index, lastNumPointers-index-1);
503 System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA,
504 mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA,
505 (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA);
506 mLastNumPointers--;
507 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 }
509
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700510 MotionEvent generateAbsMotion(InputDevice device, long curTime,
511 long curTimeNano, Display display, int orientation,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 int metaState) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700513
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700514 if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
515 return null;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700516 }
517
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700518 final int lastNumPointers = mLastNumPointers;
519 final int nextNumPointers = mNextNumPointers;
520 if (mNextNumPointers > MAX_POINTERS) {
521 Log.w("InputDevice", "Number of pointers " + mNextNumPointers
522 + " exceeded maximum of " + MAX_POINTERS);
523 mNextNumPointers = MAX_POINTERS;
524 }
525
526 int upOrDownPointer = updatePointerIdentifiers();
527
528 final float[] reportData = mReportData;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700529 final int[] rawData;
530 if (KeyInputQueue.BAD_TOUCH_HACK) {
531 rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
532 nextNumPointers);
533 } else {
534 rawData = mLastData;
535 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700536
537 final int numPointers = mLastNumPointers;
538
539 if (DEBUG_POINTERS) Log.v("InputDevice", "Processing "
540 + numPointers + " pointers (going from " + lastNumPointers
541 + " to " + nextNumPointers + ")");
542
543 for (int i=0; i<numPointers; i++) {
544 final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
545 reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
546 reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];
547 reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
548 reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700549 }
550
551 int action;
552 int edgeFlags = 0;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700553 if (nextNumPointers != lastNumPointers) {
554 if (nextNumPointers > lastNumPointers) {
555 if (lastNumPointers == 0) {
556 action = MotionEvent.ACTION_DOWN;
557 mDownTime = curTime;
558 } else {
559 action = MotionEvent.ACTION_POINTER_DOWN
560 | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700561 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700562 } else {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700563 if (numPointers == 1) {
564 action = MotionEvent.ACTION_UP;
565 } else {
566 action = MotionEvent.ACTION_POINTER_UP
567 | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
568 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700569 }
570 currentMove = null;
571 } else {
572 action = MotionEvent.ACTION_MOVE;
573 }
574
575 final int dispW = display.getWidth()-1;
576 final int dispH = display.getHeight()-1;
577 int w = dispW;
578 int h = dispH;
579 if (orientation == Surface.ROTATION_90
580 || orientation == Surface.ROTATION_270) {
581 int tmp = w;
582 w = h;
583 h = tmp;
584 }
585
586 final AbsoluteInfo absX = device.absX;
587 final AbsoluteInfo absY = device.absY;
588 final AbsoluteInfo absPressure = device.absPressure;
589 final AbsoluteInfo absSize = device.absSize;
590 for (int i=0; i<numPointers; i++) {
591 final int j = i * MotionEvent.NUM_SAMPLE_DATA;
592
593 if (absX != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700594 reportData[j + MotionEvent.SAMPLE_X] =
595 ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700596 / absX.range) * w;
597 }
598 if (absY != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700599 reportData[j + MotionEvent.SAMPLE_Y] =
600 ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700601 / absY.range) * h;
602 }
603 if (absPressure != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700604 reportData[j + MotionEvent.SAMPLE_PRESSURE] =
605 ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700606 / (float)absPressure.range);
607 }
608 if (absSize != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700609 reportData[j + MotionEvent.SAMPLE_SIZE] =
610 ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700611 / (float)absSize.range);
612 }
613
614 switch (orientation) {
615 case Surface.ROTATION_90: {
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700616 final float temp = reportData[j + MotionEvent.SAMPLE_X];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700617 reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y];
618 reportData[j + MotionEvent.SAMPLE_Y] = w-temp;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700619 break;
620 }
621 case Surface.ROTATION_180: {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700622 reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X];
623 reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700624 break;
625 }
626 case Surface.ROTATION_270: {
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700627 final float temp = reportData[j + MotionEvent.SAMPLE_X];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700628 reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y];
629 reportData[j + MotionEvent.SAMPLE_Y] = temp;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700630 break;
631 }
632 }
633 }
634
635 // We only consider the first pointer when computing the edge
636 // flags, since they are global to the event.
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700637 if (action == MotionEvent.ACTION_DOWN) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700638 if (reportData[MotionEvent.SAMPLE_X] <= 0) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700639 edgeFlags |= MotionEvent.EDGE_LEFT;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700640 } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700641 edgeFlags |= MotionEvent.EDGE_RIGHT;
642 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700643 if (reportData[MotionEvent.SAMPLE_Y] <= 0) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700644 edgeFlags |= MotionEvent.EDGE_TOP;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700645 } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700646 edgeFlags |= MotionEvent.EDGE_BOTTOM;
647 }
648 }
649
650 if (currentMove != null) {
651 if (false) Log.i("InputDevice", "Adding batch x="
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700652 + reportData[MotionEvent.SAMPLE_X]
653 + " y=" + reportData[MotionEvent.SAMPLE_Y]
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700654 + " to " + currentMove);
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700655 currentMove.addBatch(curTime, reportData, metaState);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700656 if (WindowManagerPolicy.WATCH_POINTER) {
657 Log.i("KeyInputQueue", "Updating: " + currentMove);
658 }
659 return null;
660 }
661
662 MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700663 curTimeNano, action, numPointers, mPointerIds, reportData,
664 metaState, xPrecision, yPrecision, device.id, edgeFlags);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700665 if (action == MotionEvent.ACTION_MOVE) {
666 currentMove = me;
667 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700668
669 if (nextNumPointers < lastNumPointers) {
670 removeOldPointer(upOrDownPointer);
671 }
672
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700673 return me;
674 }
675
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700676 boolean hasMore() {
677 return mLastNumPointers != mNextNumPointers;
678 }
679
680 void finish() {
681 mNextNumPointers = mAddingPointerOffset = 0;
682 mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;
683 }
684
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700685 MotionEvent generateRelMotion(InputDevice device, long curTime,
686 long curTimeNano, int orientation, int metaState) {
687
688 final float[] scaled = mReportData;
689
690 // For now we only support 1 pointer with relative motions.
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700691 scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X];
692 scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700693 scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f;
694 scaled[MotionEvent.SAMPLE_SIZE] = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 int edgeFlags = 0;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700696
697 int action;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700698 if (mNextNumPointers != mLastNumPointers) {
699 mNextData[MotionEvent.SAMPLE_X] =
700 mNextData[MotionEvent.SAMPLE_Y] = 0;
701 if (mNextNumPointers > 0 && mLastNumPointers == 0) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700702 action = MotionEvent.ACTION_DOWN;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700703 mDownTime = curTime;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700704 } else if (mNextNumPointers == 0) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700705 action = MotionEvent.ACTION_UP;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700706 } else {
707 action = MotionEvent.ACTION_MOVE;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700708 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700709 mLastNumPointers = mNextNumPointers;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700710 currentMove = null;
711 } else {
712 action = MotionEvent.ACTION_MOVE;
713 }
714
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700715 scaled[MotionEvent.SAMPLE_X] *= xMoveScale;
716 scaled[MotionEvent.SAMPLE_Y] *= yMoveScale;
717 switch (orientation) {
718 case Surface.ROTATION_90: {
719 final float temp = scaled[MotionEvent.SAMPLE_X];
720 scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y];
721 scaled[MotionEvent.SAMPLE_Y] = -temp;
722 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700724 case Surface.ROTATION_180: {
725 scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X];
726 scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y];
727 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700729 case Surface.ROTATION_270: {
730 final float temp = scaled[MotionEvent.SAMPLE_X];
731 scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y];
732 scaled[MotionEvent.SAMPLE_Y] = temp;
733 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 }
735 }
736
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700737 if (currentMove != null) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700738 if (false) Log.i("InputDevice", "Adding batch x="
739 + scaled[MotionEvent.SAMPLE_X]
740 + " y=" + scaled[MotionEvent.SAMPLE_Y]
741 + " to " + currentMove);
742 currentMove.addBatch(curTime, scaled, metaState);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700743 if (WindowManagerPolicy.WATCH_POINTER) {
744 Log.i("KeyInputQueue", "Updating: " + currentMove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700746 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700748
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700749 MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700750 curTimeNano, action, 1, mPointerIds, scaled, metaState,
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700751 xPrecision, yPrecision, device.id, edgeFlags);
752 if (action == MotionEvent.ACTION_MOVE) {
753 currentMove = me;
754 }
755 return me;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 }
757 }
758
759 static class AbsoluteInfo {
760 int minValue;
761 int maxValue;
762 int range;
763 int flat;
764 int fuzz;
765 };
766
767 InputDevice(int _id, int _classes, String _name,
768 AbsoluteInfo _absX, AbsoluteInfo _absY,
769 AbsoluteInfo _absPressure, AbsoluteInfo _absSize) {
770 id = _id;
771 classes = _classes;
772 name = _name;
773 absX = _absX;
774 absY = _absY;
775 absPressure = _absPressure;
776 absSize = _absSize;
777 }
778};