InputManagerService.java revision 38f96e5020b3e82b98fe97b0be363a5ad185860f
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(int policyFlags) { 1333 return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags); 1334 } 1335 1336 // Native callback. 1337 private long interceptKeyBeforeDispatching(InputWindowHandle focus, 1338 KeyEvent event, int policyFlags) { 1339 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); 1340 } 1341 1342 // Native callback. 1343 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 1344 KeyEvent event, int policyFlags) { 1345 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags); 1346 } 1347 1348 // Native callback. 1349 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) { 1350 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS, 1351 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED; 1352 } 1353 1354 // Native callback. 1355 private int getVirtualKeyQuietTimeMillis() { 1356 return mContext.getResources().getInteger( 1357 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis); 1358 } 1359 1360 // Native callback. 1361 private String[] getExcludedDeviceNames() { 1362 ArrayList<String> names = new ArrayList<String>(); 1363 1364 // Read partner-provided list of excluded input devices 1365 XmlPullParser parser = null; 1366 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". 1367 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH); 1368 FileReader confreader = null; 1369 try { 1370 confreader = new FileReader(confFile); 1371 parser = Xml.newPullParser(); 1372 parser.setInput(confreader); 1373 XmlUtils.beginDocument(parser, "devices"); 1374 1375 while (true) { 1376 XmlUtils.nextElement(parser); 1377 if (!"device".equals(parser.getName())) { 1378 break; 1379 } 1380 String name = parser.getAttributeValue(null, "name"); 1381 if (name != null) { 1382 names.add(name); 1383 } 1384 } 1385 } catch (FileNotFoundException e) { 1386 // It's ok if the file does not exist. 1387 } catch (Exception e) { 1388 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e); 1389 } finally { 1390 try { if (confreader != null) confreader.close(); } catch (IOException e) { } 1391 } 1392 1393 return names.toArray(new String[names.size()]); 1394 } 1395 1396 // Native callback. 1397 private int getKeyRepeatTimeout() { 1398 return ViewConfiguration.getKeyRepeatTimeout(); 1399 } 1400 1401 // Native callback. 1402 private int getKeyRepeatDelay() { 1403 return ViewConfiguration.getKeyRepeatDelay(); 1404 } 1405 1406 // Native callback. 1407 private int getHoverTapTimeout() { 1408 return ViewConfiguration.getHoverTapTimeout(); 1409 } 1410 1411 // Native callback. 1412 private int getHoverTapSlop() { 1413 return ViewConfiguration.getHoverTapSlop(); 1414 } 1415 1416 // Native callback. 1417 private int getDoubleTapTimeout() { 1418 return ViewConfiguration.getDoubleTapTimeout(); 1419 } 1420 1421 // Native callback. 1422 private int getLongPressTimeout() { 1423 return ViewConfiguration.getLongPressTimeout(); 1424 } 1425 1426 // Native callback. 1427 private int getPointerLayer() { 1428 return mWindowManagerCallbacks.getPointerLayer(); 1429 } 1430 1431 // Native callback. 1432 private PointerIcon getPointerIcon() { 1433 return PointerIcon.getDefaultIcon(mContext); 1434 } 1435 1436 // Native callback. 1437 private String[] getKeyboardLayoutOverlay(String inputDeviceDescriptor) { 1438 if (!mSystemReady) { 1439 return null; 1440 } 1441 1442 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice( 1443 inputDeviceDescriptor); 1444 if (keyboardLayoutDescriptor == null) { 1445 return null; 1446 } 1447 1448 final String[] result = new String[2]; 1449 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 1450 @Override 1451 public void visitKeyboardLayout(Resources resources, 1452 String descriptor, String label, String collection, int keyboardLayoutResId) { 1453 try { 1454 result[0] = descriptor; 1455 result[1] = Streams.readFully(new InputStreamReader( 1456 resources.openRawResource(keyboardLayoutResId))); 1457 } catch (IOException ex) { 1458 } catch (NotFoundException ex) { 1459 } 1460 } 1461 }); 1462 if (result[0] == null) { 1463 Log.w(TAG, "Could not get keyboard layout with descriptor '" 1464 + keyboardLayoutDescriptor + "'."); 1465 return null; 1466 } 1467 return result; 1468 } 1469 1470 // Native callback. 1471 private String getDeviceAlias(String uniqueId) { 1472 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) { 1473 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId) 1474 return null; 1475 } 1476 return null; 1477 } 1478 1479 /** 1480 * Callback interface implemented by the Window Manager. 1481 */ 1482 public interface WindowManagerCallbacks { 1483 public void notifyConfigurationChanged(); 1484 1485 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen); 1486 1487 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle); 1488 1489 public long notifyANR(InputApplicationHandle inputApplicationHandle, 1490 InputWindowHandle inputWindowHandle, String reason); 1491 1492 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn); 1493 1494 public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags); 1495 1496 public long interceptKeyBeforeDispatching(InputWindowHandle focus, 1497 KeyEvent event, int policyFlags); 1498 1499 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 1500 KeyEvent event, int policyFlags); 1501 1502 public int getPointerLayer(); 1503 } 1504 1505 /** 1506 * Callback interface implemented by WiredAccessoryObserver. 1507 */ 1508 public interface WiredAccessoryCallbacks { 1509 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask); 1510 } 1511 1512 /** 1513 * Private handler for the input manager. 1514 */ 1515 private final class InputManagerHandler extends Handler { 1516 public InputManagerHandler(Looper looper) { 1517 super(looper, null, true /*async*/); 1518 } 1519 1520 @Override 1521 public void handleMessage(Message msg) { 1522 switch (msg.what) { 1523 case MSG_DELIVER_INPUT_DEVICES_CHANGED: 1524 deliverInputDevicesChanged((InputDevice[])msg.obj); 1525 break; 1526 case MSG_SWITCH_KEYBOARD_LAYOUT: 1527 handleSwitchKeyboardLayout(msg.arg1, msg.arg2); 1528 break; 1529 case MSG_RELOAD_KEYBOARD_LAYOUTS: 1530 reloadKeyboardLayouts(); 1531 break; 1532 case MSG_UPDATE_KEYBOARD_LAYOUTS: 1533 updateKeyboardLayouts(); 1534 break; 1535 case MSG_RELOAD_DEVICE_ALIASES: 1536 reloadDeviceAliases(); 1537 break; 1538 } 1539 } 1540 } 1541 1542 /** 1543 * Hosting interface for input filters to call back into the input manager. 1544 */ 1545 private final class InputFilterHost extends IInputFilterHost.Stub { 1546 private boolean mDisconnected; 1547 1548 public void disconnectLocked() { 1549 mDisconnected = true; 1550 } 1551 1552 @Override 1553 public void sendInputEvent(InputEvent event, int policyFlags) { 1554 if (event == null) { 1555 throw new IllegalArgumentException("event must not be null"); 1556 } 1557 1558 synchronized (mInputFilterLock) { 1559 if (!mDisconnected) { 1560 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0, 1561 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0, 1562 policyFlags | WindowManagerPolicy.FLAG_FILTERED); 1563 } 1564 } 1565 } 1566 } 1567 1568 private static final class KeyboardLayoutDescriptor { 1569 public String packageName; 1570 public String receiverName; 1571 public String keyboardLayoutName; 1572 1573 public static String format(String packageName, 1574 String receiverName, String keyboardName) { 1575 return packageName + "/" + receiverName + "/" + keyboardName; 1576 } 1577 1578 public static KeyboardLayoutDescriptor parse(String descriptor) { 1579 int pos = descriptor.indexOf('/'); 1580 if (pos < 0 || pos + 1 == descriptor.length()) { 1581 return null; 1582 } 1583 int pos2 = descriptor.indexOf('/', pos + 1); 1584 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) { 1585 return null; 1586 } 1587 1588 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor(); 1589 result.packageName = descriptor.substring(0, pos); 1590 result.receiverName = descriptor.substring(pos + 1, pos2); 1591 result.keyboardLayoutName = descriptor.substring(pos2 + 1); 1592 return result; 1593 } 1594 } 1595 1596 private interface KeyboardLayoutVisitor { 1597 void visitKeyboardLayout(Resources resources, 1598 String descriptor, String label, String collection, int keyboardLayoutResId); 1599 } 1600 1601 private final class InputDevicesChangedListenerRecord implements DeathRecipient { 1602 private final int mPid; 1603 private final IInputDevicesChangedListener mListener; 1604 1605 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) { 1606 mPid = pid; 1607 mListener = listener; 1608 } 1609 1610 @Override 1611 public void binderDied() { 1612 if (DEBUG) { 1613 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died."); 1614 } 1615 onInputDevicesChangedListenerDied(mPid); 1616 } 1617 1618 public void notifyInputDevicesChanged(int[] info) { 1619 try { 1620 mListener.onInputDevicesChanged(info); 1621 } catch (RemoteException ex) { 1622 Slog.w(TAG, "Failed to notify process " 1623 + mPid + " that input devices changed, assuming it died.", ex); 1624 binderDied(); 1625 } 1626 } 1627 } 1628 1629 private final class VibratorToken implements DeathRecipient { 1630 public final int mDeviceId; 1631 public final IBinder mToken; 1632 public final int mTokenValue; 1633 1634 public boolean mVibrating; 1635 1636 public VibratorToken(int deviceId, IBinder token, int tokenValue) { 1637 mDeviceId = deviceId; 1638 mToken = token; 1639 mTokenValue = tokenValue; 1640 } 1641 1642 @Override 1643 public void binderDied() { 1644 if (DEBUG) { 1645 Slog.d(TAG, "Vibrator token died."); 1646 } 1647 onVibratorTokenDied(this); 1648 } 1649 } 1650 1651 private final class LocalService extends InputManagerInternal { 1652 @Override 1653 public void setDisplayViewports( 1654 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) { 1655 setDisplayViewportsInternal(defaultViewport, externalTouchViewport); 1656 } 1657 1658 @Override 1659 public boolean injectInputEvent(InputEvent event, int displayId, int mode) { 1660 return injectInputEventInternal(event, displayId, mode); 1661 } 1662 } 1663} 1664