InputManagerService.java revision 9631314e3d28b6e96ef0b7cc777f1a7747a0ac39
1/* 2 * Copyright (C) 2010 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.input; 18 19import com.android.internal.R; 20import com.android.internal.util.XmlUtils; 21import com.android.server.Watchdog; 22 23import org.xmlpull.v1.XmlPullParser; 24 25import android.Manifest; 26import android.app.Notification; 27import android.app.NotificationManager; 28import android.app.PendingIntent; 29import android.bluetooth.BluetoothAdapter; 30import android.bluetooth.BluetoothDevice; 31import android.content.BroadcastReceiver; 32import android.content.ComponentName; 33import android.content.Context; 34import android.content.Intent; 35import android.content.IntentFilter; 36import android.content.pm.ActivityInfo; 37import android.content.pm.PackageManager; 38import android.content.pm.ResolveInfo; 39import android.content.pm.PackageManager.NameNotFoundException; 40import android.content.res.Resources; 41import android.content.res.Resources.NotFoundException; 42import android.content.res.TypedArray; 43import android.content.res.XmlResourceParser; 44import android.database.ContentObserver; 45import android.hardware.input.IInputDevicesChangedListener; 46import android.hardware.input.IInputManager; 47import android.hardware.input.InputManager; 48import android.hardware.input.KeyboardLayout; 49import android.os.Binder; 50import android.os.Bundle; 51import android.os.Environment; 52import android.os.Handler; 53import android.os.IBinder; 54import android.os.Message; 55import android.os.MessageQueue; 56import android.os.Process; 57import android.os.RemoteException; 58import android.provider.Settings; 59import android.provider.Settings.SettingNotFoundException; 60import android.util.Log; 61import android.util.Slog; 62import android.util.SparseArray; 63import android.util.Xml; 64import android.view.IInputFilter; 65import android.view.IInputFilterHost; 66import android.view.InputChannel; 67import android.view.InputDevice; 68import android.view.InputEvent; 69import android.view.KeyEvent; 70import android.view.PointerIcon; 71import android.view.Surface; 72import android.view.ViewConfiguration; 73import android.view.WindowManagerPolicy; 74import android.widget.Toast; 75 76import java.io.File; 77import java.io.FileDescriptor; 78import java.io.FileNotFoundException; 79import java.io.FileReader; 80import java.io.IOException; 81import java.io.InputStreamReader; 82import java.io.PrintWriter; 83import java.util.ArrayList; 84import java.util.HashMap; 85import java.util.HashSet; 86 87import libcore.io.Streams; 88import libcore.util.Objects; 89 90/* 91 * Wraps the C++ InputManager and provides its callbacks. 92 */ 93public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor { 94 static final String TAG = "InputManager"; 95 static final boolean DEBUG = false; 96 97 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; 98 99 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1; 100 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2; 101 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3; 102 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4; 103 private static final int MSG_RELOAD_DEVICE_ALIASES = 5; 104 105 // Pointer to native input manager service object. 106 private final int mPtr; 107 108 private final Context mContext; 109 private final Callbacks mCallbacks; 110 private final InputManagerHandler mHandler; 111 private boolean mSystemReady; 112 private NotificationManager mNotificationManager; 113 114 // Persistent data store. Must be locked each time during use. 115 private final PersistentDataStore mDataStore = new PersistentDataStore(); 116 117 // List of currently registered input devices changed listeners by process id. 118 private Object mInputDevicesLock = new Object(); 119 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock 120 private InputDevice[] mInputDevices = new InputDevice[0]; 121 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners = 122 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock 123 private final ArrayList<InputDevicesChangedListenerRecord> 124 mTempInputDevicesChangedListenersToNotify = 125 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only 126 private final ArrayList<InputDevice> 127 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only 128 private boolean mKeyboardLayoutNotificationShown; 129 private PendingIntent mKeyboardLayoutIntent; 130 private Toast mSwitchedKeyboardLayoutToast; 131 132 // State for vibrator tokens. 133 private Object mVibratorLock = new Object(); 134 private HashMap<IBinder, VibratorToken> mVibratorTokens = 135 new HashMap<IBinder, VibratorToken>(); 136 private int mNextVibratorTokenValue; 137 138 // State for the currently installed input filter. 139 final Object mInputFilterLock = new Object(); 140 IInputFilter mInputFilter; // guarded by mInputFilterLock 141 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock 142 143 private static native int nativeInit(InputManagerService service, 144 Context context, MessageQueue messageQueue); 145 private static native void nativeStart(int ptr); 146 private static native void nativeSetDisplaySize(int ptr, int displayId, 147 int width, int height, int externalWidth, int externalHeight); 148 private static native void nativeSetDisplayOrientation(int ptr, int displayId, 149 int rotation, int externalRotation); 150 151 private static native int nativeGetScanCodeState(int ptr, 152 int deviceId, int sourceMask, int scanCode); 153 private static native int nativeGetKeyCodeState(int ptr, 154 int deviceId, int sourceMask, int keyCode); 155 private static native int nativeGetSwitchState(int ptr, 156 int deviceId, int sourceMask, int sw); 157 private static native boolean nativeHasKeys(int ptr, 158 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists); 159 private static native void nativeRegisterInputChannel(int ptr, InputChannel inputChannel, 160 InputWindowHandle inputWindowHandle, boolean monitor); 161 private static native void nativeUnregisterInputChannel(int ptr, InputChannel inputChannel); 162 private static native void nativeSetInputFilterEnabled(int ptr, boolean enable); 163 private static native int nativeInjectInputEvent(int ptr, InputEvent event, 164 int injectorPid, int injectorUid, int syncMode, int timeoutMillis, 165 int policyFlags); 166 private static native void nativeSetInputWindows(int ptr, InputWindowHandle[] windowHandles); 167 private static native void nativeSetInputDispatchMode(int ptr, boolean enabled, boolean frozen); 168 private static native void nativeSetSystemUiVisibility(int ptr, int visibility); 169 private static native void nativeSetFocusedApplication(int ptr, 170 InputApplicationHandle application); 171 private static native boolean nativeTransferTouchFocus(int ptr, 172 InputChannel fromChannel, InputChannel toChannel); 173 private static native void nativeSetPointerSpeed(int ptr, int speed); 174 private static native void nativeSetShowTouches(int ptr, boolean enabled); 175 private static native void nativeVibrate(int ptr, int deviceId, long[] pattern, 176 int repeat, int token); 177 private static native void nativeCancelVibrate(int ptr, int deviceId, int token); 178 private static native void nativeReloadKeyboardLayouts(int ptr); 179 private static native void nativeReloadDeviceAliases(int ptr); 180 private static native String nativeDump(int ptr); 181 private static native void nativeMonitor(int ptr); 182 183 // Input event injection constants defined in InputDispatcher.h. 184 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0; 185 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1; 186 private static final int INPUT_EVENT_INJECTION_FAILED = 2; 187 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3; 188 189 // Maximum number of milliseconds to wait for input event injection. 190 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000; 191 192 // Key states (may be returned by queries about the current state of a 193 // particular key code, scan code or switch). 194 195 /** The key state is unknown or the requested key itself is not supported. */ 196 public static final int KEY_STATE_UNKNOWN = -1; 197 198 /** The key is up. /*/ 199 public static final int KEY_STATE_UP = 0; 200 201 /** The key is down. */ 202 public static final int KEY_STATE_DOWN = 1; 203 204 /** The key is down but is a virtual key press that is being emulated by the system. */ 205 public static final int KEY_STATE_VIRTUAL = 2; 206 207 /** Scan code: Mouse / trackball button. */ 208 public static final int BTN_MOUSE = 0x110; 209 210 /** Switch code: Lid switch. When set, lid is shut. */ 211 public static final int SW_LID = 0x00; 212 213 /** Switch code: Keypad slide. When set, keyboard is exposed. */ 214 public static final int SW_KEYPAD_SLIDE = 0x0a; 215 216 public InputManagerService(Context context, Callbacks callbacks) { 217 this.mContext = context; 218 this.mCallbacks = callbacks; 219 this.mHandler = new InputManagerHandler(); 220 221 Slog.i(TAG, "Initializing input manager"); 222 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); 223 } 224 225 public void start() { 226 Slog.i(TAG, "Starting input manager"); 227 nativeStart(mPtr); 228 229 // Add ourself to the Watchdog monitors. 230 Watchdog.getInstance().addMonitor(this); 231 232 registerPointerSpeedSettingObserver(); 233 registerShowTouchesSettingObserver(); 234 235 updatePointerSpeedFromSettings(); 236 updateShowTouchesFromSettings(); 237 } 238 239 // TODO(BT) Pass in paramter for bluetooth system 240 public void systemReady() { 241 if (DEBUG) { 242 Slog.d(TAG, "System ready."); 243 } 244 mNotificationManager = (NotificationManager)mContext.getSystemService( 245 Context.NOTIFICATION_SERVICE); 246 mSystemReady = true; 247 248 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); 249 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 250 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 251 filter.addDataScheme("package"); 252 mContext.registerReceiver(new BroadcastReceiver() { 253 @Override 254 public void onReceive(Context context, Intent intent) { 255 updateKeyboardLayouts(); 256 } 257 }, filter, null, mHandler); 258 259 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED); 260 mContext.registerReceiver(new BroadcastReceiver() { 261 @Override 262 public void onReceive(Context context, Intent intent) { 263 reloadDeviceAliases(); 264 } 265 }, filter, null, mHandler); 266 267 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES); 268 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS); 269 } 270 271 private void reloadKeyboardLayouts() { 272 if (DEBUG) { 273 Slog.d(TAG, "Reloading keyboard layouts."); 274 } 275 nativeReloadKeyboardLayouts(mPtr); 276 } 277 278 private void reloadDeviceAliases() { 279 if (DEBUG) { 280 Slog.d(TAG, "Reloading device names."); 281 } 282 nativeReloadDeviceAliases(mPtr); 283 } 284 285 public void setDisplaySize(int displayId, int width, int height, 286 int externalWidth, int externalHeight) { 287 if (width <= 0 || height <= 0 || externalWidth <= 0 || externalHeight <= 0) { 288 throw new IllegalArgumentException("Invalid display id or dimensions."); 289 } 290 291 if (DEBUG) { 292 Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height 293 + " external size " + externalWidth + "x" + externalHeight); 294 } 295 nativeSetDisplaySize(mPtr, displayId, width, height, externalWidth, externalHeight); 296 } 297 298 public void setDisplayOrientation(int displayId, int rotation, int externalRotation) { 299 if (rotation < Surface.ROTATION_0 || rotation > Surface.ROTATION_270) { 300 throw new IllegalArgumentException("Invalid rotation."); 301 } 302 303 if (DEBUG) { 304 Slog.d(TAG, "Setting display #" + displayId + " orientation to rotation " + rotation 305 + " external rotation " + externalRotation); 306 } 307 nativeSetDisplayOrientation(mPtr, displayId, rotation, externalRotation); 308 } 309 310 /** 311 * Gets the current state of a key or button by key code. 312 * @param deviceId The input device id, or -1 to consult all devices. 313 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 314 * consider all input sources. An input device is consulted if at least one of its 315 * non-class input source bits matches the specified source mask. 316 * @param keyCode The key code to check. 317 * @return The key state. 318 */ 319 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) { 320 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode); 321 } 322 323 /** 324 * Gets the current state of a key or button by scan code. 325 * @param deviceId The input device id, or -1 to consult all devices. 326 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 327 * consider all input sources. An input device is consulted if at least one of its 328 * non-class input source bits matches the specified source mask. 329 * @param scanCode The scan code to check. 330 * @return The key state. 331 */ 332 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) { 333 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode); 334 } 335 336 /** 337 * Gets the current state of a switch by switch code. 338 * @param deviceId The input device id, or -1 to consult all devices. 339 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 340 * consider all input sources. An input device is consulted if at least one of its 341 * non-class input source bits matches the specified source mask. 342 * @param switchCode The switch code to check. 343 * @return The switch state. 344 */ 345 public int getSwitchState(int deviceId, int sourceMask, int switchCode) { 346 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode); 347 } 348 349 /** 350 * Determines whether the specified key codes are supported by a particular device. 351 * @param deviceId The input device id, or -1 to consult all devices. 352 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 353 * consider all input sources. An input device is consulted if at least one of its 354 * non-class input source bits matches the specified source mask. 355 * @param keyCodes The array of key codes to check. 356 * @param keyExists An array at least as large as keyCodes whose entries will be set 357 * to true or false based on the presence or absence of support for the corresponding 358 * key codes. 359 * @return True if the lookup was successful, false otherwise. 360 */ 361 @Override // Binder call 362 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) { 363 if (keyCodes == null) { 364 throw new IllegalArgumentException("keyCodes must not be null."); 365 } 366 if (keyExists == null || keyExists.length < keyCodes.length) { 367 throw new IllegalArgumentException("keyExists must not be null and must be at " 368 + "least as large as keyCodes."); 369 } 370 371 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists); 372 } 373 374 /** 375 * Creates an input channel that will receive all input from the input dispatcher. 376 * @param inputChannelName The input channel name. 377 * @return The input channel. 378 */ 379 public InputChannel monitorInput(String inputChannelName) { 380 if (inputChannelName == null) { 381 throw new IllegalArgumentException("inputChannelName must not be null."); 382 } 383 384 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); 385 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true); 386 inputChannels[0].dispose(); // don't need to retain the Java object reference 387 return inputChannels[1]; 388 } 389 390 /** 391 * Registers an input channel so that it can be used as an input event target. 392 * @param inputChannel The input channel to register. 393 * @param inputWindowHandle The handle of the input window associated with the 394 * input channel, or null if none. 395 */ 396 public void registerInputChannel(InputChannel inputChannel, 397 InputWindowHandle inputWindowHandle) { 398 if (inputChannel == null) { 399 throw new IllegalArgumentException("inputChannel must not be null."); 400 } 401 402 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false); 403 } 404 405 /** 406 * Unregisters an input channel. 407 * @param inputChannel The input channel to unregister. 408 */ 409 public void unregisterInputChannel(InputChannel inputChannel) { 410 if (inputChannel == null) { 411 throw new IllegalArgumentException("inputChannel must not be null."); 412 } 413 414 nativeUnregisterInputChannel(mPtr, inputChannel); 415 } 416 417 /** 418 * Sets an input filter that will receive all input events before they are dispatched. 419 * The input filter may then reinterpret input events or inject new ones. 420 * 421 * To ensure consistency, the input dispatcher automatically drops all events 422 * in progress whenever an input filter is installed or uninstalled. After an input 423 * filter is uninstalled, it can no longer send input events unless it is reinstalled. 424 * Any events it attempts to send after it has been uninstalled will be dropped. 425 * 426 * @param filter The input filter, or null to remove the current filter. 427 */ 428 public void setInputFilter(IInputFilter filter) { 429 synchronized (mInputFilterLock) { 430 final IInputFilter oldFilter = mInputFilter; 431 if (oldFilter == filter) { 432 return; // nothing to do 433 } 434 435 if (oldFilter != null) { 436 mInputFilter = null; 437 mInputFilterHost.disconnectLocked(); 438 mInputFilterHost = null; 439 try { 440 oldFilter.uninstall(); 441 } catch (RemoteException re) { 442 /* ignore */ 443 } 444 } 445 446 if (filter != null) { 447 mInputFilter = filter; 448 mInputFilterHost = new InputFilterHost(); 449 try { 450 filter.install(mInputFilterHost); 451 } catch (RemoteException re) { 452 /* ignore */ 453 } 454 } 455 456 nativeSetInputFilterEnabled(mPtr, filter != null); 457 } 458 } 459 460 @Override // Binder call 461 public boolean injectInputEvent(InputEvent event, int mode) { 462 if (event == null) { 463 throw new IllegalArgumentException("event must not be null"); 464 } 465 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC 466 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH 467 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) { 468 throw new IllegalArgumentException("mode is invalid"); 469 } 470 471 final int pid = Binder.getCallingPid(); 472 final int uid = Binder.getCallingUid(); 473 final long ident = Binder.clearCallingIdentity(); 474 final int result; 475 try { 476 result = nativeInjectInputEvent(mPtr, event, pid, uid, mode, 477 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); 478 } finally { 479 Binder.restoreCallingIdentity(ident); 480 } 481 switch (result) { 482 case INPUT_EVENT_INJECTION_PERMISSION_DENIED: 483 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied."); 484 throw new SecurityException( 485 "Injecting to another application requires INJECT_EVENTS permission"); 486 case INPUT_EVENT_INJECTION_SUCCEEDED: 487 return true; 488 case INPUT_EVENT_INJECTION_TIMED_OUT: 489 Slog.w(TAG, "Input event injection from pid " + pid + " timed out."); 490 return false; 491 case INPUT_EVENT_INJECTION_FAILED: 492 default: 493 Slog.w(TAG, "Input event injection from pid " + pid + " failed."); 494 return false; 495 } 496 } 497 498 /** 499 * Gets information about the input device with the specified id. 500 * @param id The device id. 501 * @return The input device or null if not found. 502 */ 503 @Override // Binder call 504 public InputDevice getInputDevice(int deviceId) { 505 synchronized (mInputDevicesLock) { 506 final int count = mInputDevices.length; 507 for (int i = 0; i < count; i++) { 508 final InputDevice inputDevice = mInputDevices[i]; 509 if (inputDevice.getId() == deviceId) { 510 return inputDevice; 511 } 512 } 513 } 514 return null; 515 } 516 517 /** 518 * Gets the ids of all input devices in the system. 519 * @return The input device ids. 520 */ 521 @Override // Binder call 522 public int[] getInputDeviceIds() { 523 synchronized (mInputDevicesLock) { 524 final int count = mInputDevices.length; 525 int[] ids = new int[count]; 526 for (int i = 0; i < count; i++) { 527 ids[i] = mInputDevices[i].getId(); 528 } 529 return ids; 530 } 531 } 532 533 /** 534 * Gets all input devices in the system. 535 * @return The array of input devices. 536 */ 537 public InputDevice[] getInputDevices() { 538 synchronized (mInputDevicesLock) { 539 return mInputDevices; 540 } 541 } 542 543 @Override // Binder call 544 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) { 545 if (listener == null) { 546 throw new IllegalArgumentException("listener must not be null"); 547 } 548 549 synchronized (mInputDevicesLock) { 550 int callingPid = Binder.getCallingPid(); 551 if (mInputDevicesChangedListeners.get(callingPid) != null) { 552 throw new SecurityException("The calling process has already " 553 + "registered an InputDevicesChangedListener."); 554 } 555 556 InputDevicesChangedListenerRecord record = 557 new InputDevicesChangedListenerRecord(callingPid, listener); 558 try { 559 IBinder binder = listener.asBinder(); 560 binder.linkToDeath(record, 0); 561 } catch (RemoteException ex) { 562 // give up 563 throw new RuntimeException(ex); 564 } 565 566 mInputDevicesChangedListeners.put(callingPid, record); 567 } 568 } 569 570 private void onInputDevicesChangedListenerDied(int pid) { 571 synchronized (mInputDevicesLock) { 572 mInputDevicesChangedListeners.remove(pid); 573 } 574 } 575 576 // Must be called on handler. 577 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) { 578 // Scan for changes. 579 int numFullKeyboardsAdded = 0; 580 mTempInputDevicesChangedListenersToNotify.clear(); 581 mTempFullKeyboards.clear(); 582 final int numListeners; 583 final int[] deviceIdAndGeneration; 584 synchronized (mInputDevicesLock) { 585 if (!mInputDevicesChangedPending) { 586 return; 587 } 588 mInputDevicesChangedPending = false; 589 590 numListeners = mInputDevicesChangedListeners.size(); 591 for (int i = 0; i < numListeners; i++) { 592 mTempInputDevicesChangedListenersToNotify.add( 593 mInputDevicesChangedListeners.valueAt(i)); 594 } 595 596 final int numDevices = mInputDevices.length; 597 deviceIdAndGeneration = new int[numDevices * 2]; 598 for (int i = 0; i < numDevices; i++) { 599 final InputDevice inputDevice = mInputDevices[i]; 600 deviceIdAndGeneration[i * 2] = inputDevice.getId(); 601 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration(); 602 603 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) { 604 if (!containsInputDeviceWithDescriptor(oldInputDevices, 605 inputDevice.getDescriptor())) { 606 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice); 607 } else { 608 mTempFullKeyboards.add(inputDevice); 609 } 610 } 611 } 612 } 613 614 // Notify listeners. 615 for (int i = 0; i < numListeners; i++) { 616 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged( 617 deviceIdAndGeneration); 618 } 619 mTempInputDevicesChangedListenersToNotify.clear(); 620 621 // Check for missing keyboard layouts. 622 if (mNotificationManager != null) { 623 final int numFullKeyboards = mTempFullKeyboards.size(); 624 boolean missingLayoutForExternalKeyboard = false; 625 boolean missingLayoutForExternalKeyboardAdded = false; 626 synchronized (mDataStore) { 627 for (int i = 0; i < numFullKeyboards; i++) { 628 final InputDevice inputDevice = mTempFullKeyboards.get(i); 629 if (mDataStore.getCurrentKeyboardLayout(inputDevice.getDescriptor()) == null) { 630 missingLayoutForExternalKeyboard = true; 631 if (i < numFullKeyboardsAdded) { 632 missingLayoutForExternalKeyboardAdded = true; 633 } 634 } 635 } 636 } 637 if (missingLayoutForExternalKeyboard) { 638 if (missingLayoutForExternalKeyboardAdded) { 639 showMissingKeyboardLayoutNotification(); 640 } 641 } else if (mKeyboardLayoutNotificationShown) { 642 hideMissingKeyboardLayoutNotification(); 643 } 644 } 645 mTempFullKeyboards.clear(); 646 } 647 648 // Must be called on handler. 649 private void showMissingKeyboardLayoutNotification() { 650 if (!mKeyboardLayoutNotificationShown) { 651 if (mKeyboardLayoutIntent == null) { 652 final Intent intent = new Intent("android.settings.INPUT_METHOD_SETTINGS"); 653 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 654 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 655 | Intent.FLAG_ACTIVITY_CLEAR_TOP); 656 mKeyboardLayoutIntent = PendingIntent.getActivity(mContext, 0, intent, 0); 657 } 658 659 Resources r = mContext.getResources(); 660 Notification notification = new Notification.Builder(mContext) 661 .setContentTitle(r.getString( 662 R.string.select_keyboard_layout_notification_title)) 663 .setContentText(r.getString( 664 R.string.select_keyboard_layout_notification_message)) 665 .setContentIntent(mKeyboardLayoutIntent) 666 .setSmallIcon(R.drawable.ic_settings_language) 667 .setPriority(Notification.PRIORITY_LOW) 668 .build(); 669 mNotificationManager.notify(R.string.select_keyboard_layout_notification_title, 670 notification); 671 mKeyboardLayoutNotificationShown = true; 672 } 673 } 674 675 // Must be called on handler. 676 private void hideMissingKeyboardLayoutNotification() { 677 if (mKeyboardLayoutNotificationShown) { 678 mKeyboardLayoutNotificationShown = false; 679 mNotificationManager.cancel(R.string.select_keyboard_layout_notification_title); 680 } 681 } 682 683 // Must be called on handler. 684 private void updateKeyboardLayouts() { 685 // Scan all input devices state for keyboard layouts that have been uninstalled. 686 final HashSet<String> availableKeyboardLayouts = new HashSet<String>(); 687 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 688 @Override 689 public void visitKeyboardLayout(Resources resources, 690 String descriptor, String label, String collection, int keyboardLayoutResId) { 691 availableKeyboardLayouts.add(descriptor); 692 } 693 }); 694 synchronized (mDataStore) { 695 try { 696 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts); 697 } finally { 698 mDataStore.saveIfNeeded(); 699 } 700 } 701 702 // Reload keyboard layouts. 703 reloadKeyboardLayouts(); 704 } 705 706 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices, 707 String descriptor) { 708 final int numDevices = inputDevices.length; 709 for (int i = 0; i < numDevices; i++) { 710 final InputDevice inputDevice = inputDevices[i]; 711 if (inputDevice.getDescriptor().equals(descriptor)) { 712 return true; 713 } 714 } 715 return false; 716 } 717 718 @Override // Binder call 719 public KeyboardLayout[] getKeyboardLayouts() { 720 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>(); 721 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 722 @Override 723 public void visitKeyboardLayout(Resources resources, 724 String descriptor, String label, String collection, int keyboardLayoutResId) { 725 list.add(new KeyboardLayout(descriptor, label, collection)); 726 } 727 }); 728 return list.toArray(new KeyboardLayout[list.size()]); 729 } 730 731 @Override // Binder call 732 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) { 733 if (keyboardLayoutDescriptor == null) { 734 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 735 } 736 737 final KeyboardLayout[] result = new KeyboardLayout[1]; 738 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 739 @Override 740 public void visitKeyboardLayout(Resources resources, 741 String descriptor, String label, String collection, int keyboardLayoutResId) { 742 result[0] = new KeyboardLayout(descriptor, label, collection); 743 } 744 }); 745 if (result[0] == null) { 746 Log.w(TAG, "Could not get keyboard layout with descriptor '" 747 + keyboardLayoutDescriptor + "'."); 748 } 749 return result[0]; 750 } 751 752 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) { 753 final PackageManager pm = mContext.getPackageManager(); 754 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS); 755 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent, 756 PackageManager.GET_META_DATA)) { 757 visitKeyboardLayoutsInPackage(pm, resolveInfo.activityInfo, null, visitor); 758 } 759 } 760 761 private void visitKeyboardLayout(String keyboardLayoutDescriptor, 762 KeyboardLayoutVisitor visitor) { 763 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor); 764 if (d != null) { 765 final PackageManager pm = mContext.getPackageManager(); 766 try { 767 ActivityInfo receiver = pm.getReceiverInfo( 768 new ComponentName(d.packageName, d.receiverName), 769 PackageManager.GET_META_DATA); 770 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, visitor); 771 } catch (NameNotFoundException ex) { 772 } 773 } 774 } 775 776 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, 777 String keyboardName, KeyboardLayoutVisitor visitor) { 778 Bundle metaData = receiver.metaData; 779 if (metaData == null) { 780 return; 781 } 782 783 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS); 784 if (configResId == 0) { 785 Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS 786 + "' on receiver " + receiver.packageName + "/" + receiver.name); 787 return; 788 } 789 790 CharSequence receiverLabel = receiver.loadLabel(pm); 791 String collection = receiverLabel != null ? receiverLabel.toString() : ""; 792 793 try { 794 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo); 795 XmlResourceParser parser = resources.getXml(configResId); 796 try { 797 XmlUtils.beginDocument(parser, "keyboard-layouts"); 798 799 for (;;) { 800 XmlUtils.nextElement(parser); 801 String element = parser.getName(); 802 if (element == null) { 803 break; 804 } 805 if (element.equals("keyboard-layout")) { 806 TypedArray a = resources.obtainAttributes( 807 parser, com.android.internal.R.styleable.KeyboardLayout); 808 try { 809 String name = a.getString( 810 com.android.internal.R.styleable.KeyboardLayout_name); 811 String label = a.getString( 812 com.android.internal.R.styleable.KeyboardLayout_label); 813 int keyboardLayoutResId = a.getResourceId( 814 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout, 815 0); 816 if (name == null || label == null || keyboardLayoutResId == 0) { 817 Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' " 818 + "attributes in keyboard layout " 819 + "resource from receiver " 820 + receiver.packageName + "/" + receiver.name); 821 } else { 822 String descriptor = KeyboardLayoutDescriptor.format( 823 receiver.packageName, receiver.name, name); 824 if (keyboardName == null || name.equals(keyboardName)) { 825 visitor.visitKeyboardLayout(resources, descriptor, 826 label, collection, keyboardLayoutResId); 827 } 828 } 829 } finally { 830 a.recycle(); 831 } 832 } else { 833 Log.w(TAG, "Skipping unrecognized element '" + element 834 + "' in keyboard layout resource from receiver " 835 + receiver.packageName + "/" + receiver.name); 836 } 837 } 838 } finally { 839 parser.close(); 840 } 841 } catch (Exception ex) { 842 Log.w(TAG, "Could not parse keyboard layout resource from receiver " 843 + receiver.packageName + "/" + receiver.name, ex); 844 } 845 } 846 847 @Override // Binder call 848 public String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor) { 849 if (inputDeviceDescriptor == null) { 850 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 851 } 852 853 synchronized (mDataStore) { 854 return mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor); 855 } 856 } 857 858 @Override // Binder call 859 public void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor, 860 String keyboardLayoutDescriptor) { 861 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 862 "setCurrentKeyboardLayoutForInputDevice()")) { 863 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 864 } 865 if (inputDeviceDescriptor == null) { 866 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 867 } 868 if (keyboardLayoutDescriptor == null) { 869 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 870 } 871 872 synchronized (mDataStore) { 873 try { 874 if (mDataStore.setCurrentKeyboardLayout( 875 inputDeviceDescriptor, keyboardLayoutDescriptor)) { 876 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 877 } 878 } finally { 879 mDataStore.saveIfNeeded(); 880 } 881 } 882 } 883 884 @Override // Binder call 885 public String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor) { 886 if (inputDeviceDescriptor == null) { 887 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 888 } 889 890 synchronized (mDataStore) { 891 return mDataStore.getKeyboardLayouts(inputDeviceDescriptor); 892 } 893 } 894 895 @Override // Binder call 896 public void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor, 897 String keyboardLayoutDescriptor) { 898 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 899 "addKeyboardLayoutForInputDevice()")) { 900 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 901 } 902 if (inputDeviceDescriptor == null) { 903 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 904 } 905 if (keyboardLayoutDescriptor == null) { 906 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 907 } 908 909 synchronized (mDataStore) { 910 try { 911 String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor); 912 if (mDataStore.addKeyboardLayout(inputDeviceDescriptor, keyboardLayoutDescriptor) 913 && !Objects.equal(oldLayout, 914 mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) { 915 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 916 } 917 } finally { 918 mDataStore.saveIfNeeded(); 919 } 920 } 921 } 922 923 @Override // Binder call 924 public void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor, 925 String keyboardLayoutDescriptor) { 926 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 927 "removeKeyboardLayoutForInputDevice()")) { 928 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 929 } 930 if (inputDeviceDescriptor == null) { 931 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 932 } 933 if (keyboardLayoutDescriptor == null) { 934 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 935 } 936 937 synchronized (mDataStore) { 938 try { 939 String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor); 940 if (mDataStore.removeKeyboardLayout(inputDeviceDescriptor, 941 keyboardLayoutDescriptor) 942 && !Objects.equal(oldLayout, 943 mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) { 944 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 945 } 946 } finally { 947 mDataStore.saveIfNeeded(); 948 } 949 } 950 } 951 952 public void switchKeyboardLayout(int deviceId, int direction) { 953 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget(); 954 } 955 956 // Must be called on handler. 957 private void handleSwitchKeyboardLayout(int deviceId, int direction) { 958 final InputDevice device = getInputDevice(deviceId); 959 final String inputDeviceDescriptor = device.getDescriptor(); 960 if (device != null) { 961 final boolean changed; 962 final String keyboardLayoutDescriptor; 963 synchronized (mDataStore) { 964 try { 965 changed = mDataStore.switchKeyboardLayout(inputDeviceDescriptor, direction); 966 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout( 967 inputDeviceDescriptor); 968 } finally { 969 mDataStore.saveIfNeeded(); 970 } 971 } 972 973 if (changed) { 974 if (mSwitchedKeyboardLayoutToast != null) { 975 mSwitchedKeyboardLayoutToast.cancel(); 976 mSwitchedKeyboardLayoutToast = null; 977 } 978 if (keyboardLayoutDescriptor != null) { 979 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor); 980 if (keyboardLayout != null) { 981 mSwitchedKeyboardLayoutToast = Toast.makeText( 982 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT); 983 mSwitchedKeyboardLayoutToast.show(); 984 } 985 } 986 987 reloadKeyboardLayouts(); 988 } 989 } 990 } 991 992 public void setInputWindows(InputWindowHandle[] windowHandles) { 993 nativeSetInputWindows(mPtr, windowHandles); 994 } 995 996 public void setFocusedApplication(InputApplicationHandle application) { 997 nativeSetFocusedApplication(mPtr, application); 998 } 999 1000 public void setInputDispatchMode(boolean enabled, boolean frozen) { 1001 nativeSetInputDispatchMode(mPtr, enabled, frozen); 1002 } 1003 1004 public void setSystemUiVisibility(int visibility) { 1005 nativeSetSystemUiVisibility(mPtr, visibility); 1006 } 1007 1008 /** 1009 * Atomically transfers touch focus from one window to another as identified by 1010 * their input channels. It is possible for multiple windows to have 1011 * touch focus if they support split touch dispatch 1012 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this 1013 * method only transfers touch focus of the specified window without affecting 1014 * other windows that may also have touch focus at the same time. 1015 * @param fromChannel The channel of a window that currently has touch focus. 1016 * @param toChannel The channel of the window that should receive touch focus in 1017 * place of the first. 1018 * @return True if the transfer was successful. False if the window with the 1019 * specified channel did not actually have touch focus at the time of the request. 1020 */ 1021 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) { 1022 if (fromChannel == null) { 1023 throw new IllegalArgumentException("fromChannel must not be null."); 1024 } 1025 if (toChannel == null) { 1026 throw new IllegalArgumentException("toChannel must not be null."); 1027 } 1028 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel); 1029 } 1030 1031 @Override // Binder call 1032 public void tryPointerSpeed(int speed) { 1033 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, 1034 "tryPointerSpeed()")) { 1035 throw new SecurityException("Requires SET_POINTER_SPEED permission"); 1036 } 1037 1038 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) { 1039 throw new IllegalArgumentException("speed out of range"); 1040 } 1041 1042 setPointerSpeedUnchecked(speed); 1043 } 1044 1045 public void updatePointerSpeedFromSettings() { 1046 int speed = getPointerSpeedSetting(); 1047 setPointerSpeedUnchecked(speed); 1048 } 1049 1050 private void setPointerSpeedUnchecked(int speed) { 1051 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED), 1052 InputManager.MAX_POINTER_SPEED); 1053 nativeSetPointerSpeed(mPtr, speed); 1054 } 1055 1056 private void registerPointerSpeedSettingObserver() { 1057 mContext.getContentResolver().registerContentObserver( 1058 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true, 1059 new ContentObserver(mHandler) { 1060 @Override 1061 public void onChange(boolean selfChange) { 1062 updatePointerSpeedFromSettings(); 1063 } 1064 }); 1065 } 1066 1067 private int getPointerSpeedSetting() { 1068 int speed = InputManager.DEFAULT_POINTER_SPEED; 1069 try { 1070 speed = Settings.System.getInt(mContext.getContentResolver(), 1071 Settings.System.POINTER_SPEED); 1072 } catch (SettingNotFoundException snfe) { 1073 } 1074 return speed; 1075 } 1076 1077 public void updateShowTouchesFromSettings() { 1078 int setting = getShowTouchesSetting(0); 1079 nativeSetShowTouches(mPtr, setting != 0); 1080 } 1081 1082 private void registerShowTouchesSettingObserver() { 1083 mContext.getContentResolver().registerContentObserver( 1084 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true, 1085 new ContentObserver(mHandler) { 1086 @Override 1087 public void onChange(boolean selfChange) { 1088 updateShowTouchesFromSettings(); 1089 } 1090 }); 1091 } 1092 1093 private int getShowTouchesSetting(int defaultValue) { 1094 int result = defaultValue; 1095 try { 1096 result = Settings.System.getInt(mContext.getContentResolver(), 1097 Settings.System.SHOW_TOUCHES); 1098 } catch (SettingNotFoundException snfe) { 1099 } 1100 return result; 1101 } 1102 1103 // Binder call 1104 @Override 1105 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) { 1106 if (repeat >= pattern.length) { 1107 throw new ArrayIndexOutOfBoundsException(); 1108 } 1109 1110 VibratorToken v; 1111 synchronized (mVibratorLock) { 1112 v = mVibratorTokens.get(token); 1113 if (v == null) { 1114 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++); 1115 try { 1116 token.linkToDeath(v, 0); 1117 } catch (RemoteException ex) { 1118 // give up 1119 throw new RuntimeException(ex); 1120 } 1121 mVibratorTokens.put(token, v); 1122 } 1123 } 1124 1125 synchronized (v) { 1126 v.mVibrating = true; 1127 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue); 1128 } 1129 } 1130 1131 // Binder call 1132 @Override 1133 public void cancelVibrate(int deviceId, IBinder token) { 1134 VibratorToken v; 1135 synchronized (mVibratorLock) { 1136 v = mVibratorTokens.get(token); 1137 if (v == null || v.mDeviceId != deviceId) { 1138 return; // nothing to cancel 1139 } 1140 } 1141 1142 cancelVibrateIfNeeded(v); 1143 } 1144 1145 void onVibratorTokenDied(VibratorToken v) { 1146 synchronized (mVibratorLock) { 1147 mVibratorTokens.remove(v.mToken); 1148 } 1149 1150 cancelVibrateIfNeeded(v); 1151 } 1152 1153 private void cancelVibrateIfNeeded(VibratorToken v) { 1154 synchronized (v) { 1155 if (v.mVibrating) { 1156 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue); 1157 v.mVibrating = false; 1158 } 1159 } 1160 } 1161 1162 @Override 1163 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1164 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 1165 != PackageManager.PERMISSION_GRANTED) { 1166 pw.println("Permission Denial: can't dump InputManager from from pid=" 1167 + Binder.getCallingPid() 1168 + ", uid=" + Binder.getCallingUid()); 1169 return; 1170 } 1171 1172 pw.println("INPUT MANAGER (dumpsys input)\n"); 1173 String dumpStr = nativeDump(mPtr); 1174 if (dumpStr != null) { 1175 pw.println(dumpStr); 1176 } 1177 } 1178 1179 private boolean checkCallingPermission(String permission, String func) { 1180 // Quick check: if the calling permission is me, it's all okay. 1181 if (Binder.getCallingPid() == Process.myPid()) { 1182 return true; 1183 } 1184 1185 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { 1186 return true; 1187 } 1188 String msg = "Permission Denial: " + func + " from pid=" 1189 + Binder.getCallingPid() 1190 + ", uid=" + Binder.getCallingUid() 1191 + " requires " + permission; 1192 Slog.w(TAG, msg); 1193 return false; 1194 } 1195 1196 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). 1197 public void monitor() { 1198 synchronized (mInputFilterLock) { } 1199 nativeMonitor(mPtr); 1200 } 1201 1202 // Native callback. 1203 private void notifyConfigurationChanged(long whenNanos) { 1204 mCallbacks.notifyConfigurationChanged(); 1205 } 1206 1207 // Native callback. 1208 private void notifyInputDevicesChanged(InputDevice[] inputDevices) { 1209 synchronized (mInputDevicesLock) { 1210 if (!mInputDevicesChangedPending) { 1211 mInputDevicesChangedPending = true; 1212 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED, 1213 mInputDevices).sendToTarget(); 1214 } 1215 1216 mInputDevices = inputDevices; 1217 } 1218 } 1219 1220 // Native callback. 1221 private void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { 1222 mCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); 1223 } 1224 1225 // Native callback. 1226 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { 1227 mCallbacks.notifyInputChannelBroken(inputWindowHandle); 1228 } 1229 1230 // Native callback. 1231 private long notifyANR(InputApplicationHandle inputApplicationHandle, 1232 InputWindowHandle inputWindowHandle) { 1233 return mCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle); 1234 } 1235 1236 // Native callback. 1237 final boolean filterInputEvent(InputEvent event, int policyFlags) { 1238 synchronized (mInputFilterLock) { 1239 if (mInputFilter != null) { 1240 try { 1241 mInputFilter.filterInputEvent(event, policyFlags); 1242 } catch (RemoteException e) { 1243 /* ignore */ 1244 } 1245 return false; 1246 } 1247 } 1248 event.recycle(); 1249 return true; 1250 } 1251 1252 // Native callback. 1253 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) { 1254 return mCallbacks.interceptKeyBeforeQueueing( 1255 event, policyFlags, isScreenOn); 1256 } 1257 1258 // Native callback. 1259 private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { 1260 return mCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags); 1261 } 1262 1263 // Native callback. 1264 private long interceptKeyBeforeDispatching(InputWindowHandle focus, 1265 KeyEvent event, int policyFlags) { 1266 return mCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); 1267 } 1268 1269 // Native callback. 1270 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 1271 KeyEvent event, int policyFlags) { 1272 return mCallbacks.dispatchUnhandledKey(focus, event, policyFlags); 1273 } 1274 1275 // Native callback. 1276 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) { 1277 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS, 1278 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED; 1279 } 1280 1281 // Native callback. 1282 private int getVirtualKeyQuietTimeMillis() { 1283 return mContext.getResources().getInteger( 1284 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis); 1285 } 1286 1287 // Native callback. 1288 private String[] getExcludedDeviceNames() { 1289 ArrayList<String> names = new ArrayList<String>(); 1290 1291 // Read partner-provided list of excluded input devices 1292 XmlPullParser parser = null; 1293 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". 1294 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH); 1295 FileReader confreader = null; 1296 try { 1297 confreader = new FileReader(confFile); 1298 parser = Xml.newPullParser(); 1299 parser.setInput(confreader); 1300 XmlUtils.beginDocument(parser, "devices"); 1301 1302 while (true) { 1303 XmlUtils.nextElement(parser); 1304 if (!"device".equals(parser.getName())) { 1305 break; 1306 } 1307 String name = parser.getAttributeValue(null, "name"); 1308 if (name != null) { 1309 names.add(name); 1310 } 1311 } 1312 } catch (FileNotFoundException e) { 1313 // It's ok if the file does not exist. 1314 } catch (Exception e) { 1315 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e); 1316 } finally { 1317 try { if (confreader != null) confreader.close(); } catch (IOException e) { } 1318 } 1319 1320 return names.toArray(new String[names.size()]); 1321 } 1322 1323 // Native callback. 1324 private int getKeyRepeatTimeout() { 1325 return ViewConfiguration.getKeyRepeatTimeout(); 1326 } 1327 1328 // Native callback. 1329 private int getKeyRepeatDelay() { 1330 return ViewConfiguration.getKeyRepeatDelay(); 1331 } 1332 1333 // Native callback. 1334 private int getHoverTapTimeout() { 1335 return ViewConfiguration.getHoverTapTimeout(); 1336 } 1337 1338 // Native callback. 1339 private int getHoverTapSlop() { 1340 return ViewConfiguration.getHoverTapSlop(); 1341 } 1342 1343 // Native callback. 1344 private int getDoubleTapTimeout() { 1345 return ViewConfiguration.getDoubleTapTimeout(); 1346 } 1347 1348 // Native callback. 1349 private int getLongPressTimeout() { 1350 return ViewConfiguration.getLongPressTimeout(); 1351 } 1352 1353 // Native callback. 1354 private int getPointerLayer() { 1355 return mCallbacks.getPointerLayer(); 1356 } 1357 1358 // Native callback. 1359 private PointerIcon getPointerIcon() { 1360 return PointerIcon.getDefaultIcon(mContext); 1361 } 1362 1363 // Native callback. 1364 private String[] getKeyboardLayoutOverlay(String inputDeviceDescriptor) { 1365 if (!mSystemReady) { 1366 return null; 1367 } 1368 1369 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice( 1370 inputDeviceDescriptor); 1371 if (keyboardLayoutDescriptor == null) { 1372 return null; 1373 } 1374 1375 final String[] result = new String[2]; 1376 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 1377 @Override 1378 public void visitKeyboardLayout(Resources resources, 1379 String descriptor, String label, String collection, int keyboardLayoutResId) { 1380 try { 1381 result[0] = descriptor; 1382 result[1] = Streams.readFully(new InputStreamReader( 1383 resources.openRawResource(keyboardLayoutResId))); 1384 } catch (IOException ex) { 1385 } catch (NotFoundException ex) { 1386 } 1387 } 1388 }); 1389 if (result[0] == null) { 1390 Log.w(TAG, "Could not get keyboard layout with descriptor '" 1391 + keyboardLayoutDescriptor + "'."); 1392 return null; 1393 } 1394 return result; 1395 } 1396 1397 // Native callback. 1398 private String getDeviceAlias(String uniqueId) { 1399 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) { 1400 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId) 1401 return null; 1402 } 1403 return null; 1404 } 1405 1406 1407 /** 1408 * Callback interface implemented by the Window Manager. 1409 */ 1410 public interface Callbacks { 1411 public void notifyConfigurationChanged(); 1412 1413 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen); 1414 1415 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle); 1416 1417 public long notifyANR(InputApplicationHandle inputApplicationHandle, 1418 InputWindowHandle inputWindowHandle); 1419 1420 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn); 1421 1422 public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags); 1423 1424 public long interceptKeyBeforeDispatching(InputWindowHandle focus, 1425 KeyEvent event, int policyFlags); 1426 1427 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 1428 KeyEvent event, int policyFlags); 1429 1430 public int getPointerLayer(); 1431 } 1432 1433 /** 1434 * Private handler for the input manager. 1435 */ 1436 private final class InputManagerHandler extends Handler { 1437 @Override 1438 public void handleMessage(Message msg) { 1439 switch (msg.what) { 1440 case MSG_DELIVER_INPUT_DEVICES_CHANGED: 1441 deliverInputDevicesChanged((InputDevice[])msg.obj); 1442 break; 1443 case MSG_SWITCH_KEYBOARD_LAYOUT: 1444 handleSwitchKeyboardLayout(msg.arg1, msg.arg2); 1445 break; 1446 case MSG_RELOAD_KEYBOARD_LAYOUTS: 1447 reloadKeyboardLayouts(); 1448 break; 1449 case MSG_UPDATE_KEYBOARD_LAYOUTS: 1450 updateKeyboardLayouts(); 1451 break; 1452 case MSG_RELOAD_DEVICE_ALIASES: 1453 reloadDeviceAliases(); 1454 break; 1455 } 1456 } 1457 } 1458 1459 /** 1460 * Hosting interface for input filters to call back into the input manager. 1461 */ 1462 private final class InputFilterHost extends IInputFilterHost.Stub { 1463 private boolean mDisconnected; 1464 1465 public void disconnectLocked() { 1466 mDisconnected = true; 1467 } 1468 1469 public void sendInputEvent(InputEvent event, int policyFlags) { 1470 if (event == null) { 1471 throw new IllegalArgumentException("event must not be null"); 1472 } 1473 1474 synchronized (mInputFilterLock) { 1475 if (!mDisconnected) { 1476 nativeInjectInputEvent(mPtr, event, 0, 0, 1477 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0, 1478 policyFlags | WindowManagerPolicy.FLAG_FILTERED); 1479 } 1480 } 1481 } 1482 } 1483 1484 private static final class KeyboardLayoutDescriptor { 1485 public String packageName; 1486 public String receiverName; 1487 public String keyboardLayoutName; 1488 1489 public static String format(String packageName, 1490 String receiverName, String keyboardName) { 1491 return packageName + "/" + receiverName + "/" + keyboardName; 1492 } 1493 1494 public static KeyboardLayoutDescriptor parse(String descriptor) { 1495 int pos = descriptor.indexOf('/'); 1496 if (pos < 0 || pos + 1 == descriptor.length()) { 1497 return null; 1498 } 1499 int pos2 = descriptor.indexOf('/', pos + 1); 1500 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) { 1501 return null; 1502 } 1503 1504 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor(); 1505 result.packageName = descriptor.substring(0, pos); 1506 result.receiverName = descriptor.substring(pos + 1, pos2); 1507 result.keyboardLayoutName = descriptor.substring(pos2 + 1); 1508 return result; 1509 } 1510 } 1511 1512 private interface KeyboardLayoutVisitor { 1513 void visitKeyboardLayout(Resources resources, 1514 String descriptor, String label, String collection, int keyboardLayoutResId); 1515 } 1516 1517 private final class InputDevicesChangedListenerRecord implements DeathRecipient { 1518 private final int mPid; 1519 private final IInputDevicesChangedListener mListener; 1520 1521 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) { 1522 mPid = pid; 1523 mListener = listener; 1524 } 1525 1526 @Override 1527 public void binderDied() { 1528 if (DEBUG) { 1529 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died."); 1530 } 1531 onInputDevicesChangedListenerDied(mPid); 1532 } 1533 1534 public void notifyInputDevicesChanged(int[] info) { 1535 try { 1536 mListener.onInputDevicesChanged(info); 1537 } catch (RemoteException ex) { 1538 Slog.w(TAG, "Failed to notify process " 1539 + mPid + " that input devices changed, assuming it died.", ex); 1540 binderDied(); 1541 } 1542 } 1543 } 1544 1545 private final class VibratorToken implements DeathRecipient { 1546 public final int mDeviceId; 1547 public final IBinder mToken; 1548 public final int mTokenValue; 1549 1550 public boolean mVibrating; 1551 1552 public VibratorToken(int deviceId, IBinder token, int tokenValue) { 1553 mDeviceId = deviceId; 1554 mToken = token; 1555 mTokenValue = tokenValue; 1556 } 1557 1558 @Override 1559 public void binderDied() { 1560 if (DEBUG) { 1561 Slog.d(TAG, "Vibrator token died."); 1562 } 1563 onVibratorTokenDied(this); 1564 } 1565 } 1566} 1567