blob: 7ca12f211da23ba3178fdcf4e079254a8b0a1003 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package com.android.server;
18
19import android.content.Context;
20import android.content.res.Configuration;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040021import android.os.Environment;
Michael Chan53071d62009-05-13 17:29:48 -070022import android.os.LatencyTimer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.os.PowerManager;
Michael Chan53071d62009-05-13 17:29:48 -070024import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.util.Log;
26import android.util.SparseArray;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040027import android.util.Xml;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.view.Display;
29import android.view.KeyEvent;
30import android.view.MotionEvent;
31import android.view.RawInputEvent;
32import android.view.Surface;
33import android.view.WindowManagerPolicy;
34
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040035import com.android.internal.util.XmlUtils;
36
37import org.xmlpull.v1.XmlPullParser;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040038
Dianne Hackborne3dd8842009-07-14 12:06:54 -070039import java.io.BufferedReader;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040040import java.io.File;
Dianne Hackborne3dd8842009-07-14 12:06:54 -070041import java.io.FileInputStream;
42import java.io.FileNotFoundException;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040043import java.io.FileReader;
Dianne Hackborne3dd8842009-07-14 12:06:54 -070044import java.io.IOException;
45import java.io.InputStreamReader;
46import java.util.ArrayList;
47
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048public abstract class KeyInputQueue {
49 static final String TAG = "KeyInputQueue";
50
Dianne Hackborne3dd8842009-07-14 12:06:54 -070051 static final boolean DEBUG_VIRTUAL_KEYS = false;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070052 static final boolean DEBUG_POINTERS = false;
Dianne Hackborne3dd8842009-07-14 12:06:54 -070053
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040054 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
55
Dianne Hackborne3dd8842009-07-14 12:06:54 -070056 final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
57 final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
Dianne Hackbornddca3ee2009-07-23 19:01:31 -070058 final HapticFeedbackCallback mHapticFeedbackCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059
60 int mGlobalMetaState = 0;
61 boolean mHaveGlobalMetaState = false;
62
63 final QueuedEvent mFirst;
64 final QueuedEvent mLast;
65 QueuedEvent mCache;
66 int mCacheCount;
67
68 Display mDisplay = null;
Dianne Hackborne3dd8842009-07-14 12:06:54 -070069 int mDisplayWidth;
70 int mDisplayHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071
72 int mOrientation = Surface.ROTATION_0;
73 int[] mKeyRotationMap = null;
74
Dianne Hackborne3dd8842009-07-14 12:06:54 -070075 VirtualKey mPressedVirtualKey = null;
76
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 PowerManager.WakeLock mWakeLock;
78
79 static final int[] KEY_90_MAP = new int[] {
80 KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT,
81 KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_UP,
82 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_LEFT,
83 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_DOWN,
84 };
85
86 static final int[] KEY_180_MAP = new int[] {
87 KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_UP,
88 KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_LEFT,
89 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN,
90 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT,
91 };
92
93 static final int[] KEY_270_MAP = new int[] {
94 KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_LEFT,
95 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_UP,
96 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_RIGHT,
97 KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_DOWN,
98 };
99
100 public static final int FILTER_REMOVE = 0;
101 public static final int FILTER_KEEP = 1;
102 public static final int FILTER_ABORT = -1;
Michael Chan53071d62009-05-13 17:29:48 -0700103
104 private static final boolean MEASURE_LATENCY = false;
105 private LatencyTimer lt;
106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 public interface FilterCallback {
108 int filterEvent(QueuedEvent ev);
109 }
110
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700111 public interface HapticFeedbackCallback {
112 void virtualKeyFeedback(KeyEvent event);
113 }
114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 static class QueuedEvent {
116 InputDevice inputDevice;
Michael Chan53071d62009-05-13 17:29:48 -0700117 long whenNano;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 int flags; // From the raw event
119 int classType; // One of the class constants in InputEvent
120 Object event;
121 boolean inQueue;
122
123 void copyFrom(QueuedEvent that) {
124 this.inputDevice = that.inputDevice;
Michael Chan53071d62009-05-13 17:29:48 -0700125 this.whenNano = that.whenNano;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 this.flags = that.flags;
127 this.classType = that.classType;
128 this.event = that.event;
129 }
130
131 @Override
132 public String toString() {
133 return "QueuedEvent{"
134 + Integer.toHexString(System.identityHashCode(this))
135 + " " + event + "}";
136 }
137
138 // not copied
139 QueuedEvent prev;
140 QueuedEvent next;
141 }
142
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700143 /**
144 * A key that exists as a part of the touch-screen, outside of the normal
145 * display area of the screen.
146 */
147 static class VirtualKey {
148 int scancode;
149 int centerx;
150 int centery;
151 int width;
152 int height;
153
154 int hitLeft;
155 int hitTop;
156 int hitRight;
157 int hitBottom;
158
159 InputDevice lastDevice;
160 int lastKeycode;
161
162 boolean checkHit(int x, int y) {
163 return (x >= hitLeft && x <= hitRight
164 && y >= hitTop && y <= hitBottom);
165 }
166
167 void computeHitRect(InputDevice dev, int dw, int dh) {
168 if (dev == lastDevice) {
169 return;
170 }
171
172 if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "computeHitRect for " + scancode
173 + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
174
175 lastDevice = dev;
176
177 int minx = dev.absX.minValue;
178 int maxx = dev.absX.maxValue;
179
180 int halfw = width/2;
181 int left = centerx - halfw;
182 int right = centerx + halfw;
183 hitLeft = minx + ((left*maxx-minx)/dw);
184 hitRight = minx + ((right*maxx-minx)/dw);
185
186 int miny = dev.absY.minValue;
187 int maxy = dev.absY.maxValue;
188
189 int halfh = height/2;
190 int top = centery - halfh;
191 int bottom = centery + halfh;
192 hitTop = miny + ((top*maxy-miny)/dh);
193 hitBottom = miny + ((bottom*maxy-miny)/dh);
194 }
195 }
Michael Chan53071d62009-05-13 17:29:48 -0700196
Iliyan Malchev75b2aed2009-08-06 14:50:57 -0700197 private void readVirtualKeys(String deviceName) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700198 try {
199 FileInputStream fis = new FileInputStream(
Iliyan Malchev75b2aed2009-08-06 14:50:57 -0700200 "/sys/board_properties/virtualkeys." + deviceName);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700201 InputStreamReader isr = new InputStreamReader(fis);
202 BufferedReader br = new BufferedReader(isr);
203 String str = br.readLine();
204 if (str != null) {
205 String[] it = str.split(":");
206 if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "***** VIRTUAL KEYS: " + it);
207 final int N = it.length-6;
208 for (int i=0; i<=N; i+=6) {
209 if (!"0x01".equals(it[i])) {
210 Log.w(TAG, "Unknown virtual key type at elem #" + i
211 + ": " + it[i]);
212 continue;
213 }
214 try {
215 VirtualKey sb = new VirtualKey();
216 sb.scancode = Integer.parseInt(it[i+1]);
217 sb.centerx = Integer.parseInt(it[i+2]);
218 sb.centery = Integer.parseInt(it[i+3]);
219 sb.width = Integer.parseInt(it[i+4]);
220 sb.height = Integer.parseInt(it[i+5]);
221 if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Virtual key "
222 + sb.scancode + ": center=" + sb.centerx + ","
223 + sb.centery + " size=" + sb.width + "x"
224 + sb.height);
225 mVirtualKeys.add(sb);
226 } catch (NumberFormatException e) {
227 Log.w(TAG, "Bad number at region " + i + " in: "
228 + str, e);
229 }
230 }
231 }
232 br.close();
233 } catch (FileNotFoundException e) {
234 Log.i(TAG, "No virtual keys found");
235 } catch (IOException e) {
236 Log.w(TAG, "Error reading virtual keys", e);
237 }
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400238 }
239
240 private void readExcludedDevices() {
241 // Read partner-provided list of excluded input devices
242 XmlPullParser parser = null;
243 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
244 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
245 FileReader confreader = null;
246 try {
247 confreader = new FileReader(confFile);
248 parser = Xml.newPullParser();
249 parser.setInput(confreader);
250 XmlUtils.beginDocument(parser, "devices");
251
252 while (true) {
253 XmlUtils.nextElement(parser);
254 if (!"device".equals(parser.getName())) {
255 break;
256 }
257 String name = parser.getAttributeValue(null, "name");
258 if (name != null) {
259 Log.d(TAG, "addExcludedDevice " + name);
260 addExcludedDevice(name);
261 }
262 }
263 } catch (FileNotFoundException e) {
264 // It's ok if the file does not exist.
265 } catch (Exception e) {
266 Log.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
267 } finally {
268 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
269 }
270 }
271
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700272 KeyInputQueue(Context context, HapticFeedbackCallback hapticFeedbackCallback) {
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400273 if (MEASURE_LATENCY) {
274 lt = new LatencyTimer(100, 1000);
275 }
276
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700277 mHapticFeedbackCallback = hapticFeedbackCallback;
278
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400279 readExcludedDevices();
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 PowerManager pm = (PowerManager)context.getSystemService(
282 Context.POWER_SERVICE);
283 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
284 "KeyInputQueue");
285 mWakeLock.setReferenceCounted(false);
286
287 mFirst = new QueuedEvent();
288 mLast = new QueuedEvent();
289 mFirst.next = mLast;
290 mLast.prev = mFirst;
291
292 mThread.start();
293 }
294
295 public void setDisplay(Display display) {
296 mDisplay = display;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700297
298 // We assume at this point that the display dimensions reflect the
299 // natural, unrotated display. We will perform hit tests for soft
300 // buttons based on that display.
301 mDisplayWidth = display.getWidth();
302 mDisplayHeight = display.getHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 }
304
305 public void getInputConfiguration(Configuration config) {
306 synchronized (mFirst) {
307 config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
308 config.keyboard = Configuration.KEYBOARD_NOKEYS;
309 config.navigation = Configuration.NAVIGATION_NONAV;
310
311 final int N = mDevices.size();
312 for (int i=0; i<N; i++) {
313 InputDevice d = mDevices.valueAt(i);
314 if (d != null) {
315 if ((d.classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
316 config.touchscreen
317 = Configuration.TOUCHSCREEN_FINGER;
318 //Log.i("foo", "***** HAVE TOUCHSCREEN!");
319 }
320 if ((d.classes&RawInputEvent.CLASS_ALPHAKEY) != 0) {
321 config.keyboard
322 = Configuration.KEYBOARD_QWERTY;
323 //Log.i("foo", "***** HAVE QWERTY!");
324 }
325 if ((d.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
326 config.navigation
327 = Configuration.NAVIGATION_TRACKBALL;
328 //Log.i("foo", "***** HAVE TRACKBALL!");
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700329 } else if ((d.classes&RawInputEvent.CLASS_DPAD) != 0) {
330 config.navigation
331 = Configuration.NAVIGATION_DPAD;
332 //Log.i("foo", "***** HAVE DPAD!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 }
334 }
335 }
336 }
337 }
338
339 public static native String getDeviceName(int deviceId);
340 public static native int getDeviceClasses(int deviceId);
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400341 public static native void addExcludedDevice(String deviceName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 public static native boolean getAbsoluteInfo(int deviceId, int axis,
343 InputDevice.AbsoluteInfo outInfo);
344 public static native int getSwitchState(int sw);
345 public static native int getSwitchState(int deviceId, int sw);
346 public static native int getScancodeState(int sw);
347 public static native int getScancodeState(int deviceId, int sw);
348 public static native int getKeycodeState(int sw);
349 public static native int getKeycodeState(int deviceId, int sw);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700350 public static native int scancodeToKeycode(int deviceId, int scancode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
352
353 public static KeyEvent newKeyEvent(InputDevice device, long downTime,
354 long eventTime, boolean down, int keycode, int repeatCount,
355 int scancode, int flags) {
356 return new KeyEvent(
357 downTime, eventTime,
358 down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
359 keycode, repeatCount,
360 device != null ? device.mMetaKeysState : 0,
361 device != null ? device.id : -1, scancode,
The Android Open Source Project10592532009-03-18 17:39:46 -0700362 flags | KeyEvent.FLAG_FROM_SYSTEM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 }
364
365 Thread mThread = new Thread("InputDeviceReader") {
366 public void run() {
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400367 Log.d(TAG, "InputDeviceReader.run()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 android.os.Process.setThreadPriority(
369 android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
370
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700371 RawInputEvent ev = new RawInputEvent();
372 while (true) {
373 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 InputDevice di;
375
376 // block, doesn't release the monitor
377 readEvent(ev);
378
379 boolean send = false;
380 boolean configChanged = false;
381
382 if (false) {
383 Log.i(TAG, "Input event: dev=0x"
384 + Integer.toHexString(ev.deviceId)
385 + " type=0x" + Integer.toHexString(ev.type)
386 + " scancode=" + ev.scancode
387 + " keycode=" + ev.keycode
388 + " value=" + ev.value);
389 }
390
391 if (ev.type == RawInputEvent.EV_DEVICE_ADDED) {
392 synchronized (mFirst) {
393 di = newInputDevice(ev.deviceId);
394 mDevices.put(ev.deviceId, di);
Iliyan Malchev75b2aed2009-08-06 14:50:57 -0700395 if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
396 readVirtualKeys(di.name);
397 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 configChanged = true;
399 }
400 } else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
401 synchronized (mFirst) {
402 Log.i(TAG, "Device removed: id=0x"
403 + Integer.toHexString(ev.deviceId));
404 di = mDevices.get(ev.deviceId);
405 if (di != null) {
406 mDevices.delete(ev.deviceId);
407 configChanged = true;
408 } else {
409 Log.w(TAG, "Bad device id: " + ev.deviceId);
410 }
411 }
412 } else {
413 di = getInputDevice(ev.deviceId);
414
415 // first crack at it
416 send = preprocessEvent(di, ev);
417
418 if (ev.type == RawInputEvent.EV_KEY) {
419 di.mMetaKeysState = makeMetaState(ev.keycode,
420 ev.value != 0, di.mMetaKeysState);
421 mHaveGlobalMetaState = false;
422 }
423 }
424
425 if (di == null) {
426 continue;
427 }
428
429 if (configChanged) {
430 synchronized (mFirst) {
Michael Chan53071d62009-05-13 17:29:48 -0700431 addLocked(di, System.nanoTime(), 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 RawInputEvent.CLASS_CONFIGURATION_CHANGED,
433 null);
434 }
435 }
436
437 if (!send) {
438 continue;
439 }
440
441 synchronized (mFirst) {
442 // NOTE: The event timebase absolutely must be the same
443 // timebase as SystemClock.uptimeMillis().
444 //curTime = gotOne ? ev.when : SystemClock.uptimeMillis();
445 final long curTime = SystemClock.uptimeMillis();
Michael Chan53071d62009-05-13 17:29:48 -0700446 final long curTimeNano = System.nanoTime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 //Log.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
448
449 final int classes = di.classes;
450 final int type = ev.type;
451 final int scancode = ev.scancode;
452 send = false;
453
454 // Is it a key event?
455 if (type == RawInputEvent.EV_KEY &&
456 (classes&RawInputEvent.CLASS_KEYBOARD) != 0 &&
457 (scancode < RawInputEvent.BTN_FIRST ||
458 scancode > RawInputEvent.BTN_LAST)) {
459 boolean down;
460 if (ev.value != 0) {
461 down = true;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700462 di.mKeyDownTime = curTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 } else {
464 down = false;
465 }
466 int keycode = rotateKeyCodeLocked(ev.keycode);
Michael Chan53071d62009-05-13 17:29:48 -0700467 addLocked(di, curTimeNano, ev.flags,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 RawInputEvent.CLASS_KEYBOARD,
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700469 newKeyEvent(di, di.mKeyDownTime, curTime, down,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 keycode, 0, scancode,
471 ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
472 ? KeyEvent.FLAG_WOKE_HERE : 0));
473 } else if (ev.type == RawInputEvent.EV_KEY) {
474 if (ev.scancode == RawInputEvent.BTN_TOUCH &&
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700475 (classes&(RawInputEvent.CLASS_TOUCHSCREEN
476 |RawInputEvent.CLASS_TOUCHSCREEN_MT))
477 == RawInputEvent.CLASS_TOUCHSCREEN) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 di.mAbs.changed = true;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700479 di.mAbs.mDown[0] = ev.value != 0;
480 } else if (ev.scancode == RawInputEvent.BTN_2 &&
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700481 (classes&(RawInputEvent.CLASS_TOUCHSCREEN
482 |RawInputEvent.CLASS_TOUCHSCREEN_MT))
483 == RawInputEvent.CLASS_TOUCHSCREEN) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700484 di.mAbs.changed = true;
485 di.mAbs.mDown[1] = ev.value != 0;
486 } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
488 di.mRel.changed = true;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700489 di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 send = true;
491 }
492
493 } else if (ev.type == RawInputEvent.EV_ABS &&
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700494 (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
495 if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {
496 di.mAbs.changed = true;
497 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
498 + MotionEvent.SAMPLE_PRESSURE] = ev.value;
499 } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) {
500 di.mAbs.changed = true;
501 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
502 + MotionEvent.SAMPLE_X] = ev.value;
503 if (DEBUG_POINTERS) Log.v(TAG, "MT @"
504 + di.mAbs.mAddingPointerOffset
505 + " X:" + ev.value);
506 } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) {
507 di.mAbs.changed = true;
508 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
509 + MotionEvent.SAMPLE_Y] = ev.value;
510 if (DEBUG_POINTERS) Log.v(TAG, "MT @"
511 + di.mAbs.mAddingPointerOffset
512 + " Y:" + ev.value);
513 } else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) {
514 di.mAbs.changed = true;
515 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
516 + MotionEvent.SAMPLE_SIZE] = ev.value;
517 }
518
519 } else if (ev.type == RawInputEvent.EV_ABS &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700521 // Finger 1
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 if (ev.scancode == RawInputEvent.ABS_X) {
523 di.mAbs.changed = true;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700524 di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 } else if (ev.scancode == RawInputEvent.ABS_Y) {
526 di.mAbs.changed = true;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700527 di.curTouchVals[MotionEvent.SAMPLE_Y] = ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) {
529 di.mAbs.changed = true;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700530 di.curTouchVals[MotionEvent.SAMPLE_PRESSURE] = ev.value;
531 di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700532 + MotionEvent.SAMPLE_PRESSURE] = ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) {
534 di.mAbs.changed = true;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700535 di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;
536 di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700537 + MotionEvent.SAMPLE_SIZE] = ev.value;
538
539 // Finger 2
540 } else if (ev.scancode == RawInputEvent.ABS_HAT0X) {
541 di.mAbs.changed = true;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700542 di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700543 + MotionEvent.SAMPLE_X] = ev.value;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700544 } else if (ev.scancode == RawInputEvent.ABS_HAT0Y) {
545 di.mAbs.changed = true;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700546 di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700547 + MotionEvent.SAMPLE_Y] = ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 }
549
550 } else if (ev.type == RawInputEvent.EV_REL &&
551 (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
552 // Add this relative movement into our totals.
553 if (ev.scancode == RawInputEvent.REL_X) {
554 di.mRel.changed = true;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700555 di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 } else if (ev.scancode == RawInputEvent.REL_Y) {
557 di.mRel.changed = true;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700558 di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 }
560 }
561
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700562 if (ev.type == RawInputEvent.EV_SYN
563 && ev.scancode == RawInputEvent.SYN_MT_REPORT
564 && di.mAbs != null) {
565 di.mAbs.changed = true;
566 if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) {
567 // If the value is <= 0, the pointer is not
568 // down, so keep it in the count.
569
570 if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
571 + MotionEvent.SAMPLE_PRESSURE] != 0) {
572 final int num = di.mAbs.mNextNumPointers+1;
573 di.mAbs.mNextNumPointers = num;
574 if (DEBUG_POINTERS) Log.v(TAG,
575 "MT_REPORT: now have " + num + " pointers");
576 final int newOffset = (num <= InputDevice.MAX_POINTERS)
577 ? (num * MotionEvent.NUM_SAMPLE_DATA)
578 : (InputDevice.MAX_POINTERS *
579 MotionEvent.NUM_SAMPLE_DATA);
580 di.mAbs.mAddingPointerOffset = newOffset;
581 di.mAbs.mNextData[newOffset
582 + MotionEvent.SAMPLE_PRESSURE] = 0;
583 } else {
584 if (DEBUG_POINTERS) Log.v(TAG, "MT_REPORT: no pointer");
585 }
586 }
587 } else if (send || (ev.type == RawInputEvent.EV_SYN
588 && ev.scancode == RawInputEvent.SYN_REPORT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 if (mDisplay != null) {
590 if (!mHaveGlobalMetaState) {
591 computeGlobalMetaStateLocked();
592 }
593
594 MotionEvent me;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700595
596 InputDevice.MotionState ms = di.mAbs;
597 if (ms.changed) {
598 ms.changed = false;
599
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700600 if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN
601 |RawInputEvent.CLASS_TOUCHSCREEN_MT))
602 == RawInputEvent.CLASS_TOUCHSCREEN) {
603 ms.mNextNumPointers = 0;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700604 if (ms.mDown[0]) {
605 System.arraycopy(di.curTouchVals, 0,
606 ms.mNextData, 0,
607 MotionEvent.NUM_SAMPLE_DATA);
608 ms.mNextNumPointers++;
609 }
610 if (ms.mDown[1]) {
611 System.arraycopy(di.curTouchVals,
612 MotionEvent.NUM_SAMPLE_DATA,
613 ms.mNextData,
614 ms.mNextNumPointers
615 * MotionEvent.NUM_SAMPLE_DATA,
616 MotionEvent.NUM_SAMPLE_DATA);
617 ms.mNextNumPointers++;
618 }
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700619 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700620
621 boolean doMotion = !monitorVirtualKey(di,
622 ev, curTime, curTimeNano);
623
624 if (doMotion && ms.mNextNumPointers > 0
625 && ms.mLastNumPointers == 0) {
626 doMotion = !generateVirtualKeyDown(di,
627 ev, curTime, curTimeNano);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700629
630 if (doMotion) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700631 // XXX Need to be able to generate
632 // multiple events here, for example
633 // if two fingers change up/down state
634 // at the same time.
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700635 do {
636 me = ms.generateAbsMotion(di, curTime,
637 curTimeNano, mDisplay,
638 mOrientation, mGlobalMetaState);
639 if (false) Log.v(TAG, "Absolute: x="
640 + di.mAbs.mNextData[MotionEvent.SAMPLE_X]
641 + " y="
642 + di.mAbs.mNextData[MotionEvent.SAMPLE_Y]
643 + " ev=" + me);
644 if (me != null) {
645 if (WindowManagerPolicy.WATCH_POINTER) {
646 Log.i(TAG, "Enqueueing: " + me);
647 }
648 addLocked(di, curTimeNano, ev.flags,
649 RawInputEvent.CLASS_TOUCHSCREEN, me);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700650 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700651 } while (ms.hasMore());
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700652 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700653
654 ms.finish();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700656
657 ms = di.mRel;
658 if (ms.changed) {
659 ms.changed = false;
660
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700661 me = ms.generateRelMotion(di, curTime,
662 curTimeNano,
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700663 mOrientation, mGlobalMetaState);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700664 if (false) Log.v(TAG, "Relative: x="
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700665 + di.mRel.mNextData[MotionEvent.SAMPLE_X]
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700666 + " y="
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700667 + di.mRel.mNextData[MotionEvent.SAMPLE_Y]
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700668 + " ev=" + me);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700669 if (me != null) {
670 addLocked(di, curTimeNano, ev.flags,
671 RawInputEvent.CLASS_TRACKBALL, me);
672 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700673
674 ms.finish();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 }
676 }
677 }
678 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700679
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700680 } catch (RuntimeException exc) {
681 Log.e(TAG, "InputReaderThread uncaught exception", exc);
682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 }
684 }
685 };
686
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700687 private boolean isInsideDisplay(InputDevice dev) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700688 final InputDevice.AbsoluteInfo absx = dev.absX;
689 final InputDevice.AbsoluteInfo absy = dev.absY;
690 final InputDevice.MotionState absm = dev.mAbs;
691 if (absx == null || absy == null || absm == null) {
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700692 return true;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700693 }
694
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700695 if (absm.mNextData[MotionEvent.SAMPLE_X] >= absx.minValue
696 && absm.mNextData[MotionEvent.SAMPLE_X] <= absx.maxValue
697 && absm.mNextData[MotionEvent.SAMPLE_Y] >= absy.minValue
698 && absm.mNextData[MotionEvent.SAMPLE_Y] <= absy.maxValue) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700699 if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input ("
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700700 + absm.mNextData[MotionEvent.SAMPLE_X]
701 + "," + absm.mNextData[MotionEvent.SAMPLE_Y]
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700702 + ") inside of display");
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700703 return true;
704 }
705
706 return false;
707 }
708
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700709 private VirtualKey findVirtualKey(InputDevice dev) {
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700710 final int N = mVirtualKeys.size();
711 if (N <= 0) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700712 return null;
713 }
714
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700715 final InputDevice.MotionState absm = dev.mAbs;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700716 for (int i=0; i<N; i++) {
717 VirtualKey sb = mVirtualKeys.get(i);
718 sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700719 if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit test ("
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700720 + absm.mNextData[MotionEvent.SAMPLE_X] + ","
721 + absm.mNextData[MotionEvent.SAMPLE_Y] + ") in code "
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700722 + sb.scancode + " - (" + sb.hitLeft
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700723 + "," + sb.hitTop + ")-(" + sb.hitRight + ","
724 + sb.hitBottom + ")");
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700725 if (sb.checkHit(absm.mNextData[MotionEvent.SAMPLE_X],
726 absm.mNextData[MotionEvent.SAMPLE_Y])) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700727 if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit!");
728 return sb;
729 }
730 }
731
732 return null;
733 }
734
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700735 private boolean generateVirtualKeyDown(InputDevice di, RawInputEvent ev,
736 long curTime, long curTimeNano) {
737 if (isInsideDisplay(di)) {
738 // Didn't consume event.
739 return false;
740 }
741
742
743 VirtualKey vk = findVirtualKey(di);
744 if (vk != null) {
745 final InputDevice.MotionState ms = di.mAbs;
746 mPressedVirtualKey = vk;
747 vk.lastKeycode = scancodeToKeycode(di.id, vk.scancode);
748 ms.mLastNumPointers = ms.mNextNumPointers;
749 di.mKeyDownTime = curTime;
750 if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
751 "Generate key down for: " + vk.scancode
752 + " (keycode=" + vk.lastKeycode + ")");
753 KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true,
754 vk.lastKeycode, 0, vk.scancode,
755 KeyEvent.FLAG_VIRTUAL_HARD_KEY);
756 mHapticFeedbackCallback.virtualKeyFeedback(event);
757 addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
758 event);
759 }
760
761 // We always consume the event, even if we didn't
762 // generate a key event. There are two reasons for
763 // this: to avoid spurious touches when holding
764 // the edges of the device near the touchscreen,
765 // and to avoid reporting events if there are virtual
766 // keys on the touchscreen outside of the display
767 // area.
768 // Note that for all of this we are only looking at the
769 // first pointer, since what we are handling here is the
770 // first pointer going down, and this is the coordinate
771 // that will be used to dispatch the event.
772 if (false) {
773 final InputDevice.AbsoluteInfo absx = di.absX;
774 final InputDevice.AbsoluteInfo absy = di.absY;
775 final InputDevice.MotionState absm = di.mAbs;
776 Log.v(TAG, "Rejecting ("
777 + absm.mNextData[MotionEvent.SAMPLE_X] + ","
778 + absm.mNextData[MotionEvent.SAMPLE_Y] + "): outside of ("
779 + absx.minValue + "," + absy.minValue
780 + ")-(" + absx.maxValue + ","
781 + absx.maxValue + ")");
782 }
783 return true;
784 }
785
786 private boolean monitorVirtualKey(InputDevice di, RawInputEvent ev,
787 long curTime, long curTimeNano) {
788 VirtualKey vk = mPressedVirtualKey;
789 if (vk == null) {
790 return false;
791 }
792
793 final InputDevice.MotionState ms = di.mAbs;
794 if (ms.mNextNumPointers <= 0) {
795 mPressedVirtualKey = null;
796 ms.mLastNumPointers = 0;
797 if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Generate key up for: " + vk.scancode);
798 KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
799 vk.lastKeycode, 0, vk.scancode,
800 KeyEvent.FLAG_VIRTUAL_HARD_KEY);
801 mHapticFeedbackCallback.virtualKeyFeedback(event);
802 addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
803 event);
804 return true;
805
806 } else if (isInsideDisplay(di)) {
807 // Whoops the pointer has moved into
808 // the display area! Cancel the
809 // virtual key and start a pointer
810 // motion.
811 mPressedVirtualKey = null;
812 if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Cancel key up for: " + vk.scancode);
813 KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
814 vk.lastKeycode, 0, vk.scancode,
815 KeyEvent.FLAG_CANCELED | KeyEvent.FLAG_VIRTUAL_HARD_KEY);
816 mHapticFeedbackCallback.virtualKeyFeedback(event);
817 addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
818 event);
819 ms.mLastNumPointers = 0;
820 return false;
821 }
822
823 return true;
824 }
825
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 /**
827 * Returns a new meta state for the given keys and old state.
828 */
829 private static final int makeMetaState(int keycode, boolean down, int old) {
830 int mask;
831 switch (keycode) {
832 case KeyEvent.KEYCODE_ALT_LEFT:
833 mask = KeyEvent.META_ALT_LEFT_ON;
834 break;
835 case KeyEvent.KEYCODE_ALT_RIGHT:
836 mask = KeyEvent.META_ALT_RIGHT_ON;
837 break;
838 case KeyEvent.KEYCODE_SHIFT_LEFT:
839 mask = KeyEvent.META_SHIFT_LEFT_ON;
840 break;
841 case KeyEvent.KEYCODE_SHIFT_RIGHT:
842 mask = KeyEvent.META_SHIFT_RIGHT_ON;
843 break;
844 case KeyEvent.KEYCODE_SYM:
845 mask = KeyEvent.META_SYM_ON;
846 break;
847 default:
848 return old;
849 }
850 int result = ~(KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON)
851 & (down ? (old | mask) : (old & ~mask));
852 if (0 != (result & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON))) {
853 result |= KeyEvent.META_ALT_ON;
854 }
855 if (0 != (result & (KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON))) {
856 result |= KeyEvent.META_SHIFT_ON;
857 }
858 return result;
859 }
860
861 private void computeGlobalMetaStateLocked() {
862 int i = mDevices.size();
863 mGlobalMetaState = 0;
864 while ((--i) >= 0) {
865 mGlobalMetaState |= mDevices.valueAt(i).mMetaKeysState;
866 }
867 mHaveGlobalMetaState = true;
868 }
869
870 /*
871 * Return true if you want the event to get passed on to the
872 * rest of the system, and false if you've handled it and want
873 * it dropped.
874 */
875 abstract boolean preprocessEvent(InputDevice device, RawInputEvent event);
876
877 InputDevice getInputDevice(int deviceId) {
878 synchronized (mFirst) {
879 return getInputDeviceLocked(deviceId);
880 }
881 }
882
883 private InputDevice getInputDeviceLocked(int deviceId) {
884 return mDevices.get(deviceId);
885 }
886
887 public void setOrientation(int orientation) {
888 synchronized(mFirst) {
889 mOrientation = orientation;
890 switch (orientation) {
891 case Surface.ROTATION_90:
892 mKeyRotationMap = KEY_90_MAP;
893 break;
894 case Surface.ROTATION_180:
895 mKeyRotationMap = KEY_180_MAP;
896 break;
897 case Surface.ROTATION_270:
898 mKeyRotationMap = KEY_270_MAP;
899 break;
900 default:
901 mKeyRotationMap = null;
902 break;
903 }
904 }
905 }
906
907 public int rotateKeyCode(int keyCode) {
908 synchronized(mFirst) {
909 return rotateKeyCodeLocked(keyCode);
910 }
911 }
912
913 private int rotateKeyCodeLocked(int keyCode) {
914 int[] map = mKeyRotationMap;
915 if (map != null) {
916 final int N = map.length;
917 for (int i=0; i<N; i+=2) {
918 if (map[i] == keyCode) {
919 return map[i+1];
920 }
921 }
922 }
923 return keyCode;
924 }
925
926 boolean hasEvents() {
927 synchronized (mFirst) {
928 return mFirst.next != mLast;
929 }
930 }
931
932 /*
933 * returns true if we returned an event, and false if we timed out
934 */
935 QueuedEvent getEvent(long timeoutMS) {
936 long begin = SystemClock.uptimeMillis();
937 final long end = begin+timeoutMS;
938 long now = begin;
939 synchronized (mFirst) {
940 while (mFirst.next == mLast && end > now) {
941 try {
942 mWakeLock.release();
943 mFirst.wait(end-now);
944 }
945 catch (InterruptedException e) {
946 }
947 now = SystemClock.uptimeMillis();
948 if (begin > now) {
949 begin = now;
950 }
951 }
952 if (mFirst.next == mLast) {
953 return null;
954 }
955 QueuedEvent p = mFirst.next;
956 mFirst.next = p.next;
957 mFirst.next.prev = mFirst;
958 p.inQueue = false;
959 return p;
960 }
961 }
962
963 void recycleEvent(QueuedEvent ev) {
964 synchronized (mFirst) {
965 //Log.i(TAG, "Recycle event: " + ev);
966 if (ev.event == ev.inputDevice.mAbs.currentMove) {
967 ev.inputDevice.mAbs.currentMove = null;
968 }
969 if (ev.event == ev.inputDevice.mRel.currentMove) {
970 if (false) Log.i(TAG, "Detach rel " + ev.event);
971 ev.inputDevice.mRel.currentMove = null;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700972 ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_X] = 0;
973 ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_Y] = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 }
975 recycleLocked(ev);
976 }
977 }
978
979 void filterQueue(FilterCallback cb) {
980 synchronized (mFirst) {
981 QueuedEvent cur = mLast.prev;
982 while (cur.prev != null) {
983 switch (cb.filterEvent(cur)) {
984 case FILTER_REMOVE:
985 cur.prev.next = cur.next;
986 cur.next.prev = cur.prev;
987 break;
988 case FILTER_ABORT:
989 return;
990 }
991 cur = cur.prev;
992 }
993 }
994 }
995
Michael Chan53071d62009-05-13 17:29:48 -0700996 private QueuedEvent obtainLocked(InputDevice device, long whenNano,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 int flags, int classType, Object event) {
998 QueuedEvent ev;
999 if (mCacheCount == 0) {
1000 ev = new QueuedEvent();
1001 } else {
1002 ev = mCache;
1003 ev.inQueue = false;
1004 mCache = ev.next;
1005 mCacheCount--;
1006 }
1007 ev.inputDevice = device;
Michael Chan53071d62009-05-13 17:29:48 -07001008 ev.whenNano = whenNano;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 ev.flags = flags;
1010 ev.classType = classType;
1011 ev.event = event;
1012 return ev;
1013 }
1014
1015 private void recycleLocked(QueuedEvent ev) {
1016 if (ev.inQueue) {
1017 throw new RuntimeException("Event already in queue!");
1018 }
1019 if (mCacheCount < 10) {
1020 mCacheCount++;
1021 ev.next = mCache;
1022 mCache = ev;
1023 ev.inQueue = true;
1024 }
1025 }
1026
Michael Chan53071d62009-05-13 17:29:48 -07001027 private void addLocked(InputDevice device, long whenNano, int flags,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 int classType, Object event) {
1029 boolean poke = mFirst.next == mLast;
1030
Michael Chan53071d62009-05-13 17:29:48 -07001031 QueuedEvent ev = obtainLocked(device, whenNano, flags, classType, event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 QueuedEvent p = mLast.prev;
Michael Chan53071d62009-05-13 17:29:48 -07001033 while (p != mFirst && ev.whenNano < p.whenNano) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 p = p.prev;
1035 }
1036
1037 ev.next = p.next;
1038 ev.prev = p;
1039 p.next = ev;
1040 ev.next.prev = ev;
1041 ev.inQueue = true;
1042
1043 if (poke) {
Michael Chan53071d62009-05-13 17:29:48 -07001044 long time;
1045 if (MEASURE_LATENCY) {
1046 time = System.nanoTime();
1047 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 mFirst.notify();
1049 mWakeLock.acquire();
Michael Chan53071d62009-05-13 17:29:48 -07001050 if (MEASURE_LATENCY) {
1051 lt.sample("1 addLocked-queued event ", System.nanoTime() - time);
1052 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 }
1054 }
1055
1056 private InputDevice newInputDevice(int deviceId) {
1057 int classes = getDeviceClasses(deviceId);
1058 String name = getDeviceName(deviceId);
1059 Log.i(TAG, "Device added: id=0x" + Integer.toHexString(deviceId)
1060 + ", name=" + name
1061 + ", classes=" + Integer.toHexString(classes));
1062 InputDevice.AbsoluteInfo absX;
1063 InputDevice.AbsoluteInfo absY;
1064 InputDevice.AbsoluteInfo absPressure;
1065 InputDevice.AbsoluteInfo absSize;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -07001066 if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
1067 absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_X, "X");
1068 absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_Y, "Y");
1069 absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure");
1070 absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size");
1071 } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_X, "X");
1073 absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_Y, "Y");
1074 absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_PRESSURE, "Pressure");
1075 absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_TOOL_WIDTH, "Size");
1076 } else {
1077 absX = null;
1078 absY = null;
1079 absPressure = null;
1080 absSize = null;
1081 }
1082
1083 return new InputDevice(deviceId, classes, name, absX, absY, absPressure, absSize);
1084 }
1085
1086 private InputDevice.AbsoluteInfo loadAbsoluteInfo(int id, int channel,
1087 String name) {
1088 InputDevice.AbsoluteInfo info = new InputDevice.AbsoluteInfo();
1089 if (getAbsoluteInfo(id, channel, info)
1090 && info.minValue != info.maxValue) {
1091 Log.i(TAG, " " + name + ": min=" + info.minValue
1092 + " max=" + info.maxValue
1093 + " flat=" + info.flat
1094 + " fuzz=" + info.fuzz);
1095 info.range = info.maxValue-info.minValue;
1096 return info;
1097 }
1098 Log.i(TAG, " " + name + ": unknown values");
1099 return null;
1100 }
1101 private static native boolean readEvent(RawInputEvent outEvent);
1102}