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