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.Slog; 20 import android.view.Display; 21 import android.view.MotionEvent; 22 import android.view.Surface; 23 import android.view.WindowManagerPolicy; 24 25 import java.io.PrintWriter; 26 27 public class InputDevice { 28 static final boolean DEBUG_POINTERS = false; 29 static final boolean DEBUG_HACKS = false; 30 31 /** Amount that trackball needs to move in order to generate a key event. */ 32 static final int TRACKBALL_MOVEMENT_THRESHOLD = 6; 33 34 /** Maximum number of pointers we will track and report. */ 35 static final int MAX_POINTERS = 10; 36 37 /** 38 * Slop distance for jumpy pointer detection. 39 * The vertical range of the screen divided by this is our epsilon value. 40 */ 41 private static final int JUMPY_EPSILON_DIVISOR = 212; 42 43 /** Number of jumpy points to drop for touchscreens that need it. */ 44 private static final int JUMPY_TRANSITION_DROPS = 3; 45 private static final int JUMPY_DROP_LIMIT = 3; 46 47 final int id; 48 final int classes; 49 final String name; 50 final AbsoluteInfo absX; 51 final AbsoluteInfo absY; 52 final AbsoluteInfo absPressure; 53 final AbsoluteInfo absSize; 54 55 long mKeyDownTime = 0; 56 int mMetaKeysState = 0; 57 58 // For use by KeyInputQueue for keeping track of the current touch 59 // data in the old non-multi-touch protocol. 60 final int[] curTouchVals = new int[MotionEvent.NUM_SAMPLE_DATA * 2]; 61 62 final MotionState mAbs = new MotionState(0, 0); 63 final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD, 64 TRACKBALL_MOVEMENT_THRESHOLD); 65 66 static class MotionState { 67 int xPrecision; 68 int yPrecision; 69 float xMoveScale; 70 float yMoveScale; 71 MotionEvent currentMove = null; 72 boolean changed = false; 73 boolean everChanged = false; 74 long mDownTime = 0; 75 76 // The currently assigned pointer IDs, corresponding to the last data. 77 int[] mPointerIds = new int[MAX_POINTERS]; 78 79 // This is the last generated pointer data, ordered to match 80 // mPointerIds. 81 boolean mSkipLastPointers; 82 int mLastNumPointers = 0; 83 final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS]; 84 85 // This is the next set of pointer data being generated. It is not 86 // in any known order, and will be propagated in to mLastData 87 // as part of mapping it to the appropriate pointer IDs. 88 // Note that we have one extra sample of data here, to help clients 89 // avoid doing bounds checking. 90 int mNextNumPointers = 0; 91 final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS) 92 + MotionEvent.NUM_SAMPLE_DATA]; 93 94 // Used to determine whether we dropped bad data, to avoid doing 95 // it repeatedly. 96 final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS]; 97 98 // Used to count the number of jumpy points dropped. 99 private int mJumpyPointsDropped = 0; 100 101 // Used to perform averaging of reported coordinates, to smooth 102 // the data and filter out transients during a release. 103 static final int HISTORY_SIZE = 5; 104 int[] mHistoryDataStart = new int[MAX_POINTERS]; 105 int[] mHistoryDataEnd = new int[MAX_POINTERS]; 106 final int[] mHistoryData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS) 107 * HISTORY_SIZE]; 108 final int[] mAveragedData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS]; 109 110 // Temporary data structures for doing the pointer ID mapping. 111 final int[] mLast2Next = new int[MAX_POINTERS]; 112 final int[] mNext2Last = new int[MAX_POINTERS]; 113 final long[] mNext2LastDistance = new long[MAX_POINTERS]; 114 115 // Temporary data structure for generating the final motion data. 116 final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS]; 117 118 // This is not used here, but can be used by callers for state tracking. 119 int mAddingPointerOffset = 0; 120 final boolean[] mDown = new boolean[MAX_POINTERS]; 121 122 void dumpIntArray(PrintWriter pw, int[] array) { 123 pw.print("["); 124 for (int i=0; i<array.length; i++) { 125 if (i > 0) pw.print(", "); 126 pw.print(array[i]); 127 } 128 pw.print("]"); 129 } 130 131 void dumpBooleanArray(PrintWriter pw, boolean[] array) { 132 pw.print("["); 133 for (int i=0; i<array.length; i++) { 134 if (i > 0) pw.print(", "); 135 pw.print(array[i] ? "true" : "false"); 136 } 137 pw.print("]"); 138 } 139 140 void dump(PrintWriter pw, String prefix) { 141 pw.print(prefix); pw.print("xPrecision="); pw.print(xPrecision); 142 pw.print(" yPrecision="); pw.println(yPrecision); 143 pw.print(prefix); pw.print("xMoveScale="); pw.print(xMoveScale); 144 pw.print(" yMoveScale="); pw.println(yMoveScale); 145 if (currentMove != null) { 146 pw.print(prefix); pw.print("currentMove="); pw.println(currentMove); 147 } 148 if (changed || mDownTime != 0) { 149 pw.print(prefix); pw.print("changed="); pw.print(changed); 150 pw.print(" mDownTime="); pw.println(mDownTime); 151 } 152 pw.print(prefix); pw.print("mPointerIds="); dumpIntArray(pw, mPointerIds); 153 pw.println(""); 154 if (mSkipLastPointers || mLastNumPointers != 0) { 155 pw.print(prefix); pw.print("mSkipLastPointers="); pw.print(mSkipLastPointers); 156 pw.print(" mLastNumPointers="); pw.println(mLastNumPointers); 157 pw.print(prefix); pw.print("mLastData="); dumpIntArray(pw, mLastData); 158 pw.println(""); 159 } 160 if (mNextNumPointers != 0) { 161 pw.print(prefix); pw.print("mNextNumPointers="); pw.println(mNextNumPointers); 162 pw.print(prefix); pw.print("mNextData="); dumpIntArray(pw, mNextData); 163 pw.println(""); 164 } 165 pw.print(prefix); pw.print("mDroppedBadPoint="); 166 dumpBooleanArray(pw, mDroppedBadPoint); pw.println(""); 167 pw.print(prefix); pw.print("mAddingPointerOffset="); pw.println(mAddingPointerOffset); 168 pw.print(prefix); pw.print("mDown="); 169 dumpBooleanArray(pw, mDown); pw.println(""); 170 } 171 172 MotionState(int mx, int my) { 173 xPrecision = mx; 174 yPrecision = my; 175 xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f; 176 yMoveScale = my != 0 ? (1.0f/my) : 1.0f; 177 for (int i=0; i<MAX_POINTERS; i++) { 178 mPointerIds[i] = i; 179 } 180 } 181 182 /** 183 * Special hack for devices that have bad screen data: if one of the 184 * points has moved more than a screen height from the last position, 185 * then drop it. 186 */ 187 void dropBadPoint(InputDevice dev) { 188 // We should always have absY, but let's be paranoid. 189 if (dev.absY == null) { 190 return; 191 } 192 // Don't do anything if a finger is going down or up. We run 193 // here before assigning pointer IDs, so there isn't a good 194 // way to do per-finger matching. 195 if (mNextNumPointers != mLastNumPointers) { 196 return; 197 } 198 199 // We consider a single movement across more than a 7/16 of 200 // the long size of the screen to be bad. This was a magic value 201 // determined by looking at the maximum distance it is feasible 202 // to actually move in one sample. 203 final int maxDy = ((dev.absY.maxValue-dev.absY.minValue)*7)/16; 204 205 // Look through all new points and see if any are farther than 206 // acceptable from all previous points. 207 for (int i=mNextNumPointers-1; i>=0; i--) { 208 final int ioff = i * MotionEvent.NUM_SAMPLE_DATA; 209 //final int x = mNextData[ioff + MotionEvent.SAMPLE_X]; 210 final int y = mNextData[ioff + MotionEvent.SAMPLE_Y]; 211 if (DEBUG_HACKS) Slog.v("InputDevice", "Looking at next point #" + i + ": y=" + y); 212 boolean dropped = false; 213 if (!mDroppedBadPoint[i] && mLastNumPointers > 0) { 214 dropped = true; 215 int closestDy = -1; 216 int closestY = -1; 217 // We will drop this new point if it is sufficiently 218 // far away from -all- last points. 219 for (int j=mLastNumPointers-1; j>=0; j--) { 220 final int joff = j * MotionEvent.NUM_SAMPLE_DATA; 221 //int dx = x - mLastData[joff + MotionEvent.SAMPLE_X]; 222 int dy = y - mLastData[joff + MotionEvent.SAMPLE_Y]; 223 //if (dx < 0) dx = -dx; 224 if (dy < 0) dy = -dy; 225 if (DEBUG_HACKS) Slog.v("InputDevice", "Comparing with last point #" + j 226 + ": y=" + mLastData[joff] + " dy=" + dy); 227 if (dy < maxDy) { 228 dropped = false; 229 break; 230 } else if (closestDy < 0 || dy < closestDy) { 231 closestDy = dy; 232 closestY = mLastData[joff + MotionEvent.SAMPLE_Y]; 233 } 234 } 235 if (dropped) { 236 dropped = true; 237 Slog.i("InputDevice", "Dropping bad point #" + i 238 + ": newY=" + y + " closestDy=" + closestDy 239 + " maxDy=" + maxDy); 240 mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY; 241 break; 242 } 243 } 244 mDroppedBadPoint[i] = dropped; 245 } 246 } 247 248 void dropJumpyPoint(InputDevice dev) { 249 // We should always have absY, but let's be paranoid. 250 if (dev.absY == null) { 251 return; 252 } 253 final int jumpyEpsilon = dev.absY.range / JUMPY_EPSILON_DIVISOR; 254 255 final int nextNumPointers = mNextNumPointers; 256 final int lastNumPointers = mLastNumPointers; 257 final int[] nextData = mNextData; 258 final int[] lastData = mLastData; 259 260 if (nextNumPointers != mLastNumPointers) { 261 if (DEBUG_HACKS) { 262 Slog.d("InputDevice", "Different pointer count " + lastNumPointers + 263 " -> " + nextNumPointers); 264 for (int i = 0; i < nextNumPointers; i++) { 265 int ioff = i * MotionEvent.NUM_SAMPLE_DATA; 266 Slog.d("InputDevice", "Pointer " + i + " (" + 267 mNextData[ioff + MotionEvent.SAMPLE_X] + ", " + 268 mNextData[ioff + MotionEvent.SAMPLE_Y] + ")"); 269 } 270 } 271 272 // Just drop the first few events going from 1 to 2 pointers. 273 // They're bad often enough that they're not worth considering. 274 if (lastNumPointers == 1 && nextNumPointers == 2 275 && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) { 276 mNextNumPointers = 1; 277 mJumpyPointsDropped++; 278 } else if (lastNumPointers == 2 && nextNumPointers == 1 279 && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) { 280 // The event when we go from 2 -> 1 tends to be messed up too 281 System.arraycopy(lastData, 0, nextData, 0, 282 lastNumPointers * MotionEvent.NUM_SAMPLE_DATA); 283 mNextNumPointers = lastNumPointers; 284 mJumpyPointsDropped++; 285 286 if (DEBUG_HACKS) { 287 for (int i = 0; i < mNextNumPointers; i++) { 288 int ioff = i * MotionEvent.NUM_SAMPLE_DATA; 289 Slog.d("InputDevice", "Pointer " + i + " replaced (" + 290 mNextData[ioff + MotionEvent.SAMPLE_X] + ", " + 291 mNextData[ioff + MotionEvent.SAMPLE_Y] + ")"); 292 } 293 } 294 } else { 295 mJumpyPointsDropped = 0; 296 297 if (DEBUG_HACKS) { 298 Slog.d("InputDevice", "Transition - drop limit reset"); 299 } 300 } 301 return; 302 } 303 304 // A 'jumpy' point is one where the coordinate value for one axis 305 // has jumped to the other pointer's location. No need to do anything 306 // else if we only have one pointer. 307 if (nextNumPointers < 2) { 308 return; 309 } 310 311 int badPointerIndex = -1; 312 int badPointerReplaceXWith = 0; 313 int badPointerReplaceYWith = 0; 314 int badPointerDistance = Integer.MIN_VALUE; 315 for (int i = nextNumPointers - 1; i >= 0; i--) { 316 boolean dropx = false; 317 boolean dropy = false; 318 319 // Limit how many times a jumpy point can get dropped. 320 if (mJumpyPointsDropped < JUMPY_DROP_LIMIT) { 321 final int ioff = i * MotionEvent.NUM_SAMPLE_DATA; 322 final int x = nextData[ioff + MotionEvent.SAMPLE_X]; 323 final int y = nextData[ioff + MotionEvent.SAMPLE_Y]; 324 325 if (DEBUG_HACKS) { 326 Slog.d("InputDevice", "Point " + i + " (" + x + ", " + y + ")"); 327 } 328 329 // Check if a touch point is too close to another's coordinates 330 for (int j = 0; j < nextNumPointers && !dropx && !dropy; j++) { 331 if (j == i) { 332 continue; 333 } 334 335 final int joff = j * MotionEvent.NUM_SAMPLE_DATA; 336 final int xOther = nextData[joff + MotionEvent.SAMPLE_X]; 337 final int yOther = nextData[joff + MotionEvent.SAMPLE_Y]; 338 339 dropx = Math.abs(x - xOther) <= jumpyEpsilon; 340 dropy = Math.abs(y - yOther) <= jumpyEpsilon; 341 } 342 343 if (dropx) { 344 int xreplace = lastData[MotionEvent.SAMPLE_X]; 345 int yreplace = lastData[MotionEvent.SAMPLE_Y]; 346 int distance = Math.abs(yreplace - y); 347 for (int j = 1; j < lastNumPointers; j++) { 348 final int joff = j * MotionEvent.NUM_SAMPLE_DATA; 349 int lasty = lastData[joff + MotionEvent.SAMPLE_Y]; 350 int currDist = Math.abs(lasty - y); 351 if (currDist < distance) { 352 xreplace = lastData[joff + MotionEvent.SAMPLE_X]; 353 yreplace = lasty; 354 distance = currDist; 355 } 356 } 357 358 int badXDelta = Math.abs(xreplace - x); 359 if (badXDelta > badPointerDistance) { 360 badPointerDistance = badXDelta; 361 badPointerIndex = i; 362 badPointerReplaceXWith = xreplace; 363 badPointerReplaceYWith = yreplace; 364 } 365 } else if (dropy) { 366 int xreplace = lastData[MotionEvent.SAMPLE_X]; 367 int yreplace = lastData[MotionEvent.SAMPLE_Y]; 368 int distance = Math.abs(xreplace - x); 369 for (int j = 1; j < lastNumPointers; j++) { 370 final int joff = j * MotionEvent.NUM_SAMPLE_DATA; 371 int lastx = lastData[joff + MotionEvent.SAMPLE_X]; 372 int currDist = Math.abs(lastx - x); 373 if (currDist < distance) { 374 xreplace = lastx; 375 yreplace = lastData[joff + MotionEvent.SAMPLE_Y]; 376 distance = currDist; 377 } 378 } 379 380 int badYDelta = Math.abs(yreplace - y); 381 if (badYDelta > badPointerDistance) { 382 badPointerDistance = badYDelta; 383 badPointerIndex = i; 384 badPointerReplaceXWith = xreplace; 385 badPointerReplaceYWith = yreplace; 386 } 387 } 388 } 389 } 390 if (badPointerIndex >= 0) { 391 if (DEBUG_HACKS) { 392 Slog.d("InputDevice", "Replacing bad pointer " + badPointerIndex + 393 " with (" + badPointerReplaceXWith + ", " + badPointerReplaceYWith + 394 ")"); 395 } 396 397 final int offset = badPointerIndex * MotionEvent.NUM_SAMPLE_DATA; 398 nextData[offset + MotionEvent.SAMPLE_X] = badPointerReplaceXWith; 399 nextData[offset + MotionEvent.SAMPLE_Y] = badPointerReplaceYWith; 400 mJumpyPointsDropped++; 401 } else { 402 mJumpyPointsDropped = 0; 403 } 404 } 405 406 /** 407 * Special hack for devices that have bad screen data: aggregate and 408 * compute averages of the coordinate data, to reduce the amount of 409 * jitter seen by applications. 410 */ 411 int[] generateAveragedData(int upOrDownPointer, int lastNumPointers, 412 int nextNumPointers) { 413 final int numPointers = mLastNumPointers; 414 final int[] rawData = mLastData; 415 if (DEBUG_HACKS) Slog.v("InputDevice", "lastNumPointers=" + lastNumPointers 416 + " nextNumPointers=" + nextNumPointers 417 + " numPointers=" + numPointers); 418 for (int i=0; i<numPointers; i++) { 419 final int ioff = i * MotionEvent.NUM_SAMPLE_DATA; 420 // We keep the average data in offsets based on the pointer 421 // ID, so we don't need to move it around as fingers are 422 // pressed and released. 423 final int p = mPointerIds[i]; 424 final int poff = p * MotionEvent.NUM_SAMPLE_DATA * HISTORY_SIZE; 425 if (i == upOrDownPointer && lastNumPointers != nextNumPointers) { 426 if (lastNumPointers < nextNumPointers) { 427 // This pointer is going down. Clear its history 428 // and start fresh. 429 if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer down @ index " 430 + upOrDownPointer + " id " + mPointerIds[i]); 431 mHistoryDataStart[i] = 0; 432 mHistoryDataEnd[i] = 0; 433 System.arraycopy(rawData, ioff, mHistoryData, poff, 434 MotionEvent.NUM_SAMPLE_DATA); 435 System.arraycopy(rawData, ioff, mAveragedData, ioff, 436 MotionEvent.NUM_SAMPLE_DATA); 437 continue; 438 } else { 439 // The pointer is going up. Just fall through to 440 // recompute the last averaged point (and don't add 441 // it as a new point to include in the average). 442 if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer up @ index " 443 + upOrDownPointer + " id " + mPointerIds[i]); 444 } 445 } else { 446 int end = mHistoryDataEnd[i]; 447 int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA); 448 int oldX = mHistoryData[eoff + MotionEvent.SAMPLE_X]; 449 int oldY = mHistoryData[eoff + MotionEvent.SAMPLE_Y]; 450 int newX = rawData[ioff + MotionEvent.SAMPLE_X]; 451 int newY = rawData[ioff + MotionEvent.SAMPLE_Y]; 452 int dx = newX-oldX; 453 int dy = newY-oldY; 454 int delta = dx*dx + dy*dy; 455 if (DEBUG_HACKS) Slog.v("InputDevice", "Delta from last: " + delta); 456 if (delta >= (75*75)) { 457 // Magic number, if moving farther than this, turn 458 // off filtering to avoid lag in response. 459 mHistoryDataStart[i] = 0; 460 mHistoryDataEnd[i] = 0; 461 System.arraycopy(rawData, ioff, mHistoryData, poff, 462 MotionEvent.NUM_SAMPLE_DATA); 463 System.arraycopy(rawData, ioff, mAveragedData, ioff, 464 MotionEvent.NUM_SAMPLE_DATA); 465 continue; 466 } else { 467 end++; 468 if (end >= HISTORY_SIZE) { 469 end -= HISTORY_SIZE; 470 } 471 mHistoryDataEnd[i] = end; 472 int noff = poff + (end*MotionEvent.NUM_SAMPLE_DATA); 473 mHistoryData[noff + MotionEvent.SAMPLE_X] = newX; 474 mHistoryData[noff + MotionEvent.SAMPLE_Y] = newY; 475 mHistoryData[noff + MotionEvent.SAMPLE_PRESSURE] 476 = rawData[ioff + MotionEvent.SAMPLE_PRESSURE]; 477 int start = mHistoryDataStart[i]; 478 if (end == start) { 479 start++; 480 if (start >= HISTORY_SIZE) { 481 start -= HISTORY_SIZE; 482 } 483 mHistoryDataStart[i] = start; 484 } 485 } 486 } 487 488 // Now compute the average. 489 int start = mHistoryDataStart[i]; 490 int end = mHistoryDataEnd[i]; 491 int x=0, y=0; 492 int totalPressure = 0; 493 while (start != end) { 494 int soff = poff + (start*MotionEvent.NUM_SAMPLE_DATA); 495 int pressure = mHistoryData[soff + MotionEvent.SAMPLE_PRESSURE]; 496 if (pressure <= 0) pressure = 1; 497 x += mHistoryData[soff + MotionEvent.SAMPLE_X] * pressure; 498 y += mHistoryData[soff + MotionEvent.SAMPLE_Y] * pressure; 499 totalPressure += pressure; 500 start++; 501 if (start >= HISTORY_SIZE) start = 0; 502 } 503 int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA); 504 int pressure = mHistoryData[eoff + MotionEvent.SAMPLE_PRESSURE]; 505 if (pressure <= 0) pressure = 1; 506 x += mHistoryData[eoff + MotionEvent.SAMPLE_X] * pressure; 507 y += mHistoryData[eoff + MotionEvent.SAMPLE_Y] * pressure; 508 totalPressure += pressure; 509 x /= totalPressure; 510 y /= totalPressure; 511 if (DEBUG_HACKS) Slog.v("InputDevice", "Averaging " + totalPressure 512 + " weight: (" + x + "," + y + ")"); 513 mAveragedData[ioff + MotionEvent.SAMPLE_X] = x; 514 mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y; 515 mAveragedData[ioff + MotionEvent.SAMPLE_PRESSURE] = 516 rawData[ioff + MotionEvent.SAMPLE_PRESSURE]; 517 mAveragedData[ioff + MotionEvent.SAMPLE_SIZE] = 518 rawData[ioff + MotionEvent.SAMPLE_SIZE]; 519 } 520 return mAveragedData; 521 } 522 523 private boolean assignPointer(int nextIndex, boolean allowOverlap) { 524 final int lastNumPointers = mLastNumPointers; 525 final int[] next2Last = mNext2Last; 526 final long[] next2LastDistance = mNext2LastDistance; 527 final int[] last2Next = mLast2Next; 528 final int[] lastData = mLastData; 529 final int[] nextData = mNextData; 530 final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA; 531 532 if (DEBUG_POINTERS) Slog.v("InputDevice", "assignPointer: nextIndex=" 533 + nextIndex + " dataOff=" + id); 534 final int x1 = nextData[id + MotionEvent.SAMPLE_X]; 535 final int y1 = nextData[id + MotionEvent.SAMPLE_Y]; 536 537 long bestDistance = -1; 538 int bestIndex = -1; 539 for (int j=0; j<lastNumPointers; j++) { 540 // If we are not allowing multiple new points to be assigned 541 // to the same old pointer, then skip this one if it is already 542 // detected as a conflict (-2). 543 if (!allowOverlap && last2Next[j] < -1) { 544 continue; 545 } 546 final int jd = j * MotionEvent.NUM_SAMPLE_DATA; 547 final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1; 548 final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1; 549 final long distance = xd*(long)xd + yd*(long)yd; 550 if (bestDistance == -1 || distance < bestDistance) { 551 bestDistance = distance; 552 bestIndex = j; 553 } 554 } 555 556 if (DEBUG_POINTERS) Slog.v("InputDevice", "New index " + nextIndex 557 + " best old index=" + bestIndex + " (distance=" 558 + bestDistance + ")"); 559 next2Last[nextIndex] = bestIndex; 560 next2LastDistance[nextIndex] = bestDistance; 561 562 if (bestIndex < 0) { 563 return true; 564 } 565 566 if (last2Next[bestIndex] == -1) { 567 last2Next[bestIndex] = nextIndex; 568 return false; 569 } 570 571 if (DEBUG_POINTERS) Slog.v("InputDevice", "Old index " + bestIndex 572 + " has multiple best new pointers!"); 573 574 last2Next[bestIndex] = -2; 575 return true; 576 } 577 578 private int updatePointerIdentifiers() { 579 final int[] lastData = mLastData; 580 final int[] nextData = mNextData; 581 final int nextNumPointers = mNextNumPointers; 582 final int lastNumPointers = mLastNumPointers; 583 584 if (nextNumPointers == 1 && lastNumPointers == 1) { 585 System.arraycopy(nextData, 0, lastData, 0, 586 MotionEvent.NUM_SAMPLE_DATA); 587 return -1; 588 } 589 590 // Clear our old state. 591 final int[] last2Next = mLast2Next; 592 for (int i=0; i<lastNumPointers; i++) { 593 last2Next[i] = -1; 594 } 595 596 if (DEBUG_POINTERS) Slog.v("InputDevice", 597 "Update pointers: lastNumPointers=" + lastNumPointers 598 + " nextNumPointers=" + nextNumPointers); 599 600 // Figure out the closes new points to the previous points. 601 final int[] next2Last = mNext2Last; 602 final long[] next2LastDistance = mNext2LastDistance; 603 boolean conflicts = false; 604 for (int i=0; i<nextNumPointers; i++) { 605 conflicts |= assignPointer(i, true); 606 } 607 608 // Resolve ambiguities in pointer mappings, when two or more 609 // new pointer locations find their best previous location is 610 // the same. 611 if (conflicts) { 612 if (DEBUG_POINTERS) Slog.v("InputDevice", "Resolving conflicts"); 613 614 for (int i=0; i<lastNumPointers; i++) { 615 if (last2Next[i] != -2) { 616 continue; 617 } 618 619 // Note that this algorithm is far from perfect. Ideally 620 // we should do something like the one described at 621 // http://portal.acm.org/citation.cfm?id=997856 622 623 if (DEBUG_POINTERS) Slog.v("InputDevice", 624 "Resolving last index #" + i); 625 626 int numFound; 627 do { 628 numFound = 0; 629 long worstDistance = 0; 630 int worstJ = -1; 631 for (int j=0; j<nextNumPointers; j++) { 632 if (next2Last[j] != i) { 633 continue; 634 } 635 numFound++; 636 if (worstDistance < next2LastDistance[j]) { 637 worstDistance = next2LastDistance[j]; 638 worstJ = j; 639 } 640 } 641 642 if (worstJ >= 0) { 643 if (DEBUG_POINTERS) Slog.v("InputDevice", 644 "Worst new pointer: " + worstJ 645 + " (distance=" + worstDistance + ")"); 646 if (assignPointer(worstJ, false)) { 647 // In this case there is no last pointer 648 // remaining for this new one! 649 next2Last[worstJ] = -1; 650 } 651 } 652 } while (numFound > 2); 653 } 654 } 655 656 int retIndex = -1; 657 658 if (lastNumPointers < nextNumPointers) { 659 // We have one or more new pointers that are down. Create a 660 // new pointer identifier for one of them. 661 if (DEBUG_POINTERS) Slog.v("InputDevice", "Adding new pointer"); 662 int nextId = 0; 663 int i=0; 664 while (i < lastNumPointers) { 665 if (mPointerIds[i] > nextId) { 666 // Found a hole, insert the pointer here. 667 if (DEBUG_POINTERS) Slog.v("InputDevice", 668 "Inserting new pointer at hole " + i); 669 System.arraycopy(mPointerIds, i, mPointerIds, 670 i+1, lastNumPointers-i); 671 System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA, 672 lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA, 673 (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA); 674 System.arraycopy(next2Last, i, next2Last, 675 i+1, lastNumPointers-i); 676 break; 677 } 678 i++; 679 nextId++; 680 } 681 682 if (DEBUG_POINTERS) Slog.v("InputDevice", 683 "New pointer id " + nextId + " at index " + i); 684 685 mLastNumPointers++; 686 retIndex = i; 687 mPointerIds[i] = nextId; 688 689 // And assign this identifier to the first new pointer. 690 for (int j=0; j<nextNumPointers; j++) { 691 if (next2Last[j] < 0) { 692 if (DEBUG_POINTERS) Slog.v("InputDevice", 693 "Assigning new id to new pointer index " + j); 694 next2Last[j] = i; 695 break; 696 } 697 } 698 } 699 700 // Propagate all of the current data into the appropriate 701 // location in the old data to match the pointer ID that was 702 // assigned to it. 703 for (int i=0; i<nextNumPointers; i++) { 704 int lastIndex = next2Last[i]; 705 if (lastIndex >= 0) { 706 if (DEBUG_POINTERS) Slog.v("InputDevice", 707 "Copying next pointer index " + i 708 + " to last index " + lastIndex); 709 System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA, 710 lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA, 711 MotionEvent.NUM_SAMPLE_DATA); 712 } 713 } 714 715 if (lastNumPointers > nextNumPointers) { 716 // One or more pointers has gone up. Find the first one, 717 // and adjust accordingly. 718 if (DEBUG_POINTERS) Slog.v("InputDevice", "Removing old pointer"); 719 for (int i=0; i<lastNumPointers; i++) { 720 if (last2Next[i] == -1) { 721 if (DEBUG_POINTERS) Slog.v("InputDevice", 722 "Removing old pointer at index " + i); 723 retIndex = i; 724 break; 725 } 726 } 727 } 728 729 return retIndex; 730 } 731 732 void removeOldPointer(int index) { 733 final int lastNumPointers = mLastNumPointers; 734 if (index >= 0 && index < lastNumPointers) { 735 System.arraycopy(mPointerIds, index+1, mPointerIds, 736 index, lastNumPointers-index-1); 737 System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA, 738 mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA, 739 (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA); 740 mLastNumPointers--; 741 } 742 } 743 744 MotionEvent generateAbsMotion(InputDevice device, long curTime, 745 long curTimeNano, Display display, int orientation, 746 int metaState) { 747 748 if (mSkipLastPointers) { 749 mSkipLastPointers = false; 750 mLastNumPointers = 0; 751 } 752 753 if (mNextNumPointers <= 0 && mLastNumPointers <= 0) { 754 return null; 755 } 756 757 final int lastNumPointers = mLastNumPointers; 758 final int nextNumPointers = mNextNumPointers; 759 if (mNextNumPointers > MAX_POINTERS) { 760 Slog.w("InputDevice", "Number of pointers " + mNextNumPointers 761 + " exceeded maximum of " + MAX_POINTERS); 762 mNextNumPointers = MAX_POINTERS; 763 } 764 765 int upOrDownPointer = updatePointerIdentifiers(); 766 767 final float[] reportData = mReportData; 768 final int[] rawData; 769 if (KeyInputQueue.BAD_TOUCH_HACK) { 770 rawData = generateAveragedData(upOrDownPointer, lastNumPointers, 771 nextNumPointers); 772 } else { 773 rawData = mLastData; 774 } 775 776 final int numPointers = mLastNumPointers; 777 778 if (DEBUG_POINTERS) Slog.v("InputDevice", "Processing " 779 + numPointers + " pointers (going from " + lastNumPointers 780 + " to " + nextNumPointers + ")"); 781 782 for (int i=0; i<numPointers; i++) { 783 final int pos = i * MotionEvent.NUM_SAMPLE_DATA; 784 reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X]; 785 reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y]; 786 reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE]; 787 reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE]; 788 } 789 790 int action; 791 int edgeFlags = 0; 792 if (nextNumPointers != lastNumPointers) { 793 if (nextNumPointers > lastNumPointers) { 794 if (lastNumPointers == 0) { 795 action = MotionEvent.ACTION_DOWN; 796 mDownTime = curTime; 797 } else { 798 action = MotionEvent.ACTION_POINTER_DOWN 799 | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT); 800 } 801 } else { 802 if (numPointers == 1) { 803 action = MotionEvent.ACTION_UP; 804 } else { 805 action = MotionEvent.ACTION_POINTER_UP 806 | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT); 807 } 808 } 809 currentMove = null; 810 } else { 811 action = MotionEvent.ACTION_MOVE; 812 } 813 814 final int dispW = display.getWidth()-1; 815 final int dispH = display.getHeight()-1; 816 int w = dispW; 817 int h = dispH; 818 if (orientation == Surface.ROTATION_90 819 || orientation == Surface.ROTATION_270) { 820 int tmp = w; 821 w = h; 822 h = tmp; 823 } 824 825 final AbsoluteInfo absX = device.absX; 826 final AbsoluteInfo absY = device.absY; 827 final AbsoluteInfo absPressure = device.absPressure; 828 final AbsoluteInfo absSize = device.absSize; 829 for (int i=0; i<numPointers; i++) { 830 final int j = i * MotionEvent.NUM_SAMPLE_DATA; 831 832 if (absX != null) { 833 reportData[j + MotionEvent.SAMPLE_X] = 834 ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue) 835 / absX.range) * w; 836 } 837 if (absY != null) { 838 reportData[j + MotionEvent.SAMPLE_Y] = 839 ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue) 840 / absY.range) * h; 841 } 842 if (absPressure != null) { 843 reportData[j + MotionEvent.SAMPLE_PRESSURE] = 844 ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue) 845 / (float)absPressure.range); 846 } 847 if (absSize != null) { 848 reportData[j + MotionEvent.SAMPLE_SIZE] = 849 ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue) 850 / (float)absSize.range); 851 } 852 853 switch (orientation) { 854 case Surface.ROTATION_90: { 855 final float temp = reportData[j + MotionEvent.SAMPLE_X]; 856 reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y]; 857 reportData[j + MotionEvent.SAMPLE_Y] = w-temp; 858 break; 859 } 860 case Surface.ROTATION_180: { 861 reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X]; 862 reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y]; 863 break; 864 } 865 case Surface.ROTATION_270: { 866 final float temp = reportData[j + MotionEvent.SAMPLE_X]; 867 reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y]; 868 reportData[j + MotionEvent.SAMPLE_Y] = temp; 869 break; 870 } 871 } 872 } 873 874 // We only consider the first pointer when computing the edge 875 // flags, since they are global to the event. 876 if (action == MotionEvent.ACTION_DOWN) { 877 if (reportData[MotionEvent.SAMPLE_X] <= 0) { 878 edgeFlags |= MotionEvent.EDGE_LEFT; 879 } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) { 880 edgeFlags |= MotionEvent.EDGE_RIGHT; 881 } 882 if (reportData[MotionEvent.SAMPLE_Y] <= 0) { 883 edgeFlags |= MotionEvent.EDGE_TOP; 884 } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) { 885 edgeFlags |= MotionEvent.EDGE_BOTTOM; 886 } 887 } 888 889 if (currentMove != null) { 890 if (false) Slog.i("InputDevice", "Adding batch x=" 891 + reportData[MotionEvent.SAMPLE_X] 892 + " y=" + reportData[MotionEvent.SAMPLE_Y] 893 + " to " + currentMove); 894 currentMove.addBatch(curTime, reportData, metaState); 895 if (WindowManagerPolicy.WATCH_POINTER) { 896 Slog.i("KeyInputQueue", "Updating: " + currentMove); 897 } 898 return null; 899 } 900 901 MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime, 902 curTimeNano, action, numPointers, mPointerIds, reportData, 903 metaState, xPrecision, yPrecision, device.id, edgeFlags); 904 if (action == MotionEvent.ACTION_MOVE) { 905 currentMove = me; 906 } 907 908 if (nextNumPointers < lastNumPointers) { 909 removeOldPointer(upOrDownPointer); 910 } 911 912 return me; 913 } 914 915 boolean hasMore() { 916 return mLastNumPointers != mNextNumPointers; 917 } 918 919 void finish() { 920 mNextNumPointers = mAddingPointerOffset = 0; 921 mNextData[MotionEvent.SAMPLE_PRESSURE] = 0; 922 } 923 924 MotionEvent generateRelMotion(InputDevice device, long curTime, 925 long curTimeNano, int orientation, int metaState) { 926 927 final float[] scaled = mReportData; 928 929 // For now we only support 1 pointer with relative motions. 930 scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X]; 931 scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y]; 932 scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f; 933 scaled[MotionEvent.SAMPLE_SIZE] = 0; 934 int edgeFlags = 0; 935 936 int action; 937 if (mNextNumPointers != mLastNumPointers) { 938 mNextData[MotionEvent.SAMPLE_X] = 939 mNextData[MotionEvent.SAMPLE_Y] = 0; 940 if (mNextNumPointers > 0 && mLastNumPointers == 0) { 941 action = MotionEvent.ACTION_DOWN; 942 mDownTime = curTime; 943 } else if (mNextNumPointers == 0) { 944 action = MotionEvent.ACTION_UP; 945 } else { 946 action = MotionEvent.ACTION_MOVE; 947 } 948 mLastNumPointers = mNextNumPointers; 949 currentMove = null; 950 } else { 951 action = MotionEvent.ACTION_MOVE; 952 } 953 954 scaled[MotionEvent.SAMPLE_X] *= xMoveScale; 955 scaled[MotionEvent.SAMPLE_Y] *= yMoveScale; 956 switch (orientation) { 957 case Surface.ROTATION_90: { 958 final float temp = scaled[MotionEvent.SAMPLE_X]; 959 scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y]; 960 scaled[MotionEvent.SAMPLE_Y] = -temp; 961 break; 962 } 963 case Surface.ROTATION_180: { 964 scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X]; 965 scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y]; 966 break; 967 } 968 case Surface.ROTATION_270: { 969 final float temp = scaled[MotionEvent.SAMPLE_X]; 970 scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y]; 971 scaled[MotionEvent.SAMPLE_Y] = temp; 972 break; 973 } 974 } 975 976 if (currentMove != null) { 977 if (false) Slog.i("InputDevice", "Adding batch x=" 978 + scaled[MotionEvent.SAMPLE_X] 979 + " y=" + scaled[MotionEvent.SAMPLE_Y] 980 + " to " + currentMove); 981 currentMove.addBatch(curTime, scaled, metaState); 982 if (WindowManagerPolicy.WATCH_POINTER) { 983 Slog.i("KeyInputQueue", "Updating: " + currentMove); 984 } 985 return null; 986 } 987 988 MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime, 989 curTimeNano, action, 1, mPointerIds, scaled, metaState, 990 xPrecision, yPrecision, device.id, edgeFlags); 991 if (action == MotionEvent.ACTION_MOVE) { 992 currentMove = me; 993 } 994 return me; 995 } 996 } 997 998 static class AbsoluteInfo { 999 int minValue; 1000 int maxValue; 1001 int range; 1002 int flat; 1003 int fuzz; 1004 1005 final void dump(PrintWriter pw) { 1006 pw.print("minValue="); pw.print(minValue); 1007 pw.print(" maxValue="); pw.print(maxValue); 1008 pw.print(" range="); pw.print(range); 1009 pw.print(" flat="); pw.print(flat); 1010 pw.print(" fuzz="); pw.print(fuzz); 1011 } 1012 }; 1013 1014 InputDevice(int _id, int _classes, String _name, 1015 AbsoluteInfo _absX, AbsoluteInfo _absY, 1016 AbsoluteInfo _absPressure, AbsoluteInfo _absSize) { 1017 id = _id; 1018 classes = _classes; 1019 name = _name; 1020 absX = _absX; 1021 absY = _absY; 1022 absPressure = _absPressure; 1023 absSize = _absSize; 1024 } 1025 }; 1026