• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      * &lt;receiver android:name=".InputDeviceReceiver"
141      *         android:label="@string/keyboard_layouts_label">
142      *     &lt;intent-filter>
143      *         &lt;action android:name="android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS" />
144      *     &lt;/intent-filter>
145      *     &lt;meta-data android:name="android.hardware.input.metadata.KEYBOARD_LAYOUTS"
146      *             android:resource="@xml/keyboard_layouts" />
147      * &lt;/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>&lt;keyboard-layouts></code> that
152      * contains zero or more <code>&lt;keyboard-layout></code> elements.
153      * Each <code>&lt;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      * &lt;?xml version="1.0" encoding="utf-8"?>
159      * &lt;keyboard-layouts xmlns:android="http://schemas.android.com/apk/res/android">
160      *     &lt;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      * &lt;/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