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