OSDN Git Service

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