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