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