• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.content.Context;
24 import android.hardware.BatteryState;
25 import android.hardware.SensorManager;
26 import android.hardware.input.InputManager.InputDeviceBatteryListener;
27 import android.hardware.input.InputManager.InputDeviceListener;
28 import android.hardware.input.InputManager.KeyEventActivityListener;
29 import android.hardware.input.InputManager.KeyGestureEventHandler;
30 import android.hardware.input.InputManager.KeyGestureEventListener;
31 import android.hardware.input.InputManager.KeyboardBacklightListener;
32 import android.hardware.input.InputManager.OnTabletModeChangedListener;
33 import android.hardware.input.InputManager.StickyModifierStateListener;
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.Binder;
39 import android.os.CombinedVibration;
40 import android.os.Handler;
41 import android.os.IBinder;
42 import android.os.IVibratorStateListener;
43 import android.os.InputEventInjectionSync;
44 import android.os.Looper;
45 import android.os.Message;
46 import android.os.Process;
47 import android.os.RemoteException;
48 import android.os.ServiceManager;
49 import android.os.VibrationEffect;
50 import android.os.Vibrator;
51 import android.os.VibratorManager;
52 import android.util.IntArray;
53 import android.util.Log;
54 import android.util.SparseArray;
55 import android.view.Display;
56 import android.view.InputDevice;
57 import android.view.InputEvent;
58 import android.view.InputMonitor;
59 import android.view.KeyCharacterMap;
60 import android.view.KeyEvent;
61 import android.view.PointerIcon;
62 import android.view.inputmethod.InputMethodInfo;
63 import android.view.inputmethod.InputMethodSubtype;
64 
65 import com.android.internal.annotations.GuardedBy;
66 import com.android.internal.annotations.VisibleForTesting;
67 import com.android.internal.os.SomeArgs;
68 
69 import java.util.ArrayList;
70 import java.util.Arrays;
71 import java.util.List;
72 import java.util.Objects;
73 import java.util.concurrent.Executor;
74 
75 /**
76  * Manages communication with the input manager service on behalf of
77  * an application process. You're probably looking for {@link InputManager}.
78  *
79  * @hide
80  */
81 public final class InputManagerGlobal {
82     private static final String TAG = "InputManagerGlobal";
83     // To enable these logs, run: 'adb shell setprop log.tag.InputManagerGlobal DEBUG'
debug()84     private boolean debug() {
85         return Log.isLoggable(TAG, Log.DEBUG);
86     }
87 
88     @GuardedBy("mInputDeviceListeners")
89     @Nullable private SparseArray<InputDevice> mInputDevices;
90     @GuardedBy("mInputDeviceListeners")
91     @Nullable private InputDevicesChangedListener mInputDevicesChangedListener;
92     @GuardedBy("mInputDeviceListeners")
93     private final ArrayList<InputDeviceListenerDelegate> mInputDeviceListeners = new ArrayList<>();
94 
95     @GuardedBy("mOnTabletModeChangedListeners")
96     private final ArrayList<OnTabletModeChangedListenerDelegate> mOnTabletModeChangedListeners =
97             new ArrayList<>();
98 
99     private final Object mBatteryListenersLock = new Object();
100     // Maps a deviceId whose battery is currently being monitored to an entry containing the
101     // registered listeners for that device.
102     @GuardedBy("mBatteryListenersLock")
103     @Nullable private SparseArray<RegisteredBatteryListeners> mBatteryListeners;
104     @GuardedBy("mBatteryListenersLock")
105     @Nullable private IInputDeviceBatteryListener mInputDeviceBatteryListener;
106 
107     private final Object mKeyboardBacklightListenerLock = new Object();
108     @GuardedBy("mKeyboardBacklightListenerLock")
109     @Nullable private ArrayList<KeyboardBacklightListenerDelegate> mKeyboardBacklightListeners;
110     @GuardedBy("mKeyboardBacklightListenerLock")
111     @Nullable private IKeyboardBacklightListener mKeyboardBacklightListener;
112 
113     private final Object mStickyModifierStateListenerLock = new Object();
114     @GuardedBy("mStickyModifierStateListenerLock")
115     @Nullable
116     private ArrayList<StickyModifierStateListenerDelegate> mStickyModifierStateListeners;
117     @GuardedBy("mStickyModifierStateListenerLock")
118     @Nullable
119     private IStickyModifierStateListener mStickyModifierStateListener;
120 
121     private final Object mKeyGestureEventListenerLock = new Object();
122     @GuardedBy("mKeyGestureEventListenerLock")
123     @Nullable
124     private ArrayList<KeyGestureEventListenerDelegate> mKeyGestureEventListeners;
125     @GuardedBy("mKeyGestureEventListenerLock")
126     @Nullable
127     private IKeyGestureEventListener mKeyGestureEventListener;
128 
129     private final Object mKeyEventActivityLock = new Object();
130     @GuardedBy("mKeyEventActivityLock")
131     private ArrayList<KeyEventActivityListener> mKeyEventActivityListeners;
132     @GuardedBy("mKeyEventActivityLock")
133     @Nullable
134     private IKeyEventActivityListener mKeyEventActivityListener;
135 
136     @GuardedBy("mKeyGesturesToHandlerMap")
137     @Nullable
138     private IKeyGestureHandler mKeyGestureHandler;
139     @GuardedBy("mKeyGesturesToHandlerMap")
140     private final SparseArray<KeyGestureEventHandler> mKeyGesturesToHandlerMap =
141             new SparseArray<>();
142 
143 
144     // InputDeviceSensorManager gets notified synchronously from the binder thread when input
145     // devices change, so it must be synchronized with the input device listeners.
146     @GuardedBy("mInputDeviceListeners")
147     @Nullable private InputDeviceSensorManager mInputDeviceSensorManager;
148 
149     private static InputManagerGlobal sInstance;
150 
151     private final String mVelocityTrackerStrategy;
152 
153     private final IInputManager mIm;
154 
InputManagerGlobal(IInputManager im)155     public InputManagerGlobal(IInputManager im) {
156         mIm = im;
157         String strategy = null;
158         try {
159             strategy = mIm.getVelocityTrackerStrategy();
160         } catch (RemoteException ex) {
161             Log.w(TAG, "Could not get VelocityTracker strategy: " + ex);
162         }
163         mVelocityTrackerStrategy = strategy;
164     }
165 
166     /**
167      * Gets an instance of the input manager global singleton.
168      *
169      * @return The input manager instance, may be null early in system startup
170      * before the input manager has been fully initialized.
171      */
getInstance()172     public static InputManagerGlobal getInstance() {
173         synchronized (InputManagerGlobal.class) {
174             if (sInstance == null) {
175                 IBinder b = ServiceManager.getService(Context.INPUT_SERVICE);
176                 if (b != null) {
177                     sInstance = new InputManagerGlobal(IInputManager.Stub.asInterface(b));
178                 }
179             }
180             return sInstance;
181         }
182     }
183 
getInputManagerService()184     public IInputManager getInputManagerService() {
185         return mIm;
186     }
187 
188     /**
189      * A test session tracker for InputManagerGlobal.
190      * @see #createTestSession(IInputManager)
191      */
192     @VisibleForTesting
193     public interface TestSession extends AutoCloseable {
194         @Override
close()195         void close();
196     }
197 
198     /**
199      * Create and set a test instance of InputManagerGlobal.
200      *
201      * @return The test session. The session must be {@link TestSession#close()}-ed at the end
202      * of the test.
203      */
204     @VisibleForTesting
createTestSession(IInputManager inputManagerService)205     public static TestSession createTestSession(IInputManager inputManagerService) {
206         synchronized (InputManagerGlobal.class) {
207             final var oldInstance = sInstance;
208             sInstance = new InputManagerGlobal(inputManagerService);
209             return () -> sInstance = oldInstance;
210         }
211     }
212 
213     /**
214      * Get the current VelocityTracker strategy.
215      * Only works when the system has fully booted up.
216      */
getVelocityTrackerStrategy()217     public String getVelocityTrackerStrategy() {
218         return mVelocityTrackerStrategy;
219     }
220 
221     /**
222      * @see InputManager#getInputDevice(int)
223      */
224     @Nullable
getInputDevice(int id)225     public InputDevice getInputDevice(int id) {
226         synchronized (mInputDeviceListeners) {
227             populateInputDevicesLocked();
228 
229             int index = mInputDevices.indexOfKey(id);
230             if (index < 0) {
231                 return null;
232             }
233 
234             InputDevice inputDevice = mInputDevices.valueAt(index);
235             if (inputDevice == null) {
236                 try {
237                     inputDevice = mIm.getInputDevice(id);
238                 } catch (RemoteException ex) {
239                     throw ex.rethrowFromSystemServer();
240                 }
241                 if (inputDevice != null) {
242                     mInputDevices.setValueAt(index, inputDevice);
243                 }
244             }
245             return inputDevice;
246         }
247     }
248 
249     @GuardedBy("mInputDeviceListeners")
populateInputDevicesLocked()250     private void populateInputDevicesLocked() {
251         if (mInputDevicesChangedListener == null) {
252             final InputDevicesChangedListener
253                     listener = new InputDevicesChangedListener();
254             try {
255                 mIm.registerInputDevicesChangedListener(listener);
256             } catch (RemoteException ex) {
257                 throw ex.rethrowFromSystemServer();
258             }
259             mInputDevicesChangedListener = listener;
260         }
261 
262         if (mInputDevices == null) {
263             final int[] ids;
264             try {
265                 ids = mIm.getInputDeviceIds();
266             } catch (RemoteException ex) {
267                 throw ex.rethrowFromSystemServer();
268             }
269 
270             mInputDevices = new SparseArray<>();
271             for (int id : ids) {
272                 mInputDevices.put(id, null);
273             }
274         }
275     }
276 
277     private final class InputDevicesChangedListener extends IInputDevicesChangedListener.Stub {
278         @Override
onInputDevicesChanged(int[] deviceIdAndGeneration)279         public void onInputDevicesChanged(int[] deviceIdAndGeneration) throws RemoteException {
280             InputManagerGlobal.this.onInputDevicesChanged(deviceIdAndGeneration);
281         }
282     }
283 
onInputDevicesChanged(int[] deviceIdAndGeneration)284     private void onInputDevicesChanged(int[] deviceIdAndGeneration) {
285         final boolean enableDebugLogs = debug();
286         if (enableDebugLogs) {
287             Log.d(TAG, "Received input devices changed: " + Arrays.toString(deviceIdAndGeneration));
288         }
289 
290         synchronized (mInputDeviceListeners) {
291             for (int i = mInputDevices.size(); --i > 0; ) {
292                 final int deviceId = mInputDevices.keyAt(i);
293                 if (!containsDeviceId(deviceIdAndGeneration, deviceId)) {
294                     if (enableDebugLogs) {
295                         final InputDevice device = mInputDevices.valueAt(i);
296                         final String name = device != null ? device.getName() : "<null>";
297                         Log.d(TAG, "Device removed: " + deviceId + " (" + name + ")");
298                     }
299                     mInputDevices.removeAt(i);
300                     if (mInputDeviceSensorManager != null) {
301                         mInputDeviceSensorManager.onInputDeviceRemoved(deviceId);
302                     }
303                     sendMessageToInputDeviceListenersLocked(
304                             InputDeviceListenerDelegate.MSG_DEVICE_REMOVED, deviceId);
305                 }
306             }
307 
308             for (int i = 0; i < deviceIdAndGeneration.length; i += 2) {
309                 final int deviceId = deviceIdAndGeneration[i];
310                 int index = mInputDevices.indexOfKey(deviceId);
311                 if (index >= 0) {
312                     final InputDevice device = mInputDevices.valueAt(index);
313                     if (device != null) {
314                         final int generation = deviceIdAndGeneration[i + 1];
315                         if (device.getGeneration() != generation) {
316                             if (enableDebugLogs) {
317                                 Log.d(TAG, "Device changed: " + deviceId + " ("
318                                         + device.getName() + ")");
319                             }
320                             mInputDevices.setValueAt(index, null);
321                             if (mInputDeviceSensorManager != null) {
322                                 mInputDeviceSensorManager.onInputDeviceChanged(deviceId);
323                             }
324                             sendMessageToInputDeviceListenersLocked(
325                                     InputDeviceListenerDelegate.MSG_DEVICE_CHANGED, deviceId);
326                         }
327                     }
328                 } else {
329                     if (enableDebugLogs) {
330                         Log.d(TAG, "Device added: " + deviceId);
331                     }
332                     mInputDevices.put(deviceId, null);
333                     if (mInputDeviceSensorManager != null) {
334                         mInputDeviceSensorManager.onInputDeviceAdded(deviceId);
335                     }
336                     sendMessageToInputDeviceListenersLocked(
337                             InputDeviceListenerDelegate.MSG_DEVICE_ADDED, deviceId);
338                 }
339             }
340         }
341     }
342 
343     private static final class InputDeviceListenerDelegate extends Handler {
344         public final InputDeviceListener mListener;
345         static final int MSG_DEVICE_ADDED = 1;
346         static final int MSG_DEVICE_REMOVED = 2;
347         static final int MSG_DEVICE_CHANGED = 3;
348 
InputDeviceListenerDelegate(InputDeviceListener listener, Handler handler)349         InputDeviceListenerDelegate(InputDeviceListener listener, Handler handler) {
350             super(handler != null ? handler.getLooper() : Looper.myLooper());
351             mListener = listener;
352         }
353 
354         @Override
handleMessage(Message msg)355         public void handleMessage(Message msg) {
356             switch (msg.what) {
357                 case MSG_DEVICE_ADDED:
358                     mListener.onInputDeviceAdded(msg.arg1);
359                     break;
360                 case MSG_DEVICE_REMOVED:
361                     mListener.onInputDeviceRemoved(msg.arg1);
362                     break;
363                 case MSG_DEVICE_CHANGED:
364                     mListener.onInputDeviceChanged(msg.arg1);
365                     break;
366             }
367         }
368     }
369 
containsDeviceId(int[] deviceIdAndGeneration, int deviceId)370     private static boolean containsDeviceId(int[] deviceIdAndGeneration, int deviceId) {
371         for (int i = 0; i < deviceIdAndGeneration.length; i += 2) {
372             if (deviceIdAndGeneration[i] == deviceId) {
373                 return true;
374             }
375         }
376         return false;
377     }
378 
379     @GuardedBy("mInputDeviceListeners")
sendMessageToInputDeviceListenersLocked(int what, int deviceId)380     private void sendMessageToInputDeviceListenersLocked(int what, int deviceId) {
381         final int numListeners = mInputDeviceListeners.size();
382         for (int i = 0; i < numListeners; i++) {
383             InputDeviceListenerDelegate listener = mInputDeviceListeners.get(i);
384             listener.sendMessage(listener.obtainMessage(what, deviceId, 0));
385         }
386     }
387 
388     /**
389      * @see InputManager#registerInputDeviceListener
390      */
registerInputDeviceListener(InputDeviceListener listener, Handler handler)391     public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) {
392         Objects.requireNonNull(listener, "listener must not be null");
393 
394         synchronized (mInputDeviceListeners) {
395             populateInputDevicesLocked();
396             int index = findInputDeviceListenerLocked(listener);
397             if (index < 0) {
398                 mInputDeviceListeners.add(new InputDeviceListenerDelegate(listener, handler));
399             }
400         }
401     }
402 
403     /**
404      * @see InputManager#unregisterInputDeviceListener
405      */
unregisterInputDeviceListener(InputDeviceListener listener)406     public void unregisterInputDeviceListener(InputDeviceListener listener) {
407         if (listener == null) {
408             throw new IllegalArgumentException("listener must not be null");
409         }
410 
411         synchronized (mInputDeviceListeners) {
412             int index = findInputDeviceListenerLocked(listener);
413             if (index >= 0) {
414                 InputDeviceListenerDelegate d = mInputDeviceListeners.get(index);
415                 d.removeCallbacksAndMessages(null);
416                 mInputDeviceListeners.remove(index);
417             }
418         }
419     }
420 
421     @GuardedBy("mInputDeviceListeners")
findInputDeviceListenerLocked(InputDeviceListener listener)422     private int findInputDeviceListenerLocked(InputDeviceListener listener) {
423         final int numListeners = mInputDeviceListeners.size();
424         for (int i = 0; i < numListeners; i++) {
425             if (mInputDeviceListeners.get(i).mListener == listener) {
426                 return i;
427             }
428         }
429         return -1;
430     }
431 
432     /**
433      * @see InputManager#getInputDeviceIds
434      */
getInputDeviceIds()435     public int[] getInputDeviceIds() {
436         synchronized (mInputDeviceListeners) {
437             populateInputDevicesLocked();
438 
439             final int count = mInputDevices.size();
440             final int[] ids = new int[count];
441             for (int i = 0; i < count; i++) {
442                 ids[i] = mInputDevices.keyAt(i);
443             }
444             return ids;
445         }
446     }
447 
448     /**
449      * @see InputManager#enableInputDevice(int)
450      */
enableInputDevice(int id)451     public void enableInputDevice(int id) {
452         try {
453             mIm.enableInputDevice(id);
454         } catch (RemoteException ex) {
455             Log.w(TAG, "Could not enable input device with id = " + id);
456             throw ex.rethrowFromSystemServer();
457         }
458     }
459 
460     /**
461      * @see InputManager#disableInputDevice(int)
462      */
disableInputDevice(int id)463     public void disableInputDevice(int id) {
464         try {
465             mIm.disableInputDevice(id);
466         } catch (RemoteException ex) {
467             Log.w(TAG, "Could not disable input device with id = " + id);
468             throw ex.rethrowFromSystemServer();
469         }
470     }
471 
472     /**
473      * @see InputManager#getInputDeviceByDescriptor
474      */
getInputDeviceByDescriptor(String descriptor)475     InputDevice getInputDeviceByDescriptor(String descriptor) {
476         Objects.requireNonNull(descriptor, "descriptor must not be null.");
477 
478         synchronized (mInputDeviceListeners) {
479             populateInputDevicesLocked();
480 
481             int numDevices = mInputDevices.size();
482             for (int i = 0; i < numDevices; i++) {
483                 InputDevice inputDevice = mInputDevices.valueAt(i);
484                 if (inputDevice == null) {
485                     int id = mInputDevices.keyAt(i);
486                     try {
487                         inputDevice = mIm.getInputDevice(id);
488                     } catch (RemoteException ex) {
489                         throw ex.rethrowFromSystemServer();
490                     }
491                     if (inputDevice == null) {
492                         continue;
493                     }
494                     mInputDevices.setValueAt(i, inputDevice);
495                 }
496                 if (descriptor.equals(inputDevice.getDescriptor())) {
497                     return inputDevice;
498                 }
499             }
500             return null;
501         }
502     }
503 
504     /**
505      * @see InputManager#getHostUsiVersion
506      */
507     @Nullable
getHostUsiVersion(@onNull Display display)508     HostUsiVersion getHostUsiVersion(@NonNull Display display) {
509         Objects.requireNonNull(display, "display should not be null");
510 
511         // Return the first valid USI version reported by any input device associated with
512         // the display.
513         synchronized (mInputDeviceListeners) {
514             populateInputDevicesLocked();
515 
516             for (int i = 0; i < mInputDevices.size(); i++) {
517                 final InputDevice device = getInputDevice(mInputDevices.keyAt(i));
518                 if (device != null && device.getAssociatedDisplayId() == display.getDisplayId()) {
519                     if (device.getHostUsiVersion() != null) {
520                         return device.getHostUsiVersion();
521                     }
522                 }
523             }
524         }
525 
526         // If there are no input devices that report a valid USI version, see if there is a config
527         // that specifies the USI version for the display. This is to handle cases where the USI
528         // input device is not registered by the kernel/driver all the time.
529         try {
530             return mIm.getHostUsiVersionFromDisplayConfig(display.getDisplayId());
531         } catch (RemoteException e) {
532             throw e.rethrowFromSystemServer();
533         }
534     }
535 
onTabletModeChanged(long whenNanos, boolean inTabletMode)536     private void onTabletModeChanged(long whenNanos, boolean inTabletMode) {
537         if (debug()) {
538             Log.d(TAG, "Received tablet mode changed: "
539                     + "whenNanos=" + whenNanos + ", inTabletMode=" + inTabletMode);
540         }
541         synchronized (mOnTabletModeChangedListeners) {
542             final int numListeners = mOnTabletModeChangedListeners.size();
543             for (int i = 0; i < numListeners; i++) {
544                 OnTabletModeChangedListenerDelegate listener =
545                         mOnTabletModeChangedListeners.get(i);
546                 listener.sendTabletModeChanged(whenNanos, inTabletMode);
547             }
548         }
549     }
550 
551     private final class TabletModeChangedListener extends ITabletModeChangedListener.Stub {
552         @Override
onTabletModeChanged(long whenNanos, boolean inTabletMode)553         public void onTabletModeChanged(long whenNanos, boolean inTabletMode) {
554             InputManagerGlobal.this.onTabletModeChanged(whenNanos, inTabletMode);
555         }
556     }
557 
558     private static final class OnTabletModeChangedListenerDelegate extends Handler {
559         private static final int MSG_TABLET_MODE_CHANGED = 0;
560 
561         public final OnTabletModeChangedListener mListener;
562 
OnTabletModeChangedListenerDelegate( OnTabletModeChangedListener listener, Handler handler)563         OnTabletModeChangedListenerDelegate(
564                 OnTabletModeChangedListener listener, Handler handler) {
565             super(handler != null ? handler.getLooper() : Looper.myLooper());
566             mListener = listener;
567         }
568 
sendTabletModeChanged(long whenNanos, boolean inTabletMode)569         public void sendTabletModeChanged(long whenNanos, boolean inTabletMode) {
570             SomeArgs args = SomeArgs.obtain();
571             args.argi1 = (int) whenNanos;
572             args.argi2 = (int) (whenNanos >> 32);
573             args.arg1 = inTabletMode;
574             obtainMessage(MSG_TABLET_MODE_CHANGED, args).sendToTarget();
575         }
576 
577         @Override
handleMessage(Message msg)578         public void handleMessage(Message msg) {
579             if (msg.what == MSG_TABLET_MODE_CHANGED) {
580                 SomeArgs args = (SomeArgs) msg.obj;
581                 long whenNanos = (args.argi1 & 0xFFFFFFFFL) | ((long) args.argi2 << 32);
582                 boolean inTabletMode = (boolean) args.arg1;
583                 mListener.onTabletModeChanged(whenNanos, inTabletMode);
584             }
585         }
586     }
587 
588     /**
589      * @see InputManager#registerInputDeviceListener(InputDeviceListener, Handler)
590      */
registerOnTabletModeChangedListener( OnTabletModeChangedListener listener, Handler handler)591     void registerOnTabletModeChangedListener(
592             OnTabletModeChangedListener listener, Handler handler) {
593         Objects.requireNonNull(listener, "listener must not be null");
594 
595         synchronized (mOnTabletModeChangedListeners) {
596             if (mOnTabletModeChangedListeners.isEmpty()) {
597                 initializeTabletModeListenerLocked();
598             }
599             int idx = findOnTabletModeChangedListenerLocked(listener);
600             if (idx < 0) {
601                 OnTabletModeChangedListenerDelegate d =
602                         new OnTabletModeChangedListenerDelegate(listener, handler);
603                 mOnTabletModeChangedListeners.add(d);
604             }
605         }
606     }
607 
608     /**
609      * @see InputManager#unregisterOnTabletModeChangedListener(OnTabletModeChangedListener)
610      */
unregisterOnTabletModeChangedListener(OnTabletModeChangedListener listener)611     void unregisterOnTabletModeChangedListener(OnTabletModeChangedListener listener) {
612         Objects.requireNonNull(listener, "listener must not be null");
613 
614         synchronized (mOnTabletModeChangedListeners) {
615             int idx = findOnTabletModeChangedListenerLocked(listener);
616             if (idx >= 0) {
617                 OnTabletModeChangedListenerDelegate d = mOnTabletModeChangedListeners.remove(idx);
618                 d.removeCallbacksAndMessages(null);
619             }
620         }
621     }
622 
623     @GuardedBy("mOnTabletModeChangedListeners")
initializeTabletModeListenerLocked()624     private void initializeTabletModeListenerLocked() {
625         final TabletModeChangedListener listener = new TabletModeChangedListener();
626         try {
627             mIm.registerTabletModeChangedListener(listener);
628         } catch (RemoteException ex) {
629             throw ex.rethrowFromSystemServer();
630         }
631     }
632 
633     @GuardedBy("mOnTabletModeChangedListeners")
findOnTabletModeChangedListenerLocked(OnTabletModeChangedListener listener)634     private int findOnTabletModeChangedListenerLocked(OnTabletModeChangedListener listener) {
635         final int n = mOnTabletModeChangedListeners.size();
636         for (int i = 0; i < n; i++) {
637             if (mOnTabletModeChangedListeners.get(i).mListener == listener) {
638                 return i;
639             }
640         }
641         return -1;
642     }
643 
644     private static final class RegisteredBatteryListeners {
645         final List<InputDeviceBatteryListenerDelegate> mDelegates = new ArrayList<>();
646         IInputDeviceBatteryState mInputDeviceBatteryState;
647     }
648 
649     private static final class InputDeviceBatteryListenerDelegate {
650         final InputDeviceBatteryListener mListener;
651         final Executor mExecutor;
652 
InputDeviceBatteryListenerDelegate(InputDeviceBatteryListener listener, Executor executor)653         InputDeviceBatteryListenerDelegate(InputDeviceBatteryListener listener, Executor executor) {
654             mListener = listener;
655             mExecutor = executor;
656         }
657 
notifyBatteryStateChanged(IInputDeviceBatteryState state)658         void notifyBatteryStateChanged(IInputDeviceBatteryState state) {
659             mExecutor.execute(() ->
660                     mListener.onBatteryStateChanged(state.deviceId, state.updateTime,
661                             new LocalBatteryState(state.isPresent, state.status, state.capacity)));
662         }
663     }
664 
665     /**
666      * @see InputManager#addInputDeviceBatteryListener(int, Executor, InputDeviceBatteryListener)
667      */
addInputDeviceBatteryListener(int deviceId, @NonNull Executor executor, @NonNull InputDeviceBatteryListener listener)668     public void addInputDeviceBatteryListener(int deviceId, @NonNull Executor executor,
669             @NonNull InputDeviceBatteryListener listener) {
670         Objects.requireNonNull(executor, "executor should not be null");
671         Objects.requireNonNull(listener, "listener should not be null");
672 
673         synchronized (mBatteryListenersLock) {
674             if (mBatteryListeners == null) {
675                 mBatteryListeners = new SparseArray<>();
676                 mInputDeviceBatteryListener = new LocalInputDeviceBatteryListener();
677             }
678             RegisteredBatteryListeners listenersForDevice = mBatteryListeners.get(deviceId);
679             if (listenersForDevice == null) {
680                 // The deviceId is currently not being monitored for battery changes.
681                 // Start monitoring the device.
682                 listenersForDevice = new RegisteredBatteryListeners();
683                 mBatteryListeners.put(deviceId, listenersForDevice);
684                 try {
685                     mIm.registerBatteryListener(deviceId, mInputDeviceBatteryListener);
686                 } catch (RemoteException e) {
687                     throw e.rethrowFromSystemServer();
688                 }
689             } else {
690                 // The deviceId is already being monitored for battery changes.
691                 // Ensure that the listener is not already registered.
692                 final int numDelegates = listenersForDevice.mDelegates.size();
693                 for (int i = 0; i < numDelegates; i++) {
694                     InputDeviceBatteryListener registeredListener =
695                             listenersForDevice.mDelegates.get(i).mListener;
696                     if (Objects.equals(listener, registeredListener)) {
697                         throw new IllegalArgumentException(
698                                 "Attempting to register an InputDeviceBatteryListener that has "
699                                         + "already been registered for deviceId: "
700                                         + deviceId);
701                     }
702                 }
703             }
704             final InputDeviceBatteryListenerDelegate delegate =
705                     new InputDeviceBatteryListenerDelegate(listener, executor);
706             listenersForDevice.mDelegates.add(delegate);
707 
708             // Notify the listener immediately if we already have the latest battery state.
709             if (listenersForDevice.mInputDeviceBatteryState != null) {
710                 delegate.notifyBatteryStateChanged(listenersForDevice.mInputDeviceBatteryState);
711             }
712         }
713     }
714 
715     /**
716      * @see InputManager#removeInputDeviceBatteryListener(int, InputDeviceBatteryListener)
717      */
removeInputDeviceBatteryListener(int deviceId, @NonNull InputDeviceBatteryListener listener)718     void removeInputDeviceBatteryListener(int deviceId,
719             @NonNull InputDeviceBatteryListener listener) {
720         Objects.requireNonNull(listener, "listener should not be null");
721 
722         synchronized (mBatteryListenersLock) {
723             if (mBatteryListeners == null) {
724                 return;
725             }
726             RegisteredBatteryListeners listenersForDevice = mBatteryListeners.get(deviceId);
727             if (listenersForDevice == null) {
728                 // The deviceId is not currently being monitored.
729                 return;
730             }
731             final List<InputDeviceBatteryListenerDelegate> delegates =
732                     listenersForDevice.mDelegates;
733             for (int i = 0; i < delegates.size();) {
734                 if (Objects.equals(listener, delegates.get(i).mListener)) {
735                     delegates.remove(i);
736                     continue;
737                 }
738                 i++;
739             }
740             if (!delegates.isEmpty()) {
741                 return;
742             }
743 
744             // There are no more battery listeners for this deviceId. Stop monitoring this device.
745             mBatteryListeners.remove(deviceId);
746             try {
747                 mIm.unregisterBatteryListener(deviceId, mInputDeviceBatteryListener);
748             } catch (RemoteException e) {
749                 throw e.rethrowFromSystemServer();
750             }
751             if (mBatteryListeners.size() == 0) {
752                 // There are no more devices being monitored, so the registered
753                 // IInputDeviceBatteryListener will be automatically dropped by the server.
754                 mBatteryListeners = null;
755                 mInputDeviceBatteryListener = null;
756             }
757         }
758     }
759 
760     private class LocalInputDeviceBatteryListener extends IInputDeviceBatteryListener.Stub {
761         @Override
onBatteryStateChanged(IInputDeviceBatteryState state)762         public void onBatteryStateChanged(IInputDeviceBatteryState state) {
763             synchronized (mBatteryListenersLock) {
764                 if (mBatteryListeners == null) return;
765                 final RegisteredBatteryListeners entry = mBatteryListeners.get(state.deviceId);
766                 if (entry == null) return;
767 
768                 entry.mInputDeviceBatteryState = state;
769                 final int numDelegates = entry.mDelegates.size();
770                 for (int i = 0; i < numDelegates; i++) {
771                     entry.mDelegates.get(i)
772                             .notifyBatteryStateChanged(entry.mInputDeviceBatteryState);
773                 }
774             }
775         }
776     }
777 
778     /**
779      * @see #getInputDeviceBatteryState(int, boolean)
780      */
781     @NonNull
getInputDeviceBatteryState(int deviceId, boolean hasBattery)782     public BatteryState getInputDeviceBatteryState(int deviceId, boolean hasBattery) {
783         if (!hasBattery) {
784             return new LocalBatteryState();
785         }
786         try {
787             final IInputDeviceBatteryState state = mIm.getBatteryState(deviceId);
788             return new LocalBatteryState(state.isPresent, state.status, state.capacity);
789         } catch (RemoteException ex) {
790             throw ex.rethrowFromSystemServer();
791         }
792     }
793 
794     // Implementation of the android.hardware.BatteryState interface used to report the battery
795     // state via the InputDevice#getBatteryState() and InputDeviceBatteryListener interfaces.
796     private static final class LocalBatteryState extends BatteryState {
797         private final boolean mIsPresent;
798         private final int mStatus;
799         private final float mCapacity;
800 
LocalBatteryState()801         LocalBatteryState() {
802             this(false /*isPresent*/, BatteryState.STATUS_UNKNOWN, Float.NaN /*capacity*/);
803         }
804 
LocalBatteryState(boolean isPresent, int status, float capacity)805         LocalBatteryState(boolean isPresent, int status, float capacity) {
806             mIsPresent = isPresent;
807             mStatus = status;
808             mCapacity = capacity;
809         }
810 
811         @Override
isPresent()812         public boolean isPresent() {
813             return mIsPresent;
814         }
815 
816         @Override
getStatus()817         public int getStatus() {
818             return mStatus;
819         }
820 
821         @Override
getCapacity()822         public float getCapacity() {
823             return mCapacity;
824         }
825     }
826 
827     private static final class KeyboardBacklightListenerDelegate {
828         final InputManager.KeyboardBacklightListener mListener;
829         final Executor mExecutor;
830 
KeyboardBacklightListenerDelegate(KeyboardBacklightListener listener, Executor executor)831         KeyboardBacklightListenerDelegate(KeyboardBacklightListener listener, Executor executor) {
832             mListener = listener;
833             mExecutor = executor;
834         }
835 
notifyKeyboardBacklightChange(int deviceId, IKeyboardBacklightState state, boolean isTriggeredByKeyPress)836         void notifyKeyboardBacklightChange(int deviceId, IKeyboardBacklightState state,
837                 boolean isTriggeredByKeyPress) {
838             mExecutor.execute(() ->
839                     mListener.onKeyboardBacklightChanged(deviceId,
840                             new LocalKeyboardBacklightState(state.brightnessLevel,
841                                     state.maxBrightnessLevel), isTriggeredByKeyPress));
842         }
843     }
844 
845     private class LocalKeyboardBacklightListener extends IKeyboardBacklightListener.Stub {
846 
847         @Override
onBrightnessChanged(int deviceId, IKeyboardBacklightState state, boolean isTriggeredByKeyPress)848         public void onBrightnessChanged(int deviceId, IKeyboardBacklightState state,
849                 boolean isTriggeredByKeyPress) {
850             synchronized (mKeyboardBacklightListenerLock) {
851                 if (mKeyboardBacklightListeners == null) return;
852                 final int numListeners = mKeyboardBacklightListeners.size();
853                 for (int i = 0; i < numListeners; i++) {
854                     mKeyboardBacklightListeners.get(i)
855                             .notifyKeyboardBacklightChange(deviceId, state, isTriggeredByKeyPress);
856                 }
857             }
858         }
859     }
860 
861     // Implementation of the android.hardware.input.KeyboardBacklightState interface used to report
862     // the keyboard backlight state via the KeyboardBacklightListener interfaces.
863     private static final class LocalKeyboardBacklightState extends KeyboardBacklightState {
864 
865         private final int mBrightnessLevel;
866         private final int mMaxBrightnessLevel;
867 
LocalKeyboardBacklightState(int brightnessLevel, int maxBrightnessLevel)868         LocalKeyboardBacklightState(int brightnessLevel, int maxBrightnessLevel) {
869             mBrightnessLevel = brightnessLevel;
870             mMaxBrightnessLevel = maxBrightnessLevel;
871         }
872 
873         @Override
getBrightnessLevel()874         public int getBrightnessLevel() {
875             return mBrightnessLevel;
876         }
877 
878         @Override
getMaxBrightnessLevel()879         public int getMaxBrightnessLevel() {
880             return mMaxBrightnessLevel;
881         }
882     }
883 
884     /**
885      * @see InputManager#registerKeyboardBacklightListener(Executor, KeyboardBacklightListener)
886      */
887     @RequiresPermission(Manifest.permission.MONITOR_KEYBOARD_BACKLIGHT)
registerKeyboardBacklightListener(@onNull Executor executor, @NonNull KeyboardBacklightListener listener)888     void registerKeyboardBacklightListener(@NonNull Executor executor,
889             @NonNull KeyboardBacklightListener listener) throws IllegalArgumentException {
890         Objects.requireNonNull(executor, "executor should not be null");
891         Objects.requireNonNull(listener, "listener should not be null");
892 
893         synchronized (mKeyboardBacklightListenerLock) {
894             if (mKeyboardBacklightListener == null) {
895                 mKeyboardBacklightListeners = new ArrayList<>();
896                 mKeyboardBacklightListener = new LocalKeyboardBacklightListener();
897 
898                 try {
899                     mIm.registerKeyboardBacklightListener(mKeyboardBacklightListener);
900                 } catch (RemoteException e) {
901                     throw e.rethrowFromSystemServer();
902                 }
903             }
904             final int numListeners = mKeyboardBacklightListeners.size();
905             for (int i = 0; i < numListeners; i++) {
906                 if (mKeyboardBacklightListeners.get(i).mListener == listener) {
907                     throw new IllegalArgumentException("Listener has already been registered!");
908                 }
909             }
910             KeyboardBacklightListenerDelegate delegate =
911                     new KeyboardBacklightListenerDelegate(listener, executor);
912             mKeyboardBacklightListeners.add(delegate);
913         }
914     }
915 
916     /**
917      * @see InputManager#unregisterKeyboardBacklightListener(KeyboardBacklightListener)
918      */
919     @RequiresPermission(Manifest.permission.MONITOR_KEYBOARD_BACKLIGHT)
unregisterKeyboardBacklightListener( @onNull KeyboardBacklightListener listener)920     void unregisterKeyboardBacklightListener(
921             @NonNull KeyboardBacklightListener listener) {
922         Objects.requireNonNull(listener, "listener should not be null");
923 
924         synchronized (mKeyboardBacklightListenerLock) {
925             if (mKeyboardBacklightListeners == null) {
926                 return;
927             }
928             mKeyboardBacklightListeners.removeIf((delegate) -> delegate.mListener == listener);
929             if (mKeyboardBacklightListeners.isEmpty()) {
930                 try {
931                     mIm.unregisterKeyboardBacklightListener(mKeyboardBacklightListener);
932                 } catch (RemoteException e) {
933                     throw e.rethrowFromSystemServer();
934                 }
935                 mKeyboardBacklightListeners = null;
936                 mKeyboardBacklightListener = null;
937             }
938         }
939     }
940 
941     private static final class StickyModifierStateListenerDelegate {
942         final InputManager.StickyModifierStateListener mListener;
943         final Executor mExecutor;
944 
StickyModifierStateListenerDelegate(StickyModifierStateListener listener, Executor executor)945         StickyModifierStateListenerDelegate(StickyModifierStateListener listener,
946                 Executor executor) {
947             mListener = listener;
948             mExecutor = executor;
949         }
950 
notifyStickyModifierStateChange(int modifierState, int lockedModifierState)951         void notifyStickyModifierStateChange(int modifierState, int lockedModifierState) {
952             mExecutor.execute(() ->
953                     mListener.onStickyModifierStateChanged(
954                             new LocalStickyModifierState(modifierState, lockedModifierState)));
955         }
956     }
957 
958     private class LocalStickyModifierStateListener extends IStickyModifierStateListener.Stub {
959 
960         @Override
onStickyModifierStateChanged(int modifierState, int lockedModifierState)961         public void onStickyModifierStateChanged(int modifierState, int lockedModifierState) {
962             synchronized (mStickyModifierStateListenerLock) {
963                 if (mStickyModifierStateListeners == null) return;
964                 final int numListeners = mStickyModifierStateListeners.size();
965                 for (int i = 0; i < numListeners; i++) {
966                     mStickyModifierStateListeners.get(i)
967                             .notifyStickyModifierStateChange(modifierState, lockedModifierState);
968                 }
969             }
970         }
971     }
972 
973     // Implementation of the android.hardware.input.StickyModifierState interface used to report
974     // the sticky modifier state via the StickyModifierStateListener interfaces.
975     private static final class LocalStickyModifierState extends StickyModifierState {
976 
977         private final int mModifierState;
978         private final int mLockedModifierState;
979 
LocalStickyModifierState(int modifierState, int lockedModifierState)980         LocalStickyModifierState(int modifierState, int lockedModifierState) {
981             mModifierState = modifierState;
982             mLockedModifierState = lockedModifierState;
983         }
984 
985         @Override
isShiftModifierOn()986         public boolean isShiftModifierOn() {
987             return (mModifierState & KeyEvent.META_SHIFT_ON) != 0;
988         }
989 
990         @Override
isShiftModifierLocked()991         public boolean isShiftModifierLocked() {
992             return (mLockedModifierState & KeyEvent.META_SHIFT_ON) != 0;
993         }
994 
995         @Override
isCtrlModifierOn()996         public boolean isCtrlModifierOn() {
997             return (mModifierState & KeyEvent.META_CTRL_ON) != 0;
998         }
999 
1000         @Override
isCtrlModifierLocked()1001         public boolean isCtrlModifierLocked() {
1002             return (mLockedModifierState & KeyEvent.META_CTRL_ON) != 0;
1003         }
1004 
1005         @Override
isMetaModifierOn()1006         public boolean isMetaModifierOn() {
1007             return (mModifierState & KeyEvent.META_META_ON) != 0;
1008         }
1009 
1010         @Override
isMetaModifierLocked()1011         public boolean isMetaModifierLocked() {
1012             return (mLockedModifierState & KeyEvent.META_META_ON) != 0;
1013         }
1014 
1015         @Override
isAltModifierOn()1016         public boolean isAltModifierOn() {
1017             return (mModifierState & KeyEvent.META_ALT_LEFT_ON) != 0;
1018         }
1019 
1020         @Override
isAltModifierLocked()1021         public boolean isAltModifierLocked() {
1022             return (mLockedModifierState & KeyEvent.META_ALT_LEFT_ON) != 0;
1023         }
1024 
1025         @Override
isAltGrModifierOn()1026         public boolean isAltGrModifierOn() {
1027             return (mModifierState & KeyEvent.META_ALT_RIGHT_ON) != 0;
1028         }
1029 
1030         @Override
isAltGrModifierLocked()1031         public boolean isAltGrModifierLocked() {
1032             return (mLockedModifierState & KeyEvent.META_ALT_RIGHT_ON) != 0;
1033         }
1034     }
1035 
1036     /**
1037      * @see InputManager#registerStickyModifierStateListener(Executor, StickyModifierStateListener)
1038      */
1039     @RequiresPermission(Manifest.permission.MONITOR_STICKY_MODIFIER_STATE)
registerStickyModifierStateListener(@onNull Executor executor, @NonNull StickyModifierStateListener listener)1040     void registerStickyModifierStateListener(@NonNull Executor executor,
1041             @NonNull StickyModifierStateListener listener) throws IllegalArgumentException {
1042         Objects.requireNonNull(executor, "executor should not be null");
1043         Objects.requireNonNull(listener, "listener should not be null");
1044 
1045         synchronized (mStickyModifierStateListenerLock) {
1046             if (mStickyModifierStateListener == null) {
1047                 mStickyModifierStateListeners = new ArrayList<>();
1048                 mStickyModifierStateListener = new LocalStickyModifierStateListener();
1049 
1050                 try {
1051                     mIm.registerStickyModifierStateListener(mStickyModifierStateListener);
1052                 } catch (RemoteException e) {
1053                     throw e.rethrowFromSystemServer();
1054                 }
1055             }
1056             final int numListeners = mStickyModifierStateListeners.size();
1057             for (int i = 0; i < numListeners; i++) {
1058                 if (mStickyModifierStateListeners.get(i).mListener == listener) {
1059                     throw new IllegalArgumentException("Listener has already been registered!");
1060                 }
1061             }
1062             StickyModifierStateListenerDelegate delegate =
1063                     new StickyModifierStateListenerDelegate(listener, executor);
1064             mStickyModifierStateListeners.add(delegate);
1065         }
1066     }
1067 
1068     /**
1069      * @see InputManager#unregisterStickyModifierStateListener(StickyModifierStateListener)
1070      */
1071     @RequiresPermission(Manifest.permission.MONITOR_STICKY_MODIFIER_STATE)
unregisterStickyModifierStateListener( @onNull StickyModifierStateListener listener)1072     void unregisterStickyModifierStateListener(
1073             @NonNull StickyModifierStateListener listener) {
1074         Objects.requireNonNull(listener, "listener should not be null");
1075 
1076         synchronized (mStickyModifierStateListenerLock) {
1077             if (mStickyModifierStateListeners == null) {
1078                 return;
1079             }
1080             mStickyModifierStateListeners.removeIf((delegate) -> delegate.mListener == listener);
1081             if (mStickyModifierStateListeners.isEmpty()) {
1082                 try {
1083                     mIm.unregisterStickyModifierStateListener(mStickyModifierStateListener);
1084                 } catch (RemoteException e) {
1085                     throw e.rethrowFromSystemServer();
1086                 }
1087                 mStickyModifierStateListeners = null;
1088                 mStickyModifierStateListener = null;
1089             }
1090         }
1091     }
1092 
1093     private static final class KeyGestureEventListenerDelegate {
1094         final KeyGestureEventListener mListener;
1095         final Executor mExecutor;
1096 
KeyGestureEventListenerDelegate(KeyGestureEventListener listener, Executor executor)1097         KeyGestureEventListenerDelegate(KeyGestureEventListener listener,
1098                 Executor executor) {
1099             mListener = listener;
1100             mExecutor = executor;
1101         }
1102 
onKeyGestureEvent(KeyGestureEvent event)1103         void onKeyGestureEvent(KeyGestureEvent event) {
1104             mExecutor.execute(() -> mListener.onKeyGestureEvent(event));
1105         }
1106     }
1107 
1108     private class LocalKeyGestureEventListener extends IKeyGestureEventListener.Stub {
1109         @Override
onKeyGestureEvent(@onNull AidlKeyGestureEvent ev)1110         public void onKeyGestureEvent(@NonNull AidlKeyGestureEvent ev) {
1111             synchronized (mKeyGestureEventListenerLock) {
1112                 if (mKeyGestureEventListeners == null) return;
1113                 final int numListeners = mKeyGestureEventListeners.size();
1114                 final KeyGestureEvent event = new KeyGestureEvent(ev);
1115                 for (int i = 0; i < numListeners; i++) {
1116                     mKeyGestureEventListeners.get(i).onKeyGestureEvent(event);
1117                 }
1118             }
1119         }
1120     }
1121 
1122     /**
1123      * @see InputManager#registerKeyGestureEventListener(Executor,
1124      * KeyGestureEventListener)
1125      */
1126     @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
registerKeyGestureEventListener(@onNull Executor executor, @NonNull KeyGestureEventListener listener)1127     void registerKeyGestureEventListener(@NonNull Executor executor,
1128             @NonNull KeyGestureEventListener listener) throws IllegalArgumentException {
1129         Objects.requireNonNull(executor, "executor should not be null");
1130         Objects.requireNonNull(listener, "listener should not be null");
1131 
1132         synchronized (mKeyGestureEventListenerLock) {
1133             if (mKeyGestureEventListener == null) {
1134                 mKeyGestureEventListeners = new ArrayList<>();
1135                 mKeyGestureEventListener = new LocalKeyGestureEventListener();
1136 
1137                 try {
1138                     mIm.registerKeyGestureEventListener(mKeyGestureEventListener);
1139                 } catch (RemoteException e) {
1140                     throw e.rethrowFromSystemServer();
1141                 }
1142             }
1143             final int numListeners = mKeyGestureEventListeners.size();
1144             for (int i = 0; i < numListeners; i++) {
1145                 if (mKeyGestureEventListeners.get(i).mListener == listener) {
1146                     throw new IllegalArgumentException("Listener has already been registered!");
1147                 }
1148             }
1149             KeyGestureEventListenerDelegate delegate =
1150                     new KeyGestureEventListenerDelegate(listener, executor);
1151             mKeyGestureEventListeners.add(delegate);
1152         }
1153     }
1154 
1155     /**
1156      * @see InputManager#unregisterKeyGestureEventListener(KeyGestureEventListener)
1157      */
1158     @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
unregisterKeyGestureEventListener(@onNull KeyGestureEventListener listener)1159     void unregisterKeyGestureEventListener(@NonNull KeyGestureEventListener listener) {
1160         Objects.requireNonNull(listener, "listener should not be null");
1161 
1162         synchronized (mKeyGestureEventListenerLock) {
1163             if (mKeyGestureEventListeners == null) {
1164                 return;
1165             }
1166             mKeyGestureEventListeners.removeIf((delegate) -> delegate.mListener == listener);
1167             if (mKeyGestureEventListeners.isEmpty()) {
1168                 try {
1169                     mIm.unregisterKeyGestureEventListener(mKeyGestureEventListener);
1170                 } catch (RemoteException e) {
1171                     throw e.rethrowFromSystemServer();
1172                 }
1173                 mKeyGestureEventListeners = null;
1174                 mKeyGestureEventListener = null;
1175             }
1176         }
1177     }
1178 
1179     private class LocalKeyGestureHandler extends IKeyGestureHandler.Stub {
1180         @Override
handleKeyGesture(@onNull AidlKeyGestureEvent ev, IBinder focusedToken)1181         public void handleKeyGesture(@NonNull AidlKeyGestureEvent ev, IBinder focusedToken) {
1182             synchronized (mKeyGesturesToHandlerMap) {
1183                 KeyGestureEventHandler handler = mKeyGesturesToHandlerMap.get(ev.gestureType);
1184                 if (handler == null) {
1185                     Log.w(TAG, "Key gesture event " + ev.gestureType
1186                             + " occurred without a registered handler!");
1187                     return;
1188                 }
1189                 handler.handleKeyGestureEvent(new KeyGestureEvent(ev), focusedToken);
1190             }
1191         }
1192     }
1193 
1194     /**
1195      * @see InputManager#registerKeyGestureEventHandler(List, KeyGestureEventHandler)
1196      */
1197     @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
registerKeyGestureEventHandler(List<Integer> keyGesturesToHandle, @NonNull KeyGestureEventHandler handler)1198     void registerKeyGestureEventHandler(List<Integer> keyGesturesToHandle,
1199             @NonNull KeyGestureEventHandler handler) throws IllegalArgumentException {
1200         Objects.requireNonNull(keyGesturesToHandle, "List of gestures should not be null");
1201         Objects.requireNonNull(handler, "handler should not be null");
1202 
1203         if (keyGesturesToHandle.isEmpty()) {
1204             throw new IllegalArgumentException("No key gestures provided!");
1205         }
1206 
1207         synchronized (mKeyGesturesToHandlerMap) {
1208             IntArray newKeyGestures = new IntArray(
1209                     keyGesturesToHandle.size() + mKeyGesturesToHandlerMap.size());
1210 
1211             // Check if the handler already exists
1212             for (int i = 0; i < mKeyGesturesToHandlerMap.size(); i++) {
1213                 KeyGestureEventHandler h = mKeyGesturesToHandlerMap.valueAt(i);
1214                 if (h == handler) {
1215                     throw new IllegalArgumentException("Handler has already been registered!");
1216                 }
1217                 newKeyGestures.add(mKeyGesturesToHandlerMap.keyAt(i));
1218             }
1219 
1220             // Check if any of the key gestures are already handled by existing handlers
1221             for (int gesture : keyGesturesToHandle) {
1222                 if (mKeyGesturesToHandlerMap.contains(gesture)) {
1223                     throw new IllegalArgumentException("Key gesture " + gesture
1224                             + " is already registered by another handler!");
1225                 }
1226                 newKeyGestures.add(gesture);
1227             }
1228 
1229             try {
1230                 // If handler was already registered for this process, we need to unregister and
1231                 // re-register it for the new set of gestures
1232                 if (mKeyGestureHandler != null) {
1233                     mIm.unregisterKeyGestureHandler(mKeyGestureHandler);
1234                 } else {
1235                     mKeyGestureHandler = new LocalKeyGestureHandler();
1236                 }
1237                 mIm.registerKeyGestureHandler(newKeyGestures.toArray(), mKeyGestureHandler);
1238                 for (int gesture : keyGesturesToHandle) {
1239                     mKeyGesturesToHandlerMap.put(gesture, handler);
1240                 }
1241             } catch (RemoteException e) {
1242                 throw e.rethrowFromSystemServer();
1243             }
1244         }
1245     }
1246 
1247     /**
1248      * @see InputManager#unregisterKeyGestureEventHandler(KeyGestureEventHandler)
1249      */
1250     @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
unregisterKeyGestureEventHandler(@onNull KeyGestureEventHandler handler)1251     void unregisterKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler) {
1252         Objects.requireNonNull(handler, "handler should not be null");
1253 
1254         synchronized (mKeyGesturesToHandlerMap) {
1255             if (mKeyGestureHandler == null) {
1256                 return;
1257             }
1258             for (int i = mKeyGesturesToHandlerMap.size() - 1; i >= 0; i--) {
1259                 if (mKeyGesturesToHandlerMap.valueAt(i) == handler) {
1260                     mKeyGesturesToHandlerMap.removeAt(i);
1261                 }
1262             }
1263             if (mKeyGesturesToHandlerMap.size() == 0) {
1264                 try {
1265                     mIm.unregisterKeyGestureHandler(mKeyGestureHandler);
1266                 } catch (RemoteException e) {
1267                     throw e.rethrowFromSystemServer();
1268                 }
1269                 mKeyGestureHandler = null;
1270             }
1271         }
1272     }
1273 
1274     private class LocalKeyEventActivityListener extends IKeyEventActivityListener.Stub {
1275         @Override
onKeyEventActivity()1276         public void onKeyEventActivity() {
1277             synchronized (mKeyEventActivityLock) {
1278                 final int numListeners = mKeyEventActivityListeners.size();
1279                 for (int i = 0; i < numListeners; i++) {
1280                     KeyEventActivityListener listener = mKeyEventActivityListeners.get(i);
1281                     listener.onKeyEventActivity();
1282                 }
1283             }
1284         }
1285     }
1286 
registerKeyEventActivityListener(@onNull KeyEventActivityListener listener)1287     boolean registerKeyEventActivityListener(@NonNull KeyEventActivityListener listener) {
1288         Objects.requireNonNull(listener, "listener should not be null");
1289         boolean success = false;
1290         synchronized (mKeyEventActivityLock) {
1291             if (mKeyEventActivityListener == null) {
1292                 mKeyEventActivityListeners = new ArrayList<>();
1293                 mKeyEventActivityListener = new LocalKeyEventActivityListener();
1294 
1295                 try {
1296                     success = mIm.registerKeyEventActivityListener(mKeyEventActivityListener);
1297                 } catch (RemoteException e) {
1298                     throw e.rethrowFromSystemServer();
1299                 }
1300             }
1301             if (mKeyEventActivityListeners.contains(listener)) {
1302                 throw new IllegalArgumentException("Listener has already been registered!");
1303             }
1304             mKeyEventActivityListeners.add(listener);
1305             return success;
1306         }
1307     }
1308 
unregisterKeyEventActivityListener(@onNull KeyEventActivityListener listener)1309     boolean unregisterKeyEventActivityListener(@NonNull KeyEventActivityListener listener) {
1310         Objects.requireNonNull(listener, "listener should not be null");
1311 
1312         boolean success = true;
1313         synchronized (mKeyEventActivityLock) {
1314             if (mKeyEventActivityListeners == null) {
1315                 return success;
1316             }
1317             mKeyEventActivityListeners.remove(listener);
1318             if (mKeyEventActivityListeners.isEmpty()) {
1319                 try {
1320                     success = mIm.unregisterKeyEventActivityListener(mKeyEventActivityListener);
1321                 } catch (RemoteException e) {
1322                     throw e.rethrowFromSystemServer();
1323                 }
1324                 mKeyEventActivityListeners = null;
1325                 mKeyEventActivityListener = null;
1326             }
1327         }
1328         return success;
1329     }
1330 
1331     /**
1332      * Sets the keyboard layout override for the specified input device. This will set the
1333      * keyboard layout as the default for the input device irrespective of the underlying IME
1334      * configuration.
1335      *
1336      * <p>
1337      * Prefer using {@link InputManager#setKeyboardLayoutForInputDevice(InputDeviceIdentifier, int,
1338      * InputMethodInfo, InputMethodSubtype, String)} for normal use cases.
1339      * </p><p>
1340      * This method is to be used only for special cases where we knowingly want to set a
1341      * particular keyboard layout for a keyboard, ignoring the IME configuration. e.g. Setting a
1342      * default layout for an Android Emulator where we know the preferred H/W keyboard layout.
1343      * </p><p>
1344      * NOTE: This may affect the typing experience if the layout isn't compatible with the IME
1345      * configuration.
1346      * </p><p>
1347      * NOTE: User can still change the keyboard layout configuration from the settings page.
1348      * </p>
1349      *
1350      * @param identifier The identifier for the input device.
1351      * @param keyboardLayoutDescriptor The keyboard layout descriptor to use.
1352      *
1353      * @hide
1354      */
1355     @RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
setKeyboardLayoutOverrideForInputDevice(@onNull InputDeviceIdentifier identifier, @NonNull String keyboardLayoutDescriptor)1356     public void setKeyboardLayoutOverrideForInputDevice(@NonNull InputDeviceIdentifier identifier,
1357             @NonNull String keyboardLayoutDescriptor) {
1358         Objects.requireNonNull(identifier, "identifier should not be null");
1359         Objects.requireNonNull(keyboardLayoutDescriptor,
1360                 "keyboardLayoutDescriptor should not be null");
1361         try {
1362             mIm.setKeyboardLayoutOverrideForInputDevice(identifier, keyboardLayoutDescriptor);
1363         } catch (RemoteException e) {
1364             throw e.rethrowFromSystemServer();
1365         }
1366     }
1367 
1368     /**
1369      * TODO(b/330517633): Cleanup the unsupported API
1370      */
1371     @NonNull
getKeyboardLayoutsForInputDevice( @onNull InputDeviceIdentifier identifier)1372     public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1373             @NonNull InputDeviceIdentifier identifier) {
1374         return new KeyboardLayout[0];
1375     }
1376 
1377     /**
1378      * TODO(b/330517633): Cleanup the unsupported API
1379      */
setCurrentKeyboardLayoutForInputDevice( @onNull InputDeviceIdentifier identifier, @NonNull String keyboardLayoutDescriptor)1380     public void setCurrentKeyboardLayoutForInputDevice(
1381             @NonNull InputDeviceIdentifier identifier,
1382             @NonNull String keyboardLayoutDescriptor) {}
1383 
1384 
1385     /**
1386      * @see InputDevice#getSensorManager()
1387      */
1388     @NonNull
getInputDeviceSensorManager(int deviceId)1389     public SensorManager getInputDeviceSensorManager(int deviceId) {
1390         synchronized (mInputDeviceListeners) {
1391             if (mInputDeviceSensorManager == null) {
1392                 mInputDeviceSensorManager = new InputDeviceSensorManager(this);
1393             }
1394             return mInputDeviceSensorManager.getSensorManager(deviceId);
1395         }
1396     }
1397 
1398     /**
1399      * Get information about all of the sensors supported by an input device
1400      * @see InputDeviceSensorManager
1401      */
getSensorList(int deviceId)1402     InputSensorInfo[] getSensorList(int deviceId) {
1403         try {
1404             return mIm.getSensorList(deviceId);
1405         } catch (RemoteException ex) {
1406             throw ex.rethrowFromSystemServer();
1407         }
1408     }
1409 
1410     /**
1411      * @see InputDeviceSensorManager
1412      */
enableSensor(int deviceId, int sensorType, int samplingPeriodUs, int maxBatchReportLatencyUs)1413     boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs,
1414             int maxBatchReportLatencyUs) {
1415         try {
1416             return mIm.enableSensor(deviceId, sensorType, samplingPeriodUs,
1417                     maxBatchReportLatencyUs);
1418         } catch (RemoteException ex) {
1419             throw ex.rethrowFromSystemServer();
1420         }
1421     }
1422 
1423     /**
1424      * @see InputDeviceSensorManager
1425      */
disableSensor(int deviceId, int sensorType)1426     void disableSensor(int deviceId, int sensorType) {
1427         try {
1428             mIm.disableSensor(deviceId, sensorType);
1429         } catch (RemoteException ex) {
1430             throw ex.rethrowFromSystemServer();
1431         }
1432     }
1433 
1434     /**
1435      * @see InputDeviceSensorManager
1436      */
flushSensor(int deviceId, int sensorType)1437     boolean flushSensor(int deviceId, int sensorType) {
1438         try {
1439             return mIm.flushSensor(deviceId, sensorType);
1440         } catch (RemoteException ex) {
1441             throw ex.rethrowFromSystemServer();
1442         }
1443     }
1444 
1445     /**
1446      * @see InputDeviceSensorManager
1447      */
registerSensorListener(IInputSensorEventListener listener)1448     boolean registerSensorListener(IInputSensorEventListener listener) {
1449         try {
1450             return mIm.registerSensorListener(listener);
1451         } catch (RemoteException ex) {
1452             throw ex.rethrowFromSystemServer();
1453         }
1454     }
1455 
1456     /**
1457      * @see InputDeviceSensorManager
1458      */
unregisterSensorListener(IInputSensorEventListener listener)1459     void unregisterSensorListener(IInputSensorEventListener listener) {
1460         try {
1461             mIm.unregisterSensorListener(listener);
1462         } catch (RemoteException ex) {
1463             throw ex.rethrowFromSystemServer();
1464         }
1465     }
1466 
1467     /**
1468      * @see InputDevice#getLightsManager()
1469      */
1470     @NonNull
getInputDeviceLightsManager(int deviceId)1471     public LightsManager getInputDeviceLightsManager(int deviceId) {
1472         return new InputDeviceLightsManager(deviceId);
1473     }
1474 
1475     /**
1476      * Gets a list of light objects associated with an input device.
1477      * @return The list of lights, never null.
1478      */
getLights(int deviceId)1479     @NonNull List<Light> getLights(int deviceId) {
1480         try {
1481             return mIm.getLights(deviceId);
1482         } catch (RemoteException e) {
1483             throw e.rethrowFromSystemServer();
1484         }
1485     }
1486 
1487     /**
1488      * Returns the state of an input device light.
1489      * @return the light state
1490      */
getLightState(int deviceId, @NonNull Light light)1491     @NonNull LightState getLightState(int deviceId, @NonNull Light light) {
1492         try {
1493             return mIm.getLightState(deviceId, light.getId());
1494         } catch (RemoteException e) {
1495             throw e.rethrowFromSystemServer();
1496         }
1497     }
1498 
1499     /**
1500      * Request to modify the states of multiple lights.
1501      *
1502      * @param request the settings for lights that should change
1503      */
requestLights(int deviceId, @NonNull LightsRequest request, IBinder token)1504     void requestLights(int deviceId, @NonNull LightsRequest request, IBinder token) {
1505         try {
1506             List<Integer> lightIdList = request.getLights();
1507             int[] lightIds = new int[lightIdList.size()];
1508             for (int i = 0; i < lightIds.length; i++) {
1509                 lightIds[i] = lightIdList.get(i);
1510             }
1511             List<LightState> lightStateList = request.getLightStates();
1512             mIm.setLightStates(deviceId, lightIds,
1513                     lightStateList.toArray(new LightState[0]),
1514                     token);
1515         } catch (RemoteException e) {
1516             throw e.rethrowFromSystemServer();
1517         }
1518     }
1519 
1520     /**
1521      * Open light session for input device manager
1522      *
1523      * @param token The token for the light session
1524      */
openLightSession(int deviceId, String opPkg, @NonNull IBinder token)1525     void openLightSession(int deviceId, String opPkg, @NonNull IBinder token) {
1526         try {
1527             mIm.openLightSession(deviceId, opPkg, token);
1528         } catch (RemoteException e) {
1529             throw e.rethrowFromSystemServer();
1530         }
1531     }
1532 
1533     /**
1534      * Close light session
1535      *
1536      */
closeLightSession(int deviceId, @NonNull IBinder token)1537     void closeLightSession(int deviceId, @NonNull IBinder token) {
1538         try {
1539             mIm.closeLightSession(deviceId, token);
1540         } catch (RemoteException e) {
1541             throw e.rethrowFromSystemServer();
1542         }
1543     }
1544 
1545     /**
1546      * @see InputManager#getInputDeviceVibrator(int, int)
1547      */
getInputDeviceVibrator(int deviceId, int vibratorId)1548     public Vibrator getInputDeviceVibrator(int deviceId, int vibratorId) {
1549         return new InputDeviceVibrator(deviceId, vibratorId);
1550     }
1551 
1552     /**
1553      * @see InputDevice#getVibratorManager()
1554      */
1555     @NonNull
getInputDeviceVibratorManager(int deviceId)1556     public VibratorManager getInputDeviceVibratorManager(int deviceId) {
1557         return new InputDeviceVibratorManager(deviceId);
1558     }
1559 
1560     /*
1561      * Get the list of device vibrators
1562      * @return The list of vibrators IDs
1563      */
getVibratorIds(int deviceId)1564     int[] getVibratorIds(int deviceId) {
1565         try {
1566             return mIm.getVibratorIds(deviceId);
1567         } catch (RemoteException ex) {
1568             throw ex.rethrowFromSystemServer();
1569         }
1570     }
1571 
1572     /*
1573      * Perform vibration effect
1574      */
vibrate(int deviceId, VibrationEffect effect, IBinder token)1575     void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
1576         try {
1577             mIm.vibrate(deviceId, effect, token);
1578         } catch (RemoteException ex) {
1579             throw ex.rethrowFromSystemServer();
1580         }
1581     }
1582 
1583     /*
1584      * Perform combined vibration effect
1585      */
vibrate(int deviceId, CombinedVibration effect, IBinder token)1586     void vibrate(int deviceId, CombinedVibration effect, IBinder token) {
1587         try {
1588             mIm.vibrateCombined(deviceId, effect, token);
1589         } catch (RemoteException ex) {
1590             throw ex.rethrowFromSystemServer();
1591         }
1592     }
1593 
1594     /*
1595      * Cancel an ongoing vibration
1596      */
cancelVibrate(int deviceId, IBinder token)1597     void cancelVibrate(int deviceId, IBinder token) {
1598         try {
1599             mIm.cancelVibrate(deviceId, token);
1600         } catch (RemoteException ex) {
1601             throw ex.rethrowFromSystemServer();
1602         }
1603     }
1604 
1605     /*
1606      * Check if input device is vibrating
1607      */
isVibrating(int deviceId)1608     boolean isVibrating(int deviceId)  {
1609         try {
1610             return mIm.isVibrating(deviceId);
1611         } catch (RemoteException ex) {
1612             throw ex.rethrowFromSystemServer();
1613         }
1614     }
1615 
1616     /**
1617      * Register input device vibrator state listener
1618      */
registerVibratorStateListener(int deviceId, IVibratorStateListener listener)1619     boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
1620         try {
1621             return mIm.registerVibratorStateListener(deviceId, listener);
1622         } catch (RemoteException ex) {
1623             throw ex.rethrowFromSystemServer();
1624         }
1625     }
1626 
1627     /**
1628      * Unregister input device vibrator state listener
1629      */
unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener)1630     boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
1631         try {
1632             return mIm.unregisterVibratorStateListener(deviceId, listener);
1633         } catch (RemoteException ex) {
1634             throw ex.rethrowFromSystemServer();
1635         }
1636     }
1637 
1638     /**
1639      * @see InputManager#deviceHasKeys(int[])
1640      */
deviceHasKeys(int[] keyCodes)1641     public boolean[] deviceHasKeys(int[] keyCodes) {
1642         return deviceHasKeys(-1, keyCodes);
1643     }
1644 
1645     /**
1646      * @see InputManager#deviceHasKeys(int, int[])
1647      */
deviceHasKeys(int id, int[] keyCodes)1648     public boolean[] deviceHasKeys(int id, int[] keyCodes) {
1649         boolean[] ret = new boolean[keyCodes.length];
1650         try {
1651             mIm.hasKeys(id, InputDevice.SOURCE_ANY, keyCodes, ret);
1652         } catch (RemoteException e) {
1653             throw e.rethrowFromSystemServer();
1654         }
1655         return ret;
1656     }
1657 
1658     /**
1659      * @see InputManager#getKeyCodeForKeyLocation(int, int)
1660      */
getKeyCodeForKeyLocation(int deviceId, int locationKeyCode)1661     public int getKeyCodeForKeyLocation(int deviceId, int locationKeyCode) {
1662         try {
1663             return mIm.getKeyCodeForKeyLocation(deviceId, locationKeyCode);
1664         } catch (RemoteException e) {
1665             throw e.rethrowFromSystemServer();
1666         }
1667     }
1668 
1669     /**
1670      * Returns KeyCharacterMap for the provided Keyboard layout. If provided layout is null it will
1671      * return KeyCharacter map for the default layout {@code Generic.kl}.
1672      */
getKeyCharacterMap(@ullable KeyboardLayout keyboardLayout)1673     public KeyCharacterMap getKeyCharacterMap(@Nullable KeyboardLayout keyboardLayout) {
1674         if (keyboardLayout == null) {
1675             return KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
1676         }
1677         try {
1678             return mIm.getKeyCharacterMap(keyboardLayout.getDescriptor());
1679         } catch (RemoteException e) {
1680             throw e.rethrowFromSystemServer();
1681         }
1682     }
1683 
1684     /**
1685      * @see InputManager#injectInputEvent(InputEvent, int, int)
1686      */
1687 
injectInputEvent(InputEvent event, int mode, int targetUid)1688     public boolean injectInputEvent(InputEvent event, int mode, int targetUid) {
1689         Objects.requireNonNull(event , "event must not be null");
1690 
1691         if (mode != InputEventInjectionSync.NONE
1692                 && mode != InputEventInjectionSync.WAIT_FOR_FINISHED
1693                 && mode != InputEventInjectionSync.WAIT_FOR_RESULT) {
1694             throw new IllegalArgumentException("mode is invalid");
1695         }
1696 
1697         try {
1698             return mIm.injectInputEventToTarget(event, mode, targetUid);
1699         } catch (RemoteException ex) {
1700             throw ex.rethrowFromSystemServer();
1701         }
1702     }
1703 
1704     /**
1705      * @see InputManager#injectInputEvent(InputEvent, int)
1706      */
injectInputEvent(InputEvent event, int mode)1707     public boolean injectInputEvent(InputEvent event, int mode) {
1708         return injectInputEvent(event, mode, Process.INVALID_UID);
1709     }
1710 
1711     /**
1712      * @see InputManager#setPointerIcon(PointerIcon, int, int, int, IBinder)
1713      */
setPointerIcon(PointerIcon icon, int displayId, int deviceId, int pointerId, IBinder inputToken)1714     public boolean setPointerIcon(PointerIcon icon, int displayId, int deviceId, int pointerId,
1715             IBinder inputToken) {
1716         try {
1717             return mIm.setPointerIcon(icon, displayId, deviceId, pointerId, inputToken);
1718         } catch (RemoteException ex) {
1719             throw ex.rethrowFromSystemServer();
1720         }
1721     }
1722 
1723     /**
1724      * @see InputManager#requestPointerCapture(IBinder, boolean)
1725      */
requestPointerCapture(IBinder windowToken, boolean enable)1726     public void requestPointerCapture(IBinder windowToken, boolean enable) {
1727         try {
1728             mIm.requestPointerCapture(windowToken, enable);
1729         } catch (RemoteException ex) {
1730             throw ex.rethrowFromSystemServer();
1731         }
1732     }
1733 
1734     /**
1735      * @see InputManager#monitorGestureInput(String, int)
1736      */
monitorGestureInput(String name, int displayId)1737     public InputMonitor monitorGestureInput(String name, int displayId) {
1738         try {
1739             return mIm.monitorGestureInput(new Binder(), name, displayId);
1740         } catch (RemoteException ex) {
1741             throw ex.rethrowFromSystemServer();
1742         }
1743     }
1744 
1745     /**
1746      * @see InputManager#addUniqueIdAssociationByPort(String, String)
1747      */
addUniqueIdAssociationByPort(@onNull String inputPort, @NonNull String displayUniqueId)1748     public void addUniqueIdAssociationByPort(@NonNull String inputPort,
1749             @NonNull String displayUniqueId) {
1750         try {
1751             mIm.addUniqueIdAssociationByPort(inputPort, displayUniqueId);
1752         } catch (RemoteException e) {
1753             throw e.rethrowFromSystemServer();
1754         }
1755     }
1756 
1757     /**
1758      * @see InputManager#removeUniqueIdAssociationByPort(String)
1759      */
removeUniqueIdAssociationByPort(@onNull String inputPort)1760     public void removeUniqueIdAssociationByPort(@NonNull String inputPort) {
1761         try {
1762             mIm.removeUniqueIdAssociationByPort(inputPort);
1763         } catch (RemoteException e) {
1764             throw e.rethrowFromSystemServer();
1765         }
1766     }
1767 
1768     /**
1769      * @see InputManager#addUniqueIdAssociationByDescriptor(String, String)
1770      */
addUniqueIdAssociationByDescriptor(@onNull String inputDeviceDescriptor, @NonNull String displayUniqueId)1771     public void addUniqueIdAssociationByDescriptor(@NonNull String inputDeviceDescriptor,
1772                                                    @NonNull String displayUniqueId) {
1773         try {
1774             mIm.addUniqueIdAssociationByDescriptor(inputDeviceDescriptor, displayUniqueId);
1775         } catch (RemoteException e) {
1776             throw e.rethrowFromSystemServer();
1777         }
1778     }
1779 
1780     /**
1781      * @see InputManager#removeUniqueIdAssociationByDescriptor(String)
1782      */
removeUniqueIdAssociationByDescriptor(@onNull String inputDeviceDescriptor)1783     public void removeUniqueIdAssociationByDescriptor(@NonNull String inputDeviceDescriptor) {
1784         try {
1785             mIm.removeUniqueIdAssociationByDescriptor(inputDeviceDescriptor);
1786         } catch (RemoteException e) {
1787             throw e.rethrowFromSystemServer();
1788         }
1789     }
1790 
1791     /**
1792      * @see InputManager#getInputDeviceBluetoothAddress(int)
1793      */
1794     @RequiresPermission(Manifest.permission.BLUETOOTH)
1795     @Nullable
getInputDeviceBluetoothAddress(int deviceId)1796     public String getInputDeviceBluetoothAddress(int deviceId) {
1797         try {
1798             return mIm.getInputDeviceBluetoothAddress(deviceId);
1799         } catch (RemoteException e) {
1800             throw e.rethrowFromSystemServer();
1801         }
1802     }
1803 
1804     /**
1805      * @see InputManager#cancelCurrentTouch()
1806      */
cancelCurrentTouch()1807     public void cancelCurrentTouch() {
1808         try {
1809             mIm.cancelCurrentTouch();
1810         } catch (RemoteException e) {
1811             throw e.rethrowFromSystemServer();
1812         }
1813     }
1814 
1815     /**
1816      * @see InputManager#pilferPointers(IBinder)
1817      */
1818     @RequiresPermission(Manifest.permission.MONITOR_INPUT)
pilferPointers(IBinder inputChannelToken)1819     public void pilferPointers(IBinder inputChannelToken) {
1820         try {
1821             mIm.pilferPointers(inputChannelToken);
1822         } catch (RemoteException e) {
1823             throw e.rethrowFromSystemServer();
1824         }
1825     }
1826 }
1827