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