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