• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.server;
18 
19 import android.util.Log;
20 import android.view.Display;
21 import android.view.MotionEvent;
22 import android.view.Surface;
23 import android.view.WindowManagerPolicy;
24 
25 public class InputDevice {
26     static final boolean DEBUG_POINTERS = false;
27     static final boolean DEBUG_HACKS = false;
28 
29     /** Amount that trackball needs to move in order to generate a key event. */
30     static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
31 
32     /** Maximum number of pointers we will track and report. */
33     static final int MAX_POINTERS = 10;
34 
35     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 
43     long mKeyDownTime = 0;
44     int mMetaKeysState = 0;
45 
46     // 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 
50     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;
61         long mDownTime = 0;
62 
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         boolean mSkipLastPointers;
69         int mLastNumPointers = 0;
70         final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
71 
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 
81         // 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 
94         // 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.
100         final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
101 
102         // 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 
MotionState(int mx, int my)106         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;
111             for (int i=0; i<MAX_POINTERS; i++) {
112                 mPointerIds[i] = i;
113             }
114         }
115 
116         /**
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          */
dropBadPoint(InputDevice dev)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          */
generateAveragedData(int upOrDownPointer, int lastNumPointers, int nextNumPointers)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];
272                     if (pressure <= 0) pressure = 1;
273                     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];
281                 if (pressure <= 0) pressure = 1;
282                 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;
291             }
292             return mAveragedData;
293         }
294 
assignPointer(int nextIndex, boolean allowOverlap)295         private boolean assignPointer(int nextIndex, boolean allowOverlap) {
296             final int lastNumPointers = mLastNumPointers;
297             final int[] next2Last = mNext2Last;
298             final long[] next2LastDistance = mNext2LastDistance;
299             final int[] last2Next = mLast2Next;
300             final int[] lastData = mLastData;
301             final int[] nextData = mNextData;
302             final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
303 
304             if (DEBUG_POINTERS) Log.v("InputDevice", "assignPointer: nextIndex="
305                     + nextIndex + " dataOff=" + id);
306             final int x1 = nextData[id + MotionEvent.SAMPLE_X];
307             final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
308 
309             long bestDistance = -1;
310             int bestIndex = -1;
311             for (int j=0; j<lastNumPointers; j++) {
312                 if (!allowOverlap && last2Next[j] < 0) {
313                     continue;
314                 }
315                 final int jd = j * MotionEvent.NUM_SAMPLE_DATA;
316                 final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1;
317                 final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1;
318                 final long distance = xd*(long)xd + yd*(long)yd;
319                 if (j == 0 || distance < bestDistance) {
320                     bestDistance = distance;
321                     bestIndex = j;
322                 }
323             }
324 
325             if (DEBUG_POINTERS) Log.v("InputDevice", "New index " + nextIndex
326                     + " best old index=" + bestIndex + " (distance="
327                     + bestDistance + ")");
328             next2Last[nextIndex] = bestIndex;
329             next2LastDistance[nextIndex] = bestDistance;
330 
331             if (bestIndex < 0) {
332                 return true;
333             }
334 
335             if (last2Next[bestIndex] == -1) {
336                 last2Next[bestIndex] = nextIndex;
337                 return false;
338             }
339 
340             if (DEBUG_POINTERS) Log.v("InputDevice", "Old index " + bestIndex
341                     + " has multiple best new pointers!");
342 
343             last2Next[bestIndex] = -2;
344             return true;
345         }
346 
updatePointerIdentifiers()347         private int updatePointerIdentifiers() {
348             final int[] lastData = mLastData;
349             final int[] nextData = mNextData;
350             final int nextNumPointers = mNextNumPointers;
351             final int lastNumPointers = mLastNumPointers;
352 
353             if (nextNumPointers == 1 && lastNumPointers == 1) {
354                 System.arraycopy(nextData, 0, lastData, 0,
355                         MotionEvent.NUM_SAMPLE_DATA);
356                 return -1;
357             }
358 
359             // Clear our old state.
360             final int[] last2Next = mLast2Next;
361             for (int i=0; i<lastNumPointers; i++) {
362                 last2Next[i] = -1;
363             }
364 
365             if (DEBUG_POINTERS) Log.v("InputDevice",
366                     "Update pointers: lastNumPointers=" + lastNumPointers
367                     + " nextNumPointers=" + nextNumPointers);
368 
369             // Figure out the closes new points to the previous points.
370             final int[] next2Last = mNext2Last;
371             final long[] next2LastDistance = mNext2LastDistance;
372             boolean conflicts = false;
373             for (int i=0; i<nextNumPointers; i++) {
374                 conflicts |= assignPointer(i, true);
375             }
376 
377             // Resolve ambiguities in pointer mappings, when two or more
378             // new pointer locations find their best previous location is
379             // the same.
380             if (conflicts) {
381                 if (DEBUG_POINTERS) Log.v("InputDevice", "Resolving conflicts");
382 
383                 for (int i=0; i<lastNumPointers; i++) {
384                     if (last2Next[i] != -2) {
385                         continue;
386                     }
387 
388                     // Note that this algorithm is far from perfect.  Ideally
389                     // we should do something like the one described at
390                     // http://portal.acm.org/citation.cfm?id=997856
391 
392                     if (DEBUG_POINTERS) Log.v("InputDevice",
393                             "Resolving last index #" + i);
394 
395                     int numFound;
396                     do {
397                         numFound = 0;
398                         long worstDistance = 0;
399                         int worstJ = -1;
400                         for (int j=0; j<nextNumPointers; j++) {
401                             if (next2Last[j] != i) {
402                                 continue;
403                             }
404                             numFound++;
405                             if (worstDistance < next2LastDistance[j]) {
406                                 worstDistance = next2LastDistance[j];
407                                 worstJ = j;
408                             }
409                         }
410 
411                         if (worstJ >= 0) {
412                             if (DEBUG_POINTERS) Log.v("InputDevice",
413                                     "Worst new pointer: " + worstJ
414                                     + " (distance=" + worstDistance + ")");
415                             if (assignPointer(worstJ, false)) {
416                                 // In this case there is no last pointer
417                                 // remaining for this new one!
418                                 next2Last[worstJ] = -1;
419                             }
420                         }
421                     } while (numFound > 2);
422                 }
423             }
424 
425             int retIndex = -1;
426 
427             if (lastNumPointers < nextNumPointers) {
428                 // We have one or more new pointers that are down.  Create a
429                 // new pointer identifier for one of them.
430                 if (DEBUG_POINTERS) Log.v("InputDevice", "Adding new pointer");
431                 int nextId = 0;
432                 int i=0;
433                 while (i < lastNumPointers) {
434                     if (mPointerIds[i] > nextId) {
435                         // Found a hole, insert the pointer here.
436                         if (DEBUG_POINTERS) Log.v("InputDevice",
437                                 "Inserting new pointer at hole " + i);
438                         System.arraycopy(mPointerIds, i, mPointerIds,
439                                 i+1, lastNumPointers-i);
440                         System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA,
441                                 lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA,
442                                 (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA);
443                         break;
444                     }
445                     i++;
446                     nextId++;
447                 }
448 
449                 if (DEBUG_POINTERS) Log.v("InputDevice",
450                         "New pointer id " + nextId + " at index " + i);
451 
452                 mLastNumPointers++;
453                 retIndex = i;
454                 mPointerIds[i] = nextId;
455 
456                 // And assign this identifier to the first new pointer.
457                 for (int j=0; j<nextNumPointers; j++) {
458                     if (next2Last[j] < 0) {
459                         if (DEBUG_POINTERS) Log.v("InputDevice",
460                                 "Assigning new id to new pointer index " + j);
461                         next2Last[j] = i;
462                         break;
463                     }
464                 }
465             }
466 
467             // Propagate all of the current data into the appropriate
468             // location in the old data to match the pointer ID that was
469             // assigned to it.
470             for (int i=0; i<nextNumPointers; i++) {
471                 int lastIndex = next2Last[i];
472                 if (lastIndex >= 0) {
473                     if (DEBUG_POINTERS) Log.v("InputDevice",
474                             "Copying next pointer index " + i
475                             + " to last index " + lastIndex);
476                     System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
477                             lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA,
478                             MotionEvent.NUM_SAMPLE_DATA);
479                 }
480             }
481 
482             if (lastNumPointers > nextNumPointers) {
483                 // One or more pointers has gone up.  Find the first one,
484                 // and adjust accordingly.
485                 if (DEBUG_POINTERS) Log.v("InputDevice", "Removing old pointer");
486                 for (int i=0; i<lastNumPointers; i++) {
487                     if (last2Next[i] == -1) {
488                         if (DEBUG_POINTERS) Log.v("InputDevice",
489                                 "Removing old pointer at index " + i);
490                         retIndex = i;
491                         break;
492                     }
493                 }
494             }
495 
496             return retIndex;
497         }
498 
removeOldPointer(int index)499         void removeOldPointer(int index) {
500             final int lastNumPointers = mLastNumPointers;
501             if (index >= 0 && index < lastNumPointers) {
502                 System.arraycopy(mPointerIds, index+1, mPointerIds,
503                         index, lastNumPointers-index-1);
504                 System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA,
505                         mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA,
506                         (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA);
507                 mLastNumPointers--;
508             }
509         }
510 
generateAbsMotion(InputDevice device, long curTime, long curTimeNano, Display display, int orientation, int metaState)511         MotionEvent generateAbsMotion(InputDevice device, long curTime,
512                 long curTimeNano, Display display, int orientation,
513                 int metaState) {
514 
515             if (mSkipLastPointers) {
516                 mSkipLastPointers = false;
517                 mLastNumPointers = 0;
518             }
519 
520             if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
521                 return null;
522             }
523 
524             final int lastNumPointers = mLastNumPointers;
525             final int nextNumPointers = mNextNumPointers;
526             if (mNextNumPointers > MAX_POINTERS) {
527                 Log.w("InputDevice", "Number of pointers " + mNextNumPointers
528                         + " exceeded maximum of " + MAX_POINTERS);
529                 mNextNumPointers = MAX_POINTERS;
530             }
531 
532             int upOrDownPointer = updatePointerIdentifiers();
533 
534             final float[] reportData = mReportData;
535             final int[] rawData;
536             if (KeyInputQueue.BAD_TOUCH_HACK) {
537                 rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
538                         nextNumPointers);
539             } else {
540                 rawData = mLastData;
541             }
542 
543             final int numPointers = mLastNumPointers;
544 
545             if (DEBUG_POINTERS) Log.v("InputDevice", "Processing "
546                     + numPointers + " pointers (going from " + lastNumPointers
547                     + " to " + nextNumPointers + ")");
548 
549             for (int i=0; i<numPointers; i++) {
550                 final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
551                 reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
552                 reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];
553                 reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
554                 reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
555             }
556 
557             int action;
558             int edgeFlags = 0;
559             if (nextNumPointers != lastNumPointers) {
560                 if (nextNumPointers > lastNumPointers) {
561                     if (lastNumPointers == 0) {
562                         action = MotionEvent.ACTION_DOWN;
563                         mDownTime = curTime;
564                     } else {
565                         action = MotionEvent.ACTION_POINTER_DOWN
566                                 | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
567                     }
568                 } else {
569                     if (numPointers == 1) {
570                         action = MotionEvent.ACTION_UP;
571                     } else {
572                         action = MotionEvent.ACTION_POINTER_UP
573                                 | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
574                     }
575                 }
576                 currentMove = null;
577             } else {
578                 action = MotionEvent.ACTION_MOVE;
579             }
580 
581             final int dispW = display.getWidth()-1;
582             final int dispH = display.getHeight()-1;
583             int w = dispW;
584             int h = dispH;
585             if (orientation == Surface.ROTATION_90
586                     || orientation == Surface.ROTATION_270) {
587                 int tmp = w;
588                 w = h;
589                 h = tmp;
590             }
591 
592             final AbsoluteInfo absX = device.absX;
593             final AbsoluteInfo absY = device.absY;
594             final AbsoluteInfo absPressure = device.absPressure;
595             final AbsoluteInfo absSize = device.absSize;
596             for (int i=0; i<numPointers; i++) {
597                 final int j = i * MotionEvent.NUM_SAMPLE_DATA;
598 
599                 if (absX != null) {
600                     reportData[j + MotionEvent.SAMPLE_X] =
601                             ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
602                                 / absX.range) * w;
603                 }
604                 if (absY != null) {
605                     reportData[j + MotionEvent.SAMPLE_Y] =
606                             ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)
607                                 / absY.range) * h;
608                 }
609                 if (absPressure != null) {
610                     reportData[j + MotionEvent.SAMPLE_PRESSURE] =
611                             ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
612                                 / (float)absPressure.range);
613                 }
614                 if (absSize != null) {
615                     reportData[j + MotionEvent.SAMPLE_SIZE] =
616                             ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
617                                 / (float)absSize.range);
618                 }
619 
620                 switch (orientation) {
621                     case Surface.ROTATION_90: {
622                         final float temp = reportData[j + MotionEvent.SAMPLE_X];
623                         reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y];
624                         reportData[j + MotionEvent.SAMPLE_Y] = w-temp;
625                         break;
626                     }
627                     case Surface.ROTATION_180: {
628                         reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X];
629                         reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y];
630                         break;
631                     }
632                     case Surface.ROTATION_270: {
633                         final float temp = reportData[j + MotionEvent.SAMPLE_X];
634                         reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y];
635                         reportData[j + MotionEvent.SAMPLE_Y] = temp;
636                         break;
637                     }
638                 }
639             }
640 
641             // We only consider the first pointer when computing the edge
642             // flags, since they are global to the event.
643             if (action == MotionEvent.ACTION_DOWN) {
644                 if (reportData[MotionEvent.SAMPLE_X] <= 0) {
645                     edgeFlags |= MotionEvent.EDGE_LEFT;
646                 } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) {
647                     edgeFlags |= MotionEvent.EDGE_RIGHT;
648                 }
649                 if (reportData[MotionEvent.SAMPLE_Y] <= 0) {
650                     edgeFlags |= MotionEvent.EDGE_TOP;
651                 } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {
652                     edgeFlags |= MotionEvent.EDGE_BOTTOM;
653                 }
654             }
655 
656             if (currentMove != null) {
657                 if (false) Log.i("InputDevice", "Adding batch x="
658                         + reportData[MotionEvent.SAMPLE_X]
659                         + " y=" + reportData[MotionEvent.SAMPLE_Y]
660                         + " to " + currentMove);
661                 currentMove.addBatch(curTime, reportData, metaState);
662                 if (WindowManagerPolicy.WATCH_POINTER) {
663                     Log.i("KeyInputQueue", "Updating: " + currentMove);
664                 }
665                 return null;
666             }
667 
668             MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
669                     curTimeNano, action, numPointers, mPointerIds, reportData,
670                     metaState, xPrecision, yPrecision, device.id, edgeFlags);
671             if (action == MotionEvent.ACTION_MOVE) {
672                 currentMove = me;
673             }
674 
675             if (nextNumPointers < lastNumPointers) {
676                 removeOldPointer(upOrDownPointer);
677             }
678 
679             return me;
680         }
681 
hasMore()682         boolean hasMore() {
683             return mLastNumPointers != mNextNumPointers;
684         }
685 
finish()686         void finish() {
687             mNextNumPointers = mAddingPointerOffset = 0;
688             mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;
689         }
690 
generateRelMotion(InputDevice device, long curTime, long curTimeNano, int orientation, int metaState)691         MotionEvent generateRelMotion(InputDevice device, long curTime,
692                 long curTimeNano, int orientation, int metaState) {
693 
694             final float[] scaled = mReportData;
695 
696             // For now we only support 1 pointer with relative motions.
697             scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X];
698             scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y];
699             scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f;
700             scaled[MotionEvent.SAMPLE_SIZE] = 0;
701             int edgeFlags = 0;
702 
703             int action;
704             if (mNextNumPointers != mLastNumPointers) {
705                 mNextData[MotionEvent.SAMPLE_X] =
706                         mNextData[MotionEvent.SAMPLE_Y] = 0;
707                 if (mNextNumPointers > 0 && mLastNumPointers == 0) {
708                     action = MotionEvent.ACTION_DOWN;
709                     mDownTime = curTime;
710                 } else if (mNextNumPointers == 0) {
711                     action = MotionEvent.ACTION_UP;
712                 } else {
713                     action = MotionEvent.ACTION_MOVE;
714                 }
715                 mLastNumPointers = mNextNumPointers;
716                 currentMove = null;
717             } else {
718                 action = MotionEvent.ACTION_MOVE;
719             }
720 
721             scaled[MotionEvent.SAMPLE_X] *= xMoveScale;
722             scaled[MotionEvent.SAMPLE_Y] *= yMoveScale;
723             switch (orientation) {
724                 case Surface.ROTATION_90: {
725                     final float temp = scaled[MotionEvent.SAMPLE_X];
726                     scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y];
727                     scaled[MotionEvent.SAMPLE_Y] = -temp;
728                     break;
729                 }
730                 case Surface.ROTATION_180: {
731                     scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X];
732                     scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y];
733                     break;
734                 }
735                 case Surface.ROTATION_270: {
736                     final float temp = scaled[MotionEvent.SAMPLE_X];
737                     scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y];
738                     scaled[MotionEvent.SAMPLE_Y] = temp;
739                     break;
740                 }
741             }
742 
743             if (currentMove != null) {
744                 if (false) Log.i("InputDevice", "Adding batch x="
745                         + scaled[MotionEvent.SAMPLE_X]
746                         + " y=" + scaled[MotionEvent.SAMPLE_Y]
747                         + " to " + currentMove);
748                 currentMove.addBatch(curTime, scaled, metaState);
749                 if (WindowManagerPolicy.WATCH_POINTER) {
750                     Log.i("KeyInputQueue", "Updating: " + currentMove);
751                 }
752                 return null;
753             }
754 
755             MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
756                     curTimeNano, action, 1, mPointerIds, scaled, metaState,
757                     xPrecision, yPrecision, device.id, edgeFlags);
758             if (action == MotionEvent.ACTION_MOVE) {
759                 currentMove = me;
760             }
761             return me;
762         }
763     }
764 
765     static class AbsoluteInfo {
766         int minValue;
767         int maxValue;
768         int range;
769         int flat;
770         int fuzz;
771     };
772 
InputDevice(int _id, int _classes, String _name, AbsoluteInfo _absX, AbsoluteInfo _absY, AbsoluteInfo _absPressure, AbsoluteInfo _absSize)773     InputDevice(int _id, int _classes, String _name,
774             AbsoluteInfo _absX, AbsoluteInfo _absY,
775             AbsoluteInfo _absPressure, AbsoluteInfo _absSize) {
776         id = _id;
777         classes = _classes;
778         name = _name;
779         absX = _absX;
780         absY = _absY;
781         absPressure = _absPressure;
782         absSize = _absSize;
783     }
784 };
785