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 17 package com.android.server.input; 18 19 import com.android.internal.R; 20 import com.android.internal.util.XmlUtils; 21 import com.android.server.Watchdog; 22 23 import org.xmlpull.v1.XmlPullParser; 24 25 import android.Manifest; 26 import android.app.Notification; 27 import android.app.NotificationManager; 28 import android.app.PendingIntent; 29 import android.bluetooth.BluetoothAdapter; 30 import android.bluetooth.BluetoothDevice; 31 import android.content.BroadcastReceiver; 32 import android.content.ComponentName; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.IntentFilter; 36 import android.content.pm.ActivityInfo; 37 import android.content.pm.PackageManager; 38 import android.content.pm.ResolveInfo; 39 import android.content.pm.PackageManager.NameNotFoundException; 40 import android.content.res.Resources; 41 import android.content.res.Resources.NotFoundException; 42 import android.content.res.TypedArray; 43 import android.content.res.XmlResourceParser; 44 import android.database.ContentObserver; 45 import android.hardware.input.IInputManager; 46 import android.hardware.input.IInputDevicesChangedListener; 47 import android.hardware.input.InputManager; 48 import android.hardware.input.KeyboardLayout; 49 import android.os.Binder; 50 import android.os.Bundle; 51 import android.os.Environment; 52 import android.os.Handler; 53 import android.os.IBinder; 54 import android.os.Message; 55 import android.os.MessageQueue; 56 import android.os.Process; 57 import android.os.RemoteException; 58 import android.provider.Settings; 59 import android.provider.Settings.SettingNotFoundException; 60 import android.server.BluetoothService; 61 import android.util.Log; 62 import android.util.Slog; 63 import android.util.SparseArray; 64 import android.util.Xml; 65 import android.view.InputChannel; 66 import android.view.InputDevice; 67 import android.view.InputEvent; 68 import android.view.KeyEvent; 69 import android.view.PointerIcon; 70 import android.view.Surface; 71 import android.view.ViewConfiguration; 72 import android.view.WindowManagerPolicy; 73 import android.widget.Toast; 74 75 import java.io.File; 76 import java.io.FileDescriptor; 77 import java.io.FileNotFoundException; 78 import java.io.FileReader; 79 import java.io.IOException; 80 import java.io.InputStreamReader; 81 import java.io.PrintWriter; 82 import java.util.ArrayList; 83 import java.util.HashMap; 84 import java.util.HashSet; 85 86 import libcore.io.Streams; 87 import libcore.util.Objects; 88 89 /* 90 * Wraps the C++ InputManager and provides its callbacks. 91 */ 92 public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor { 93 static final String TAG = "InputManager"; 94 static final boolean DEBUG = false; 95 96 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; 97 98 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1; 99 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2; 100 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3; 101 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4; 102 private static final int MSG_RELOAD_DEVICE_ALIASES = 5; 103 104 // Pointer to native input manager service object. 105 private final int mPtr; 106 107 private final Context mContext; 108 private final Callbacks mCallbacks; 109 private final InputManagerHandler mHandler; 110 private boolean mSystemReady; 111 private BluetoothService mBluetoothService; 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 InputFilter 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 public void systemReady(BluetoothService bluetoothService) { 240 if (DEBUG) { 241 Slog.d(TAG, "System ready."); 242 } 243 mBluetoothService = bluetoothService; 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(InputFilter filter) { 429 synchronized (mInputFilterLock) { 430 final InputFilter 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 oldFilter.uninstall(); 440 } 441 442 if (filter != null) { 443 mInputFilter = filter; 444 mInputFilterHost = new InputFilterHost(); 445 filter.install(mInputFilterHost); 446 } 447 448 nativeSetInputFilterEnabled(mPtr, filter != null); 449 } 450 } 451 452 @Override // Binder call 453 public boolean injectInputEvent(InputEvent event, int mode) { 454 if (event == null) { 455 throw new IllegalArgumentException("event must not be null"); 456 } 457 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC 458 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH 459 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) { 460 throw new IllegalArgumentException("mode is invalid"); 461 } 462 463 final int pid = Binder.getCallingPid(); 464 final int uid = Binder.getCallingUid(); 465 final long ident = Binder.clearCallingIdentity(); 466 final int result; 467 try { 468 result = nativeInjectInputEvent(mPtr, event, pid, uid, mode, 469 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); 470 } finally { 471 Binder.restoreCallingIdentity(ident); 472 } 473 switch (result) { 474 case INPUT_EVENT_INJECTION_PERMISSION_DENIED: 475 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied."); 476 throw new SecurityException( 477 "Injecting to another application requires INJECT_EVENTS permission"); 478 case INPUT_EVENT_INJECTION_SUCCEEDED: 479 return true; 480 case INPUT_EVENT_INJECTION_TIMED_OUT: 481 Slog.w(TAG, "Input event injection from pid " + pid + " timed out."); 482 return false; 483 case INPUT_EVENT_INJECTION_FAILED: 484 default: 485 Slog.w(TAG, "Input event injection from pid " + pid + " failed."); 486 return false; 487 } 488 } 489 490 /** 491 * Gets information about the input device with the specified id. 492 * @param id The device id. 493 * @return The input device or null if not found. 494 */ 495 @Override // Binder call 496 public InputDevice getInputDevice(int deviceId) { 497 synchronized (mInputDevicesLock) { 498 final int count = mInputDevices.length; 499 for (int i = 0; i < count; i++) { 500 final InputDevice inputDevice = mInputDevices[i]; 501 if (inputDevice.getId() == deviceId) { 502 return inputDevice; 503 } 504 } 505 } 506 return null; 507 } 508 509 /** 510 * Gets the ids of all input devices in the system. 511 * @return The input device ids. 512 */ 513 @Override // Binder call 514 public int[] getInputDeviceIds() { 515 synchronized (mInputDevicesLock) { 516 final int count = mInputDevices.length; 517 int[] ids = new int[count]; 518 for (int i = 0; i < count; i++) { 519 ids[i] = mInputDevices[i].getId(); 520 } 521 return ids; 522 } 523 } 524 525 /** 526 * Gets all input devices in the system. 527 * @return The array of input devices. 528 */ 529 public InputDevice[] getInputDevices() { 530 synchronized (mInputDevicesLock) { 531 return mInputDevices; 532 } 533 } 534 535 @Override // Binder call 536 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) { 537 if (listener == null) { 538 throw new IllegalArgumentException("listener must not be null"); 539 } 540 541 synchronized (mInputDevicesLock) { 542 int callingPid = Binder.getCallingPid(); 543 if (mInputDevicesChangedListeners.get(callingPid) != null) { 544 throw new SecurityException("The calling process has already " 545 + "registered an InputDevicesChangedListener."); 546 } 547 548 InputDevicesChangedListenerRecord record = 549 new InputDevicesChangedListenerRecord(callingPid, listener); 550 try { 551 IBinder binder = listener.asBinder(); 552 binder.linkToDeath(record, 0); 553 } catch (RemoteException ex) { 554 // give up 555 throw new RuntimeException(ex); 556 } 557 558 mInputDevicesChangedListeners.put(callingPid, record); 559 } 560 } 561 562 private void onInputDevicesChangedListenerDied(int pid) { 563 synchronized (mInputDevicesLock) { 564 mInputDevicesChangedListeners.remove(pid); 565 } 566 } 567 568 // Must be called on handler. 569 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) { 570 // Scan for changes. 571 int numFullKeyboardsAdded = 0; 572 mTempInputDevicesChangedListenersToNotify.clear(); 573 mTempFullKeyboards.clear(); 574 final int numListeners; 575 final int[] deviceIdAndGeneration; 576 synchronized (mInputDevicesLock) { 577 if (!mInputDevicesChangedPending) { 578 return; 579 } 580 mInputDevicesChangedPending = false; 581 582 numListeners = mInputDevicesChangedListeners.size(); 583 for (int i = 0; i < numListeners; i++) { 584 mTempInputDevicesChangedListenersToNotify.add( 585 mInputDevicesChangedListeners.valueAt(i)); 586 } 587 588 final int numDevices = mInputDevices.length; 589 deviceIdAndGeneration = new int[numDevices * 2]; 590 for (int i = 0; i < numDevices; i++) { 591 final InputDevice inputDevice = mInputDevices[i]; 592 deviceIdAndGeneration[i * 2] = inputDevice.getId(); 593 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration(); 594 595 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) { 596 if (!containsInputDeviceWithDescriptor(oldInputDevices, 597 inputDevice.getDescriptor())) { 598 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice); 599 } else { 600 mTempFullKeyboards.add(inputDevice); 601 } 602 } 603 } 604 } 605 606 // Notify listeners. 607 for (int i = 0; i < numListeners; i++) { 608 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged( 609 deviceIdAndGeneration); 610 } 611 mTempInputDevicesChangedListenersToNotify.clear(); 612 613 // Check for missing keyboard layouts. 614 if (mNotificationManager != null) { 615 final int numFullKeyboards = mTempFullKeyboards.size(); 616 boolean missingLayoutForExternalKeyboard = false; 617 boolean missingLayoutForExternalKeyboardAdded = false; 618 synchronized (mDataStore) { 619 for (int i = 0; i < numFullKeyboards; i++) { 620 final InputDevice inputDevice = mTempFullKeyboards.get(i); 621 if (mDataStore.getCurrentKeyboardLayout(inputDevice.getDescriptor()) == null) { 622 missingLayoutForExternalKeyboard = true; 623 if (i < numFullKeyboardsAdded) { 624 missingLayoutForExternalKeyboardAdded = true; 625 } 626 } 627 } 628 } 629 if (missingLayoutForExternalKeyboard) { 630 if (missingLayoutForExternalKeyboardAdded) { 631 showMissingKeyboardLayoutNotification(); 632 } 633 } else if (mKeyboardLayoutNotificationShown) { 634 hideMissingKeyboardLayoutNotification(); 635 } 636 } 637 mTempFullKeyboards.clear(); 638 } 639 640 // Must be called on handler. 641 private void showMissingKeyboardLayoutNotification() { 642 if (!mKeyboardLayoutNotificationShown) { 643 if (mKeyboardLayoutIntent == null) { 644 final Intent intent = new Intent("android.settings.INPUT_METHOD_SETTINGS"); 645 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 646 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 647 | Intent.FLAG_ACTIVITY_CLEAR_TOP); 648 mKeyboardLayoutIntent = PendingIntent.getActivity(mContext, 0, intent, 0); 649 } 650 651 Resources r = mContext.getResources(); 652 Notification notification = new Notification.Builder(mContext) 653 .setContentTitle(r.getString( 654 R.string.select_keyboard_layout_notification_title)) 655 .setContentText(r.getString( 656 R.string.select_keyboard_layout_notification_message)) 657 .setContentIntent(mKeyboardLayoutIntent) 658 .setSmallIcon(R.drawable.ic_settings_language) 659 .setPriority(Notification.PRIORITY_LOW) 660 .build(); 661 mNotificationManager.notify(R.string.select_keyboard_layout_notification_title, 662 notification); 663 mKeyboardLayoutNotificationShown = true; 664 } 665 } 666 667 // Must be called on handler. 668 private void hideMissingKeyboardLayoutNotification() { 669 if (mKeyboardLayoutNotificationShown) { 670 mKeyboardLayoutNotificationShown = false; 671 mNotificationManager.cancel(R.string.select_keyboard_layout_notification_title); 672 } 673 } 674 675 // Must be called on handler. 676 private void updateKeyboardLayouts() { 677 // Scan all input devices state for keyboard layouts that have been uninstalled. 678 final HashSet<String> availableKeyboardLayouts = new HashSet<String>(); 679 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 680 @Override 681 public void visitKeyboardLayout(Resources resources, 682 String descriptor, String label, String collection, int keyboardLayoutResId) { 683 availableKeyboardLayouts.add(descriptor); 684 } 685 }); 686 synchronized (mDataStore) { 687 try { 688 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts); 689 } finally { 690 mDataStore.saveIfNeeded(); 691 } 692 } 693 694 // Reload keyboard layouts. 695 reloadKeyboardLayouts(); 696 } 697 698 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices, 699 String descriptor) { 700 final int numDevices = inputDevices.length; 701 for (int i = 0; i < numDevices; i++) { 702 final InputDevice inputDevice = inputDevices[i]; 703 if (inputDevice.getDescriptor().equals(descriptor)) { 704 return true; 705 } 706 } 707 return false; 708 } 709 710 @Override // Binder call 711 public KeyboardLayout[] getKeyboardLayouts() { 712 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>(); 713 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 714 @Override 715 public void visitKeyboardLayout(Resources resources, 716 String descriptor, String label, String collection, int keyboardLayoutResId) { 717 list.add(new KeyboardLayout(descriptor, label, collection)); 718 } 719 }); 720 return list.toArray(new KeyboardLayout[list.size()]); 721 } 722 723 @Override // Binder call 724 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) { 725 if (keyboardLayoutDescriptor == null) { 726 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 727 } 728 729 final KeyboardLayout[] result = new KeyboardLayout[1]; 730 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 731 @Override 732 public void visitKeyboardLayout(Resources resources, 733 String descriptor, String label, String collection, int keyboardLayoutResId) { 734 result[0] = new KeyboardLayout(descriptor, label, collection); 735 } 736 }); 737 if (result[0] == null) { 738 Log.w(TAG, "Could not get keyboard layout with descriptor '" 739 + keyboardLayoutDescriptor + "'."); 740 } 741 return result[0]; 742 } 743 744 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) { 745 final PackageManager pm = mContext.getPackageManager(); 746 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS); 747 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent, 748 PackageManager.GET_META_DATA)) { 749 visitKeyboardLayoutsInPackage(pm, resolveInfo.activityInfo, null, visitor); 750 } 751 } 752 753 private void visitKeyboardLayout(String keyboardLayoutDescriptor, 754 KeyboardLayoutVisitor visitor) { 755 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor); 756 if (d != null) { 757 final PackageManager pm = mContext.getPackageManager(); 758 try { 759 ActivityInfo receiver = pm.getReceiverInfo( 760 new ComponentName(d.packageName, d.receiverName), 761 PackageManager.GET_META_DATA); 762 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, visitor); 763 } catch (NameNotFoundException ex) { 764 } 765 } 766 } 767 768 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, 769 String keyboardName, KeyboardLayoutVisitor visitor) { 770 Bundle metaData = receiver.metaData; 771 if (metaData == null) { 772 return; 773 } 774 775 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS); 776 if (configResId == 0) { 777 Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS 778 + "' on receiver " + receiver.packageName + "/" + receiver.name); 779 return; 780 } 781 782 CharSequence receiverLabel = receiver.loadLabel(pm); 783 String collection = receiverLabel != null ? receiverLabel.toString() : ""; 784 785 try { 786 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo); 787 XmlResourceParser parser = resources.getXml(configResId); 788 try { 789 XmlUtils.beginDocument(parser, "keyboard-layouts"); 790 791 for (;;) { 792 XmlUtils.nextElement(parser); 793 String element = parser.getName(); 794 if (element == null) { 795 break; 796 } 797 if (element.equals("keyboard-layout")) { 798 TypedArray a = resources.obtainAttributes( 799 parser, com.android.internal.R.styleable.KeyboardLayout); 800 try { 801 String name = a.getString( 802 com.android.internal.R.styleable.KeyboardLayout_name); 803 String label = a.getString( 804 com.android.internal.R.styleable.KeyboardLayout_label); 805 int keyboardLayoutResId = a.getResourceId( 806 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout, 807 0); 808 if (name == null || label == null || keyboardLayoutResId == 0) { 809 Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' " 810 + "attributes in keyboard layout " 811 + "resource from receiver " 812 + receiver.packageName + "/" + receiver.name); 813 } else { 814 String descriptor = KeyboardLayoutDescriptor.format( 815 receiver.packageName, receiver.name, name); 816 if (keyboardName == null || name.equals(keyboardName)) { 817 visitor.visitKeyboardLayout(resources, descriptor, 818 label, collection, keyboardLayoutResId); 819 } 820 } 821 } finally { 822 a.recycle(); 823 } 824 } else { 825 Log.w(TAG, "Skipping unrecognized element '" + element 826 + "' in keyboard layout resource from receiver " 827 + receiver.packageName + "/" + receiver.name); 828 } 829 } 830 } finally { 831 parser.close(); 832 } 833 } catch (Exception ex) { 834 Log.w(TAG, "Could not parse keyboard layout resource from receiver " 835 + receiver.packageName + "/" + receiver.name, ex); 836 } 837 } 838 839 @Override // Binder call 840 public String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor) { 841 if (inputDeviceDescriptor == null) { 842 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 843 } 844 845 synchronized (mDataStore) { 846 return mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor); 847 } 848 } 849 850 @Override // Binder call 851 public void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor, 852 String keyboardLayoutDescriptor) { 853 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 854 "setCurrentKeyboardLayoutForInputDevice()")) { 855 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 856 } 857 if (inputDeviceDescriptor == null) { 858 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 859 } 860 if (keyboardLayoutDescriptor == null) { 861 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 862 } 863 864 synchronized (mDataStore) { 865 try { 866 if (mDataStore.setCurrentKeyboardLayout( 867 inputDeviceDescriptor, keyboardLayoutDescriptor)) { 868 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 869 } 870 } finally { 871 mDataStore.saveIfNeeded(); 872 } 873 } 874 } 875 876 @Override // Binder call 877 public String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor) { 878 if (inputDeviceDescriptor == null) { 879 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 880 } 881 882 synchronized (mDataStore) { 883 return mDataStore.getKeyboardLayouts(inputDeviceDescriptor); 884 } 885 } 886 887 @Override // Binder call 888 public void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor, 889 String keyboardLayoutDescriptor) { 890 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 891 "addKeyboardLayoutForInputDevice()")) { 892 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 893 } 894 if (inputDeviceDescriptor == null) { 895 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 896 } 897 if (keyboardLayoutDescriptor == null) { 898 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 899 } 900 901 synchronized (mDataStore) { 902 try { 903 String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor); 904 if (mDataStore.addKeyboardLayout(inputDeviceDescriptor, keyboardLayoutDescriptor) 905 && !Objects.equal(oldLayout, 906 mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) { 907 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 908 } 909 } finally { 910 mDataStore.saveIfNeeded(); 911 } 912 } 913 } 914 915 @Override // Binder call 916 public void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor, 917 String keyboardLayoutDescriptor) { 918 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 919 "removeKeyboardLayoutForInputDevice()")) { 920 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 921 } 922 if (inputDeviceDescriptor == null) { 923 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 924 } 925 if (keyboardLayoutDescriptor == null) { 926 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 927 } 928 929 synchronized (mDataStore) { 930 try { 931 String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor); 932 if (mDataStore.removeKeyboardLayout(inputDeviceDescriptor, 933 keyboardLayoutDescriptor) 934 && !Objects.equal(oldLayout, 935 mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) { 936 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 937 } 938 } finally { 939 mDataStore.saveIfNeeded(); 940 } 941 } 942 } 943 944 public void switchKeyboardLayout(int deviceId, int direction) { 945 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget(); 946 } 947 948 // Must be called on handler. 949 private void handleSwitchKeyboardLayout(int deviceId, int direction) { 950 final InputDevice device = getInputDevice(deviceId); 951 final String inputDeviceDescriptor = device.getDescriptor(); 952 if (device != null) { 953 final boolean changed; 954 final String keyboardLayoutDescriptor; 955 synchronized (mDataStore) { 956 try { 957 changed = mDataStore.switchKeyboardLayout(inputDeviceDescriptor, direction); 958 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout( 959 inputDeviceDescriptor); 960 } finally { 961 mDataStore.saveIfNeeded(); 962 } 963 } 964 965 if (changed) { 966 if (mSwitchedKeyboardLayoutToast != null) { 967 mSwitchedKeyboardLayoutToast.cancel(); 968 mSwitchedKeyboardLayoutToast = null; 969 } 970 if (keyboardLayoutDescriptor != null) { 971 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor); 972 if (keyboardLayout != null) { 973 mSwitchedKeyboardLayoutToast = Toast.makeText( 974 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT); 975 mSwitchedKeyboardLayoutToast.show(); 976 } 977 } 978 979 reloadKeyboardLayouts(); 980 } 981 } 982 } 983 984 public void setInputWindows(InputWindowHandle[] windowHandles) { 985 nativeSetInputWindows(mPtr, windowHandles); 986 } 987 988 public void setFocusedApplication(InputApplicationHandle application) { 989 nativeSetFocusedApplication(mPtr, application); 990 } 991 992 public void setInputDispatchMode(boolean enabled, boolean frozen) { 993 nativeSetInputDispatchMode(mPtr, enabled, frozen); 994 } 995 996 public void setSystemUiVisibility(int visibility) { 997 nativeSetSystemUiVisibility(mPtr, visibility); 998 } 999 1000 /** 1001 * Atomically transfers touch focus from one window to another as identified by 1002 * their input channels. It is possible for multiple windows to have 1003 * touch focus if they support split touch dispatch 1004 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this 1005 * method only transfers touch focus of the specified window without affecting 1006 * other windows that may also have touch focus at the same time. 1007 * @param fromChannel The channel of a window that currently has touch focus. 1008 * @param toChannel The channel of the window that should receive touch focus in 1009 * place of the first. 1010 * @return True if the transfer was successful. False if the window with the 1011 * specified channel did not actually have touch focus at the time of the request. 1012 */ 1013 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) { 1014 if (fromChannel == null) { 1015 throw new IllegalArgumentException("fromChannel must not be null."); 1016 } 1017 if (toChannel == null) { 1018 throw new IllegalArgumentException("toChannel must not be null."); 1019 } 1020 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel); 1021 } 1022 1023 @Override // Binder call 1024 public void tryPointerSpeed(int speed) { 1025 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, 1026 "tryPointerSpeed()")) { 1027 throw new SecurityException("Requires SET_POINTER_SPEED permission"); 1028 } 1029 1030 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) { 1031 throw new IllegalArgumentException("speed out of range"); 1032 } 1033 1034 setPointerSpeedUnchecked(speed); 1035 } 1036 1037 public void updatePointerSpeedFromSettings() { 1038 int speed = getPointerSpeedSetting(); 1039 setPointerSpeedUnchecked(speed); 1040 } 1041 1042 private void setPointerSpeedUnchecked(int speed) { 1043 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED), 1044 InputManager.MAX_POINTER_SPEED); 1045 nativeSetPointerSpeed(mPtr, speed); 1046 } 1047 1048 private void registerPointerSpeedSettingObserver() { 1049 mContext.getContentResolver().registerContentObserver( 1050 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true, 1051 new ContentObserver(mHandler) { 1052 @Override 1053 public void onChange(boolean selfChange) { 1054 updatePointerSpeedFromSettings(); 1055 } 1056 }); 1057 } 1058 1059 private int getPointerSpeedSetting() { 1060 int speed = InputManager.DEFAULT_POINTER_SPEED; 1061 try { 1062 speed = Settings.System.getInt(mContext.getContentResolver(), 1063 Settings.System.POINTER_SPEED); 1064 } catch (SettingNotFoundException snfe) { 1065 } 1066 return speed; 1067 } 1068 1069 public void updateShowTouchesFromSettings() { 1070 int setting = getShowTouchesSetting(0); 1071 nativeSetShowTouches(mPtr, setting != 0); 1072 } 1073 1074 private void registerShowTouchesSettingObserver() { 1075 mContext.getContentResolver().registerContentObserver( 1076 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true, 1077 new ContentObserver(mHandler) { 1078 @Override 1079 public void onChange(boolean selfChange) { 1080 updateShowTouchesFromSettings(); 1081 } 1082 }); 1083 } 1084 1085 private int getShowTouchesSetting(int defaultValue) { 1086 int result = defaultValue; 1087 try { 1088 result = Settings.System.getInt(mContext.getContentResolver(), 1089 Settings.System.SHOW_TOUCHES); 1090 } catch (SettingNotFoundException snfe) { 1091 } 1092 return result; 1093 } 1094 1095 // Binder call 1096 @Override 1097 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) { 1098 if (repeat >= pattern.length) { 1099 throw new ArrayIndexOutOfBoundsException(); 1100 } 1101 1102 VibratorToken v; 1103 synchronized (mVibratorLock) { 1104 v = mVibratorTokens.get(token); 1105 if (v == null) { 1106 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++); 1107 try { 1108 token.linkToDeath(v, 0); 1109 } catch (RemoteException ex) { 1110 // give up 1111 throw new RuntimeException(ex); 1112 } 1113 mVibratorTokens.put(token, v); 1114 } 1115 } 1116 1117 synchronized (v) { 1118 v.mVibrating = true; 1119 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue); 1120 } 1121 } 1122 1123 // Binder call 1124 @Override 1125 public void cancelVibrate(int deviceId, IBinder token) { 1126 VibratorToken v; 1127 synchronized (mVibratorLock) { 1128 v = mVibratorTokens.get(token); 1129 if (v == null || v.mDeviceId != deviceId) { 1130 return; // nothing to cancel 1131 } 1132 } 1133 1134 cancelVibrateIfNeeded(v); 1135 } 1136 1137 void onVibratorTokenDied(VibratorToken v) { 1138 synchronized (mVibratorLock) { 1139 mVibratorTokens.remove(v.mToken); 1140 } 1141 1142 cancelVibrateIfNeeded(v); 1143 } 1144 1145 private void cancelVibrateIfNeeded(VibratorToken v) { 1146 synchronized (v) { 1147 if (v.mVibrating) { 1148 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue); 1149 v.mVibrating = false; 1150 } 1151 } 1152 } 1153 1154 @Override 1155 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1156 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 1157 != PackageManager.PERMISSION_GRANTED) { 1158 pw.println("Permission Denial: can't dump InputManager from from pid=" 1159 + Binder.getCallingPid() 1160 + ", uid=" + Binder.getCallingUid()); 1161 return; 1162 } 1163 1164 pw.println("INPUT MANAGER (dumpsys input)\n"); 1165 String dumpStr = nativeDump(mPtr); 1166 if (dumpStr != null) { 1167 pw.println(dumpStr); 1168 } 1169 } 1170 1171 private boolean checkCallingPermission(String permission, String func) { 1172 // Quick check: if the calling permission is me, it's all okay. 1173 if (Binder.getCallingPid() == Process.myPid()) { 1174 return true; 1175 } 1176 1177 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { 1178 return true; 1179 } 1180 String msg = "Permission Denial: " + func + " from pid=" 1181 + Binder.getCallingPid() 1182 + ", uid=" + Binder.getCallingUid() 1183 + " requires " + permission; 1184 Slog.w(TAG, msg); 1185 return false; 1186 } 1187 1188 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). 1189 public void monitor() { 1190 synchronized (mInputFilterLock) { } 1191 nativeMonitor(mPtr); 1192 } 1193 1194 // Native callback. 1195 private void notifyConfigurationChanged(long whenNanos) { 1196 mCallbacks.notifyConfigurationChanged(); 1197 } 1198 1199 // Native callback. 1200 private void notifyInputDevicesChanged(InputDevice[] inputDevices) { 1201 synchronized (mInputDevicesLock) { 1202 if (!mInputDevicesChangedPending) { 1203 mInputDevicesChangedPending = true; 1204 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED, 1205 mInputDevices).sendToTarget(); 1206 } 1207 1208 mInputDevices = inputDevices; 1209 } 1210 } 1211 1212 // Native callback. 1213 private void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { 1214 mCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); 1215 } 1216 1217 // Native callback. 1218 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { 1219 mCallbacks.notifyInputChannelBroken(inputWindowHandle); 1220 } 1221 1222 // Native callback. 1223 private long notifyANR(InputApplicationHandle inputApplicationHandle, 1224 InputWindowHandle inputWindowHandle) { 1225 return mCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle); 1226 } 1227 1228 // Native callback. 1229 final boolean filterInputEvent(InputEvent event, int policyFlags) { 1230 synchronized (mInputFilterLock) { 1231 if (mInputFilter != null) { 1232 mInputFilter.filterInputEvent(event, policyFlags); 1233 return false; 1234 } 1235 } 1236 event.recycle(); 1237 return true; 1238 } 1239 1240 // Native callback. 1241 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) { 1242 return mCallbacks.interceptKeyBeforeQueueing( 1243 event, policyFlags, isScreenOn); 1244 } 1245 1246 // Native callback. 1247 private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { 1248 return mCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags); 1249 } 1250 1251 // Native callback. 1252 private long interceptKeyBeforeDispatching(InputWindowHandle focus, 1253 KeyEvent event, int policyFlags) { 1254 return mCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); 1255 } 1256 1257 // Native callback. 1258 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 1259 KeyEvent event, int policyFlags) { 1260 return mCallbacks.dispatchUnhandledKey(focus, event, policyFlags); 1261 } 1262 1263 // Native callback. 1264 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) { 1265 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS, 1266 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED; 1267 } 1268 1269 // Native callback. 1270 private int getVirtualKeyQuietTimeMillis() { 1271 return mContext.getResources().getInteger( 1272 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis); 1273 } 1274 1275 // Native callback. 1276 private String[] getExcludedDeviceNames() { 1277 ArrayList<String> names = new ArrayList<String>(); 1278 1279 // Read partner-provided list of excluded input devices 1280 XmlPullParser parser = null; 1281 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". 1282 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH); 1283 FileReader confreader = null; 1284 try { 1285 confreader = new FileReader(confFile); 1286 parser = Xml.newPullParser(); 1287 parser.setInput(confreader); 1288 XmlUtils.beginDocument(parser, "devices"); 1289 1290 while (true) { 1291 XmlUtils.nextElement(parser); 1292 if (!"device".equals(parser.getName())) { 1293 break; 1294 } 1295 String name = parser.getAttributeValue(null, "name"); 1296 if (name != null) { 1297 names.add(name); 1298 } 1299 } 1300 } catch (FileNotFoundException e) { 1301 // It's ok if the file does not exist. 1302 } catch (Exception e) { 1303 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e); 1304 } finally { 1305 try { if (confreader != null) confreader.close(); } catch (IOException e) { } 1306 } 1307 1308 return names.toArray(new String[names.size()]); 1309 } 1310 1311 // Native callback. 1312 private int getKeyRepeatTimeout() { 1313 return ViewConfiguration.getKeyRepeatTimeout(); 1314 } 1315 1316 // Native callback. 1317 private int getKeyRepeatDelay() { 1318 return ViewConfiguration.getKeyRepeatDelay(); 1319 } 1320 1321 // Native callback. 1322 private int getHoverTapTimeout() { 1323 return ViewConfiguration.getHoverTapTimeout(); 1324 } 1325 1326 // Native callback. 1327 private int getHoverTapSlop() { 1328 return ViewConfiguration.getHoverTapSlop(); 1329 } 1330 1331 // Native callback. 1332 private int getDoubleTapTimeout() { 1333 return ViewConfiguration.getDoubleTapTimeout(); 1334 } 1335 1336 // Native callback. 1337 private int getLongPressTimeout() { 1338 return ViewConfiguration.getLongPressTimeout(); 1339 } 1340 1341 // Native callback. 1342 private int getPointerLayer() { 1343 return mCallbacks.getPointerLayer(); 1344 } 1345 1346 // Native callback. 1347 private PointerIcon getPointerIcon() { 1348 return PointerIcon.getDefaultIcon(mContext); 1349 } 1350 1351 // Native callback. 1352 private String[] getKeyboardLayoutOverlay(String inputDeviceDescriptor) { 1353 if (!mSystemReady) { 1354 return null; 1355 } 1356 1357 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice( 1358 inputDeviceDescriptor); 1359 if (keyboardLayoutDescriptor == null) { 1360 return null; 1361 } 1362 1363 final String[] result = new String[2]; 1364 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 1365 @Override 1366 public void visitKeyboardLayout(Resources resources, 1367 String descriptor, String label, String collection, int keyboardLayoutResId) { 1368 try { 1369 result[0] = descriptor; 1370 result[1] = Streams.readFully(new InputStreamReader( 1371 resources.openRawResource(keyboardLayoutResId))); 1372 } catch (IOException ex) { 1373 } catch (NotFoundException ex) { 1374 } 1375 } 1376 }); 1377 if (result[0] == null) { 1378 Log.w(TAG, "Could not get keyboard layout with descriptor '" 1379 + keyboardLayoutDescriptor + "'."); 1380 return null; 1381 } 1382 return result; 1383 } 1384 1385 // Native callback. 1386 private String getDeviceAlias(String uniqueId) { 1387 if (mBluetoothService != null && 1388 BluetoothAdapter.checkBluetoothAddress(uniqueId)) { 1389 return mBluetoothService.getRemoteAlias(uniqueId); 1390 } 1391 return null; 1392 } 1393 1394 1395 /** 1396 * Callback interface implemented by the Window Manager. 1397 */ 1398 public interface Callbacks { 1399 public void notifyConfigurationChanged(); 1400 1401 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen); 1402 1403 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle); 1404 1405 public long notifyANR(InputApplicationHandle inputApplicationHandle, 1406 InputWindowHandle inputWindowHandle); 1407 1408 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn); 1409 1410 public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags); 1411 1412 public long interceptKeyBeforeDispatching(InputWindowHandle focus, 1413 KeyEvent event, int policyFlags); 1414 1415 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 1416 KeyEvent event, int policyFlags); 1417 1418 public int getPointerLayer(); 1419 } 1420 1421 /** 1422 * Private handler for the input manager. 1423 */ 1424 private final class InputManagerHandler extends Handler { 1425 @Override 1426 public void handleMessage(Message msg) { 1427 switch (msg.what) { 1428 case MSG_DELIVER_INPUT_DEVICES_CHANGED: 1429 deliverInputDevicesChanged((InputDevice[])msg.obj); 1430 break; 1431 case MSG_SWITCH_KEYBOARD_LAYOUT: 1432 handleSwitchKeyboardLayout(msg.arg1, msg.arg2); 1433 break; 1434 case MSG_RELOAD_KEYBOARD_LAYOUTS: 1435 reloadKeyboardLayouts(); 1436 break; 1437 case MSG_UPDATE_KEYBOARD_LAYOUTS: 1438 updateKeyboardLayouts(); 1439 break; 1440 case MSG_RELOAD_DEVICE_ALIASES: 1441 reloadDeviceAliases(); 1442 break; 1443 } 1444 } 1445 } 1446 1447 /** 1448 * Hosting interface for input filters to call back into the input manager. 1449 */ 1450 private final class InputFilterHost implements InputFilter.Host { 1451 private boolean mDisconnected; 1452 1453 public void disconnectLocked() { 1454 mDisconnected = true; 1455 } 1456 1457 public void sendInputEvent(InputEvent event, int policyFlags) { 1458 if (event == null) { 1459 throw new IllegalArgumentException("event must not be null"); 1460 } 1461 1462 synchronized (mInputFilterLock) { 1463 if (!mDisconnected) { 1464 nativeInjectInputEvent(mPtr, event, 0, 0, 1465 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0, 1466 policyFlags | WindowManagerPolicy.FLAG_FILTERED); 1467 } 1468 } 1469 } 1470 } 1471 1472 private static final class KeyboardLayoutDescriptor { 1473 public String packageName; 1474 public String receiverName; 1475 public String keyboardLayoutName; 1476 1477 public static String format(String packageName, 1478 String receiverName, String keyboardName) { 1479 return packageName + "/" + receiverName + "/" + keyboardName; 1480 } 1481 1482 public static KeyboardLayoutDescriptor parse(String descriptor) { 1483 int pos = descriptor.indexOf('/'); 1484 if (pos < 0 || pos + 1 == descriptor.length()) { 1485 return null; 1486 } 1487 int pos2 = descriptor.indexOf('/', pos + 1); 1488 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) { 1489 return null; 1490 } 1491 1492 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor(); 1493 result.packageName = descriptor.substring(0, pos); 1494 result.receiverName = descriptor.substring(pos + 1, pos2); 1495 result.keyboardLayoutName = descriptor.substring(pos2 + 1); 1496 return result; 1497 } 1498 } 1499 1500 private interface KeyboardLayoutVisitor { 1501 void visitKeyboardLayout(Resources resources, 1502 String descriptor, String label, String collection, int keyboardLayoutResId); 1503 } 1504 1505 private final class InputDevicesChangedListenerRecord implements DeathRecipient { 1506 private final int mPid; 1507 private final IInputDevicesChangedListener mListener; 1508 1509 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) { 1510 mPid = pid; 1511 mListener = listener; 1512 } 1513 1514 @Override 1515 public void binderDied() { 1516 if (DEBUG) { 1517 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died."); 1518 } 1519 onInputDevicesChangedListenerDied(mPid); 1520 } 1521 1522 public void notifyInputDevicesChanged(int[] info) { 1523 try { 1524 mListener.onInputDevicesChanged(info); 1525 } catch (RemoteException ex) { 1526 Slog.w(TAG, "Failed to notify process " 1527 + mPid + " that input devices changed, assuming it died.", ex); 1528 binderDied(); 1529 } 1530 } 1531 } 1532 1533 private final class VibratorToken implements DeathRecipient { 1534 public final int mDeviceId; 1535 public final IBinder mToken; 1536 public final int mTokenValue; 1537 1538 public boolean mVibrating; 1539 1540 public VibratorToken(int deviceId, IBinder token, int tokenValue) { 1541 mDeviceId = deviceId; 1542 mToken = token; 1543 mTokenValue = tokenValue; 1544 } 1545 1546 @Override 1547 public void binderDied() { 1548 if (DEBUG) { 1549 Slog.d(TAG, "Vibrator token died."); 1550 } 1551 onVibratorTokenDied(this); 1552 } 1553 } 1554 } 1555