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