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