blob: d5e94ecf584929894b03db484ef356232ae98d7e [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
Joe Onorato8a9b2202010-02-26 18:56:32 -080019import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.view.Display;
21import android.view.MotionEvent;
22import android.view.Surface;
23import android.view.WindowManagerPolicy;
24
Dianne Hackborna2e92262010-03-02 17:19:29 -080025import java.io.PrintWriter;
26
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027public class InputDevice {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070028 static final boolean DEBUG_POINTERS = false;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -070029 static final boolean DEBUG_HACKS = false;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070030
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031 /** Amount that trackball needs to move in order to generate a key event. */
32 static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
33
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070034 /** Maximum number of pointers we will track and report. */
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070035 static final int MAX_POINTERS = 10;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070036
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 final int id;
38 final int classes;
39 final String name;
40 final AbsoluteInfo absX;
41 final AbsoluteInfo absY;
42 final AbsoluteInfo absPressure;
43 final AbsoluteInfo absSize;
44
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070045 long mKeyDownTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046 int mMetaKeysState = 0;
47
Dianne Hackborn2a2b34432009-08-12 17:13:55 -070048 // For use by KeyInputQueue for keeping track of the current touch
49 // data in the old non-multi-touch protocol.
50 final int[] curTouchVals = new int[MotionEvent.NUM_SAMPLE_DATA * 2];
51
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052 final MotionState mAbs = new MotionState(0, 0);
53 final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD,
54 TRACKBALL_MOVEMENT_THRESHOLD);
55
56 static class MotionState {
57 int xPrecision;
58 int yPrecision;
59 float xMoveScale;
60 float yMoveScale;
61 MotionEvent currentMove = null;
62 boolean changed = false;
Dianne Hackborna2e92262010-03-02 17:19:29 -080063 boolean everChanged = false;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070064 long mDownTime = 0;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070065
66 // The currently assigned pointer IDs, corresponding to the last data.
67 int[] mPointerIds = new int[MAX_POINTERS];
68
69 // This is the last generated pointer data, ordered to match
70 // mPointerIds.
Dianne Hackborndc953722009-10-19 11:24:39 -070071 boolean mSkipLastPointers;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070072 int mLastNumPointers = 0;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -070073 final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070074
75 // This is the next set of pointer data being generated. It is not
76 // in any known order, and will be propagated in to mLastData
77 // as part of mapping it to the appropriate pointer IDs.
78 // Note that we have one extra sample of data here, to help clients
79 // avoid doing bounds checking.
80 int mNextNumPointers = 0;
81 final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
82 + MotionEvent.NUM_SAMPLE_DATA];
83
Dianne Hackborn1411d1c2009-10-12 23:21:18 -070084 // Used to determine whether we dropped bad data, to avoid doing
85 // it repeatedly.
86 final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS];
87
88 // Used to perform averaging of reported coordinates, to smooth
89 // the data and filter out transients during a release.
90 static final int HISTORY_SIZE = 5;
91 int[] mHistoryDataStart = new int[MAX_POINTERS];
92 int[] mHistoryDataEnd = new int[MAX_POINTERS];
93 final int[] mHistoryData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
94 * HISTORY_SIZE];
95 final int[] mAveragedData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
96
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070097 // Temporary data structures for doing the pointer ID mapping.
98 final int[] mLast2Next = new int[MAX_POINTERS];
99 final int[] mNext2Last = new int[MAX_POINTERS];
100 final long[] mNext2LastDistance = new long[MAX_POINTERS];
101
102 // Temporary data structure for generating the final motion data.
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700103 final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700105 // This is not used here, but can be used by callers for state tracking.
106 int mAddingPointerOffset = 0;
107 final boolean[] mDown = new boolean[MAX_POINTERS];
108
Dianne Hackborna2e92262010-03-02 17:19:29 -0800109 void dumpIntArray(PrintWriter pw, int[] array) {
110 pw.print("[");
111 for (int i=0; i<array.length; i++) {
112 if (i > 0) pw.print(", ");
113 pw.print(array[i]);
114 }
115 pw.print("]");
116 }
117
118 void dumpBooleanArray(PrintWriter pw, boolean[] array) {
119 pw.print("[");
120 for (int i=0; i<array.length; i++) {
121 if (i > 0) pw.print(", ");
122 pw.print(array[i] ? "true" : "false");
123 }
124 pw.print("]");
125 }
126
127 void dump(PrintWriter pw, String prefix) {
128 pw.print(prefix); pw.print("xPrecision="); pw.print(xPrecision);
129 pw.print(" yPrecision="); pw.println(yPrecision);
130 pw.print(prefix); pw.print("xMoveScale="); pw.print(xMoveScale);
131 pw.print(" yMoveScale="); pw.println(yMoveScale);
132 if (currentMove != null) {
133 pw.print(prefix); pw.print("currentMove="); pw.println(currentMove);
134 }
135 if (changed || mDownTime != 0) {
136 pw.print(prefix); pw.print("changed="); pw.print(changed);
137 pw.print(" mDownTime="); pw.println(mDownTime);
138 }
139 pw.print(prefix); pw.print("mPointerIds="); dumpIntArray(pw, mPointerIds);
140 pw.println("");
141 if (mSkipLastPointers || mLastNumPointers != 0) {
142 pw.print(prefix); pw.print("mSkipLastPointers="); pw.print(mSkipLastPointers);
143 pw.print(" mLastNumPointers="); pw.println(mLastNumPointers);
144 pw.print(prefix); pw.print("mLastData="); dumpIntArray(pw, mLastData);
145 pw.println("");
146 }
147 if (mNextNumPointers != 0) {
148 pw.print(prefix); pw.print("mNextNumPointers="); pw.println(mNextNumPointers);
149 pw.print(prefix); pw.print("mNextData="); dumpIntArray(pw, mNextData);
150 pw.println("");
151 }
152 pw.print(prefix); pw.print("mDroppedBadPoint=");
153 dumpBooleanArray(pw, mDroppedBadPoint); pw.println("");
154 pw.print(prefix); pw.print("mAddingPointerOffset="); pw.println(mAddingPointerOffset);
155 pw.print(prefix); pw.print("mDown=");
156 dumpBooleanArray(pw, mDown); pw.println("");
157 }
158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 MotionState(int mx, int my) {
160 xPrecision = mx;
161 yPrecision = my;
162 xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f;
163 yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700164 for (int i=0; i<MAX_POINTERS; i++) {
165 mPointerIds[i] = i;
166 }
167 }
168
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700169 /**
170 * Special hack for devices that have bad screen data: if one of the
171 * points has moved more than a screen height from the last position,
172 * then drop it.
173 */
174 void dropBadPoint(InputDevice dev) {
175 // We should always have absY, but let's be paranoid.
176 if (dev.absY == null) {
177 return;
178 }
179 // Don't do anything if a finger is going down or up. We run
180 // here before assigning pointer IDs, so there isn't a good
181 // way to do per-finger matching.
182 if (mNextNumPointers != mLastNumPointers) {
183 return;
184 }
185
186 // We consider a single movement across more than a 7/16 of
187 // the long size of the screen to be bad. This was a magic value
188 // determined by looking at the maximum distance it is feasible
189 // to actually move in one sample.
190 final int maxDy = ((dev.absY.maxValue-dev.absY.minValue)*7)/16;
191
192 // Look through all new points and see if any are farther than
193 // acceptable from all previous points.
194 for (int i=mNextNumPointers-1; i>=0; i--) {
195 final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
196 //final int x = mNextData[ioff + MotionEvent.SAMPLE_X];
197 final int y = mNextData[ioff + MotionEvent.SAMPLE_Y];
Joe Onorato8a9b2202010-02-26 18:56:32 -0800198 if (DEBUG_HACKS) Slog.v("InputDevice", "Looking at next point #" + i + ": y=" + y);
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700199 boolean dropped = false;
200 if (!mDroppedBadPoint[i] && mLastNumPointers > 0) {
201 dropped = true;
202 int closestDy = -1;
203 int closestY = -1;
204 // We will drop this new point if it is sufficiently
205 // far away from -all- last points.
206 for (int j=mLastNumPointers-1; j>=0; j--) {
207 final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
208 //int dx = x - mLastData[joff + MotionEvent.SAMPLE_X];
209 int dy = y - mLastData[joff + MotionEvent.SAMPLE_Y];
210 //if (dx < 0) dx = -dx;
211 if (dy < 0) dy = -dy;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800212 if (DEBUG_HACKS) Slog.v("InputDevice", "Comparing with last point #" + j
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700213 + ": y=" + mLastData[joff] + " dy=" + dy);
214 if (dy < maxDy) {
215 dropped = false;
216 break;
217 } else if (closestDy < 0 || dy < closestDy) {
218 closestDy = dy;
219 closestY = mLastData[joff + MotionEvent.SAMPLE_Y];
220 }
221 }
222 if (dropped) {
223 dropped = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800224 Slog.i("InputDevice", "Dropping bad point #" + i
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700225 + ": newY=" + y + " closestDy=" + closestDy
226 + " maxDy=" + maxDy);
227 mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY;
228 break;
229 }
230 }
231 mDroppedBadPoint[i] = dropped;
232 }
233 }
234
235 /**
236 * Special hack for devices that have bad screen data: aggregate and
237 * compute averages of the coordinate data, to reduce the amount of
238 * jitter seen by applications.
239 */
240 int[] generateAveragedData(int upOrDownPointer, int lastNumPointers,
241 int nextNumPointers) {
242 final int numPointers = mLastNumPointers;
243 final int[] rawData = mLastData;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800244 if (DEBUG_HACKS) Slog.v("InputDevice", "lastNumPointers=" + lastNumPointers
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700245 + " nextNumPointers=" + nextNumPointers
246 + " numPointers=" + numPointers);
247 for (int i=0; i<numPointers; i++) {
248 final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
249 // We keep the average data in offsets based on the pointer
250 // ID, so we don't need to move it around as fingers are
251 // pressed and released.
252 final int p = mPointerIds[i];
253 final int poff = p * MotionEvent.NUM_SAMPLE_DATA * HISTORY_SIZE;
254 if (i == upOrDownPointer && lastNumPointers != nextNumPointers) {
255 if (lastNumPointers < nextNumPointers) {
256 // This pointer is going down. Clear its history
257 // and start fresh.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800258 if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer down @ index "
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700259 + upOrDownPointer + " id " + mPointerIds[i]);
260 mHistoryDataStart[i] = 0;
261 mHistoryDataEnd[i] = 0;
262 System.arraycopy(rawData, ioff, mHistoryData, poff,
263 MotionEvent.NUM_SAMPLE_DATA);
264 System.arraycopy(rawData, ioff, mAveragedData, ioff,
265 MotionEvent.NUM_SAMPLE_DATA);
266 continue;
267 } else {
268 // The pointer is going up. Just fall through to
269 // recompute the last averaged point (and don't add
270 // it as a new point to include in the average).
Joe Onorato8a9b2202010-02-26 18:56:32 -0800271 if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer up @ index "
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700272 + upOrDownPointer + " id " + mPointerIds[i]);
273 }
274 } else {
275 int end = mHistoryDataEnd[i];
276 int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
277 int oldX = mHistoryData[eoff + MotionEvent.SAMPLE_X];
278 int oldY = mHistoryData[eoff + MotionEvent.SAMPLE_Y];
279 int newX = rawData[ioff + MotionEvent.SAMPLE_X];
280 int newY = rawData[ioff + MotionEvent.SAMPLE_Y];
281 int dx = newX-oldX;
282 int dy = newY-oldY;
283 int delta = dx*dx + dy*dy;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800284 if (DEBUG_HACKS) Slog.v("InputDevice", "Delta from last: " + delta);
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700285 if (delta >= (75*75)) {
286 // Magic number, if moving farther than this, turn
287 // off filtering to avoid lag in response.
288 mHistoryDataStart[i] = 0;
289 mHistoryDataEnd[i] = 0;
290 System.arraycopy(rawData, ioff, mHistoryData, poff,
291 MotionEvent.NUM_SAMPLE_DATA);
292 System.arraycopy(rawData, ioff, mAveragedData, ioff,
293 MotionEvent.NUM_SAMPLE_DATA);
294 continue;
295 } else {
296 end++;
297 if (end >= HISTORY_SIZE) {
298 end -= HISTORY_SIZE;
299 }
300 mHistoryDataEnd[i] = end;
301 int noff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
302 mHistoryData[noff + MotionEvent.SAMPLE_X] = newX;
303 mHistoryData[noff + MotionEvent.SAMPLE_Y] = newY;
304 mHistoryData[noff + MotionEvent.SAMPLE_PRESSURE]
305 = rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
306 int start = mHistoryDataStart[i];
307 if (end == start) {
308 start++;
309 if (start >= HISTORY_SIZE) {
310 start -= HISTORY_SIZE;
311 }
312 mHistoryDataStart[i] = start;
313 }
314 }
315 }
316
317 // Now compute the average.
318 int start = mHistoryDataStart[i];
319 int end = mHistoryDataEnd[i];
320 int x=0, y=0;
321 int totalPressure = 0;
322 while (start != end) {
323 int soff = poff + (start*MotionEvent.NUM_SAMPLE_DATA);
324 int pressure = mHistoryData[soff + MotionEvent.SAMPLE_PRESSURE];
Dianne Hackborn53cd5792009-10-13 19:50:51 -0700325 if (pressure <= 0) pressure = 1;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700326 x += mHistoryData[soff + MotionEvent.SAMPLE_X] * pressure;
327 y += mHistoryData[soff + MotionEvent.SAMPLE_Y] * pressure;
328 totalPressure += pressure;
329 start++;
330 if (start >= HISTORY_SIZE) start = 0;
331 }
332 int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
333 int pressure = mHistoryData[eoff + MotionEvent.SAMPLE_PRESSURE];
Dianne Hackborn53cd5792009-10-13 19:50:51 -0700334 if (pressure <= 0) pressure = 1;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700335 x += mHistoryData[eoff + MotionEvent.SAMPLE_X] * pressure;
336 y += mHistoryData[eoff + MotionEvent.SAMPLE_Y] * pressure;
337 totalPressure += pressure;
338 x /= totalPressure;
339 y /= totalPressure;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800340 if (DEBUG_HACKS) Slog.v("InputDevice", "Averaging " + totalPressure
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700341 + " weight: (" + x + "," + y + ")");
342 mAveragedData[ioff + MotionEvent.SAMPLE_X] = x;
343 mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y;
Dianne Hackborn05799982009-11-23 13:08:14 -0800344 mAveragedData[ioff + MotionEvent.SAMPLE_PRESSURE] =
345 rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
346 mAveragedData[ioff + MotionEvent.SAMPLE_SIZE] =
347 rawData[ioff + MotionEvent.SAMPLE_SIZE];
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700348 }
349 return mAveragedData;
350 }
351
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700352 private boolean assignPointer(int nextIndex, boolean allowOverlap) {
353 final int lastNumPointers = mLastNumPointers;
354 final int[] next2Last = mNext2Last;
355 final long[] next2LastDistance = mNext2LastDistance;
356 final int[] last2Next = mLast2Next;
357 final int[] lastData = mLastData;
358 final int[] nextData = mNextData;
359 final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
360
Joe Onorato8a9b2202010-02-26 18:56:32 -0800361 if (DEBUG_POINTERS) Slog.v("InputDevice", "assignPointer: nextIndex="
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700362 + nextIndex + " dataOff=" + id);
363 final int x1 = nextData[id + MotionEvent.SAMPLE_X];
364 final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
365
366 long bestDistance = -1;
367 int bestIndex = -1;
368 for (int j=0; j<lastNumPointers; j++) {
Dianne Hackborn709d6db2009-12-02 18:42:39 -0800369 // If we are not allowing multiple new points to be assigned
370 // to the same old pointer, then skip this one if it is already
371 // detected as a conflict (-2).
372 if (!allowOverlap && last2Next[j] < -1) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700373 continue;
374 }
375 final int jd = j * MotionEvent.NUM_SAMPLE_DATA;
376 final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1;
377 final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1;
378 final long distance = xd*(long)xd + yd*(long)yd;
Dianne Hackborn709d6db2009-12-02 18:42:39 -0800379 if (bestDistance == -1 || distance < bestDistance) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700380 bestDistance = distance;
381 bestIndex = j;
382 }
383 }
384
Joe Onorato8a9b2202010-02-26 18:56:32 -0800385 if (DEBUG_POINTERS) Slog.v("InputDevice", "New index " + nextIndex
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700386 + " best old index=" + bestIndex + " (distance="
387 + bestDistance + ")");
388 next2Last[nextIndex] = bestIndex;
389 next2LastDistance[nextIndex] = bestDistance;
390
391 if (bestIndex < 0) {
392 return true;
393 }
394
395 if (last2Next[bestIndex] == -1) {
396 last2Next[bestIndex] = nextIndex;
397 return false;
398 }
399
Joe Onorato8a9b2202010-02-26 18:56:32 -0800400 if (DEBUG_POINTERS) Slog.v("InputDevice", "Old index " + bestIndex
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700401 + " has multiple best new pointers!");
402
403 last2Next[bestIndex] = -2;
404 return true;
405 }
406
407 private int updatePointerIdentifiers() {
408 final int[] lastData = mLastData;
409 final int[] nextData = mNextData;
410 final int nextNumPointers = mNextNumPointers;
411 final int lastNumPointers = mLastNumPointers;
412
413 if (nextNumPointers == 1 && lastNumPointers == 1) {
414 System.arraycopy(nextData, 0, lastData, 0,
415 MotionEvent.NUM_SAMPLE_DATA);
416 return -1;
417 }
418
419 // Clear our old state.
420 final int[] last2Next = mLast2Next;
421 for (int i=0; i<lastNumPointers; i++) {
422 last2Next[i] = -1;
423 }
424
Joe Onorato8a9b2202010-02-26 18:56:32 -0800425 if (DEBUG_POINTERS) Slog.v("InputDevice",
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700426 "Update pointers: lastNumPointers=" + lastNumPointers
427 + " nextNumPointers=" + nextNumPointers);
428
429 // Figure out the closes new points to the previous points.
430 final int[] next2Last = mNext2Last;
431 final long[] next2LastDistance = mNext2LastDistance;
432 boolean conflicts = false;
433 for (int i=0; i<nextNumPointers; i++) {
434 conflicts |= assignPointer(i, true);
435 }
436
437 // Resolve ambiguities in pointer mappings, when two or more
438 // new pointer locations find their best previous location is
439 // the same.
440 if (conflicts) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800441 if (DEBUG_POINTERS) Slog.v("InputDevice", "Resolving conflicts");
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700442
443 for (int i=0; i<lastNumPointers; i++) {
444 if (last2Next[i] != -2) {
445 continue;
446 }
447
448 // Note that this algorithm is far from perfect. Ideally
449 // we should do something like the one described at
450 // http://portal.acm.org/citation.cfm?id=997856
451
Joe Onorato8a9b2202010-02-26 18:56:32 -0800452 if (DEBUG_POINTERS) Slog.v("InputDevice",
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700453 "Resolving last index #" + i);
454
455 int numFound;
456 do {
457 numFound = 0;
458 long worstDistance = 0;
459 int worstJ = -1;
460 for (int j=0; j<nextNumPointers; j++) {
461 if (next2Last[j] != i) {
462 continue;
463 }
464 numFound++;
465 if (worstDistance < next2LastDistance[j]) {
466 worstDistance = next2LastDistance[j];
467 worstJ = j;
468 }
469 }
470
471 if (worstJ >= 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800472 if (DEBUG_POINTERS) Slog.v("InputDevice",
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700473 "Worst new pointer: " + worstJ
474 + " (distance=" + worstDistance + ")");
475 if (assignPointer(worstJ, false)) {
476 // In this case there is no last pointer
477 // remaining for this new one!
478 next2Last[worstJ] = -1;
479 }
480 }
481 } while (numFound > 2);
482 }
483 }
484
485 int retIndex = -1;
486
487 if (lastNumPointers < nextNumPointers) {
488 // We have one or more new pointers that are down. Create a
489 // new pointer identifier for one of them.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800490 if (DEBUG_POINTERS) Slog.v("InputDevice", "Adding new pointer");
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700491 int nextId = 0;
492 int i=0;
493 while (i < lastNumPointers) {
494 if (mPointerIds[i] > nextId) {
495 // Found a hole, insert the pointer here.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800496 if (DEBUG_POINTERS) Slog.v("InputDevice",
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700497 "Inserting new pointer at hole " + i);
498 System.arraycopy(mPointerIds, i, mPointerIds,
499 i+1, lastNumPointers-i);
500 System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA,
501 lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA,
502 (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA);
503 break;
504 }
505 i++;
506 nextId++;
507 }
508
Joe Onorato8a9b2202010-02-26 18:56:32 -0800509 if (DEBUG_POINTERS) Slog.v("InputDevice",
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700510 "New pointer id " + nextId + " at index " + i);
511
512 mLastNumPointers++;
513 retIndex = i;
514 mPointerIds[i] = nextId;
515
516 // And assign this identifier to the first new pointer.
517 for (int j=0; j<nextNumPointers; j++) {
518 if (next2Last[j] < 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800519 if (DEBUG_POINTERS) Slog.v("InputDevice",
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700520 "Assigning new id to new pointer index " + j);
521 next2Last[j] = i;
522 break;
523 }
524 }
525 }
526
527 // Propagate all of the current data into the appropriate
528 // location in the old data to match the pointer ID that was
529 // assigned to it.
530 for (int i=0; i<nextNumPointers; i++) {
531 int lastIndex = next2Last[i];
532 if (lastIndex >= 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800533 if (DEBUG_POINTERS) Slog.v("InputDevice",
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700534 "Copying next pointer index " + i
535 + " to last index " + lastIndex);
536 System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
537 lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA,
538 MotionEvent.NUM_SAMPLE_DATA);
539 }
540 }
541
542 if (lastNumPointers > nextNumPointers) {
543 // One or more pointers has gone up. Find the first one,
544 // and adjust accordingly.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800545 if (DEBUG_POINTERS) Slog.v("InputDevice", "Removing old pointer");
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700546 for (int i=0; i<lastNumPointers; i++) {
547 if (last2Next[i] == -1) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800548 if (DEBUG_POINTERS) Slog.v("InputDevice",
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700549 "Removing old pointer at index " + i);
550 retIndex = i;
551 break;
552 }
553 }
554 }
555
556 return retIndex;
557 }
558
559 void removeOldPointer(int index) {
560 final int lastNumPointers = mLastNumPointers;
561 if (index >= 0 && index < lastNumPointers) {
562 System.arraycopy(mPointerIds, index+1, mPointerIds,
563 index, lastNumPointers-index-1);
564 System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA,
565 mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA,
566 (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA);
567 mLastNumPointers--;
568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 }
570
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700571 MotionEvent generateAbsMotion(InputDevice device, long curTime,
572 long curTimeNano, Display display, int orientation,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 int metaState) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700574
Dianne Hackborndc953722009-10-19 11:24:39 -0700575 if (mSkipLastPointers) {
576 mSkipLastPointers = false;
577 mLastNumPointers = 0;
578 }
579
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700580 if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
581 return null;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700582 }
583
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700584 final int lastNumPointers = mLastNumPointers;
585 final int nextNumPointers = mNextNumPointers;
586 if (mNextNumPointers > MAX_POINTERS) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800587 Slog.w("InputDevice", "Number of pointers " + mNextNumPointers
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700588 + " exceeded maximum of " + MAX_POINTERS);
589 mNextNumPointers = MAX_POINTERS;
590 }
591
592 int upOrDownPointer = updatePointerIdentifiers();
593
594 final float[] reportData = mReportData;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700595 final int[] rawData;
596 if (KeyInputQueue.BAD_TOUCH_HACK) {
597 rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
598 nextNumPointers);
599 } else {
600 rawData = mLastData;
601 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700602
603 final int numPointers = mLastNumPointers;
604
Joe Onorato8a9b2202010-02-26 18:56:32 -0800605 if (DEBUG_POINTERS) Slog.v("InputDevice", "Processing "
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700606 + numPointers + " pointers (going from " + lastNumPointers
607 + " to " + nextNumPointers + ")");
608
609 for (int i=0; i<numPointers; i++) {
610 final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
611 reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
612 reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];
613 reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
614 reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700615 }
616
617 int action;
618 int edgeFlags = 0;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700619 if (nextNumPointers != lastNumPointers) {
620 if (nextNumPointers > lastNumPointers) {
621 if (lastNumPointers == 0) {
622 action = MotionEvent.ACTION_DOWN;
623 mDownTime = curTime;
624 } else {
625 action = MotionEvent.ACTION_POINTER_DOWN
Dianne Hackbornb125dc52010-02-12 15:52:09 -0800626 | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700627 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700628 } else {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700629 if (numPointers == 1) {
630 action = MotionEvent.ACTION_UP;
631 } else {
632 action = MotionEvent.ACTION_POINTER_UP
Dianne Hackbornb125dc52010-02-12 15:52:09 -0800633 | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700634 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700635 }
636 currentMove = null;
637 } else {
638 action = MotionEvent.ACTION_MOVE;
639 }
640
641 final int dispW = display.getWidth()-1;
642 final int dispH = display.getHeight()-1;
643 int w = dispW;
644 int h = dispH;
645 if (orientation == Surface.ROTATION_90
646 || orientation == Surface.ROTATION_270) {
647 int tmp = w;
648 w = h;
649 h = tmp;
650 }
651
652 final AbsoluteInfo absX = device.absX;
653 final AbsoluteInfo absY = device.absY;
654 final AbsoluteInfo absPressure = device.absPressure;
655 final AbsoluteInfo absSize = device.absSize;
656 for (int i=0; i<numPointers; i++) {
657 final int j = i * MotionEvent.NUM_SAMPLE_DATA;
658
659 if (absX != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700660 reportData[j + MotionEvent.SAMPLE_X] =
661 ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700662 / absX.range) * w;
663 }
664 if (absY != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700665 reportData[j + MotionEvent.SAMPLE_Y] =
666 ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700667 / absY.range) * h;
668 }
669 if (absPressure != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700670 reportData[j + MotionEvent.SAMPLE_PRESSURE] =
671 ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700672 / (float)absPressure.range);
673 }
674 if (absSize != null) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700675 reportData[j + MotionEvent.SAMPLE_SIZE] =
676 ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700677 / (float)absSize.range);
678 }
679
680 switch (orientation) {
681 case Surface.ROTATION_90: {
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700682 final float temp = reportData[j + MotionEvent.SAMPLE_X];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700683 reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y];
684 reportData[j + MotionEvent.SAMPLE_Y] = w-temp;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700685 break;
686 }
687 case Surface.ROTATION_180: {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700688 reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X];
689 reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700690 break;
691 }
692 case Surface.ROTATION_270: {
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700693 final float temp = reportData[j + MotionEvent.SAMPLE_X];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700694 reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y];
695 reportData[j + MotionEvent.SAMPLE_Y] = temp;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700696 break;
697 }
698 }
699 }
700
701 // We only consider the first pointer when computing the edge
702 // flags, since they are global to the event.
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700703 if (action == MotionEvent.ACTION_DOWN) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700704 if (reportData[MotionEvent.SAMPLE_X] <= 0) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700705 edgeFlags |= MotionEvent.EDGE_LEFT;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700706 } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700707 edgeFlags |= MotionEvent.EDGE_RIGHT;
708 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700709 if (reportData[MotionEvent.SAMPLE_Y] <= 0) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700710 edgeFlags |= MotionEvent.EDGE_TOP;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700711 } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700712 edgeFlags |= MotionEvent.EDGE_BOTTOM;
713 }
714 }
715
716 if (currentMove != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800717 if (false) Slog.i("InputDevice", "Adding batch x="
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700718 + reportData[MotionEvent.SAMPLE_X]
719 + " y=" + reportData[MotionEvent.SAMPLE_Y]
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700720 + " to " + currentMove);
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700721 currentMove.addBatch(curTime, reportData, metaState);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700722 if (WindowManagerPolicy.WATCH_POINTER) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800723 Slog.i("KeyInputQueue", "Updating: " + currentMove);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700724 }
725 return null;
726 }
727
728 MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700729 curTimeNano, action, numPointers, mPointerIds, reportData,
730 metaState, xPrecision, yPrecision, device.id, edgeFlags);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700731 if (action == MotionEvent.ACTION_MOVE) {
732 currentMove = me;
733 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700734
735 if (nextNumPointers < lastNumPointers) {
736 removeOldPointer(upOrDownPointer);
737 }
738
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700739 return me;
740 }
741
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700742 boolean hasMore() {
743 return mLastNumPointers != mNextNumPointers;
744 }
745
746 void finish() {
747 mNextNumPointers = mAddingPointerOffset = 0;
748 mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;
749 }
750
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700751 MotionEvent generateRelMotion(InputDevice device, long curTime,
752 long curTimeNano, int orientation, int metaState) {
753
754 final float[] scaled = mReportData;
755
756 // For now we only support 1 pointer with relative motions.
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700757 scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X];
758 scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y];
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700759 scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f;
760 scaled[MotionEvent.SAMPLE_SIZE] = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 int edgeFlags = 0;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700762
763 int action;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700764 if (mNextNumPointers != mLastNumPointers) {
765 mNextData[MotionEvent.SAMPLE_X] =
766 mNextData[MotionEvent.SAMPLE_Y] = 0;
767 if (mNextNumPointers > 0 && mLastNumPointers == 0) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700768 action = MotionEvent.ACTION_DOWN;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700769 mDownTime = curTime;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700770 } else if (mNextNumPointers == 0) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700771 action = MotionEvent.ACTION_UP;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700772 } else {
773 action = MotionEvent.ACTION_MOVE;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700774 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700775 mLastNumPointers = mNextNumPointers;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700776 currentMove = null;
777 } else {
778 action = MotionEvent.ACTION_MOVE;
779 }
780
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700781 scaled[MotionEvent.SAMPLE_X] *= xMoveScale;
782 scaled[MotionEvent.SAMPLE_Y] *= yMoveScale;
783 switch (orientation) {
784 case Surface.ROTATION_90: {
785 final float temp = scaled[MotionEvent.SAMPLE_X];
786 scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y];
787 scaled[MotionEvent.SAMPLE_Y] = -temp;
788 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700790 case Surface.ROTATION_180: {
791 scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X];
792 scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y];
793 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 }
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700795 case Surface.ROTATION_270: {
796 final float temp = scaled[MotionEvent.SAMPLE_X];
797 scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y];
798 scaled[MotionEvent.SAMPLE_Y] = temp;
799 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 }
801 }
802
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700803 if (currentMove != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800804 if (false) Slog.i("InputDevice", "Adding batch x="
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700805 + scaled[MotionEvent.SAMPLE_X]
806 + " y=" + scaled[MotionEvent.SAMPLE_Y]
807 + " to " + currentMove);
808 currentMove.addBatch(curTime, scaled, metaState);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700809 if (WindowManagerPolicy.WATCH_POINTER) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800810 Slog.i("KeyInputQueue", "Updating: " + currentMove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700812 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700814
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700815 MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700816 curTimeNano, action, 1, mPointerIds, scaled, metaState,
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700817 xPrecision, yPrecision, device.id, edgeFlags);
818 if (action == MotionEvent.ACTION_MOVE) {
819 currentMove = me;
820 }
821 return me;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 }
823 }
824
825 static class AbsoluteInfo {
826 int minValue;
827 int maxValue;
828 int range;
829 int flat;
830 int fuzz;
Dianne Hackborna2e92262010-03-02 17:19:29 -0800831
832 final void dump(PrintWriter pw) {
833 pw.print("minValue="); pw.print(minValue);
834 pw.print(" maxValue="); pw.print(maxValue);
835 pw.print(" range="); pw.print(range);
836 pw.print(" flat="); pw.print(flat);
837 pw.print(" fuzz="); pw.print(fuzz);
838 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 };
840
841 InputDevice(int _id, int _classes, String _name,
842 AbsoluteInfo _absX, AbsoluteInfo _absY,
843 AbsoluteInfo _absPressure, AbsoluteInfo _absSize) {
844 id = _id;
845 classes = _classes;
846 name = _name;
847 absX = _absX;
848 absY = _absY;
849 absPressure = _absPressure;
850 absSize = _absSize;
851 }
852};