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