Home | History | Annotate | Download | only in server
      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