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.content.Context;
     20 import android.content.res.Configuration;
     21 import android.content.res.Resources;
     22 import android.os.Environment;
     23 import android.os.LatencyTimer;
     24 import android.os.PowerManager;
     25 import android.os.SystemClock;
     26 import android.os.SystemProperties;
     27 import android.util.Slog;
     28 import android.util.SparseArray;
     29 import android.util.Xml;
     30 import android.view.Display;
     31 import android.view.KeyEvent;
     32 import android.view.MotionEvent;
     33 import android.view.RawInputEvent;
     34 import android.view.Surface;
     35 import android.view.WindowManagerPolicy;
     36 
     37 import com.android.internal.util.XmlUtils;
     38 
     39 import org.xmlpull.v1.XmlPullParser;
     40 
     41 import java.io.BufferedReader;
     42 import java.io.File;
     43 import java.io.FileInputStream;
     44 import java.io.FileNotFoundException;
     45 import java.io.FileReader;
     46 import java.io.IOException;
     47 import java.io.InputStreamReader;
     48 import java.io.PrintWriter;
     49 import java.util.ArrayList;
     50 
     51 public abstract class KeyInputQueue {
     52     static final String TAG = "KeyInputQueue";
     53 
     54     static final boolean DEBUG = false;
     55     static final boolean DEBUG_VIRTUAL_KEYS = false;
     56     static final boolean DEBUG_POINTERS = false;
     57 
     58     /**
     59      * Turn on some hacks we have to improve the touch interaction with a
     60      * certain device whose screen currently is not all that good.
     61      */
     62     static boolean BAD_TOUCH_HACK = false;
     63 
     64     /**
     65      * Turn on some hacks to improve touch interaction with another device
     66      * where touch coordinate data can get corrupted.
     67      */
     68     static boolean JUMPY_TOUCH_HACK = false;
     69 
     70     private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
     71 
     72     final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
     73     final SparseArray<InputDevice> mIgnoredDevices = new SparseArray<InputDevice>();
     74     final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
     75     final HapticFeedbackCallback mHapticFeedbackCallback;
     76 
     77     int mGlobalMetaState = 0;
     78     boolean mHaveGlobalMetaState = false;
     79 
     80     final QueuedEvent mFirst;
     81     final QueuedEvent mLast;
     82     QueuedEvent mCache;
     83     int mCacheCount;
     84 
     85     Display mDisplay = null;
     86     int mDisplayWidth;
     87     int mDisplayHeight;
     88 
     89     int mOrientation = Surface.ROTATION_0;
     90     int[] mKeyRotationMap = null;
     91 
     92     VirtualKey mPressedVirtualKey = null;
     93 
     94     PowerManager.WakeLock mWakeLock;
     95 
     96     static final int[] KEY_90_MAP = new int[] {
     97         KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT,
     98         KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_UP,
     99         KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_LEFT,
    100         KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_DOWN,
    101     };
    102 
    103     static final int[] KEY_180_MAP = new int[] {
    104         KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_UP,
    105         KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_LEFT,
    106         KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN,
    107         KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT,
    108     };
    109 
    110     static final int[] KEY_270_MAP = new int[] {
    111         KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_LEFT,
    112         KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_UP,
    113         KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_RIGHT,
    114         KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_DOWN,
    115     };
    116 
    117     public static final int FILTER_REMOVE = 0;
    118     public static final int FILTER_KEEP = 1;
    119     public static final int FILTER_ABORT = -1;
    120 
    121     private static final boolean MEASURE_LATENCY = false;
    122     private LatencyTimer lt;
    123 
    124     public interface FilterCallback {
    125         int filterEvent(QueuedEvent ev);
    126     }
    127 
    128     public interface HapticFeedbackCallback {
    129         void virtualKeyFeedback(KeyEvent event);
    130     }
    131 
    132     static class QueuedEvent {
    133         InputDevice inputDevice;
    134         long whenNano;
    135         int flags; // From the raw event
    136         int classType; // One of the class constants in InputEvent
    137         Object event;
    138         boolean inQueue;
    139 
    140         void copyFrom(QueuedEvent that) {
    141             this.inputDevice = that.inputDevice;
    142             this.whenNano = that.whenNano;
    143             this.flags = that.flags;
    144             this.classType = that.classType;
    145             this.event = that.event;
    146         }
    147 
    148         @Override
    149         public String toString() {
    150             return "QueuedEvent{"
    151                 + Integer.toHexString(System.identityHashCode(this))
    152                 + " " + event + "}";
    153         }
    154 
    155         // not copied
    156         QueuedEvent prev;
    157         QueuedEvent next;
    158     }
    159 
    160     /**
    161      * A key that exists as a part of the touch-screen, outside of the normal
    162      * display area of the screen.
    163      */
    164     static class VirtualKey {
    165         int scancode;
    166         int centerx;
    167         int centery;
    168         int width;
    169         int height;
    170 
    171         int hitLeft;
    172         int hitTop;
    173         int hitRight;
    174         int hitBottom;
    175 
    176         InputDevice lastDevice;
    177         int lastKeycode;
    178 
    179         boolean checkHit(int x, int y) {
    180             return (x >= hitLeft && x <= hitRight
    181                     && y >= hitTop && y <= hitBottom);
    182         }
    183 
    184         void computeHitRect(InputDevice dev, int dw, int dh) {
    185             if (dev == lastDevice) {
    186                 return;
    187             }
    188 
    189             if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "computeHitRect for " + scancode
    190                     + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
    191 
    192             lastDevice = dev;
    193 
    194             int minx = dev.absX.minValue;
    195             int maxx = dev.absX.maxValue;
    196 
    197             int halfw = width/2;
    198             int left = centerx - halfw;
    199             int right = centerx + halfw;
    200             hitLeft = minx + ((left*maxx-minx)/dw);
    201             hitRight = minx + ((right*maxx-minx)/dw);
    202 
    203             int miny = dev.absY.minValue;
    204             int maxy = dev.absY.maxValue;
    205 
    206             int halfh = height/2;
    207             int top = centery - halfh;
    208             int bottom = centery + halfh;
    209             hitTop = miny + ((top*maxy-miny)/dh);
    210             hitBottom = miny + ((bottom*maxy-miny)/dh);
    211         }
    212     }
    213 
    214     private void readVirtualKeys(String deviceName) {
    215         try {
    216             FileInputStream fis = new FileInputStream(
    217                     "/sys/board_properties/virtualkeys." + deviceName);
    218             InputStreamReader isr = new InputStreamReader(fis);
    219             BufferedReader br = new BufferedReader(isr, 2048);
    220             String str = br.readLine();
    221             if (str != null) {
    222                 String[] it = str.split(":");
    223                 if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it);
    224                 final int N = it.length-6;
    225                 for (int i=0; i<=N; i+=6) {
    226                     if (!"0x01".equals(it[i])) {
    227                         Slog.w(TAG, "Unknown virtual key type at elem #" + i
    228                                 + ": " + it[i]);
    229                         continue;
    230                     }
    231                     try {
    232                         VirtualKey sb = new VirtualKey();
    233                         sb.scancode = Integer.parseInt(it[i+1]);
    234                         sb.centerx = Integer.parseInt(it[i+2]);
    235                         sb.centery = Integer.parseInt(it[i+3]);
    236                         sb.width = Integer.parseInt(it[i+4]);
    237                         sb.height = Integer.parseInt(it[i+5]);
    238                         if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key "
    239                                 + sb.scancode + ": center=" + sb.centerx + ","
    240                                 + sb.centery + " size=" + sb.width + "x"
    241                                 + sb.height);
    242                         mVirtualKeys.add(sb);
    243                     } catch (NumberFormatException e) {
    244                         Slog.w(TAG, "Bad number at region " + i + " in: "
    245                                 + str, e);
    246                     }
    247                 }
    248             }
    249             br.close();
    250         } catch (FileNotFoundException e) {
    251             Slog.i(TAG, "No virtual keys found");
    252         } catch (IOException e) {
    253             Slog.w(TAG, "Error reading virtual keys", e);
    254         }
    255     }
    256 
    257     private void readExcludedDevices() {
    258         // Read partner-provided list of excluded input devices
    259         XmlPullParser parser = null;
    260         // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
    261         File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
    262         FileReader confreader = null;
    263         try {
    264             confreader = new FileReader(confFile);
    265             parser = Xml.newPullParser();
    266             parser.setInput(confreader);
    267             XmlUtils.beginDocument(parser, "devices");
    268 
    269             while (true) {
    270                 XmlUtils.nextElement(parser);
    271                 if (!"device".equals(parser.getName())) {
    272                     break;
    273                 }
    274                 String name = parser.getAttributeValue(null, "name");
    275                 if (name != null) {
    276                     if (DEBUG) Slog.v(TAG, "addExcludedDevice " + name);
    277                     addExcludedDevice(name);
    278                 }
    279             }
    280         } catch (FileNotFoundException e) {
    281             // It's ok if the file does not exist.
    282         } catch (Exception e) {
    283             Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
    284         } finally {
    285             try { if (confreader != null) confreader.close(); } catch (IOException e) { }
    286         }
    287     }
    288 
    289     KeyInputQueue(Context context, HapticFeedbackCallback  hapticFeedbackCallback) {
    290         if (MEASURE_LATENCY) {
    291             lt = new LatencyTimer(100, 1000);
    292         }
    293 
    294         Resources r = context.getResources();
    295         BAD_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterTouchEvents);
    296 
    297         JUMPY_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterJumpyTouchEvents);
    298 
    299         mHapticFeedbackCallback = hapticFeedbackCallback;
    300 
    301         readExcludedDevices();
    302 
    303         PowerManager pm = (PowerManager)context.getSystemService(
    304                                                         Context.POWER_SERVICE);
    305         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
    306                                                         "KeyInputQueue");
    307         mWakeLock.setReferenceCounted(false);
    308 
    309         mFirst = new QueuedEvent();
    310         mLast = new QueuedEvent();
    311         mFirst.next = mLast;
    312         mLast.prev = mFirst;
    313 
    314         mThread.start();
    315     }
    316 
    317     public void setDisplay(Display display) {
    318         mDisplay = display;
    319 
    320         // We assume at this point that the display dimensions reflect the
    321         // natural, unrotated display.  We will perform hit tests for soft
    322         // buttons based on that display.
    323         mDisplayWidth = display.getWidth();
    324         mDisplayHeight = display.getHeight();
    325     }
    326 
    327     public void getInputConfiguration(Configuration config) {
    328         synchronized (mFirst) {
    329             config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
    330             config.keyboard = Configuration.KEYBOARD_NOKEYS;
    331             config.navigation = Configuration.NAVIGATION_NONAV;
    332 
    333             final int N = mDevices.size();
    334             for (int i=0; i<N; i++) {
    335                 InputDevice d = mDevices.valueAt(i);
    336                 if (d != null) {
    337                     if ((d.classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
    338                         config.touchscreen
    339                                 = Configuration.TOUCHSCREEN_FINGER;
    340                         //Slog.i("foo", "***** HAVE TOUCHSCREEN!");
    341                     }
    342                     if ((d.classes&RawInputEvent.CLASS_ALPHAKEY) != 0) {
    343                         config.keyboard
    344                                 = Configuration.KEYBOARD_QWERTY;
    345                         //Slog.i("foo", "***** HAVE QWERTY!");
    346                     }
    347                     if ((d.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
    348                         config.navigation
    349                                 = Configuration.NAVIGATION_TRACKBALL;
    350                         //Slog.i("foo", "***** HAVE TRACKBALL!");
    351                     } else if ((d.classes&RawInputEvent.CLASS_DPAD) != 0) {
    352                         config.navigation
    353                                 = Configuration.NAVIGATION_DPAD;
    354                         //Slog.i("foo", "***** HAVE DPAD!");
    355                     }
    356                 }
    357             }
    358         }
    359     }
    360 
    361     public int getScancodeState(int code) {
    362         synchronized (mFirst) {
    363             VirtualKey vk = mPressedVirtualKey;
    364             if (vk != null) {
    365                 if (vk.scancode == code) {
    366                     return 2;
    367                 }
    368             }
    369             return nativeGetScancodeState(code);
    370         }
    371     }
    372 
    373     public int getScancodeState(int deviceId, int code) {
    374         synchronized (mFirst) {
    375             VirtualKey vk = mPressedVirtualKey;
    376             if (vk != null) {
    377                 if (vk.scancode == code) {
    378                     return 2;
    379                 }
    380             }
    381             return nativeGetScancodeState(deviceId, code);
    382         }
    383     }
    384 
    385     public int getTrackballScancodeState(int code) {
    386         synchronized (mFirst) {
    387             final int N = mDevices.size();
    388             for (int i=0; i<N; i++) {
    389                 InputDevice dev = mDevices.valueAt(i);
    390                 if ((dev.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
    391                     int res = nativeGetScancodeState(dev.id, code);
    392                     if (res > 0) {
    393                         return res;
    394                     }
    395                 }
    396             }
    397         }
    398 
    399         return 0;
    400     }
    401 
    402     public int getDPadScancodeState(int code) {
    403         synchronized (mFirst) {
    404             final int N = mDevices.size();
    405             for (int i=0; i<N; i++) {
    406                 InputDevice dev = mDevices.valueAt(i);
    407                 if ((dev.classes&RawInputEvent.CLASS_DPAD) != 0) {
    408                     int res = nativeGetScancodeState(dev.id, code);
    409                     if (res > 0) {
    410                         return res;
    411                     }
    412                 }
    413             }
    414         }
    415 
    416         return 0;
    417     }
    418 
    419     public int getKeycodeState(int code) {
    420         synchronized (mFirst) {
    421             VirtualKey vk = mPressedVirtualKey;
    422             if (vk != null) {
    423                 if (vk.lastKeycode == code) {
    424                     return 2;
    425                 }
    426             }
    427             return nativeGetKeycodeState(code);
    428         }
    429     }
    430 
    431     public int getKeycodeState(int deviceId, int code) {
    432         synchronized (mFirst) {
    433             VirtualKey vk = mPressedVirtualKey;
    434             if (vk != null) {
    435                 if (vk.lastKeycode == code) {
    436                     return 2;
    437                 }
    438             }
    439             return nativeGetKeycodeState(deviceId, code);
    440         }
    441     }
    442 
    443     public int getTrackballKeycodeState(int code) {
    444         synchronized (mFirst) {
    445             final int N = mDevices.size();
    446             for (int i=0; i<N; i++) {
    447                 InputDevice dev = mDevices.valueAt(i);
    448                 if ((dev.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
    449                     int res = nativeGetKeycodeState(dev.id, code);
    450                     if (res > 0) {
    451                         return res;
    452                     }
    453                 }
    454             }
    455         }
    456 
    457         return 0;
    458     }
    459 
    460     public int getDPadKeycodeState(int code) {
    461         synchronized (mFirst) {
    462             final int N = mDevices.size();
    463             for (int i=0; i<N; i++) {
    464                 InputDevice dev = mDevices.valueAt(i);
    465                 if ((dev.classes&RawInputEvent.CLASS_DPAD) != 0) {
    466                     int res = nativeGetKeycodeState(dev.id, code);
    467                     if (res > 0) {
    468                         return res;
    469                     }
    470                 }
    471             }
    472         }
    473 
    474         return 0;
    475     }
    476 
    477     public static native String getDeviceName(int deviceId);
    478     public static native int getDeviceClasses(int deviceId);
    479     public static native void addExcludedDevice(String deviceName);
    480     public static native boolean getAbsoluteInfo(int deviceId, int axis,
    481             InputDevice.AbsoluteInfo outInfo);
    482     public static native int getSwitchState(int sw);
    483     public static native int getSwitchState(int deviceId, int sw);
    484     public static native int nativeGetScancodeState(int code);
    485     public static native int nativeGetScancodeState(int deviceId, int code);
    486     public static native int nativeGetKeycodeState(int code);
    487     public static native int nativeGetKeycodeState(int deviceId, int code);
    488     public static native int scancodeToKeycode(int deviceId, int scancode);
    489     public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
    490 
    491     public static KeyEvent newKeyEvent(InputDevice device, long downTime,
    492             long eventTime, boolean down, int keycode, int repeatCount,
    493             int scancode, int flags) {
    494         return new KeyEvent(
    495                 downTime, eventTime,
    496                 down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
    497                 keycode, repeatCount,
    498                 device != null ? device.mMetaKeysState : 0,
    499                 device != null ? device.id : -1, scancode,
    500                 flags | KeyEvent.FLAG_FROM_SYSTEM);
    501     }
    502 
    503     Thread mThread = new Thread("InputDeviceReader") {
    504         public void run() {
    505             if (DEBUG) Slog.v(TAG, "InputDeviceReader.run()");
    506             android.os.Process.setThreadPriority(
    507                     android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
    508 
    509             RawInputEvent ev = new RawInputEvent();
    510             while (true) {
    511                 try {
    512                     InputDevice di;
    513 
    514                     // block, doesn't release the monitor
    515                     readEvent(ev);
    516 
    517                     boolean send = false;
    518                     boolean configChanged = false;
    519 
    520                     if (false) {
    521                         Slog.i(TAG, "Input event: dev=0x"
    522                                 + Integer.toHexString(ev.deviceId)
    523                                 + " type=0x" + Integer.toHexString(ev.type)
    524                                 + " scancode=" + ev.scancode
    525                                 + " keycode=" + ev.keycode
    526                                 + " value=" + ev.value);
    527                     }
    528 
    529                     if (ev.type == RawInputEvent.EV_DEVICE_ADDED) {
    530                         synchronized (mFirst) {
    531                             di = newInputDevice(ev.deviceId);
    532                             if (di.classes != 0) {
    533                                 // If this device is some kind of input class,
    534                                 // we care about it.
    535                                 mDevices.put(ev.deviceId, di);
    536                                 if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
    537                                     readVirtualKeys(di.name);
    538                                 }
    539                                 // The configuration may have changed because
    540                                 // of this device.
    541                                 configChanged = true;
    542                             } else {
    543                                 // We won't do anything with this device.
    544                                 mIgnoredDevices.put(ev.deviceId, di);
    545                                 Slog.i(TAG, "Ignoring non-input device: id=0x"
    546                                         + Integer.toHexString(di.id)
    547                                         + ", name=" + di.name);
    548                             }
    549                         }
    550                     } else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
    551                         synchronized (mFirst) {
    552                             if (false) {
    553                                 Slog.i(TAG, "Device removed: id=0x"
    554                                         + Integer.toHexString(ev.deviceId));
    555                             }
    556                             di = mDevices.get(ev.deviceId);
    557                             if (di != null) {
    558                                 mDevices.delete(ev.deviceId);
    559                                 // The configuration may have changed because
    560                                 // of this device.
    561                                 configChanged = true;
    562                             } else if ((di=mIgnoredDevices.get(ev.deviceId)) != null) {
    563                                 mIgnoredDevices.remove(ev.deviceId);
    564                             } else {
    565                                 Slog.w(TAG, "Removing bad device id: "
    566                                         + Integer.toHexString(ev.deviceId));
    567                                 continue;
    568                             }
    569                         }
    570                     } else {
    571                         di = getInputDevice(ev.deviceId);
    572                         if (di == null) {
    573                             // This may be some junk from an ignored device.
    574                             continue;
    575                         }
    576 
    577                         // first crack at it
    578                         send = preprocessEvent(di, ev);
    579 
    580                         if (ev.type == RawInputEvent.EV_KEY) {
    581                             di.mMetaKeysState = makeMetaState(ev.keycode,
    582                                     ev.value != 0, di.mMetaKeysState);
    583                             mHaveGlobalMetaState = false;
    584                         }
    585                     }
    586 
    587                     if (configChanged) {
    588                         synchronized (mFirst) {
    589                             addLocked(di, System.nanoTime(), 0,
    590                                     RawInputEvent.CLASS_CONFIGURATION_CHANGED,
    591                                     null);
    592                         }
    593                     }
    594 
    595                     if (!send) {
    596                         continue;
    597                     }
    598 
    599                     synchronized (mFirst) {
    600                         // NOTE: The event timebase absolutely must be the same
    601                         // timebase as SystemClock.uptimeMillis().
    602                         //curTime = gotOne ? ev.when : SystemClock.uptimeMillis();
    603                         final long curTime = SystemClock.uptimeMillis();
    604                         final long curTimeNano = System.nanoTime();
    605                         //Slog.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
    606 
    607                         final int classes = di.classes;
    608                         final int type = ev.type;
    609                         final int scancode = ev.scancode;
    610                         send = false;
    611 
    612                         // Is it a key event?
    613                         if (type == RawInputEvent.EV_KEY &&
    614                                 (classes&RawInputEvent.CLASS_KEYBOARD) != 0 &&
    615                                 (scancode < RawInputEvent.BTN_FIRST ||
    616                                         scancode > RawInputEvent.BTN_LAST)) {
    617                             boolean down;
    618                             if (ev.value != 0) {
    619                                 down = true;
    620                                 di.mKeyDownTime = curTime;
    621                             } else {
    622                                 down = false;
    623                             }
    624                             int keycode = rotateKeyCodeLocked(ev.keycode);
    625                             addLocked(di, curTimeNano, ev.flags,
    626                                     RawInputEvent.CLASS_KEYBOARD,
    627                                     newKeyEvent(di, di.mKeyDownTime, curTime, down,
    628                                             keycode, 0, scancode,
    629                                             ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
    630                                              ? KeyEvent.FLAG_WOKE_HERE : 0));
    631 
    632                         } else if (ev.type == RawInputEvent.EV_KEY) {
    633                             // Single touch protocol: touch going down or up.
    634                             if (ev.scancode == RawInputEvent.BTN_TOUCH &&
    635                                     (classes&(RawInputEvent.CLASS_TOUCHSCREEN
    636                                             |RawInputEvent.CLASS_TOUCHSCREEN_MT))
    637                                             == RawInputEvent.CLASS_TOUCHSCREEN) {
    638                                 di.mAbs.changed = true;
    639                                 di.mAbs.mDown[0] = ev.value != 0;
    640 
    641                             // Trackball (mouse) protocol: press down or up.
    642                             } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
    643                                     (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
    644                                 di.mRel.changed = true;
    645                                 di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;
    646                                 send = true;
    647                             }
    648 
    649                         // Process position events from multitouch protocol.
    650                         } else if (ev.type == RawInputEvent.EV_ABS &&
    651                                 (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
    652                             if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {
    653                                 di.mAbs.changed = true;
    654                                 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
    655                                         + MotionEvent.SAMPLE_PRESSURE] = ev.value;
    656                             } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) {
    657                                 di.mAbs.changed = true;
    658                                 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
    659                                     + MotionEvent.SAMPLE_X] = ev.value;
    660                                 if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
    661                                         + di.mAbs.mAddingPointerOffset
    662                                         + " X:" + ev.value);
    663                             } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) {
    664                                 di.mAbs.changed = true;
    665                                 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
    666                                     + MotionEvent.SAMPLE_Y] = ev.value;
    667                                 if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
    668                                         + di.mAbs.mAddingPointerOffset
    669                                         + " Y:" + ev.value);
    670                             } else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) {
    671                                 di.mAbs.changed = true;
    672                                 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
    673                                     + MotionEvent.SAMPLE_SIZE] = ev.value;
    674                             }
    675 
    676                         // Process position events from single touch protocol.
    677                         } else if (ev.type == RawInputEvent.EV_ABS &&
    678                                 (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
    679                             if (ev.scancode == RawInputEvent.ABS_X) {
    680                                 di.mAbs.changed = true;
    681                                 di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;
    682                             } else if (ev.scancode == RawInputEvent.ABS_Y) {
    683                                 di.mAbs.changed = true;
    684                                 di.curTouchVals[MotionEvent.SAMPLE_Y] = ev.value;
    685                             } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) {
    686                                 di.mAbs.changed = true;
    687                                 di.curTouchVals[MotionEvent.SAMPLE_PRESSURE] = ev.value;
    688                                 di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
    689                                                  + MotionEvent.SAMPLE_PRESSURE] = ev.value;
    690                             } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) {
    691                                 di.mAbs.changed = true;
    692                                 di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;
    693                                 di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
    694                                                  + MotionEvent.SAMPLE_SIZE] = ev.value;
    695                             }
    696 
    697                         // Process movement events from trackball (mouse) protocol.
    698                         } else if (ev.type == RawInputEvent.EV_REL &&
    699                                 (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
    700                             // Add this relative movement into our totals.
    701                             if (ev.scancode == RawInputEvent.REL_X) {
    702                                 di.mRel.changed = true;
    703                                 di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;
    704                             } else if (ev.scancode == RawInputEvent.REL_Y) {
    705                                 di.mRel.changed = true;
    706                                 di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;
    707                             }
    708                         }
    709 
    710                         // Handle multitouch protocol sync: tells us that the
    711                         // driver has returned all data for -one- of the pointers
    712                         // that is currently down.
    713                         if (ev.type == RawInputEvent.EV_SYN
    714                                 && ev.scancode == RawInputEvent.SYN_MT_REPORT
    715                                 && di.mAbs != null) {
    716                             di.mAbs.changed = true;
    717                             if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) {
    718                                 // If the value is <= 0, the pointer is not
    719                                 // down, so keep it in the count.
    720 
    721                                 if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
    722                                                       + MotionEvent.SAMPLE_PRESSURE] != 0) {
    723                                     final int num = di.mAbs.mNextNumPointers+1;
    724                                     di.mAbs.mNextNumPointers = num;
    725                                     if (DEBUG_POINTERS) Slog.v(TAG,
    726                                             "MT_REPORT: now have " + num + " pointers");
    727                                     final int newOffset = (num <= InputDevice.MAX_POINTERS)
    728                                             ? (num * MotionEvent.NUM_SAMPLE_DATA)
    729                                             : (InputDevice.MAX_POINTERS *
    730                                                     MotionEvent.NUM_SAMPLE_DATA);
    731                                     di.mAbs.mAddingPointerOffset = newOffset;
    732                                     di.mAbs.mNextData[newOffset
    733                                             + MotionEvent.SAMPLE_PRESSURE] = 0;
    734                                 } else {
    735                                     if (DEBUG_POINTERS) Slog.v(TAG, "MT_REPORT: no pointer");
    736                                 }
    737                             }
    738 
    739                         // Handle general event sync: all data for the current
    740                         // event update has been delivered.
    741                         } else if (send || (ev.type == RawInputEvent.EV_SYN
    742                                 && ev.scancode == RawInputEvent.SYN_REPORT)) {
    743                             if (mDisplay != null) {
    744                                 if (!mHaveGlobalMetaState) {
    745                                     computeGlobalMetaStateLocked();
    746                                 }
    747 
    748                                 MotionEvent me;
    749 
    750                                 InputDevice.MotionState ms = di.mAbs;
    751                                 if (ms.changed) {
    752                                     ms.everChanged = true;
    753                                     ms.changed = false;
    754 
    755                                     if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN
    756                                             |RawInputEvent.CLASS_TOUCHSCREEN_MT))
    757                                             == RawInputEvent.CLASS_TOUCHSCREEN) {
    758                                         ms.mNextNumPointers = 0;
    759                                         if (ms.mDown[0]) {
    760                                             System.arraycopy(di.curTouchVals, 0,
    761                                                     ms.mNextData, 0,
    762                                                     MotionEvent.NUM_SAMPLE_DATA);
    763                                             ms.mNextNumPointers++;
    764                                         }
    765                                     }
    766 
    767                                     if (BAD_TOUCH_HACK) {
    768                                         ms.dropBadPoint(di);
    769                                     }
    770                                     if (JUMPY_TOUCH_HACK) {
    771                                         ms.dropJumpyPoint(di);
    772                                     }
    773 
    774                                     boolean doMotion = !monitorVirtualKey(di,
    775                                             ev, curTime, curTimeNano);
    776 
    777                                     if (doMotion && ms.mNextNumPointers > 0
    778                                             && (ms.mLastNumPointers == 0
    779                                                     || ms.mSkipLastPointers)) {
    780                                         doMotion = !generateVirtualKeyDown(di,
    781                                                 ev, curTime, curTimeNano);
    782                                     }
    783 
    784                                     if (doMotion) {
    785                                         // XXX Need to be able to generate
    786                                         // multiple events here, for example
    787                                         // if two fingers change up/down state
    788                                         // at the same time.
    789                                         do {
    790                                             me = ms.generateAbsMotion(di, curTime,
    791                                                     curTimeNano, mDisplay,
    792                                                     mOrientation, mGlobalMetaState);
    793                                             if (DEBUG_POINTERS) Slog.v(TAG, "Absolute: x="
    794                                                     + di.mAbs.mNextData[MotionEvent.SAMPLE_X]
    795                                                     + " y="
    796                                                     + di.mAbs.mNextData[MotionEvent.SAMPLE_Y]
    797                                                     + " ev=" + me);
    798                                             if (me != null) {
    799                                                 if (WindowManagerPolicy.WATCH_POINTER) {
    800                                                     Slog.i(TAG, "Enqueueing: " + me);
    801                                                 }
    802                                                 addLocked(di, curTimeNano, ev.flags,
    803                                                         RawInputEvent.CLASS_TOUCHSCREEN, me);
    804                                             }
    805                                         } while (ms.hasMore());
    806                                     } else {
    807                                         // We are consuming movement in the
    808                                         // virtual key area...  but still
    809                                         // propagate this to the previous
    810                                         // data for comparisons.
    811                                         int num = ms.mNextNumPointers;
    812                                         if (num > InputDevice.MAX_POINTERS) {
    813                                             num = InputDevice.MAX_POINTERS;
    814                                         }
    815                                         System.arraycopy(ms.mNextData, 0,
    816                                                 ms.mLastData, 0,
    817                                                 num * MotionEvent.NUM_SAMPLE_DATA);
    818                                         ms.mLastNumPointers = num;
    819                                         ms.mSkipLastPointers = true;
    820                                     }
    821 
    822                                     ms.finish();
    823                                 }
    824 
    825                                 ms = di.mRel;
    826                                 if (ms.changed) {
    827                                     ms.everChanged = true;
    828                                     ms.changed = false;
    829 
    830                                     me = ms.generateRelMotion(di, curTime,
    831                                             curTimeNano,
    832                                             mOrientation, mGlobalMetaState);
    833                                     if (false) Slog.v(TAG, "Relative: x="
    834                                             + di.mRel.mNextData[MotionEvent.SAMPLE_X]
    835                                             + " y="
    836                                             + di.mRel.mNextData[MotionEvent.SAMPLE_Y]
    837                                             + " ev=" + me);
    838                                     if (me != null) {
    839                                         addLocked(di, curTimeNano, ev.flags,
    840                                                 RawInputEvent.CLASS_TRACKBALL, me);
    841                                     }
    842                                 }
    843                             }
    844                         }
    845                     }
    846 
    847                 } catch (RuntimeException exc) {
    848                     Slog.e(TAG, "InputReaderThread uncaught exception", exc);
    849                 }
    850             }
    851         }
    852     };
    853 
    854     private boolean isInsideDisplay(InputDevice dev) {
    855         final InputDevice.AbsoluteInfo absx = dev.absX;
    856         final InputDevice.AbsoluteInfo absy = dev.absY;
    857         final InputDevice.MotionState absm = dev.mAbs;
    858         if (absx == null || absy == null || absm == null) {
    859             return true;
    860         }
    861 
    862         if (absm.mNextData[MotionEvent.SAMPLE_X] >= absx.minValue
    863                 && absm.mNextData[MotionEvent.SAMPLE_X] <= absx.maxValue
    864                 && absm.mNextData[MotionEvent.SAMPLE_Y] >= absy.minValue
    865                 && absm.mNextData[MotionEvent.SAMPLE_Y] <= absy.maxValue) {
    866             if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Input ("
    867                     + absm.mNextData[MotionEvent.SAMPLE_X]
    868                     + "," + absm.mNextData[MotionEvent.SAMPLE_Y]
    869                     + ") inside of display");
    870             return true;
    871         }
    872 
    873         return false;
    874     }
    875 
    876     private VirtualKey findVirtualKey(InputDevice dev) {
    877         final int N = mVirtualKeys.size();
    878         if (N <= 0) {
    879             return null;
    880         }
    881 
    882         final InputDevice.MotionState absm = dev.mAbs;
    883         for (int i=0; i<N; i++) {
    884             VirtualKey sb = mVirtualKeys.get(i);
    885             sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
    886             if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit test ("
    887                     + absm.mNextData[MotionEvent.SAMPLE_X] + ","
    888                     + absm.mNextData[MotionEvent.SAMPLE_Y] + ") in code "
    889                     + sb.scancode + " - (" + sb.hitLeft
    890                     + "," + sb.hitTop + ")-(" + sb.hitRight + ","
    891                     + sb.hitBottom + ")");
    892             if (sb.checkHit(absm.mNextData[MotionEvent.SAMPLE_X],
    893                     absm.mNextData[MotionEvent.SAMPLE_Y])) {
    894                 if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit!");
    895                 return sb;
    896             }
    897         }
    898 
    899         return null;
    900     }
    901 
    902     private boolean generateVirtualKeyDown(InputDevice di, RawInputEvent ev,
    903             long curTime, long curTimeNano) {
    904         if (isInsideDisplay(di)) {
    905             // Didn't consume event.
    906             return false;
    907         }
    908 
    909 
    910         VirtualKey vk = findVirtualKey(di);
    911         if (vk != null) {
    912             final InputDevice.MotionState ms = di.mAbs;
    913             mPressedVirtualKey = vk;
    914             vk.lastKeycode = scancodeToKeycode(di.id, vk.scancode);
    915             ms.mLastNumPointers = ms.mNextNumPointers;
    916             di.mKeyDownTime = curTime;
    917             if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG,
    918                     "Generate key down for: " + vk.scancode
    919                     + " (keycode=" + vk.lastKeycode + ")");
    920             KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true,
    921                     vk.lastKeycode, 0, vk.scancode,
    922                     KeyEvent.FLAG_VIRTUAL_HARD_KEY);
    923             mHapticFeedbackCallback.virtualKeyFeedback(event);
    924             addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
    925                     event);
    926         }
    927 
    928         // We always consume the event, even if we didn't
    929         // generate a key event.  There are two reasons for
    930         // this: to avoid spurious touches when holding
    931         // the edges of the device near the touchscreen,
    932         // and to avoid reporting events if there are virtual
    933         // keys on the touchscreen outside of the display
    934         // area.
    935         // Note that for all of this we are only looking at the
    936         // first pointer, since what we are handling here is the
    937         // first pointer going down, and this is the coordinate
    938         // that will be used to dispatch the event.
    939         if (false) {
    940             final InputDevice.AbsoluteInfo absx = di.absX;
    941             final InputDevice.AbsoluteInfo absy = di.absY;
    942             final InputDevice.MotionState absm = di.mAbs;
    943             Slog.v(TAG, "Rejecting ("
    944                 + absm.mNextData[MotionEvent.SAMPLE_X] + ","
    945                 + absm.mNextData[MotionEvent.SAMPLE_Y] + "): outside of ("
    946                 + absx.minValue + "," + absy.minValue
    947                 + ")-(" + absx.maxValue + ","
    948                 + absx.maxValue + ")");
    949         }
    950         return true;
    951     }
    952 
    953     private boolean monitorVirtualKey(InputDevice di, RawInputEvent ev,
    954             long curTime, long curTimeNano) {
    955         VirtualKey vk = mPressedVirtualKey;
    956         if (vk == null) {
    957             return false;
    958         }
    959 
    960         final InputDevice.MotionState ms = di.mAbs;
    961         if (ms.mNextNumPointers <= 0) {
    962             mPressedVirtualKey = null;
    963             ms.mLastNumPointers = 0;
    964             if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Generate key up for: " + vk.scancode);
    965             KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
    966                     vk.lastKeycode, 0, vk.scancode,
    967                     KeyEvent.FLAG_VIRTUAL_HARD_KEY);
    968             mHapticFeedbackCallback.virtualKeyFeedback(event);
    969             addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
    970                     event);
    971             return true;
    972 
    973         } else if (isInsideDisplay(di)) {
    974             // Whoops the pointer has moved into
    975             // the display area!  Cancel the
    976             // virtual key and start a pointer
    977             // motion.
    978             mPressedVirtualKey = null;
    979             if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Cancel key up for: " + vk.scancode);
    980             KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
    981                     vk.lastKeycode, 0, vk.scancode,
    982                     KeyEvent.FLAG_CANCELED | KeyEvent.FLAG_VIRTUAL_HARD_KEY);
    983             mHapticFeedbackCallback.virtualKeyFeedback(event);
    984             addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
    985                     event);
    986             ms.mLastNumPointers = 0;
    987             return false;
    988         }
    989 
    990         return true;
    991     }
    992 
    993     /**
    994      * Returns a new meta state for the given keys and old state.
    995      */
    996     private static final int makeMetaState(int keycode, boolean down, int old) {
    997         int mask;
    998         switch (keycode) {
    999         case KeyEvent.KEYCODE_ALT_LEFT:
   1000             mask = KeyEvent.META_ALT_LEFT_ON;
   1001             break;
   1002         case KeyEvent.KEYCODE_ALT_RIGHT:
   1003             mask = KeyEvent.META_ALT_RIGHT_ON;
   1004             break;
   1005         case KeyEvent.KEYCODE_SHIFT_LEFT:
   1006             mask = KeyEvent.META_SHIFT_LEFT_ON;
   1007             break;
   1008         case KeyEvent.KEYCODE_SHIFT_RIGHT:
   1009             mask = KeyEvent.META_SHIFT_RIGHT_ON;
   1010             break;
   1011         case KeyEvent.KEYCODE_SYM:
   1012             mask = KeyEvent.META_SYM_ON;
   1013             break;
   1014         default:
   1015             return old;
   1016         }
   1017         int result = ~(KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON)
   1018                     & (down ? (old | mask) : (old & ~mask));
   1019         if (0 != (result & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON))) {
   1020             result |= KeyEvent.META_ALT_ON;
   1021         }
   1022         if (0 != (result & (KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON))) {
   1023             result |= KeyEvent.META_SHIFT_ON;
   1024         }
   1025         return result;
   1026     }
   1027 
   1028     private void computeGlobalMetaStateLocked() {
   1029         int i = mDevices.size();
   1030         mGlobalMetaState = 0;
   1031         while ((--i) >= 0) {
   1032             mGlobalMetaState |= mDevices.valueAt(i).mMetaKeysState;
   1033         }
   1034         mHaveGlobalMetaState = true;
   1035     }
   1036 
   1037     /*
   1038      * Return true if you want the event to get passed on to the
   1039      * rest of the system, and false if you've handled it and want
   1040      * it dropped.
   1041      */
   1042     abstract boolean preprocessEvent(InputDevice device, RawInputEvent event);
   1043 
   1044     InputDevice getInputDevice(int deviceId) {
   1045         synchronized (mFirst) {
   1046             return getInputDeviceLocked(deviceId);
   1047         }
   1048     }
   1049 
   1050     private InputDevice getInputDeviceLocked(int deviceId) {
   1051         return mDevices.get(deviceId);
   1052     }
   1053 
   1054     public void setOrientation(int orientation) {
   1055         synchronized(mFirst) {
   1056             mOrientation = orientation;
   1057             switch (orientation) {
   1058                 case Surface.ROTATION_90:
   1059                     mKeyRotationMap = KEY_90_MAP;
   1060                     break;
   1061                 case Surface.ROTATION_180:
   1062                     mKeyRotationMap = KEY_180_MAP;
   1063                     break;
   1064                 case Surface.ROTATION_270:
   1065                     mKeyRotationMap = KEY_270_MAP;
   1066                     break;
   1067                 default:
   1068                     mKeyRotationMap = null;
   1069                     break;
   1070             }
   1071         }
   1072     }
   1073 
   1074     public int rotateKeyCode(int keyCode) {
   1075         synchronized(mFirst) {
   1076             return rotateKeyCodeLocked(keyCode);
   1077         }
   1078     }
   1079 
   1080     private int rotateKeyCodeLocked(int keyCode) {
   1081         int[] map = mKeyRotationMap;
   1082         if (map != null) {
   1083             final int N = map.length;
   1084             for (int i=0; i<N; i+=2) {
   1085                 if (map[i] == keyCode) {
   1086                     return map[i+1];
   1087                 }
   1088             }
   1089         }
   1090         return keyCode;
   1091     }
   1092 
   1093     boolean hasEvents() {
   1094         synchronized (mFirst) {
   1095             return mFirst.next != mLast;
   1096         }
   1097     }
   1098 
   1099     /*
   1100      * returns true if we returned an event, and false if we timed out
   1101      */
   1102     QueuedEvent getEvent(long timeoutMS) {
   1103         long begin = SystemClock.uptimeMillis();
   1104         final long end = begin+timeoutMS;
   1105         long now = begin;
   1106         synchronized (mFirst) {
   1107             while (mFirst.next == mLast && end > now) {
   1108                 try {
   1109                     mWakeLock.release();
   1110                     mFirst.wait(end-now);
   1111                 }
   1112                 catch (InterruptedException e) {
   1113                 }
   1114                 now = SystemClock.uptimeMillis();
   1115                 if (begin > now) {
   1116                     begin = now;
   1117                 }
   1118             }
   1119             if (mFirst.next == mLast) {
   1120                 return null;
   1121             }
   1122             QueuedEvent p = mFirst.next;
   1123             mFirst.next = p.next;
   1124             mFirst.next.prev = mFirst;
   1125             p.inQueue = false;
   1126             return p;
   1127         }
   1128     }
   1129 
   1130     /**
   1131      * Return true if the queue has an up event pending that corresponds
   1132      * to the same key as the given key event.
   1133      */
   1134     boolean hasKeyUpEvent(KeyEvent origEvent) {
   1135         synchronized (mFirst) {
   1136             final int keyCode = origEvent.getKeyCode();
   1137             QueuedEvent cur = mLast.prev;
   1138             while (cur.prev != null) {
   1139                 if (cur.classType == RawInputEvent.CLASS_KEYBOARD) {
   1140                     KeyEvent ke = (KeyEvent)cur.event;
   1141                     if (ke.getAction() == KeyEvent.ACTION_UP
   1142                             && ke.getKeyCode() == keyCode) {
   1143                         return true;
   1144                     }
   1145                 }
   1146                 cur = cur.prev;
   1147             }
   1148         }
   1149 
   1150         return false;
   1151     }
   1152 
   1153     void recycleEvent(QueuedEvent ev) {
   1154         synchronized (mFirst) {
   1155             //Slog.i(TAG, "Recycle event: " + ev);
   1156             if (ev.event == ev.inputDevice.mAbs.currentMove) {
   1157                 ev.inputDevice.mAbs.currentMove = null;
   1158             }
   1159             if (ev.event == ev.inputDevice.mRel.currentMove) {
   1160                 if (false) Slog.i(TAG, "Detach rel " + ev.event);
   1161                 ev.inputDevice.mRel.currentMove = null;
   1162                 ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_X] = 0;
   1163                 ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_Y] = 0;
   1164             }
   1165             recycleLocked(ev);
   1166         }
   1167     }
   1168 
   1169     void filterQueue(FilterCallback cb) {
   1170         synchronized (mFirst) {
   1171             QueuedEvent cur = mLast.prev;
   1172             while (cur.prev != null) {
   1173                 switch (cb.filterEvent(cur)) {
   1174                     case FILTER_REMOVE:
   1175                         cur.prev.next = cur.next;
   1176                         cur.next.prev = cur.prev;
   1177                         break;
   1178                     case FILTER_ABORT:
   1179                         return;
   1180                 }
   1181                 cur = cur.prev;
   1182             }
   1183         }
   1184     }
   1185 
   1186     private QueuedEvent obtainLocked(InputDevice device, long whenNano,
   1187             int flags, int classType, Object event) {
   1188         QueuedEvent ev;
   1189         if (mCacheCount == 0) {
   1190             ev = new QueuedEvent();
   1191         } else {
   1192             ev = mCache;
   1193             ev.inQueue = false;
   1194             mCache = ev.next;
   1195             mCacheCount--;
   1196         }
   1197         ev.inputDevice = device;
   1198         ev.whenNano = whenNano;
   1199         ev.flags = flags;
   1200         ev.classType = classType;
   1201         ev.event = event;
   1202         return ev;
   1203     }
   1204 
   1205     private void recycleLocked(QueuedEvent ev) {
   1206         if (ev.inQueue) {
   1207             throw new RuntimeException("Event already in queue!");
   1208         }
   1209         if (mCacheCount < 10) {
   1210             mCacheCount++;
   1211             ev.next = mCache;
   1212             mCache = ev;
   1213             ev.inQueue = true;
   1214         }
   1215     }
   1216 
   1217     private void addLocked(InputDevice device, long whenNano, int flags,
   1218             int classType, Object event) {
   1219         boolean poke = mFirst.next == mLast;
   1220 
   1221         QueuedEvent ev = obtainLocked(device, whenNano, flags, classType, event);
   1222         QueuedEvent p = mLast.prev;
   1223         while (p != mFirst && ev.whenNano < p.whenNano) {
   1224             p = p.prev;
   1225         }
   1226 
   1227         ev.next = p.next;
   1228         ev.prev = p;
   1229         p.next = ev;
   1230         ev.next.prev = ev;
   1231         ev.inQueue = true;
   1232 
   1233         if (poke) {
   1234             long time;
   1235             if (MEASURE_LATENCY) {
   1236                 time = System.nanoTime();
   1237             }
   1238             mFirst.notify();
   1239             mWakeLock.acquire();
   1240             if (MEASURE_LATENCY) {
   1241                 lt.sample("1 addLocked-queued event ", System.nanoTime() - time);
   1242             }
   1243         }
   1244     }
   1245 
   1246     private InputDevice newInputDevice(int deviceId) {
   1247         int classes = getDeviceClasses(deviceId);
   1248         String name = getDeviceName(deviceId);
   1249         InputDevice.AbsoluteInfo absX = null;
   1250         InputDevice.AbsoluteInfo absY = null;
   1251         InputDevice.AbsoluteInfo absPressure = null;
   1252         InputDevice.AbsoluteInfo absSize = null;
   1253         if (classes != 0) {
   1254             Slog.i(TAG, "Device added: id=0x" + Integer.toHexString(deviceId)
   1255                     + ", name=" + name
   1256                     + ", classes=" + Integer.toHexString(classes));
   1257             if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
   1258                 absX = loadAbsoluteInfo(deviceId,
   1259                         RawInputEvent.ABS_MT_POSITION_X, "X");
   1260                 absY = loadAbsoluteInfo(deviceId,
   1261                         RawInputEvent.ABS_MT_POSITION_Y, "Y");
   1262                 absPressure = loadAbsoluteInfo(deviceId,
   1263                         RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure");
   1264                 absSize = loadAbsoluteInfo(deviceId,
   1265                         RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size");
   1266             } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
   1267                 absX = loadAbsoluteInfo(deviceId,
   1268                         RawInputEvent.ABS_X, "X");
   1269                 absY = loadAbsoluteInfo(deviceId,
   1270                         RawInputEvent.ABS_Y, "Y");
   1271                 absPressure = loadAbsoluteInfo(deviceId,
   1272                         RawInputEvent.ABS_PRESSURE, "Pressure");
   1273                 absSize = loadAbsoluteInfo(deviceId,
   1274                         RawInputEvent.ABS_TOOL_WIDTH, "Size");
   1275             }
   1276         }
   1277 
   1278         return new InputDevice(deviceId, classes, name, absX, absY, absPressure, absSize);
   1279     }
   1280 
   1281     private InputDevice.AbsoluteInfo loadAbsoluteInfo(int id, int channel,
   1282             String name) {
   1283         InputDevice.AbsoluteInfo info = new InputDevice.AbsoluteInfo();
   1284         if (getAbsoluteInfo(id, channel, info)
   1285                 && info.minValue != info.maxValue) {
   1286             Slog.i(TAG, "  " + name + ": min=" + info.minValue
   1287                     + " max=" + info.maxValue
   1288                     + " flat=" + info.flat
   1289                     + " fuzz=" + info.fuzz);
   1290             info.range = info.maxValue-info.minValue;
   1291             return info;
   1292         }
   1293         Slog.i(TAG, "  " + name + ": unknown values");
   1294         return null;
   1295     }
   1296     private static native boolean readEvent(RawInputEvent outEvent);
   1297 
   1298     void dump(PrintWriter pw, String prefix) {
   1299         synchronized (mFirst) {
   1300             for (int i=0; i<mDevices.size(); i++) {
   1301                 InputDevice dev = mDevices.valueAt(i);
   1302                 pw.print(prefix); pw.print("Device #");
   1303                         pw.print(mDevices.keyAt(i)); pw.print(" ");
   1304                         pw.print(dev.name); pw.print(" (classes=0x");
   1305                         pw.print(Integer.toHexString(dev.classes));
   1306                         pw.println("):");
   1307                 pw.print(prefix); pw.print("  mKeyDownTime=");
   1308                         pw.print(dev.mKeyDownTime); pw.print(" mMetaKeysState=");
   1309                         pw.println(dev.mMetaKeysState);
   1310                 if (dev.absX != null) {
   1311                     pw.print(prefix); pw.print("  absX: "); dev.absX.dump(pw);
   1312                             pw.println("");
   1313                 }
   1314                 if (dev.absY != null) {
   1315                     pw.print(prefix); pw.print("  absY: "); dev.absY.dump(pw);
   1316                             pw.println("");
   1317                 }
   1318                 if (dev.absPressure != null) {
   1319                     pw.print(prefix); pw.print("  absPressure: ");
   1320                             dev.absPressure.dump(pw); pw.println("");
   1321                 }
   1322                 if (dev.absSize != null) {
   1323                     pw.print(prefix); pw.print("  absSize: ");
   1324                             dev.absSize.dump(pw); pw.println("");
   1325                 }
   1326                 if (dev.mAbs.everChanged) {
   1327                     pw.print(prefix); pw.println("  mAbs:");
   1328                     dev.mAbs.dump(pw, prefix + "    ");
   1329                 }
   1330                 if (dev.mRel.everChanged) {
   1331                     pw.print(prefix); pw.println("  mRel:");
   1332                     dev.mRel.dump(pw, prefix + "    ");
   1333                 }
   1334             }
   1335             pw.println(" ");
   1336             for (int i=0; i<mIgnoredDevices.size(); i++) {
   1337                 InputDevice dev = mIgnoredDevices.valueAt(i);
   1338                 pw.print(prefix); pw.print("Ignored Device #");
   1339                         pw.print(mIgnoredDevices.keyAt(i)); pw.print(" ");
   1340                         pw.print(dev.name); pw.print(" (classes=0x");
   1341                         pw.print(Integer.toHexString(dev.classes));
   1342                         pw.println(")");
   1343             }
   1344             pw.println(" ");
   1345             for (int i=0; i<mVirtualKeys.size(); i++) {
   1346                 VirtualKey vk = mVirtualKeys.get(i);
   1347                 pw.print(prefix); pw.print("Virtual Key #");
   1348                         pw.print(i); pw.println(":");
   1349                 pw.print(prefix); pw.print("  scancode="); pw.println(vk.scancode);
   1350                 pw.print(prefix); pw.print("  centerx="); pw.print(vk.centerx);
   1351                         pw.print(" centery="); pw.print(vk.centery);
   1352                         pw.print(" width="); pw.print(vk.width);
   1353                         pw.print(" height="); pw.println(vk.height);
   1354                 pw.print(prefix); pw.print("  hitLeft="); pw.print(vk.hitLeft);
   1355                         pw.print(" hitTop="); pw.print(vk.hitTop);
   1356                         pw.print(" hitRight="); pw.print(vk.hitRight);
   1357                         pw.print(" hitBottom="); pw.println(vk.hitBottom);
   1358                 if (vk.lastDevice != null) {
   1359                     pw.print(prefix); pw.print("  lastDevice=#");
   1360                             pw.println(vk.lastDevice.id);
   1361                 }
   1362                 if (vk.lastKeycode != 0) {
   1363                     pw.print(prefix); pw.print("  lastKeycode=");
   1364                             pw.println(vk.lastKeycode);
   1365                 }
   1366             }
   1367             pw.println(" ");
   1368             pw.print(prefix); pw.print("  Default keyboard: ");
   1369                     pw.println(SystemProperties.get("hw.keyboards.0.devname"));
   1370             pw.print(prefix); pw.print("  mGlobalMetaState=");
   1371                     pw.print(mGlobalMetaState); pw.print(" mHaveGlobalMetaState=");
   1372                     pw.println(mHaveGlobalMetaState);
   1373             pw.print(prefix); pw.print("  mDisplayWidth=");
   1374                     pw.print(mDisplayWidth); pw.print(" mDisplayHeight=");
   1375                     pw.println(mDisplayHeight);
   1376             pw.print(prefix); pw.print("  mOrientation=");
   1377                     pw.println(mOrientation);
   1378             if (mPressedVirtualKey != null) {
   1379                 pw.print(prefix); pw.print("  mPressedVirtualKey.scancode=");
   1380                         pw.println(mPressedVirtualKey.scancode);
   1381             }
   1382         }
   1383     }
   1384 }
   1385