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