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