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