1 /* 2 * Copyright (C) 2012 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 17 package android.hardware.input; 18 19 import android.Manifest; 20 import android.annotation.FloatRange; 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.RequiresPermission; 25 import android.annotation.SdkConstant; 26 import android.annotation.SdkConstant.SdkConstantType; 27 import android.annotation.SystemService; 28 import android.annotation.TestApi; 29 import android.app.ActivityThread; 30 import android.compat.annotation.ChangeId; 31 import android.compat.annotation.UnsupportedAppUsage; 32 import android.content.Context; 33 import android.hardware.SensorManager; 34 import android.hardware.lights.Light; 35 import android.hardware.lights.LightState; 36 import android.hardware.lights.LightsManager; 37 import android.hardware.lights.LightsRequest; 38 import android.os.BlockUntrustedTouchesMode; 39 import android.os.Build; 40 import android.os.CombinedVibration; 41 import android.os.Handler; 42 import android.os.IBinder; 43 import android.os.IVibratorStateListener; 44 import android.os.InputEventInjectionSync; 45 import android.os.Looper; 46 import android.os.Message; 47 import android.os.RemoteException; 48 import android.os.ServiceManager; 49 import android.os.ServiceManager.ServiceNotFoundException; 50 import android.os.SystemClock; 51 import android.os.VibrationEffect; 52 import android.os.Vibrator; 53 import android.os.VibratorManager; 54 import android.provider.Settings; 55 import android.provider.Settings.SettingNotFoundException; 56 import android.util.Log; 57 import android.util.SparseArray; 58 import android.view.InputDevice; 59 import android.view.InputEvent; 60 import android.view.InputMonitor; 61 import android.view.MotionEvent; 62 import android.view.PointerIcon; 63 import android.view.VerifiedInputEvent; 64 import android.view.WindowManager.LayoutParams; 65 66 import com.android.internal.annotations.VisibleForTesting; 67 import com.android.internal.os.SomeArgs; 68 import com.android.internal.util.ArrayUtils; 69 70 import java.lang.annotation.Retention; 71 import java.lang.annotation.RetentionPolicy; 72 import java.util.ArrayList; 73 import java.util.List; 74 75 /** 76 * Provides information about input devices and available key layouts. 77 */ 78 @SystemService(Context.INPUT_SERVICE) 79 public final class InputManager { 80 private static final String TAG = "InputManager"; 81 private static final boolean DEBUG = false; 82 83 private static final int MSG_DEVICE_ADDED = 1; 84 private static final int MSG_DEVICE_REMOVED = 2; 85 private static final int MSG_DEVICE_CHANGED = 3; 86 87 /** @hide */ 88 public static final int[] BLOCK_UNTRUSTED_TOUCHES_MODES = { 89 BlockUntrustedTouchesMode.DISABLED, 90 BlockUntrustedTouchesMode.PERMISSIVE, 91 BlockUntrustedTouchesMode.BLOCK 92 }; 93 94 private static InputManager sInstance; 95 96 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 97 private final IInputManager mIm; 98 99 // Guarded by mInputDevicesLock 100 private final Object mInputDevicesLock = new Object(); 101 private SparseArray<InputDevice> mInputDevices; 102 private InputDevicesChangedListener mInputDevicesChangedListener; 103 private final ArrayList<InputDeviceListenerDelegate> mInputDeviceListeners = 104 new ArrayList<InputDeviceListenerDelegate>(); 105 106 // Guarded by mTabletModeLock 107 private final Object mTabletModeLock = new Object(); 108 private TabletModeChangedListener mTabletModeChangedListener; 109 private List<OnTabletModeChangedListenerDelegate> mOnTabletModeChangedListeners; 110 111 private InputDeviceSensorManager mInputDeviceSensorManager; 112 /** 113 * Broadcast Action: Query available keyboard layouts. 114 * <p> 115 * The input manager service locates available keyboard layouts 116 * by querying broadcast receivers that are registered for this action. 117 * An application can offer additional keyboard layouts to the user 118 * by declaring a suitable broadcast receiver in its manifest. 119 * </p><p> 120 * Here is an example broadcast receiver declaration that an application 121 * might include in its AndroidManifest.xml to advertise keyboard layouts. 122 * The meta-data specifies a resource that contains a description of each keyboard 123 * layout that is provided by the application. 124 * <pre><code> 125 * <receiver android:name=".InputDeviceReceiver" 126 * android:label="@string/keyboard_layouts_label"> 127 * <intent-filter> 128 * <action android:name="android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS" /> 129 * </intent-filter> 130 * <meta-data android:name="android.hardware.input.metadata.KEYBOARD_LAYOUTS" 131 * android:resource="@xml/keyboard_layouts" /> 132 * </receiver> 133 * </code></pre> 134 * </p><p> 135 * In the above example, the <code>@xml/keyboard_layouts</code> resource refers to 136 * an XML resource whose root element is <code><keyboard-layouts></code> that 137 * contains zero or more <code><keyboard-layout></code> elements. 138 * Each <code><keyboard-layout></code> element specifies the name, label, and location 139 * of a key character map for a particular keyboard layout. The label on the receiver 140 * is used to name the collection of keyboard layouts provided by this receiver in the 141 * keyboard layout settings. 142 * <pre><code> 143 * <?xml version="1.0" encoding="utf-8"?> 144 * <keyboard-layouts xmlns:android="http://schemas.android.com/apk/res/android"> 145 * <keyboard-layout android:name="keyboard_layout_english_us" 146 * android:label="@string/keyboard_layout_english_us_label" 147 * android:keyboardLayout="@raw/keyboard_layout_english_us" /> 148 * </keyboard-layouts> 149 * </pre></code> 150 * </p><p> 151 * The <code>android:name</code> attribute specifies an identifier by which 152 * the keyboard layout will be known in the package. 153 * The <code>android:label</code> attribute specifies a human-readable descriptive 154 * label to describe the keyboard layout in the user interface, such as "English (US)". 155 * The <code>android:keyboardLayout</code> attribute refers to a 156 * <a href="http://source.android.com/tech/input/key-character-map-files.html"> 157 * key character map</a> resource that defines the keyboard layout. 158 * </p> 159 */ 160 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 161 public static final String ACTION_QUERY_KEYBOARD_LAYOUTS = 162 "android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS"; 163 164 /** 165 * Metadata Key: Keyboard layout metadata associated with 166 * {@link #ACTION_QUERY_KEYBOARD_LAYOUTS}. 167 * <p> 168 * Specifies the resource id of a XML resource that describes the keyboard 169 * layouts that are provided by the application. 170 * </p> 171 */ 172 public static final String META_DATA_KEYBOARD_LAYOUTS = 173 "android.hardware.input.metadata.KEYBOARD_LAYOUTS"; 174 175 /** 176 * Pointer Speed: The minimum (slowest) pointer speed (-7). 177 * @hide 178 */ 179 public static final int MIN_POINTER_SPEED = -7; 180 181 /** 182 * Pointer Speed: The maximum (fastest) pointer speed (7). 183 * @hide 184 */ 185 public static final int MAX_POINTER_SPEED = 7; 186 187 /** 188 * Pointer Speed: The default pointer speed (0). 189 * @hide 190 */ 191 public static final int DEFAULT_POINTER_SPEED = 0; 192 193 /** 194 * The maximum allowed obscuring opacity by UID to propagate touches (0 <= x <= 1). 195 * @hide 196 */ 197 public static final float DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH = .8f; 198 199 /** 200 * Default mode of the block untrusted touches mode feature. 201 * @hide 202 */ 203 @BlockUntrustedTouchesMode 204 public static final int DEFAULT_BLOCK_UNTRUSTED_TOUCHES_MODE = 205 BlockUntrustedTouchesMode.BLOCK; 206 207 /** 208 * Prevent touches from being consumed by apps if these touches passed through a non-trusted 209 * window from a different UID and are considered unsafe. 210 * 211 * @hide 212 */ 213 @TestApi 214 @ChangeId 215 public static final long BLOCK_UNTRUSTED_TOUCHES = 158002302L; 216 217 /** 218 * Check whether apps are using FLAG_SLIPPERY for their windows. We expect that this flag is 219 * only used by the system components. If so, we can lock it down. 220 * @hide 221 */ 222 @ChangeId 223 public static final long BLOCK_FLAG_SLIPPERY = android.os.IInputConstants.BLOCK_FLAG_SLIPPERY; 224 225 /** 226 * Input Event Injection Synchronization Mode: None. 227 * Never blocks. Injection is asynchronous and is assumed always to be successful. 228 * @hide 229 */ 230 public static final int INJECT_INPUT_EVENT_MODE_ASYNC = InputEventInjectionSync.NONE; 231 232 /** 233 * Input Event Injection Synchronization Mode: Wait for result. 234 * Waits for previous events to be dispatched so that the input dispatcher can 235 * determine whether input event injection will be permitted based on the current 236 * input focus. Does not wait for the input event to finish being handled 237 * by the application. 238 * @hide 239 */ 240 public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 241 InputEventInjectionSync.WAIT_FOR_RESULT; 242 243 /** 244 * Input Event Injection Synchronization Mode: Wait for finish. 245 * Waits for the event to be delivered to the application and handled. 246 * @hide 247 */ 248 @UnsupportedAppUsage(trackingBug = 171972397) 249 public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 250 InputEventInjectionSync.WAIT_FOR_FINISHED; 251 252 /** @hide */ 253 @Retention(RetentionPolicy.SOURCE) 254 @IntDef(prefix = { "SWITCH_STATE_" }, value = { 255 SWITCH_STATE_UNKNOWN, 256 SWITCH_STATE_OFF, 257 SWITCH_STATE_ON 258 }) 259 public @interface SwitchState {} 260 261 /** 262 * Switch State: Unknown. 263 * 264 * The system has yet to report a valid value for the switch. 265 * @hide 266 */ 267 public static final int SWITCH_STATE_UNKNOWN = -1; 268 269 /** 270 * Switch State: Off. 271 * @hide 272 */ 273 public static final int SWITCH_STATE_OFF = 0; 274 275 /** 276 * Switch State: On. 277 * @hide 278 */ 279 public static final int SWITCH_STATE_ON = 1; 280 InputManager(IInputManager im)281 private InputManager(IInputManager im) { 282 mIm = im; 283 } 284 285 /** 286 * Gets an instance of the input manager. 287 * 288 * @return The input manager instance. 289 * 290 * @hide 291 */ 292 @VisibleForTesting resetInstance(IInputManager inputManagerService)293 public static InputManager resetInstance(IInputManager inputManagerService) { 294 synchronized (InputManager.class) { 295 sInstance = new InputManager(inputManagerService); 296 return sInstance; 297 } 298 } 299 300 /** 301 * Clear the instance of the input manager. 302 * 303 * @hide 304 */ 305 @VisibleForTesting clearInstance()306 public static void clearInstance() { 307 synchronized (InputManager.class) { 308 sInstance = null; 309 } 310 } 311 312 /** 313 * Gets an instance of the input manager. 314 * 315 * @return The input manager instance. 316 * 317 * @hide 318 */ 319 @UnsupportedAppUsage getInstance()320 public static InputManager getInstance() { 321 synchronized (InputManager.class) { 322 if (sInstance == null) { 323 try { 324 sInstance = new InputManager(IInputManager.Stub 325 .asInterface(ServiceManager.getServiceOrThrow(Context.INPUT_SERVICE))); 326 } catch (ServiceNotFoundException e) { 327 throw new IllegalStateException(e); 328 } 329 } 330 return sInstance; 331 } 332 } 333 334 /** 335 * Gets information about the input device with the specified id. 336 * @param id The device id. 337 * @return The input device or null if not found. 338 */ getInputDevice(int id)339 public InputDevice getInputDevice(int id) { 340 synchronized (mInputDevicesLock) { 341 populateInputDevicesLocked(); 342 343 int index = mInputDevices.indexOfKey(id); 344 if (index < 0) { 345 return null; 346 } 347 348 InputDevice inputDevice = mInputDevices.valueAt(index); 349 if (inputDevice == null) { 350 try { 351 inputDevice = mIm.getInputDevice(id); 352 } catch (RemoteException ex) { 353 throw ex.rethrowFromSystemServer(); 354 } 355 if (inputDevice != null) { 356 mInputDevices.setValueAt(index, inputDevice); 357 } 358 } 359 return inputDevice; 360 } 361 } 362 363 /** 364 * Gets information about the input device with the specified descriptor. 365 * @param descriptor The input device descriptor. 366 * @return The input device or null if not found. 367 * @hide 368 */ getInputDeviceByDescriptor(String descriptor)369 public InputDevice getInputDeviceByDescriptor(String descriptor) { 370 if (descriptor == null) { 371 throw new IllegalArgumentException("descriptor must not be null."); 372 } 373 374 synchronized (mInputDevicesLock) { 375 populateInputDevicesLocked(); 376 377 int numDevices = mInputDevices.size(); 378 for (int i = 0; i < numDevices; i++) { 379 InputDevice inputDevice = mInputDevices.valueAt(i); 380 if (inputDevice == null) { 381 int id = mInputDevices.keyAt(i); 382 try { 383 inputDevice = mIm.getInputDevice(id); 384 } catch (RemoteException ex) { 385 throw ex.rethrowFromSystemServer(); 386 } 387 if (inputDevice == null) { 388 continue; 389 } 390 mInputDevices.setValueAt(i, inputDevice); 391 } 392 if (descriptor.equals(inputDevice.getDescriptor())) { 393 return inputDevice; 394 } 395 } 396 return null; 397 } 398 } 399 400 /** 401 * Gets the ids of all input devices in the system. 402 * @return The input device ids. 403 */ getInputDeviceIds()404 public int[] getInputDeviceIds() { 405 synchronized (mInputDevicesLock) { 406 populateInputDevicesLocked(); 407 408 final int count = mInputDevices.size(); 409 final int[] ids = new int[count]; 410 for (int i = 0; i < count; i++) { 411 ids[i] = mInputDevices.keyAt(i); 412 } 413 return ids; 414 } 415 } 416 417 /** 418 * Returns true if an input device is enabled. Should return true for most 419 * situations. Some system apps may disable an input device, for 420 * example to prevent unwanted touch events. 421 * 422 * @param id The input device Id. 423 * 424 * @hide 425 */ isInputDeviceEnabled(int id)426 public boolean isInputDeviceEnabled(int id) { 427 try { 428 return mIm.isInputDeviceEnabled(id); 429 } catch (RemoteException ex) { 430 Log.w(TAG, "Could not check enabled status of input device with id = " + id); 431 throw ex.rethrowFromSystemServer(); 432 } 433 } 434 435 /** 436 * Enables an InputDevice. 437 * <p> 438 * Requires {@link android.Manifest.permissions.DISABLE_INPUT_DEVICE}. 439 * </p> 440 * 441 * @param id The input device Id. 442 * 443 * @hide 444 */ enableInputDevice(int id)445 public void enableInputDevice(int id) { 446 try { 447 mIm.enableInputDevice(id); 448 } catch (RemoteException ex) { 449 Log.w(TAG, "Could not enable input device with id = " + id); 450 throw ex.rethrowFromSystemServer(); 451 } 452 } 453 454 /** 455 * Disables an InputDevice. 456 * <p> 457 * Requires {@link android.Manifest.permissions.DISABLE_INPUT_DEVICE}. 458 * </p> 459 * 460 * @param id The input device Id. 461 * 462 * @hide 463 */ disableInputDevice(int id)464 public void disableInputDevice(int id) { 465 try { 466 mIm.disableInputDevice(id); 467 } catch (RemoteException ex) { 468 Log.w(TAG, "Could not disable input device with id = " + id); 469 throw ex.rethrowFromSystemServer(); 470 } 471 } 472 473 /** 474 * Registers an input device listener to receive notifications about when 475 * input devices are added, removed or changed. 476 * 477 * @param listener The listener to register. 478 * @param handler The handler on which the listener should be invoked, or null 479 * if the listener should be invoked on the calling thread's looper. 480 * 481 * @see #unregisterInputDeviceListener 482 */ registerInputDeviceListener(InputDeviceListener listener, Handler handler)483 public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { 484 if (listener == null) { 485 throw new IllegalArgumentException("listener must not be null"); 486 } 487 488 synchronized (mInputDevicesLock) { 489 populateInputDevicesLocked(); 490 int index = findInputDeviceListenerLocked(listener); 491 if (index < 0) { 492 mInputDeviceListeners.add(new InputDeviceListenerDelegate(listener, handler)); 493 } 494 } 495 } 496 497 /** 498 * Unregisters an input device listener. 499 * 500 * @param listener The listener to unregister. 501 * 502 * @see #registerInputDeviceListener 503 */ unregisterInputDeviceListener(InputDeviceListener listener)504 public void unregisterInputDeviceListener(InputDeviceListener listener) { 505 if (listener == null) { 506 throw new IllegalArgumentException("listener must not be null"); 507 } 508 509 synchronized (mInputDevicesLock) { 510 int index = findInputDeviceListenerLocked(listener); 511 if (index >= 0) { 512 InputDeviceListenerDelegate d = mInputDeviceListeners.get(index); 513 d.removeCallbacksAndMessages(null); 514 mInputDeviceListeners.remove(index); 515 } 516 } 517 } 518 findInputDeviceListenerLocked(InputDeviceListener listener)519 private int findInputDeviceListenerLocked(InputDeviceListener listener) { 520 final int numListeners = mInputDeviceListeners.size(); 521 for (int i = 0; i < numListeners; i++) { 522 if (mInputDeviceListeners.get(i).mListener == listener) { 523 return i; 524 } 525 } 526 return -1; 527 } 528 529 /** 530 * Queries whether the device is in tablet mode. 531 * 532 * @return The tablet switch state which is one of {@link #SWITCH_STATE_UNKNOWN}, 533 * {@link #SWITCH_STATE_OFF} or {@link #SWITCH_STATE_ON}. 534 * @hide 535 */ 536 @SwitchState isInTabletMode()537 public int isInTabletMode() { 538 try { 539 return mIm.isInTabletMode(); 540 } catch (RemoteException ex) { 541 throw ex.rethrowFromSystemServer(); 542 } 543 } 544 545 /** 546 * Register a tablet mode changed listener. 547 * 548 * @param listener The listener to register. 549 * @param handler The handler on which the listener should be invoked, or null 550 * if the listener should be invoked on the calling thread's looper. 551 * @hide 552 */ registerOnTabletModeChangedListener( OnTabletModeChangedListener listener, Handler handler)553 public void registerOnTabletModeChangedListener( 554 OnTabletModeChangedListener listener, Handler handler) { 555 if (listener == null) { 556 throw new IllegalArgumentException("listener must not be null"); 557 } 558 synchronized (mTabletModeLock) { 559 if (mOnTabletModeChangedListeners == null) { 560 initializeTabletModeListenerLocked(); 561 } 562 int idx = findOnTabletModeChangedListenerLocked(listener); 563 if (idx < 0) { 564 OnTabletModeChangedListenerDelegate d = 565 new OnTabletModeChangedListenerDelegate(listener, handler); 566 mOnTabletModeChangedListeners.add(d); 567 } 568 } 569 } 570 571 /** 572 * Unregister a tablet mode changed listener. 573 * 574 * @param listener The listener to unregister. 575 * @hide 576 */ unregisterOnTabletModeChangedListener(OnTabletModeChangedListener listener)577 public void unregisterOnTabletModeChangedListener(OnTabletModeChangedListener listener) { 578 if (listener == null) { 579 throw new IllegalArgumentException("listener must not be null"); 580 } 581 synchronized (mTabletModeLock) { 582 int idx = findOnTabletModeChangedListenerLocked(listener); 583 if (idx >= 0) { 584 OnTabletModeChangedListenerDelegate d = mOnTabletModeChangedListeners.remove(idx); 585 d.removeCallbacksAndMessages(null); 586 } 587 } 588 } 589 initializeTabletModeListenerLocked()590 private void initializeTabletModeListenerLocked() { 591 final TabletModeChangedListener listener = new TabletModeChangedListener(); 592 try { 593 mIm.registerTabletModeChangedListener(listener); 594 } catch (RemoteException ex) { 595 throw ex.rethrowFromSystemServer(); 596 } 597 mTabletModeChangedListener = listener; 598 mOnTabletModeChangedListeners = new ArrayList<>(); 599 } 600 findOnTabletModeChangedListenerLocked(OnTabletModeChangedListener listener)601 private int findOnTabletModeChangedListenerLocked(OnTabletModeChangedListener listener) { 602 final int N = mOnTabletModeChangedListeners.size(); 603 for (int i = 0; i < N; i++) { 604 if (mOnTabletModeChangedListeners.get(i).mListener == listener) { 605 return i; 606 } 607 } 608 return -1; 609 } 610 611 /** 612 * Queries whether the device's microphone is muted 613 * 614 * @return The mic mute switch state which is one of {@link #SWITCH_STATE_UNKNOWN}, 615 * {@link #SWITCH_STATE_OFF} or {@link #SWITCH_STATE_ON}. 616 * @hide 617 */ 618 @SwitchState isMicMuted()619 public int isMicMuted() { 620 try { 621 return mIm.isMicMuted(); 622 } catch (RemoteException ex) { 623 throw ex.rethrowFromSystemServer(); 624 } 625 } 626 627 /** 628 * Gets information about all supported keyboard layouts. 629 * <p> 630 * The input manager consults the built-in keyboard layouts as well 631 * as all keyboard layouts advertised by applications using a 632 * {@link #ACTION_QUERY_KEYBOARD_LAYOUTS} broadcast receiver. 633 * </p> 634 * 635 * @return A list of all supported keyboard layouts. 636 * 637 * @hide 638 */ getKeyboardLayouts()639 public KeyboardLayout[] getKeyboardLayouts() { 640 try { 641 return mIm.getKeyboardLayouts(); 642 } catch (RemoteException ex) { 643 throw ex.rethrowFromSystemServer(); 644 } 645 } 646 647 /** 648 * Gets information about all supported keyboard layouts appropriate 649 * for a specific input device. 650 * <p> 651 * The input manager consults the built-in keyboard layouts as well 652 * as all keyboard layouts advertised by applications using a 653 * {@link #ACTION_QUERY_KEYBOARD_LAYOUTS} broadcast receiver. 654 * </p> 655 * 656 * @return A list of all supported keyboard layouts for a specific 657 * input device. 658 * 659 * @hide 660 */ getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier)661 public KeyboardLayout[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { 662 try { 663 return mIm.getKeyboardLayoutsForInputDevice(identifier); 664 } catch (RemoteException ex) { 665 throw ex.rethrowFromSystemServer(); 666 } 667 } 668 669 /** 670 * Gets the keyboard layout with the specified descriptor. 671 * 672 * @param keyboardLayoutDescriptor The keyboard layout descriptor, as returned by 673 * {@link KeyboardLayout#getDescriptor()}. 674 * @return The keyboard layout, or null if it could not be loaded. 675 * 676 * @hide 677 */ getKeyboardLayout(String keyboardLayoutDescriptor)678 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) { 679 if (keyboardLayoutDescriptor == null) { 680 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 681 } 682 683 try { 684 return mIm.getKeyboardLayout(keyboardLayoutDescriptor); 685 } catch (RemoteException ex) { 686 throw ex.rethrowFromSystemServer(); 687 } 688 } 689 690 /** 691 * Gets the current keyboard layout descriptor for the specified input 692 * device. 693 * 694 * @param identifier Identifier for the input device 695 * @return The keyboard layout descriptor, or null if no keyboard layout has 696 * been set. 697 * @hide 698 */ getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier)699 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) { 700 try { 701 return mIm.getCurrentKeyboardLayoutForInputDevice(identifier); 702 } catch (RemoteException ex) { 703 throw ex.rethrowFromSystemServer(); 704 } 705 } 706 707 /** 708 * Sets the current keyboard layout descriptor for the specified input 709 * device. 710 * <p> 711 * This method may have the side-effect of causing the input device in 712 * question to be reconfigured. 713 * </p> 714 * 715 * @param identifier The identifier for the input device. 716 * @param keyboardLayoutDescriptor The keyboard layout descriptor to use, 717 * must not be null. 718 * @hide 719 */ setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)720 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 721 String keyboardLayoutDescriptor) { 722 if (identifier == null) { 723 throw new IllegalArgumentException("identifier must not be null"); 724 } 725 if (keyboardLayoutDescriptor == null) { 726 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 727 } 728 729 try { 730 mIm.setCurrentKeyboardLayoutForInputDevice(identifier, 731 keyboardLayoutDescriptor); 732 } catch (RemoteException ex) { 733 throw ex.rethrowFromSystemServer(); 734 } 735 } 736 737 /** 738 * Gets all keyboard layout descriptors that are enabled for the specified 739 * input device. 740 * 741 * @param identifier The identifier for the input device. 742 * @return The keyboard layout descriptors. 743 * @hide 744 */ getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier)745 public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { 746 if (identifier == null) { 747 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 748 } 749 750 try { 751 return mIm.getEnabledKeyboardLayoutsForInputDevice(identifier); 752 } catch (RemoteException ex) { 753 throw ex.rethrowFromSystemServer(); 754 } 755 } 756 757 /** 758 * Adds the keyboard layout descriptor for the specified input device. 759 * <p> 760 * This method may have the side-effect of causing the input device in 761 * question to be reconfigured. 762 * </p> 763 * 764 * @param identifier The identifier for the input device. 765 * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to 766 * add. 767 * @hide 768 */ addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)769 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 770 String keyboardLayoutDescriptor) { 771 if (identifier == null) { 772 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 773 } 774 if (keyboardLayoutDescriptor == null) { 775 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 776 } 777 778 try { 779 mIm.addKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor); 780 } catch (RemoteException ex) { 781 throw ex.rethrowFromSystemServer(); 782 } 783 } 784 785 /** 786 * Removes the keyboard layout descriptor for the specified input device. 787 * <p> 788 * This method may have the side-effect of causing the input device in 789 * question to be reconfigured. 790 * </p> 791 * 792 * @param identifier The identifier for the input device. 793 * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to 794 * remove. 795 * @hide 796 */ removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)797 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 798 String keyboardLayoutDescriptor) { 799 if (identifier == null) { 800 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 801 } 802 if (keyboardLayoutDescriptor == null) { 803 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 804 } 805 806 try { 807 mIm.removeKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor); 808 } catch (RemoteException ex) { 809 throw ex.rethrowFromSystemServer(); 810 } 811 } 812 813 /** 814 * Gets the TouchCalibration applied to the specified input device's coordinates. 815 * 816 * @param inputDeviceDescriptor The input device descriptor. 817 * @return The TouchCalibration currently assigned for use with the given 818 * input device. If none is set, an identity TouchCalibration is returned. 819 * 820 * @hide 821 */ getTouchCalibration(String inputDeviceDescriptor, int surfaceRotation)822 public TouchCalibration getTouchCalibration(String inputDeviceDescriptor, int surfaceRotation) { 823 try { 824 return mIm.getTouchCalibrationForInputDevice(inputDeviceDescriptor, surfaceRotation); 825 } catch (RemoteException ex) { 826 throw ex.rethrowFromSystemServer(); 827 } 828 } 829 830 /** 831 * Sets the TouchCalibration to apply to the specified input device's coordinates. 832 * <p> 833 * This method may have the side-effect of causing the input device in question 834 * to be reconfigured. Requires {@link android.Manifest.permissions.SET_INPUT_CALIBRATION}. 835 * </p> 836 * 837 * @param inputDeviceDescriptor The input device descriptor. 838 * @param calibration The calibration to be applied 839 * 840 * @hide 841 */ setTouchCalibration(String inputDeviceDescriptor, int surfaceRotation, TouchCalibration calibration)842 public void setTouchCalibration(String inputDeviceDescriptor, int surfaceRotation, 843 TouchCalibration calibration) { 844 try { 845 mIm.setTouchCalibrationForInputDevice(inputDeviceDescriptor, surfaceRotation, calibration); 846 } catch (RemoteException ex) { 847 throw ex.rethrowFromSystemServer(); 848 } 849 } 850 851 /** 852 * Gets the mouse pointer speed. 853 * <p> 854 * Only returns the permanent mouse pointer speed. Ignores any temporary pointer 855 * speed set by {@link #tryPointerSpeed}. 856 * </p> 857 * 858 * @param context The application context. 859 * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and 860 * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}. 861 * 862 * @hide 863 */ getPointerSpeed(Context context)864 public int getPointerSpeed(Context context) { 865 int speed = DEFAULT_POINTER_SPEED; 866 try { 867 speed = Settings.System.getInt(context.getContentResolver(), 868 Settings.System.POINTER_SPEED); 869 } catch (SettingNotFoundException snfe) { 870 } 871 return speed; 872 } 873 874 /** 875 * Sets the mouse pointer speed. 876 * <p> 877 * Requires {@link android.Manifest.permissions.WRITE_SETTINGS}. 878 * </p> 879 * 880 * @param context The application context. 881 * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and 882 * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}. 883 * 884 * @hide 885 */ setPointerSpeed(Context context, int speed)886 public void setPointerSpeed(Context context, int speed) { 887 if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) { 888 throw new IllegalArgumentException("speed out of range"); 889 } 890 891 Settings.System.putInt(context.getContentResolver(), 892 Settings.System.POINTER_SPEED, speed); 893 } 894 895 /** 896 * Changes the mouse pointer speed temporarily, but does not save the setting. 897 * <p> 898 * Requires {@link android.Manifest.permission.SET_POINTER_SPEED}. 899 * </p> 900 * 901 * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and 902 * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}. 903 * 904 * @hide 905 */ tryPointerSpeed(int speed)906 public void tryPointerSpeed(int speed) { 907 if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) { 908 throw new IllegalArgumentException("speed out of range"); 909 } 910 911 try { 912 mIm.tryPointerSpeed(speed); 913 } catch (RemoteException ex) { 914 throw ex.rethrowFromSystemServer(); 915 } 916 } 917 918 /** 919 * Returns the maximum allowed obscuring opacity per UID to propagate touches. 920 * 921 * <p>For certain window types (eg. {@link LayoutParams#TYPE_APPLICATION_OVERLAY}), the decision 922 * of honoring {@link LayoutParams#FLAG_NOT_TOUCHABLE} or not depends on the combined obscuring 923 * opacity of the windows above the touch-consuming window, per UID. Check documentation of 924 * {@link LayoutParams#FLAG_NOT_TOUCHABLE} for more details. 925 * 926 * <p>The value returned is between 0 (inclusive) and 1 (inclusive). 927 * 928 * @see LayoutParams#FLAG_NOT_TOUCHABLE 929 */ 930 @FloatRange(from = 0, to = 1) getMaximumObscuringOpacityForTouch()931 public float getMaximumObscuringOpacityForTouch() { 932 Context context = ActivityThread.currentApplication(); 933 return Settings.Global.getFloat(context.getContentResolver(), 934 Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH, 935 DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH); 936 } 937 938 /** 939 * Sets the maximum allowed obscuring opacity by UID to propagate touches. 940 * 941 * <p>For certain window types (eg. SAWs), the decision of honoring {@link LayoutParams 942 * #FLAG_NOT_TOUCHABLE} or not depends on the combined obscuring opacity of the windows 943 * above the touch-consuming window. 944 * 945 * <p>For a certain UID: 946 * <ul> 947 * <li>If it's the same as the UID of the touch-consuming window, allow it to propagate 948 * the touch. 949 * <li>Otherwise take all its windows of eligible window types above the touch-consuming 950 * window, compute their combined obscuring opacity considering that {@code 951 * opacity(A, B) = 1 - (1 - opacity(A))*(1 - opacity(B))}. If the computed value is 952 * lesser than or equal to this setting and there are no other windows preventing the 953 * touch, allow the UID to propagate the touch. 954 * </ul> 955 * 956 * <p>This value should be between 0 (inclusive) and 1 (inclusive). 957 * 958 * @see #getMaximumObscuringOpacityForTouch() 959 * 960 * @hide 961 */ 962 @TestApi 963 @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) setMaximumObscuringOpacityForTouch(@loatRangefrom = 0, to = 1) float opacity)964 public void setMaximumObscuringOpacityForTouch(@FloatRange(from = 0, to = 1) float opacity) { 965 if (opacity < 0 || opacity > 1) { 966 throw new IllegalArgumentException( 967 "Maximum obscuring opacity for touch should be >= 0 and <= 1"); 968 } 969 Context context = ActivityThread.currentApplication(); 970 Settings.Global.putFloat(context.getContentResolver(), 971 Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH, opacity); 972 } 973 974 /** 975 * Returns the current mode of the block untrusted touches feature, one of: 976 * <ul> 977 * <li>{@link BlockUntrustedTouchesMode#DISABLED} 978 * <li>{@link BlockUntrustedTouchesMode#PERMISSIVE} 979 * <li>{@link BlockUntrustedTouchesMode#BLOCK} 980 * </ul> 981 * 982 * @hide 983 */ 984 @TestApi 985 @BlockUntrustedTouchesMode getBlockUntrustedTouchesMode(@onNull Context context)986 public int getBlockUntrustedTouchesMode(@NonNull Context context) { 987 int mode = Settings.Global.getInt(context.getContentResolver(), 988 Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE, DEFAULT_BLOCK_UNTRUSTED_TOUCHES_MODE); 989 if (!ArrayUtils.contains(BLOCK_UNTRUSTED_TOUCHES_MODES, mode)) { 990 Log.w(TAG, "Unknown block untrusted touches feature mode " + mode + ", using " 991 + "default " + DEFAULT_BLOCK_UNTRUSTED_TOUCHES_MODE); 992 return DEFAULT_BLOCK_UNTRUSTED_TOUCHES_MODE; 993 } 994 return mode; 995 } 996 997 /** 998 * Sets the mode of the block untrusted touches feature to one of: 999 * <ul> 1000 * <li>{@link BlockUntrustedTouchesMode#DISABLED} 1001 * <li>{@link BlockUntrustedTouchesMode#PERMISSIVE} 1002 * <li>{@link BlockUntrustedTouchesMode#BLOCK} 1003 * </ul> 1004 * 1005 * @hide 1006 */ 1007 @TestApi 1008 @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) setBlockUntrustedTouchesMode(@onNull Context context, @BlockUntrustedTouchesMode int mode)1009 public void setBlockUntrustedTouchesMode(@NonNull Context context, 1010 @BlockUntrustedTouchesMode int mode) { 1011 if (!ArrayUtils.contains(BLOCK_UNTRUSTED_TOUCHES_MODES, mode)) { 1012 throw new IllegalArgumentException("Invalid feature mode " + mode); 1013 } 1014 Settings.Global.putInt(context.getContentResolver(), 1015 Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE, mode); 1016 } 1017 1018 /** 1019 * Queries the framework about whether any physical keys exist on the 1020 * any keyboard attached to the device that are capable of producing the given 1021 * array of key codes. 1022 * 1023 * @param keyCodes The array of key codes to query. 1024 * @return A new array of the same size as the key codes array whose elements 1025 * are set to true if at least one attached keyboard supports the corresponding key code 1026 * at the same index in the key codes array. 1027 * 1028 * @hide 1029 */ deviceHasKeys(int[] keyCodes)1030 public boolean[] deviceHasKeys(int[] keyCodes) { 1031 return deviceHasKeys(-1, keyCodes); 1032 } 1033 1034 /** 1035 * Queries the framework about whether any physical keys exist on the 1036 * any keyboard attached to the device that are capable of producing the given 1037 * array of key codes. 1038 * 1039 * @param id The id of the device to query. 1040 * @param keyCodes The array of key codes to query. 1041 * @return A new array of the same size as the key codes array whose elements are set to true 1042 * if the given device could produce the corresponding key code at the same index in the key 1043 * codes array. 1044 * 1045 * @hide 1046 */ deviceHasKeys(int id, int[] keyCodes)1047 public boolean[] deviceHasKeys(int id, int[] keyCodes) { 1048 boolean[] ret = new boolean[keyCodes.length]; 1049 try { 1050 mIm.hasKeys(id, InputDevice.SOURCE_ANY, keyCodes, ret); 1051 } catch (RemoteException e) { 1052 throw e.rethrowFromSystemServer(); 1053 } 1054 return ret; 1055 } 1056 1057 1058 /** 1059 * Injects an input event into the event system on behalf of an application. 1060 * The synchronization mode determines whether the method blocks while waiting for 1061 * input injection to proceed. 1062 * <p> 1063 * Requires {@link android.Manifest.permission.INJECT_EVENTS} to inject into 1064 * windows that are owned by other applications. 1065 * </p><p> 1066 * Make sure you correctly set the event time and input source of the event 1067 * before calling this method. 1068 * </p> 1069 * 1070 * @param event The event to inject. 1071 * @param mode The synchronization mode. One of: 1072 * {@link android.os.InputEventInjectionSync.NONE}, 1073 * {@link android.os.InputEventInjectionSync.WAIT_FOR_RESULT}, or 1074 * {@link android.os.InputEventInjectionSync.WAIT_FOR_FINISHED}. 1075 * @return True if input event injection succeeded. 1076 * 1077 * @hide 1078 */ 1079 @UnsupportedAppUsage injectInputEvent(InputEvent event, int mode)1080 public boolean injectInputEvent(InputEvent event, int mode) { 1081 if (event == null) { 1082 throw new IllegalArgumentException("event must not be null"); 1083 } 1084 if (mode != InputEventInjectionSync.NONE 1085 && mode != InputEventInjectionSync.WAIT_FOR_FINISHED 1086 && mode != InputEventInjectionSync.WAIT_FOR_RESULT) { 1087 throw new IllegalArgumentException("mode is invalid"); 1088 } 1089 1090 try { 1091 return mIm.injectInputEvent(event, mode); 1092 } catch (RemoteException ex) { 1093 throw ex.rethrowFromSystemServer(); 1094 } 1095 } 1096 1097 /** 1098 * Verify the details of an {@link android.view.InputEvent} that came from the system. 1099 * If the event did not come from the system, or its details could not be verified, then this 1100 * will return {@code null}. Receiving {@code null} does not mean that the event did not 1101 * originate from the system, just that we were unable to verify it. This can 1102 * happen for a number of reasons during normal operation. 1103 * 1104 * @param event The {@link android.view.InputEvent} to check 1105 * 1106 * @return {@link android.view.VerifiedInputEvent}, which is a subset of the provided 1107 * {@link android.view.InputEvent} 1108 * {@code null} if the event could not be verified. 1109 */ verifyInputEvent(@onNull InputEvent event)1110 public @Nullable VerifiedInputEvent verifyInputEvent(@NonNull InputEvent event) { 1111 try { 1112 return mIm.verifyInputEvent(event); 1113 } catch (RemoteException ex) { 1114 throw ex.rethrowFromSystemServer(); 1115 } 1116 } 1117 1118 /** 1119 * Changes the mouse pointer's icon shape into the specified id. 1120 * 1121 * @param iconId The id of the pointer graphic, as a value between 1122 * {@link PointerIcon.TYPE_ARROW} and {@link PointerIcon.TYPE_GRABBING}. 1123 * 1124 * @hide 1125 */ 1126 @UnsupportedAppUsage setPointerIconType(int iconId)1127 public void setPointerIconType(int iconId) { 1128 try { 1129 mIm.setPointerIconType(iconId); 1130 } catch (RemoteException ex) { 1131 throw ex.rethrowFromSystemServer(); 1132 } 1133 } 1134 1135 /** @hide */ setCustomPointerIcon(PointerIcon icon)1136 public void setCustomPointerIcon(PointerIcon icon) { 1137 try { 1138 mIm.setCustomPointerIcon(icon); 1139 } catch (RemoteException ex) { 1140 throw ex.rethrowFromSystemServer(); 1141 } 1142 } 1143 1144 /** 1145 * Request or release pointer capture. 1146 * <p> 1147 * When in capturing mode, the pointer icon disappears and all mouse events are dispatched to 1148 * the window which has requested the capture. Relative position changes are available through 1149 * {@link MotionEvent#getX} and {@link MotionEvent#getY}. 1150 * 1151 * @param enable true when requesting pointer capture, false when releasing. 1152 * 1153 * @hide 1154 */ requestPointerCapture(IBinder windowToken, boolean enable)1155 public void requestPointerCapture(IBinder windowToken, boolean enable) { 1156 try { 1157 mIm.requestPointerCapture(windowToken, enable); 1158 } catch (RemoteException ex) { 1159 throw ex.rethrowFromSystemServer(); 1160 } 1161 } 1162 1163 /** 1164 * Monitor input on the specified display for gestures. 1165 * 1166 * @hide 1167 */ monitorGestureInput(String name, int displayId)1168 public InputMonitor monitorGestureInput(String name, int displayId) { 1169 try { 1170 return mIm.monitorGestureInput(name, displayId); 1171 } catch (RemoteException ex) { 1172 throw ex.rethrowFromSystemServer(); 1173 } 1174 } 1175 1176 /** 1177 * Get sensors information as list. 1178 * 1179 * @hide 1180 */ getSensorList(int deviceId)1181 public InputSensorInfo[] getSensorList(int deviceId) { 1182 try { 1183 return mIm.getSensorList(deviceId); 1184 } catch (RemoteException ex) { 1185 throw ex.rethrowFromSystemServer(); 1186 } 1187 } 1188 1189 /** 1190 * Enable input device sensor 1191 * 1192 * @hide 1193 */ enableSensor(int deviceId, int sensorType, int samplingPeriodUs, int maxBatchReportLatencyUs)1194 public boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs, 1195 int maxBatchReportLatencyUs) { 1196 try { 1197 return mIm.enableSensor(deviceId, sensorType, samplingPeriodUs, 1198 maxBatchReportLatencyUs); 1199 } catch (RemoteException ex) { 1200 throw ex.rethrowFromSystemServer(); 1201 } 1202 } 1203 1204 /** 1205 * Enable input device sensor 1206 * 1207 * @hide 1208 */ disableSensor(int deviceId, int sensorType)1209 public void disableSensor(int deviceId, int sensorType) { 1210 try { 1211 mIm.disableSensor(deviceId, sensorType); 1212 } catch (RemoteException ex) { 1213 throw ex.rethrowFromSystemServer(); 1214 } 1215 } 1216 1217 /** 1218 * Flush input device sensor 1219 * 1220 * @hide 1221 */ flushSensor(int deviceId, int sensorType)1222 public boolean flushSensor(int deviceId, int sensorType) { 1223 try { 1224 return mIm.flushSensor(deviceId, sensorType); 1225 } catch (RemoteException ex) { 1226 throw ex.rethrowFromSystemServer(); 1227 } 1228 } 1229 1230 /** 1231 * Register input device sensor listener 1232 * 1233 * @hide 1234 */ registerSensorListener(IInputSensorEventListener listener)1235 public boolean registerSensorListener(IInputSensorEventListener listener) { 1236 try { 1237 return mIm.registerSensorListener(listener); 1238 } catch (RemoteException ex) { 1239 throw ex.rethrowFromSystemServer(); 1240 } 1241 } 1242 1243 /** 1244 * Unregister input device sensor listener 1245 * 1246 * @hide 1247 */ unregisterSensorListener(IInputSensorEventListener listener)1248 public void unregisterSensorListener(IInputSensorEventListener listener) { 1249 try { 1250 mIm.unregisterSensorListener(listener); 1251 } catch (RemoteException ex) { 1252 throw ex.rethrowFromSystemServer(); 1253 } 1254 } 1255 1256 /** 1257 * Get the battery status of the input device 1258 * @param deviceId The input device ID 1259 * @hide 1260 */ getBatteryStatus(int deviceId)1261 public int getBatteryStatus(int deviceId) { 1262 try { 1263 return mIm.getBatteryStatus(deviceId); 1264 } catch (RemoteException ex) { 1265 throw ex.rethrowFromSystemServer(); 1266 } 1267 } 1268 1269 /** 1270 * Get the remaining battery capacity of the input device 1271 * @param deviceId The input device ID 1272 * @hide 1273 */ getBatteryCapacity(int deviceId)1274 public int getBatteryCapacity(int deviceId) { 1275 try { 1276 return mIm.getBatteryCapacity(deviceId); 1277 } catch (RemoteException ex) { 1278 throw ex.rethrowFromSystemServer(); 1279 } 1280 } 1281 1282 /** 1283 * Add a runtime association between the input port and the display port. This overrides any 1284 * static associations. 1285 * @param inputPort The port of the input device. 1286 * @param displayPort The physical port of the associated display. 1287 * <p> 1288 * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}. 1289 * </p> 1290 * @hide 1291 */ addPortAssociation(@onNull String inputPort, int displayPort)1292 public void addPortAssociation(@NonNull String inputPort, int displayPort) { 1293 try { 1294 mIm.addPortAssociation(inputPort, displayPort); 1295 } catch (RemoteException ex) { 1296 throw ex.rethrowFromSystemServer(); 1297 } 1298 } 1299 1300 /** 1301 * Remove the runtime association between the input port and the display port. Any existing 1302 * static association for the cleared input port will be restored. 1303 * @param inputPort The port of the input device to be cleared. 1304 * <p> 1305 * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}. 1306 * </p> 1307 * @hide 1308 */ removePortAssociation(@onNull String inputPort)1309 public void removePortAssociation(@NonNull String inputPort) { 1310 try { 1311 mIm.removePortAssociation(inputPort); 1312 } catch (RemoteException ex) { 1313 throw ex.rethrowFromSystemServer(); 1314 } 1315 } 1316 1317 /** 1318 * Add a runtime association between the input device name and display, by unique id. Input 1319 * device names are expected to be unique. 1320 * @param inputDeviceName The name of the input device. 1321 * @param displayUniqueId The unique id of the associated display. 1322 * <p> 1323 * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}. 1324 * </p> 1325 * @hide 1326 */ addUniqueIdAssociation(@onNull String inputDeviceName, @NonNull String displayUniqueId)1327 public void addUniqueIdAssociation(@NonNull String inputDeviceName, 1328 @NonNull String displayUniqueId) { 1329 try { 1330 mIm.addUniqueIdAssociation(inputDeviceName, displayUniqueId); 1331 } catch (RemoteException e) { 1332 throw e.rethrowFromSystemServer(); 1333 } 1334 } 1335 1336 /** 1337 * Removes a runtime association between the input device and display. 1338 * @param inputDeviceName The name of the input device. 1339 * <p> 1340 * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}. 1341 * </p> 1342 * @hide 1343 */ removeUniqueIdAssociation(@onNull String inputDeviceName)1344 public void removeUniqueIdAssociation(@NonNull String inputDeviceName) { 1345 try { 1346 mIm.removeUniqueIdAssociation(inputDeviceName); 1347 } catch (RemoteException e) { 1348 throw e.rethrowFromSystemServer(); 1349 } 1350 } 1351 populateInputDevicesLocked()1352 private void populateInputDevicesLocked() { 1353 if (mInputDevicesChangedListener == null) { 1354 final InputDevicesChangedListener listener = new InputDevicesChangedListener(); 1355 try { 1356 mIm.registerInputDevicesChangedListener(listener); 1357 } catch (RemoteException ex) { 1358 throw ex.rethrowFromSystemServer(); 1359 } 1360 mInputDevicesChangedListener = listener; 1361 } 1362 1363 if (mInputDevices == null) { 1364 final int[] ids; 1365 try { 1366 ids = mIm.getInputDeviceIds(); 1367 } catch (RemoteException ex) { 1368 throw ex.rethrowFromSystemServer(); 1369 } 1370 1371 mInputDevices = new SparseArray<InputDevice>(); 1372 for (int i = 0; i < ids.length; i++) { 1373 mInputDevices.put(ids[i], null); 1374 } 1375 } 1376 } 1377 onInputDevicesChanged(int[] deviceIdAndGeneration)1378 private void onInputDevicesChanged(int[] deviceIdAndGeneration) { 1379 if (DEBUG) { 1380 Log.d(TAG, "Received input devices changed."); 1381 } 1382 1383 synchronized (mInputDevicesLock) { 1384 for (int i = mInputDevices.size(); --i > 0; ) { 1385 final int deviceId = mInputDevices.keyAt(i); 1386 if (!containsDeviceId(deviceIdAndGeneration, deviceId)) { 1387 if (DEBUG) { 1388 Log.d(TAG, "Device removed: " + deviceId); 1389 } 1390 mInputDevices.removeAt(i); 1391 sendMessageToInputDeviceListenersLocked(MSG_DEVICE_REMOVED, deviceId); 1392 } 1393 } 1394 1395 for (int i = 0; i < deviceIdAndGeneration.length; i += 2) { 1396 final int deviceId = deviceIdAndGeneration[i]; 1397 int index = mInputDevices.indexOfKey(deviceId); 1398 if (index >= 0) { 1399 final InputDevice device = mInputDevices.valueAt(index); 1400 if (device != null) { 1401 final int generation = deviceIdAndGeneration[i + 1]; 1402 if (device.getGeneration() != generation) { 1403 if (DEBUG) { 1404 Log.d(TAG, "Device changed: " + deviceId); 1405 } 1406 mInputDevices.setValueAt(index, null); 1407 sendMessageToInputDeviceListenersLocked(MSG_DEVICE_CHANGED, deviceId); 1408 } 1409 } 1410 } else { 1411 if (DEBUG) { 1412 Log.d(TAG, "Device added: " + deviceId); 1413 } 1414 mInputDevices.put(deviceId, null); 1415 sendMessageToInputDeviceListenersLocked(MSG_DEVICE_ADDED, deviceId); 1416 } 1417 } 1418 } 1419 } 1420 sendMessageToInputDeviceListenersLocked(int what, int deviceId)1421 private void sendMessageToInputDeviceListenersLocked(int what, int deviceId) { 1422 final int numListeners = mInputDeviceListeners.size(); 1423 for (int i = 0; i < numListeners; i++) { 1424 InputDeviceListenerDelegate listener = mInputDeviceListeners.get(i); 1425 listener.sendMessage(listener.obtainMessage(what, deviceId, 0)); 1426 } 1427 } 1428 containsDeviceId(int[] deviceIdAndGeneration, int deviceId)1429 private static boolean containsDeviceId(int[] deviceIdAndGeneration, int deviceId) { 1430 for (int i = 0; i < deviceIdAndGeneration.length; i += 2) { 1431 if (deviceIdAndGeneration[i] == deviceId) { 1432 return true; 1433 } 1434 } 1435 return false; 1436 } 1437 1438 onTabletModeChanged(long whenNanos, boolean inTabletMode)1439 private void onTabletModeChanged(long whenNanos, boolean inTabletMode) { 1440 if (DEBUG) { 1441 Log.d(TAG, "Received tablet mode changed: " 1442 + "whenNanos=" + whenNanos + ", inTabletMode=" + inTabletMode); 1443 } 1444 synchronized (mTabletModeLock) { 1445 final int N = mOnTabletModeChangedListeners.size(); 1446 for (int i = 0; i < N; i++) { 1447 OnTabletModeChangedListenerDelegate listener = 1448 mOnTabletModeChangedListeners.get(i); 1449 listener.sendTabletModeChanged(whenNanos, inTabletMode); 1450 } 1451 } 1452 } 1453 1454 /** 1455 * Gets a vibrator service associated with an input device, always creates a new instance. 1456 * @return The vibrator, never null. 1457 * @hide 1458 */ getInputDeviceVibrator(int deviceId, int vibratorId)1459 public Vibrator getInputDeviceVibrator(int deviceId, int vibratorId) { 1460 return new InputDeviceVibrator(this, deviceId, vibratorId); 1461 } 1462 1463 /** 1464 * Gets a vibrator manager service associated with an input device, always creates a new 1465 * instance. 1466 * @return The vibrator manager, never null. 1467 * @hide 1468 */ 1469 @NonNull getInputDeviceVibratorManager(int deviceId)1470 public VibratorManager getInputDeviceVibratorManager(int deviceId) { 1471 return new InputDeviceVibratorManager(InputManager.this, deviceId); 1472 } 1473 1474 /* 1475 * Get the list of device vibrators 1476 * @return The list of vibrators IDs 1477 */ getVibratorIds(int deviceId)1478 int[] getVibratorIds(int deviceId) { 1479 try { 1480 return mIm.getVibratorIds(deviceId); 1481 } catch (RemoteException ex) { 1482 throw ex.rethrowFromSystemServer(); 1483 } 1484 } 1485 1486 /* 1487 * Perform vibration effect 1488 */ vibrate(int deviceId, VibrationEffect effect, IBinder token)1489 void vibrate(int deviceId, VibrationEffect effect, IBinder token) { 1490 try { 1491 mIm.vibrate(deviceId, effect, token); 1492 } catch (RemoteException ex) { 1493 throw ex.rethrowFromSystemServer(); 1494 } 1495 } 1496 1497 /* 1498 * Perform combined vibration effect 1499 */ vibrate(int deviceId, CombinedVibration effect, IBinder token)1500 void vibrate(int deviceId, CombinedVibration effect, IBinder token) { 1501 try { 1502 mIm.vibrateCombined(deviceId, effect, token); 1503 } catch (RemoteException ex) { 1504 throw ex.rethrowFromSystemServer(); 1505 } 1506 } 1507 1508 /* 1509 * Cancel an ongoing vibration 1510 */ cancelVibrate(int deviceId, IBinder token)1511 void cancelVibrate(int deviceId, IBinder token) { 1512 try { 1513 mIm.cancelVibrate(deviceId, token); 1514 } catch (RemoteException ex) { 1515 throw ex.rethrowFromSystemServer(); 1516 } 1517 } 1518 1519 /* 1520 * Check if input device is vibrating 1521 */ isVibrating(int deviceId)1522 boolean isVibrating(int deviceId) { 1523 try { 1524 return mIm.isVibrating(deviceId); 1525 } catch (RemoteException ex) { 1526 throw ex.rethrowFromSystemServer(); 1527 } 1528 } 1529 1530 /** 1531 * Register input device vibrator state listener 1532 */ registerVibratorStateListener(int deviceId, IVibratorStateListener listener)1533 boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) { 1534 try { 1535 return mIm.registerVibratorStateListener(deviceId, listener); 1536 } catch (RemoteException ex) { 1537 throw ex.rethrowFromSystemServer(); 1538 } 1539 } 1540 1541 /** 1542 * Unregister input device vibrator state listener 1543 */ unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener)1544 boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) { 1545 try { 1546 return mIm.unregisterVibratorStateListener(deviceId, listener); 1547 } catch (RemoteException ex) { 1548 throw ex.rethrowFromSystemServer(); 1549 } 1550 } 1551 1552 /** 1553 * Gets a sensor manager service associated with an input device, always creates a new instance. 1554 * @return The sensor manager, never null. 1555 * @hide 1556 */ 1557 @NonNull getInputDeviceSensorManager(int deviceId)1558 public SensorManager getInputDeviceSensorManager(int deviceId) { 1559 if (mInputDeviceSensorManager == null) { 1560 mInputDeviceSensorManager = new InputDeviceSensorManager(this); 1561 } 1562 return mInputDeviceSensorManager.getSensorManager(deviceId); 1563 } 1564 1565 /** 1566 * Gets a battery state object associated with an input device, assuming it has one. 1567 * @return The battery, never null. 1568 * @hide 1569 */ getInputDeviceBatteryState(int deviceId, boolean hasBattery)1570 public InputDeviceBatteryState getInputDeviceBatteryState(int deviceId, boolean hasBattery) { 1571 return new InputDeviceBatteryState(this, deviceId, hasBattery); 1572 } 1573 1574 /** 1575 * Gets a lights manager associated with an input device, always creates a new instance. 1576 * @return The lights manager, never null. 1577 * @hide 1578 */ 1579 @NonNull getInputDeviceLightsManager(int deviceId)1580 public LightsManager getInputDeviceLightsManager(int deviceId) { 1581 return new InputDeviceLightsManager(InputManager.this, deviceId); 1582 } 1583 1584 /** 1585 * Gets a list of light objects associated with an input device. 1586 * @return The list of lights, never null. 1587 */ getLights(int deviceId)1588 @NonNull List<Light> getLights(int deviceId) { 1589 try { 1590 return mIm.getLights(deviceId); 1591 } catch (RemoteException e) { 1592 throw e.rethrowFromSystemServer(); 1593 } 1594 } 1595 1596 /** 1597 * Returns the state of an input device light. 1598 * @return the light state 1599 */ getLightState(int deviceId, @NonNull Light light)1600 @NonNull LightState getLightState(int deviceId, @NonNull Light light) { 1601 try { 1602 return mIm.getLightState(deviceId, light.getId()); 1603 } catch (RemoteException e) { 1604 throw e.rethrowFromSystemServer(); 1605 } 1606 } 1607 1608 /** 1609 * Request to modify the states of multiple lights. 1610 * 1611 * @param request the settings for lights that should change 1612 */ requestLights(int deviceId, @NonNull LightsRequest request, IBinder token)1613 void requestLights(int deviceId, @NonNull LightsRequest request, IBinder token) { 1614 try { 1615 List<Integer> lightIdList = request.getLights(); 1616 int[] lightIds = new int[lightIdList.size()]; 1617 for (int i = 0; i < lightIds.length; i++) { 1618 lightIds[i] = lightIdList.get(i); 1619 } 1620 List<LightState> lightStateList = request.getLightStates(); 1621 mIm.setLightStates(deviceId, lightIds, 1622 lightStateList.toArray(new LightState[lightStateList.size()]), 1623 token); 1624 } catch (RemoteException e) { 1625 throw e.rethrowFromSystemServer(); 1626 } 1627 } 1628 1629 /** 1630 * Open light session for input device manager 1631 * 1632 * @param token The token for the light session 1633 */ openLightSession(int deviceId, String opPkg, @NonNull IBinder token)1634 void openLightSession(int deviceId, String opPkg, @NonNull IBinder token) { 1635 try { 1636 mIm.openLightSession(deviceId, opPkg, token); 1637 } catch (RemoteException e) { 1638 throw e.rethrowFromSystemServer(); 1639 } 1640 } 1641 1642 /** 1643 * Close light session 1644 * 1645 */ closeLightSession(int deviceId, @NonNull IBinder token)1646 void closeLightSession(int deviceId, @NonNull IBinder token) { 1647 try { 1648 mIm.closeLightSession(deviceId, token); 1649 } catch (RemoteException e) { 1650 throw e.rethrowFromSystemServer(); 1651 } 1652 } 1653 1654 /** 1655 * Listens for changes in input devices. 1656 */ 1657 public interface InputDeviceListener { 1658 /** 1659 * Called whenever an input device has been added to the system. 1660 * Use {@link InputManager#getInputDevice} to get more information about the device. 1661 * 1662 * @param deviceId The id of the input device that was added. 1663 */ onInputDeviceAdded(int deviceId)1664 void onInputDeviceAdded(int deviceId); 1665 1666 /** 1667 * Called whenever an input device has been removed from the system. 1668 * 1669 * @param deviceId The id of the input device that was removed. 1670 */ onInputDeviceRemoved(int deviceId)1671 void onInputDeviceRemoved(int deviceId); 1672 1673 /** 1674 * Called whenever the properties of an input device have changed since they 1675 * were last queried. Use {@link InputManager#getInputDevice} to get 1676 * a fresh {@link InputDevice} object with the new properties. 1677 * 1678 * @param deviceId The id of the input device that changed. 1679 */ onInputDeviceChanged(int deviceId)1680 void onInputDeviceChanged(int deviceId); 1681 } 1682 1683 private final class InputDevicesChangedListener extends IInputDevicesChangedListener.Stub { 1684 @Override onInputDevicesChanged(int[] deviceIdAndGeneration)1685 public void onInputDevicesChanged(int[] deviceIdAndGeneration) throws RemoteException { 1686 InputManager.this.onInputDevicesChanged(deviceIdAndGeneration); 1687 } 1688 } 1689 1690 private static final class InputDeviceListenerDelegate extends Handler { 1691 public final InputDeviceListener mListener; 1692 InputDeviceListenerDelegate(InputDeviceListener listener, Handler handler)1693 public InputDeviceListenerDelegate(InputDeviceListener listener, Handler handler) { 1694 super(handler != null ? handler.getLooper() : Looper.myLooper()); 1695 mListener = listener; 1696 } 1697 1698 @Override handleMessage(Message msg)1699 public void handleMessage(Message msg) { 1700 switch (msg.what) { 1701 case MSG_DEVICE_ADDED: 1702 mListener.onInputDeviceAdded(msg.arg1); 1703 break; 1704 case MSG_DEVICE_REMOVED: 1705 mListener.onInputDeviceRemoved(msg.arg1); 1706 break; 1707 case MSG_DEVICE_CHANGED: 1708 mListener.onInputDeviceChanged(msg.arg1); 1709 break; 1710 } 1711 } 1712 } 1713 1714 /** @hide */ 1715 public interface OnTabletModeChangedListener { 1716 /** 1717 * Called whenever the device goes into or comes out of tablet mode. 1718 * 1719 * @param whenNanos The time at which the device transitioned into or 1720 * out of tablet mode. This is given in nanoseconds in the 1721 * {@link SystemClock#uptimeMillis} time base. 1722 */ onTabletModeChanged(long whenNanos, boolean inTabletMode)1723 void onTabletModeChanged(long whenNanos, boolean inTabletMode); 1724 } 1725 1726 private final class TabletModeChangedListener extends ITabletModeChangedListener.Stub { 1727 @Override onTabletModeChanged(long whenNanos, boolean inTabletMode)1728 public void onTabletModeChanged(long whenNanos, boolean inTabletMode) { 1729 InputManager.this.onTabletModeChanged(whenNanos, inTabletMode); 1730 } 1731 } 1732 1733 private static final class OnTabletModeChangedListenerDelegate extends Handler { 1734 private static final int MSG_TABLET_MODE_CHANGED = 0; 1735 1736 public final OnTabletModeChangedListener mListener; 1737 OnTabletModeChangedListenerDelegate( OnTabletModeChangedListener listener, Handler handler)1738 public OnTabletModeChangedListenerDelegate( 1739 OnTabletModeChangedListener listener, Handler handler) { 1740 super(handler != null ? handler.getLooper() : Looper.myLooper()); 1741 mListener = listener; 1742 } 1743 sendTabletModeChanged(long whenNanos, boolean inTabletMode)1744 public void sendTabletModeChanged(long whenNanos, boolean inTabletMode) { 1745 SomeArgs args = SomeArgs.obtain(); 1746 args.argi1 = (int) (whenNanos & 0xFFFFFFFF); 1747 args.argi2 = (int) (whenNanos >> 32); 1748 args.arg1 = (Boolean) inTabletMode; 1749 obtainMessage(MSG_TABLET_MODE_CHANGED, args).sendToTarget(); 1750 } 1751 1752 @Override handleMessage(Message msg)1753 public void handleMessage(Message msg) { 1754 switch (msg.what) { 1755 case MSG_TABLET_MODE_CHANGED: 1756 SomeArgs args = (SomeArgs) msg.obj; 1757 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32); 1758 boolean inTabletMode = (boolean) args.arg1; 1759 mListener.onTabletModeChanged(whenNanos, inTabletMode); 1760 break; 1761 } 1762 } 1763 } 1764 } 1765