• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 com.android.server.input;
18 
19 import static android.view.KeyEvent.KEYCODE_UNKNOWN;
20 
21 import android.Manifest;
22 import android.annotation.EnforcePermission;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.app.ActivityManagerInternal;
26 import android.app.Notification;
27 import android.app.NotificationManager;
28 import android.app.PendingIntent;
29 import android.bluetooth.BluetoothAdapter;
30 import android.bluetooth.BluetoothDevice;
31 import android.content.BroadcastReceiver;
32 import android.content.ComponentName;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.content.IntentFilter;
36 import android.content.pm.ActivityInfo;
37 import android.content.pm.ApplicationInfo;
38 import android.content.pm.PackageManager;
39 import android.content.pm.PackageManager.NameNotFoundException;
40 import android.content.pm.ResolveInfo;
41 import android.content.res.Resources;
42 import android.content.res.Resources.NotFoundException;
43 import android.content.res.TypedArray;
44 import android.content.res.XmlResourceParser;
45 import android.database.ContentObserver;
46 import android.graphics.PointF;
47 import android.hardware.SensorPrivacyManager;
48 import android.hardware.SensorPrivacyManager.Sensors;
49 import android.hardware.SensorPrivacyManagerInternal;
50 import android.hardware.display.DisplayManager;
51 import android.hardware.display.DisplayViewport;
52 import android.hardware.input.IInputDeviceBatteryListener;
53 import android.hardware.input.IInputDevicesChangedListener;
54 import android.hardware.input.IInputManager;
55 import android.hardware.input.IInputSensorEventListener;
56 import android.hardware.input.ITabletModeChangedListener;
57 import android.hardware.input.InputDeviceIdentifier;
58 import android.hardware.input.InputManager;
59 import android.hardware.input.InputManagerInternal;
60 import android.hardware.input.InputManagerInternal.LidSwitchCallback;
61 import android.hardware.input.InputSensorInfo;
62 import android.hardware.input.KeyboardLayout;
63 import android.hardware.input.TouchCalibration;
64 import android.hardware.lights.Light;
65 import android.hardware.lights.LightState;
66 import android.media.AudioManager;
67 import android.os.Binder;
68 import android.os.Bundle;
69 import android.os.CombinedVibration;
70 import android.os.Environment;
71 import android.os.Handler;
72 import android.os.IBinder;
73 import android.os.IInputConstants;
74 import android.os.IVibratorStateListener;
75 import android.os.InputEventInjectionResult;
76 import android.os.InputEventInjectionSync;
77 import android.os.LocaleList;
78 import android.os.Looper;
79 import android.os.Message;
80 import android.os.Process;
81 import android.os.RemoteCallbackList;
82 import android.os.RemoteException;
83 import android.os.ResultReceiver;
84 import android.os.ShellCallback;
85 import android.os.UserHandle;
86 import android.os.VibrationEffect;
87 import android.os.vibrator.StepSegment;
88 import android.os.vibrator.VibrationEffectSegment;
89 import android.provider.DeviceConfig;
90 import android.provider.Settings;
91 import android.provider.Settings.SettingNotFoundException;
92 import android.text.TextUtils;
93 import android.util.ArrayMap;
94 import android.util.Log;
95 import android.util.Slog;
96 import android.util.SparseArray;
97 import android.util.SparseBooleanArray;
98 import android.view.Display;
99 import android.view.IInputFilter;
100 import android.view.IInputFilterHost;
101 import android.view.IInputMonitorHost;
102 import android.view.InputApplicationHandle;
103 import android.view.InputChannel;
104 import android.view.InputDevice;
105 import android.view.InputEvent;
106 import android.view.InputMonitor;
107 import android.view.KeyEvent;
108 import android.view.PointerIcon;
109 import android.view.Surface;
110 import android.view.SurfaceControl;
111 import android.view.VerifiedInputEvent;
112 import android.view.ViewConfiguration;
113 import android.widget.Toast;
114 
115 import com.android.internal.R;
116 import com.android.internal.annotations.GuardedBy;
117 import com.android.internal.annotations.VisibleForTesting;
118 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
119 import com.android.internal.notification.SystemNotificationChannels;
120 import com.android.internal.os.SomeArgs;
121 import com.android.internal.util.ArrayUtils;
122 import com.android.internal.util.DumpUtils;
123 import com.android.internal.util.Preconditions;
124 import com.android.internal.util.XmlUtils;
125 import com.android.server.DisplayThread;
126 import com.android.server.LocalServices;
127 import com.android.server.Watchdog;
128 import com.android.server.policy.WindowManagerPolicy;
129 
130 import libcore.io.IoUtils;
131 import libcore.io.Streams;
132 
133 import java.io.File;
134 import java.io.FileDescriptor;
135 import java.io.FileInputStream;
136 import java.io.FileNotFoundException;
137 import java.io.FileWriter;
138 import java.io.IOException;
139 import java.io.InputStream;
140 import java.io.InputStreamReader;
141 import java.io.PrintWriter;
142 import java.util.ArrayList;
143 import java.util.Arrays;
144 import java.util.Collections;
145 import java.util.HashMap;
146 import java.util.HashSet;
147 import java.util.List;
148 import java.util.Locale;
149 import java.util.Map;
150 import java.util.Objects;
151 import java.util.OptionalInt;
152 import java.util.function.Consumer;
153 
154 /** The system implementation of {@link IInputManager} that manages input devices. */
155 public class InputManagerService extends IInputManager.Stub
156         implements Watchdog.Monitor {
157     static final String TAG = "InputManager";
158     static final boolean DEBUG = false;
159 
160     private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
161     private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml";
162 
163     // Feature flag name for the deep press feature
164     private static final String DEEP_PRESS_ENABLED = "deep_press_enabled";
165 
166     private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
167     private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
168     private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
169     private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
170     private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
171     private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
172     private static final int MSG_POINTER_DISPLAY_ID_CHANGED = 7;
173 
174     private static final int DEFAULT_VIBRATION_MAGNITUDE = 192;
175     private static final AdditionalDisplayInputProperties
176             DEFAULT_ADDITIONAL_DISPLAY_INPUT_PROPERTIES = new AdditionalDisplayInputProperties();
177 
178     /**
179      * We know the issue and are working to fix it, so suppressing the toast to not annoy
180      * dogfooders.
181      *
182      * TODO(b/169067926): Remove this
183      */
184     private static final String[] PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST = {
185             "com.snapchat.android" // b/173297887
186     };
187 
188     /** TODO(b/169067926): Remove this. */
189     private static final boolean UNTRUSTED_TOUCHES_TOAST = false;
190 
191     private final NativeInputManagerService mNative;
192 
193     private final Context mContext;
194     private final InputManagerHandler mHandler;
195 
196     // Context cache used for loading pointer resources.
197     private Context mPointerIconDisplayContext;
198 
199     private final File mDoubleTouchGestureEnableFile;
200 
201     private WindowManagerCallbacks mWindowManagerCallbacks;
202     private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
203     private boolean mSystemReady;
204     private NotificationManager mNotificationManager;
205 
206     private final Object mTabletModeLock = new Object();
207     // List of currently registered tablet mode changed listeners by process id
208     @GuardedBy("mTabletModeLock")
209     private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
210             new SparseArray<>();
211     private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
212             new ArrayList<>();
213 
214     private final Object mSensorEventLock = new Object();
215     // List of currently registered sensor event listeners by process id
216     @GuardedBy("mSensorEventLock")
217     private final SparseArray<SensorEventListenerRecord> mSensorEventListeners =
218             new SparseArray<>();
219     private final List<SensorEventListenerRecord> mSensorEventListenersToNotify =
220             new ArrayList<>();
221     private final List<SensorEventListenerRecord> mSensorAccuracyListenersToNotify =
222             new ArrayList<>();
223 
224     // Persistent data store.  Must be locked each time during use.
225     private final PersistentDataStore mDataStore = new PersistentDataStore();
226 
227     // List of currently registered input devices changed listeners by process id.
228     private final Object mInputDevicesLock = new Object();
229     @GuardedBy("mInputDevicesLock")
230     private boolean mInputDevicesChangedPending;
231     @GuardedBy("mInputDevicesLock")
232     private InputDevice[] mInputDevices = new InputDevice[0];
233     @GuardedBy("mInputDevicesLock")
234     private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
235             new SparseArray<>();
236     private final ArrayList<InputDevicesChangedListenerRecord>
237             mTempInputDevicesChangedListenersToNotify = new ArrayList<>(); // handler thread only
238     private final ArrayList<InputDevice> mTempFullKeyboards =
239             new ArrayList<>(); // handler thread only
240     private boolean mKeyboardLayoutNotificationShown;
241     private Toast mSwitchedKeyboardLayoutToast;
242 
243     // State for vibrator tokens.
244     private final Object mVibratorLock = new Object();
245     private final Map<IBinder, VibratorToken> mVibratorTokens = new ArrayMap<>();
246     private int mNextVibratorTokenValue;
247 
248     // List of currently registered vibrator state changed listeners by device id.
249     @GuardedBy("mVibratorLock")
250     private final SparseArray<RemoteCallbackList<IVibratorStateListener>> mVibratorStateListeners =
251             new SparseArray<>();
252     // List of vibrator states by device id.
253     @GuardedBy("mVibratorLock")
254     private final SparseBooleanArray mIsVibrating = new SparseBooleanArray();
255     private final Object mLightLock = new Object();
256     // State for light tokens. A light token marks a lights manager session, it is generated
257     // by light session open() and deleted in session close().
258     // When lights session requests light states, the token will be used to find the light session.
259     @GuardedBy("mLightLock")
260     private final ArrayMap<IBinder, LightSession> mLightSessions = new ArrayMap<>();
261 
262     // State for lid switch
263     // Lock for the lid switch state. Held when triggering callbacks to guarantee lid switch events
264     // are delivered in order. For ex, when a new lid switch callback is registered the lock is held
265     // while the callback is processing the initial lid switch event which guarantees that any
266     // events that occur at the same time are delivered after the callback has returned.
267     private final Object mLidSwitchLock = new Object();
268     @GuardedBy("mLidSwitchLock")
269     private final List<LidSwitchCallback> mLidSwitchCallbacks = new ArrayList<>();
270 
271     // State for the currently installed input filter.
272     final Object mInputFilterLock = new Object();
273     @GuardedBy("mInputFilterLock")
274     IInputFilter mInputFilter;
275     @GuardedBy("mInputFilterLock")
276     InputFilterHost mInputFilterHost;
277 
278     // The associations of input devices to displays by port. Maps from input device port (String)
279     // to display id (int). Currently only accessed by InputReader.
280     private final Map<String, Integer> mStaticAssociations;
281     private final Object mAssociationsLock = new Object();
282     @GuardedBy("mAssociationLock")
283     private final Map<String, Integer> mRuntimeAssociations = new ArrayMap<>();
284     @GuardedBy("mAssociationLock")
285     private final Map<String, String> mUniqueIdAssociations = new ArrayMap<>();
286 
287     // Guards per-display input properties and properties relating to the mouse pointer.
288     // Threads can wait on this lock to be notified the next time the display on which the mouse
289     // pointer is shown has changed.
290     // WARNING: Do not call other services outside of input while holding this lock.
291     private final Object mAdditionalDisplayInputPropertiesLock = new Object();
292 
293     // Forces the PointerController to target a specific display id.
294     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
295     private int mOverriddenPointerDisplayId = Display.INVALID_DISPLAY;
296 
297     // PointerController is the source of truth of the pointer display. This is the value of the
298     // latest pointer display id reported by PointerController.
299     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
300     private int mAcknowledgedPointerDisplayId = Display.INVALID_DISPLAY;
301     // This is the latest display id that IMS has requested PointerController to use. If there are
302     // no devices that can control the pointer, PointerController may end up disregarding this
303     // value.
304     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
305     private int mRequestedPointerDisplayId = Display.INVALID_DISPLAY;
306     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
307     private final SparseArray<AdditionalDisplayInputProperties> mAdditionalDisplayInputProperties =
308             new SparseArray<>();
309     // This contains the per-display properties that are currently applied by native code. It should
310     // be kept in sync with the properties for mRequestedPointerDisplayId.
311     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
312     private final AdditionalDisplayInputProperties mCurrentDisplayProperties =
313             new AdditionalDisplayInputProperties();
314     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
315     private int mIconType = PointerIcon.TYPE_NOT_SPECIFIED;
316     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
317     private PointerIcon mIcon;
318 
319     // Holds all the registered gesture monitors that are implemented as spy windows. The spy
320     // windows are mapped by their InputChannel tokens.
321     @GuardedBy("mInputMonitors")
322     final Map<IBinder, GestureMonitorSpyWindow> mInputMonitors = new HashMap<>();
323 
324     // Manages battery state for input devices.
325     private final BatteryController mBatteryController;
326 
327     // Maximum number of milliseconds to wait for input event injection.
328     private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
329 
330     // Key states (may be returned by queries about the current state of a
331     // particular key code, scan code or switch).
332 
333     /** The key state is unknown or the requested key itself is not supported. */
334     public static final int KEY_STATE_UNKNOWN = -1;
335 
336     /** The key is up. /*/
337     public static final int KEY_STATE_UP = 0;
338 
339     /** The key is down. */
340     public static final int KEY_STATE_DOWN = 1;
341 
342     /** The key is down but is a virtual key press that is being emulated by the system. */
343     public static final int KEY_STATE_VIRTUAL = 2;
344 
345     /** Scan code: Mouse / trackball button. */
346     public static final int BTN_MOUSE = 0x110;
347 
348     // Switch code values must match bionic/libc/kernel/common/linux/input.h
349     /** Switch code: Lid switch.  When set, lid is shut. */
350     public static final int SW_LID = 0x00;
351 
352     /** Switch code: Tablet mode switch.
353      * When set, the device is in tablet mode (i.e. no keyboard is connected).
354      */
355     public static final int SW_TABLET_MODE = 0x01;
356 
357     /** Switch code: Keypad slide.  When set, keyboard is exposed. */
358     public static final int SW_KEYPAD_SLIDE = 0x0a;
359 
360     /** Switch code: Headphone.  When set, headphone is inserted. */
361     public static final int SW_HEADPHONE_INSERT = 0x02;
362 
363     /** Switch code: Microphone.  When set, microphone is inserted. */
364     public static final int SW_MICROPHONE_INSERT = 0x04;
365 
366     /** Switch code: Line out.  When set, Line out (hi-Z) is inserted. */
367     public static final int SW_LINEOUT_INSERT = 0x06;
368 
369     /** Switch code: Headphone/Microphone Jack.  When set, something is inserted. */
370     public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
371 
372     /** Switch code: Camera lens cover. When set the lens is covered. */
373     public static final int SW_CAMERA_LENS_COVER = 0x09;
374 
375     /** Switch code: Microphone. When set it is off. */
376     public static final int SW_MUTE_DEVICE = 0x0e;
377 
378     public static final int SW_LID_BIT = 1 << SW_LID;
379     public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
380     public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
381     public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
382     public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
383     public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
384     public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
385     public static final int SW_JACK_BITS =
386             SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
387     public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
388     public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE;
389 
390     /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
391     final boolean mUseDevInputEventForAudioJack;
392 
393     /** Point of injection for test dependencies. */
394     @VisibleForTesting
395     static class Injector {
396         private final Context mContext;
397         private final Looper mLooper;
398 
Injector(Context context, Looper looper)399         Injector(Context context, Looper looper) {
400             mContext = context;
401             mLooper = looper;
402         }
403 
getContext()404         Context getContext() {
405             return mContext;
406         }
407 
getLooper()408         Looper getLooper() {
409             return mLooper;
410         }
411 
getNativeService(InputManagerService service)412         NativeInputManagerService getNativeService(InputManagerService service) {
413             return new NativeInputManagerService.NativeImpl(service, mContext, mLooper.getQueue());
414         }
415 
registerLocalService(InputManagerInternal localService)416         void registerLocalService(InputManagerInternal localService) {
417             LocalServices.addService(InputManagerInternal.class, localService);
418         }
419     }
420 
InputManagerService(Context context)421     public InputManagerService(Context context) {
422         this(new Injector(context, DisplayThread.get().getLooper()));
423     }
424 
425     @VisibleForTesting
InputManagerService(Injector injector)426     InputManagerService(Injector injector) {
427         // The static association map is accessed by both java and native code, so it must be
428         // initialized before initializing the native service.
429         mStaticAssociations = loadStaticInputPortAssociations();
430 
431         mContext = injector.getContext();
432         mHandler = new InputManagerHandler(injector.getLooper());
433         mNative = injector.getNativeService(this);
434         mBatteryController = new BatteryController(mContext, mNative);
435 
436         mUseDevInputEventForAudioJack =
437                 mContext.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
438         Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
439                 + mUseDevInputEventForAudioJack);
440 
441         String doubleTouchGestureEnablePath = mContext.getResources().getString(
442                 R.string.config_doubleTouchGestureEnableFile);
443         mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
444             new File(doubleTouchGestureEnablePath);
445 
446         injector.registerLocalService(new LocalService());
447     }
448 
setWindowManagerCallbacks(WindowManagerCallbacks callbacks)449     public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
450         if (mWindowManagerCallbacks != null) {
451             unregisterLidSwitchCallbackInternal(mWindowManagerCallbacks);
452         }
453         mWindowManagerCallbacks = callbacks;
454         registerLidSwitchCallbackInternal(mWindowManagerCallbacks);
455     }
456 
setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks)457     public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
458         mWiredAccessoryCallbacks = callbacks;
459     }
460 
registerLidSwitchCallbackInternal(@onNull LidSwitchCallback callback)461     void registerLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
462         synchronized (mLidSwitchLock) {
463             mLidSwitchCallbacks.add(callback);
464 
465             // Skip triggering the initial callback if the system is not yet ready as the switch
466             // state will be reported as KEY_STATE_UNKNOWN. The callback will be triggered in
467             // systemRunning().
468             if (mSystemReady) {
469                 boolean lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID)
470                         == KEY_STATE_UP;
471                 callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen);
472             }
473         }
474     }
475 
unregisterLidSwitchCallbackInternal(@onNull LidSwitchCallback callback)476     void unregisterLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
477         synchronized (mLidSwitchLock) {
478             mLidSwitchCallbacks.remove(callback);
479         }
480     }
481 
start()482     public void start() {
483         Slog.i(TAG, "Starting input manager");
484         mNative.start();
485 
486         // Add ourselves to the Watchdog monitors.
487         Watchdog.getInstance().addMonitor(this);
488 
489         registerPointerSpeedSettingObserver();
490         registerShowTouchesSettingObserver();
491         registerAccessibilityLargePointerSettingObserver();
492         registerLongPressTimeoutObserver();
493         registerMaximumObscuringOpacityForTouchSettingObserver();
494         registerBlockUntrustedTouchesModeSettingObserver();
495 
496         mContext.registerReceiver(new BroadcastReceiver() {
497             @Override
498             public void onReceive(Context context, Intent intent) {
499                 updatePointerSpeedFromSettings();
500                 updateShowTouchesFromSettings();
501                 updateAccessibilityLargePointerFromSettings();
502                 updateDeepPressStatusFromSettings("user switched");
503             }
504         }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
505 
506         updatePointerSpeedFromSettings();
507         updateShowTouchesFromSettings();
508         updateAccessibilityLargePointerFromSettings();
509         updateDeepPressStatusFromSettings("just booted");
510         updateMaximumObscuringOpacityForTouchFromSettings();
511         updateBlockUntrustedTouchesModeFromSettings();
512     }
513 
514     // TODO(BT) Pass in parameter for bluetooth system
systemRunning()515     public void systemRunning() {
516         if (DEBUG) {
517             Slog.d(TAG, "System ready.");
518         }
519         mNotificationManager = (NotificationManager)mContext.getSystemService(
520                 Context.NOTIFICATION_SERVICE);
521 
522         synchronized (mLidSwitchLock) {
523             mSystemReady = true;
524 
525             // Send the initial lid switch state to any callback registered before the system was
526             // ready.
527             int switchState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID);
528             for (int i = 0; i < mLidSwitchCallbacks.size(); i++) {
529                 LidSwitchCallback callback = mLidSwitchCallbacks.get(i);
530                 callback.notifyLidSwitchChanged(0 /* whenNanos */, switchState == KEY_STATE_UP);
531             }
532         }
533 
534         // Set the HW mic toggle switch state
535         final int micMuteState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY,
536                 SW_MUTE_DEVICE);
537         if (micMuteState != InputManager.SWITCH_STATE_UNKNOWN) {
538             setSensorPrivacy(Sensors.MICROPHONE, micMuteState != InputManager.SWITCH_STATE_OFF);
539         }
540         // Set the HW camera toggle switch state
541         final int cameraMuteState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY,
542                 SW_CAMERA_LENS_COVER);
543         if (cameraMuteState != InputManager.SWITCH_STATE_UNKNOWN) {
544             setSensorPrivacy(Sensors.CAMERA, cameraMuteState != InputManager.SWITCH_STATE_OFF);
545         }
546 
547         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
548         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
549         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
550         filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
551         filter.addDataScheme("package");
552         mContext.registerReceiver(new BroadcastReceiver() {
553             @Override
554             public void onReceive(Context context, Intent intent) {
555                 updateKeyboardLayouts();
556             }
557         }, filter, null, mHandler);
558 
559         filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
560         mContext.registerReceiver(new BroadcastReceiver() {
561             @Override
562             public void onReceive(Context context, Intent intent) {
563                 reloadDeviceAliases();
564             }
565         }, filter, null, mHandler);
566 
567         mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
568         mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
569 
570         if (mWiredAccessoryCallbacks != null) {
571             mWiredAccessoryCallbacks.systemReady();
572         }
573     }
574 
reloadKeyboardLayouts()575     private void reloadKeyboardLayouts() {
576         if (DEBUG) {
577             Slog.d(TAG, "Reloading keyboard layouts.");
578         }
579         mNative.reloadKeyboardLayouts();
580     }
581 
reloadDeviceAliases()582     private void reloadDeviceAliases() {
583         if (DEBUG) {
584             Slog.d(TAG, "Reloading device names.");
585         }
586         mNative.reloadDeviceAliases();
587     }
588 
setDisplayViewportsInternal(List<DisplayViewport> viewports)589     private void setDisplayViewportsInternal(List<DisplayViewport> viewports) {
590         final DisplayViewport[] vArray = new DisplayViewport[viewports.size()];
591         for (int i = viewports.size() - 1; i >= 0; --i) {
592             vArray[i] = viewports.get(i);
593         }
594         mNative.setDisplayViewports(vArray);
595 
596         // Attempt to update the pointer display when viewports change when there is no override.
597         // Take care to not make calls to window manager while holding internal locks.
598         final int pointerDisplayId = mWindowManagerCallbacks.getPointerDisplayId();
599         synchronized (mAdditionalDisplayInputPropertiesLock) {
600             if (mOverriddenPointerDisplayId == Display.INVALID_DISPLAY) {
601                 updatePointerDisplayIdLocked(pointerDisplayId);
602             }
603         }
604     }
605 
606     /**
607      * Gets the current state of a key or button by key code.
608      * @param deviceId The input device id, or -1 to consult all devices.
609      * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
610      * consider all input sources.  An input device is consulted if at least one of its
611      * non-class input source bits matches the specified source mask.
612      * @param keyCode The key code to check.
613      * @return The key state.
614      */
getKeyCodeState(int deviceId, int sourceMask, int keyCode)615     public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
616         return mNative.getKeyCodeState(deviceId, sourceMask, keyCode);
617     }
618 
619     /**
620      * Gets the current state of a key or button by scan code.
621      * @param deviceId The input device id, or -1 to consult all devices.
622      * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
623      * consider all input sources.  An input device is consulted if at least one of its
624      * non-class input source bits matches the specified source mask.
625      * @param scanCode The scan code to check.
626      * @return The key state.
627      */
getScanCodeState(int deviceId, int sourceMask, int scanCode)628     public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
629         return mNative.getScanCodeState(deviceId, sourceMask, scanCode);
630     }
631 
632     /**
633      * Gets the current state of a switch by switch code.
634      * @param deviceId The input device id, or -1 to consult all devices.
635      * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
636      * consider all input sources.  An input device is consulted if at least one of its
637      * non-class input source bits matches the specified source mask.
638      * @param switchCode The switch code to check.
639      * @return The switch state.
640      */
getSwitchState(int deviceId, int sourceMask, int switchCode)641     public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
642         return mNative.getSwitchState(deviceId, sourceMask, switchCode);
643     }
644 
645     /**
646      * Determines whether the specified key codes are supported by a particular device.
647      * @param deviceId The input device id, or -1 to consult all devices.
648      * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
649      * consider all input sources.  An input device is consulted if at least one of its
650      * non-class input source bits matches the specified source mask.
651      * @param keyCodes The array of key codes to check.
652      * @param keyExists An array at least as large as keyCodes whose entries will be set
653      * to true or false based on the presence or absence of support for the corresponding
654      * key codes.
655      * @return True if the lookup was successful, false otherwise.
656      */
657     @Override // Binder call
hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists)658     public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
659         Objects.requireNonNull(keyCodes, "keyCodes must not be null");
660         Objects.requireNonNull(keyExists, "keyExists must not be null");
661         if (keyExists.length < keyCodes.length) {
662             throw new IllegalArgumentException("keyExists must be at least as large as keyCodes");
663         }
664 
665         return mNative.hasKeys(deviceId, sourceMask, keyCodes, keyExists);
666     }
667 
668     /**
669      * Returns the keyCode generated by the specified location on a US keyboard layout.
670      * This takes into consideration the currently active keyboard layout.
671      *
672      * @param deviceId The input device id.
673      * @param locationKeyCode The location of a key on a US keyboard layout.
674      * @return The KeyCode this physical key location produces.
675      */
676     @Override // Binder call
getKeyCodeForKeyLocation(int deviceId, int locationKeyCode)677     public int getKeyCodeForKeyLocation(int deviceId, int locationKeyCode) {
678         if (locationKeyCode <= KEYCODE_UNKNOWN || locationKeyCode > KeyEvent.getMaxKeyCode()) {
679             return KEYCODE_UNKNOWN;
680         }
681         return mNative.getKeyCodeForKeyLocation(deviceId, locationKeyCode);
682     }
683 
684     /**
685      * Transfer the current touch gesture to the provided window.
686      *
687      * @param destChannelToken The token of the window or input channel that should receive the
688      * gesture
689      * @return True if the transfer succeeded, false if there was no active touch gesture happening
690      */
transferTouch(IBinder destChannelToken, int displayId)691     public boolean transferTouch(IBinder destChannelToken, int displayId) {
692         // TODO(b/162194035): Replace this with a SPY window
693         Objects.requireNonNull(destChannelToken, "destChannelToken must not be null");
694         return mNative.transferTouch(destChannelToken, displayId);
695     }
696 
697     /**
698      * Creates an input channel that will receive all input from the input dispatcher.
699      * @param inputChannelName The input channel name.
700      * @param displayId Target display id.
701      * @return The input channel.
702      */
monitorInput(String inputChannelName, int displayId)703     public InputChannel monitorInput(String inputChannelName, int displayId) {
704         Objects.requireNonNull(inputChannelName, "inputChannelName not be null");
705 
706         if (displayId < Display.DEFAULT_DISPLAY) {
707             throw new IllegalArgumentException("displayId must >= 0.");
708         }
709 
710         return mNative.createInputMonitor(displayId, inputChannelName, Binder.getCallingPid());
711     }
712 
713     @NonNull
createSpyWindowGestureMonitor(IBinder monitorToken, String name, int displayId, int pid, int uid)714     private InputChannel createSpyWindowGestureMonitor(IBinder monitorToken, String name,
715             int displayId, int pid, int uid) {
716         final SurfaceControl sc = mWindowManagerCallbacks.createSurfaceForGestureMonitor(name,
717                 displayId);
718         if (sc == null) {
719             throw new IllegalArgumentException(
720                     "Could not create gesture monitor surface on display: " + displayId);
721         }
722         final InputChannel channel = createInputChannel(name);
723 
724         try {
725             monitorToken.linkToDeath(() -> removeSpyWindowGestureMonitor(channel.getToken()), 0);
726         } catch (RemoteException e) {
727             Slog.i(TAG, "Client died before '" + name + "' could be created.");
728             return null;
729         }
730         synchronized (mInputMonitors) {
731             mInputMonitors.put(channel.getToken(),
732                     new GestureMonitorSpyWindow(monitorToken, name, displayId, pid, uid, sc,
733                             channel));
734         }
735 
736         final InputChannel outInputChannel = new InputChannel();
737         channel.copyTo(outInputChannel);
738         return outInputChannel;
739     }
740 
removeSpyWindowGestureMonitor(IBinder inputChannelToken)741     private void removeSpyWindowGestureMonitor(IBinder inputChannelToken) {
742         final GestureMonitorSpyWindow monitor;
743         synchronized (mInputMonitors) {
744             monitor = mInputMonitors.remove(inputChannelToken);
745         }
746         removeInputChannel(inputChannelToken);
747         if (monitor == null) return;
748         monitor.remove();
749     }
750 
751     /**
752      * Creates an input monitor that will receive pointer events for the purposes of system-wide
753      * gesture interpretation.
754      *
755      * @param requestedName The input channel name.
756      * @param displayId Target display id.
757      * @return The input channel.
758      */
759     @Override // Binder call
monitorGestureInput(IBinder monitorToken, @NonNull String requestedName, int displayId)760     public InputMonitor monitorGestureInput(IBinder monitorToken, @NonNull String requestedName,
761             int displayId) {
762         if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT,
763                 "monitorGestureInput()")) {
764             throw new SecurityException("Requires MONITOR_INPUT permission");
765         }
766         Objects.requireNonNull(requestedName, "name must not be null.");
767         Objects.requireNonNull(monitorToken, "token must not be null.");
768 
769         if (displayId < Display.DEFAULT_DISPLAY) {
770             throw new IllegalArgumentException("displayId must >= 0.");
771         }
772         final String name = "[Gesture Monitor] " + requestedName;
773         final int pid = Binder.getCallingPid();
774         final int uid = Binder.getCallingUid();
775 
776         final long ident = Binder.clearCallingIdentity();
777         try {
778             final InputChannel inputChannel =
779                             createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid);
780             return new InputMonitor(inputChannel, new InputMonitorHost(inputChannel.getToken()));
781         } finally {
782             Binder.restoreCallingIdentity(ident);
783         }
784     }
785 
786     /**
787      * Creates an input channel to be used as an input event target.
788      *
789      * @param name The name of this input channel
790      */
createInputChannel(String name)791     public InputChannel createInputChannel(String name) {
792         return mNative.createInputChannel(name);
793     }
794 
795     /**
796      * Removes an input channel.
797      * @param connectionToken The input channel to unregister.
798      */
removeInputChannel(IBinder connectionToken)799     public void removeInputChannel(IBinder connectionToken) {
800         Objects.requireNonNull(connectionToken, "connectionToken must not be null");
801         mNative.removeInputChannel(connectionToken);
802     }
803 
804     /**
805      * Sets an input filter that will receive all input events before they are dispatched.
806      * The input filter may then reinterpret input events or inject new ones.
807      *
808      * To ensure consistency, the input dispatcher automatically drops all events
809      * in progress whenever an input filter is installed or uninstalled.  After an input
810      * filter is uninstalled, it can no longer send input events unless it is reinstalled.
811      * Any events it attempts to send after it has been uninstalled will be dropped.
812      *
813      * @param filter The input filter, or null to remove the current filter.
814      */
setInputFilter(IInputFilter filter)815     public void setInputFilter(IInputFilter filter) {
816         synchronized (mInputFilterLock) {
817             final IInputFilter oldFilter = mInputFilter;
818             if (oldFilter == filter) {
819                 return; // nothing to do
820             }
821 
822             if (oldFilter != null) {
823                 mInputFilter = null;
824                 mInputFilterHost.disconnectLocked();
825                 mInputFilterHost = null;
826                 try {
827                     oldFilter.uninstall();
828                 } catch (RemoteException re) {
829                     /* ignore */
830                 }
831             }
832 
833             if (filter != null) {
834                 mInputFilter = filter;
835                 mInputFilterHost = new InputFilterHost();
836                 try {
837                     filter.install(mInputFilterHost);
838                 } catch (RemoteException re) {
839                     /* ignore */
840                 }
841             }
842 
843             mNative.setInputFilterEnabled(filter != null);
844         }
845     }
846 
847     /**
848      * Set the state of the touch mode.
849      *
850      * WindowManager remains the source of truth of the touch mode state.
851      * However, we need to keep a copy of this state in input.
852      *
853      * The apps determine the touch mode state. Therefore, a single app will
854      * affect the global state. That state change needs to be propagated to
855      * other apps, when they become focused.
856      *
857      * When input dispatches focus to the apps, the touch mode state
858      * will be sent together with the focus change (but each one in its own event).
859      *
860      * @param inTouchMode true if the device is in touch mode
861      * @param pid the pid of the process that requested to switch touch mode state
862      * @param uid the uid of the process that requested to switch touch mode state
863      * @param hasPermission if set to {@code true} then no further authorization will be performed
864      * @return {@code true} if the touch mode was successfully changed, {@code false} otherwise
865      */
setInTouchMode(boolean inTouchMode, int pid, int uid, boolean hasPermission)866     public boolean setInTouchMode(boolean inTouchMode, int pid, int uid, boolean hasPermission) {
867         return mNative.setInTouchMode(inTouchMode, pid, uid, hasPermission);
868     }
869 
870     @Override // Binder call
injectInputEvent(InputEvent event, int mode)871     public boolean injectInputEvent(InputEvent event, int mode) {
872         return injectInputEventToTarget(event, mode, Process.INVALID_UID);
873     }
874 
875     @Override // Binder call
injectInputEventToTarget(InputEvent event, int mode, int targetUid)876     public boolean injectInputEventToTarget(InputEvent event, int mode, int targetUid) {
877         if (!checkCallingPermission(android.Manifest.permission.INJECT_EVENTS,
878                 "injectInputEvent()", true /*checkInstrumentationSource*/)) {
879             throw new SecurityException(
880                     "Injecting input events requires the caller (or the source of the "
881                             + "instrumentation, if any) to have the INJECT_EVENTS permission.");
882         }
883         // We are not checking if targetUid matches the callingUid, since having the permission
884         // already means you can inject into any window.
885         Objects.requireNonNull(event, "event must not be null");
886         if (mode != InputEventInjectionSync.NONE
887                 && mode != InputEventInjectionSync.WAIT_FOR_FINISHED
888                 && mode != InputEventInjectionSync.WAIT_FOR_RESULT) {
889             throw new IllegalArgumentException("mode is invalid");
890         }
891 
892         final int pid = Binder.getCallingPid();
893         final long ident = Binder.clearCallingIdentity();
894         final boolean injectIntoUid = targetUid != Process.INVALID_UID;
895         final int result;
896         try {
897             result = mNative.injectInputEvent(event, injectIntoUid,
898                     targetUid, mode, INJECTION_TIMEOUT_MILLIS,
899                     WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
900         } finally {
901             Binder.restoreCallingIdentity(ident);
902         }
903         switch (result) {
904             case InputEventInjectionResult.SUCCEEDED:
905                 return true;
906             case InputEventInjectionResult.TARGET_MISMATCH:
907                 if (!injectIntoUid) {
908                     throw new IllegalStateException("Injection should not result in TARGET_MISMATCH"
909                             + " when it is not targeted into to a specific uid.");
910                 }
911                 // TODO(b/228161340): Remove the fallback of targeting injection into all windows
912                 //  when the caller has the injection permission.
913                 // Explicitly maintain the same behavior as previous versions of Android, where
914                 // injection is allowed into all windows if the caller has the INJECT_EVENTS
915                 // permission, even if it is targeting a certain uid.
916                 if (checkCallingPermission(android.Manifest.permission.INJECT_EVENTS,
917                         "injectInputEvent-target-mismatch-fallback")) {
918                     Slog.w(TAG, "Targeted input event was not directed at a window owned by uid "
919                             + targetUid + ". Falling back to injecting into all windows.");
920                     return injectInputEventToTarget(event, mode, Process.INVALID_UID);
921                 }
922                 throw new IllegalArgumentException(
923                     "Targeted input event injection from pid " + pid
924                             + " was not directed at a window owned by uid "
925                             + targetUid + ".");
926             case InputEventInjectionResult.TIMED_OUT:
927                 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
928                 return false;
929             case InputEventInjectionResult.FAILED:
930             default:
931                 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
932                 return false;
933         }
934     }
935 
936     @Override // Binder call
verifyInputEvent(InputEvent event)937     public VerifiedInputEvent verifyInputEvent(InputEvent event) {
938         Objects.requireNonNull(event, "event must not be null");
939         return mNative.verifyInputEvent(event);
940     }
941 
942     /**
943      * Gets information about the input device with the specified id.
944      * @param deviceId The device id.
945      * @return The input device or null if not found.
946      */
947     @Override // Binder call
getInputDevice(int deviceId)948     public InputDevice getInputDevice(int deviceId) {
949         synchronized (mInputDevicesLock) {
950             for (final InputDevice inputDevice : mInputDevices) {
951                 if (inputDevice.getId() == deviceId) {
952                     return inputDevice;
953                 }
954             }
955         }
956         return null;
957     }
958 
959     // Binder call
960     @Override
isInputDeviceEnabled(int deviceId)961     public boolean isInputDeviceEnabled(int deviceId) {
962         return mNative.isInputDeviceEnabled(deviceId);
963     }
964 
965     // Binder call
966     @Override
enableInputDevice(int deviceId)967     public void enableInputDevice(int deviceId) {
968         if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
969                 "enableInputDevice()")) {
970             throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
971         }
972         mNative.enableInputDevice(deviceId);
973     }
974 
975     // Binder call
976     @Override
disableInputDevice(int deviceId)977     public void disableInputDevice(int deviceId) {
978         if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
979                 "disableInputDevice()")) {
980             throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
981         }
982         mNative.disableInputDevice(deviceId);
983     }
984 
985     /**
986      * Gets the ids of all input devices in the system.
987      * @return The input device ids.
988      */
989     @Override // Binder call
getInputDeviceIds()990     public int[] getInputDeviceIds() {
991         synchronized (mInputDevicesLock) {
992             final int count = mInputDevices.length;
993             int[] ids = new int[count];
994             for (int i = 0; i < count; i++) {
995                 ids[i] = mInputDevices[i].getId();
996             }
997             return ids;
998         }
999     }
1000 
1001     /**
1002      * Gets all input devices in the system.
1003      * @return The array of input devices.
1004      */
getInputDevices()1005     public InputDevice[] getInputDevices() {
1006         synchronized (mInputDevicesLock) {
1007             return mInputDevices;
1008         }
1009     }
1010 
1011     @Override // Binder call
registerInputDevicesChangedListener(IInputDevicesChangedListener listener)1012     public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
1013         Objects.requireNonNull(listener, "listener must not be null");
1014 
1015         synchronized (mInputDevicesLock) {
1016             int callingPid = Binder.getCallingPid();
1017             if (mInputDevicesChangedListeners.get(callingPid) != null) {
1018                 throw new SecurityException("The calling process has already "
1019                         + "registered an InputDevicesChangedListener.");
1020             }
1021 
1022             InputDevicesChangedListenerRecord record =
1023                     new InputDevicesChangedListenerRecord(callingPid, listener);
1024             try {
1025                 IBinder binder = listener.asBinder();
1026                 binder.linkToDeath(record, 0);
1027             } catch (RemoteException ex) {
1028                 // give up
1029                 throw new RuntimeException(ex);
1030             }
1031 
1032             mInputDevicesChangedListeners.put(callingPid, record);
1033         }
1034     }
1035 
onInputDevicesChangedListenerDied(int pid)1036     private void onInputDevicesChangedListenerDied(int pid) {
1037         synchronized (mInputDevicesLock) {
1038             mInputDevicesChangedListeners.remove(pid);
1039         }
1040     }
1041 
1042     // Must be called on handler.
deliverInputDevicesChanged(InputDevice[] oldInputDevices)1043     private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
1044         // Scan for changes.
1045         int numFullKeyboardsAdded = 0;
1046         mTempInputDevicesChangedListenersToNotify.clear();
1047         mTempFullKeyboards.clear();
1048         final int numListeners;
1049         final int[] deviceIdAndGeneration;
1050         synchronized (mInputDevicesLock) {
1051             if (!mInputDevicesChangedPending) {
1052                 return;
1053             }
1054             mInputDevicesChangedPending = false;
1055 
1056             numListeners = mInputDevicesChangedListeners.size();
1057             for (int i = 0; i < numListeners; i++) {
1058                 mTempInputDevicesChangedListenersToNotify.add(
1059                         mInputDevicesChangedListeners.valueAt(i));
1060             }
1061 
1062             final int numDevices = mInputDevices.length;
1063             deviceIdAndGeneration = new int[numDevices * 2];
1064             for (int i = 0; i < numDevices; i++) {
1065                 final InputDevice inputDevice = mInputDevices[i];
1066                 deviceIdAndGeneration[i * 2] = inputDevice.getId();
1067                 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
1068 
1069                 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
1070                     if (!containsInputDeviceWithDescriptor(oldInputDevices,
1071                             inputDevice.getDescriptor())) {
1072                         mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
1073                     } else {
1074                         mTempFullKeyboards.add(inputDevice);
1075                     }
1076                 }
1077             }
1078         }
1079 
1080         // Notify listeners.
1081         for (int i = 0; i < numListeners; i++) {
1082             mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
1083                     deviceIdAndGeneration);
1084         }
1085         mTempInputDevicesChangedListenersToNotify.clear();
1086 
1087         // Check for missing keyboard layouts.
1088         List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
1089         final int numFullKeyboards = mTempFullKeyboards.size();
1090         synchronized (mDataStore) {
1091             for (int i = 0; i < numFullKeyboards; i++) {
1092                 final InputDevice inputDevice = mTempFullKeyboards.get(i);
1093                 String layout =
1094                     getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
1095                 if (layout == null) {
1096                     layout = getDefaultKeyboardLayout(inputDevice);
1097                     if (layout != null) {
1098                         setCurrentKeyboardLayoutForInputDevice(
1099                                 inputDevice.getIdentifier(), layout);
1100                     }
1101                 }
1102                 if (layout == null) {
1103                     keyboardsMissingLayout.add(inputDevice);
1104                 }
1105             }
1106         }
1107 
1108         if (mNotificationManager != null) {
1109             if (!keyboardsMissingLayout.isEmpty()) {
1110                 if (keyboardsMissingLayout.size() > 1) {
1111                     // We have more than one keyboard missing a layout, so drop the
1112                     // user at the generic input methods page so they can pick which
1113                     // one to set.
1114                     showMissingKeyboardLayoutNotification(null);
1115                 } else {
1116                     showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
1117                 }
1118             } else if (mKeyboardLayoutNotificationShown) {
1119                 hideMissingKeyboardLayoutNotification();
1120             }
1121         }
1122         mTempFullKeyboards.clear();
1123     }
1124 
getDefaultKeyboardLayout(final InputDevice d)1125     private String getDefaultKeyboardLayout(final InputDevice d) {
1126         final Locale systemLocale = mContext.getResources().getConfiguration().locale;
1127         // If our locale doesn't have a language for some reason, then we don't really have a
1128         // reasonable default.
1129         if (TextUtils.isEmpty(systemLocale.getLanguage())) {
1130             return null;
1131         }
1132         final List<KeyboardLayout> layouts = new ArrayList<>();
1133         visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> {
1134             // Only select a default when we know the layout is appropriate. For now, this
1135             // means it's a custom layout for a specific keyboard.
1136             if (layout.getVendorId() != d.getVendorId()
1137                     || layout.getProductId() != d.getProductId()) {
1138                 return;
1139             }
1140             final LocaleList locales = layout.getLocales();
1141             final int numLocales = locales.size();
1142             for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
1143                 if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
1144                     layouts.add(layout);
1145                     break;
1146                 }
1147             }
1148         });
1149 
1150         if (layouts.isEmpty()) {
1151             return null;
1152         }
1153 
1154         // First sort so that ones with higher priority are listed at the top
1155         Collections.sort(layouts);
1156         // Next we want to try to find an exact match of language, country and variant.
1157         final int N = layouts.size();
1158         for (int i = 0; i < N; i++) {
1159             KeyboardLayout layout = layouts.get(i);
1160             final LocaleList locales = layout.getLocales();
1161             final int numLocales = locales.size();
1162             for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
1163                 final Locale locale = locales.get(localeIndex);
1164                 if (locale.getCountry().equals(systemLocale.getCountry())
1165                         && locale.getVariant().equals(systemLocale.getVariant())) {
1166                     return layout.getDescriptor();
1167                 }
1168             }
1169         }
1170         // Then try an exact match of language and country
1171         for (int i = 0; i < N; i++) {
1172             KeyboardLayout layout = layouts.get(i);
1173             final LocaleList locales = layout.getLocales();
1174             final int numLocales = locales.size();
1175             for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
1176                 final Locale locale = locales.get(localeIndex);
1177                 if (locale.getCountry().equals(systemLocale.getCountry())) {
1178                     return layout.getDescriptor();
1179                 }
1180             }
1181         }
1182 
1183         // Give up and just use the highest priority layout with matching language
1184         return layouts.get(0).getDescriptor();
1185     }
1186 
isCompatibleLocale(Locale systemLocale, Locale keyboardLocale)1187     private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
1188         // Different languages are never compatible
1189         if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
1190             return false;
1191         }
1192         // If both the system and the keyboard layout have a country specifier, they must be equal.
1193         if (!TextUtils.isEmpty(systemLocale.getCountry())
1194                 && !TextUtils.isEmpty(keyboardLocale.getCountry())
1195                 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
1196             return false;
1197         }
1198         return true;
1199     }
1200 
1201     @Override // Binder call & native callback
getTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation)1202     public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
1203             int surfaceRotation) {
1204         Objects.requireNonNull(inputDeviceDescriptor, "inputDeviceDescriptor must not be null");
1205 
1206         synchronized (mDataStore) {
1207             return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
1208         }
1209     }
1210 
1211     @Override // Binder call
setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation, TouchCalibration calibration)1212     public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
1213             TouchCalibration calibration) {
1214         if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
1215                 "setTouchCalibrationForInputDevice()")) {
1216             throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
1217         }
1218         Objects.requireNonNull(inputDeviceDescriptor, "inputDeviceDescriptor must not be null");
1219         Objects.requireNonNull(calibration, "calibration must not be null");
1220         if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
1221             throw new IllegalArgumentException("surfaceRotation value out of bounds");
1222         }
1223 
1224         synchronized (mDataStore) {
1225             try {
1226                 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
1227                         calibration)) {
1228                     mNative.reloadCalibration();
1229                 }
1230             } finally {
1231                 mDataStore.saveIfNeeded();
1232             }
1233         }
1234     }
1235 
1236     @Override // Binder call
isInTabletMode()1237     public int isInTabletMode() {
1238         if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
1239                 "isInTabletMode()")) {
1240             throw new SecurityException("Requires TABLET_MODE permission");
1241         }
1242         return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
1243     }
1244 
1245     @Override // Binder call
isMicMuted()1246     public int isMicMuted() {
1247         return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MUTE_DEVICE);
1248     }
1249 
1250     @Override // Binder call
registerTabletModeChangedListener(ITabletModeChangedListener listener)1251     public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
1252         if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
1253                 "registerTabletModeChangedListener()")) {
1254             throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
1255         }
1256         Objects.requireNonNull(listener, "event must not be null");
1257 
1258         synchronized (mTabletModeLock) {
1259             final int callingPid = Binder.getCallingPid();
1260             if (mTabletModeChangedListeners.get(callingPid) != null) {
1261                 throw new IllegalStateException("The calling process has already registered "
1262                         + "a TabletModeChangedListener.");
1263             }
1264             TabletModeChangedListenerRecord record =
1265                     new TabletModeChangedListenerRecord(callingPid, listener);
1266             try {
1267                 IBinder binder = listener.asBinder();
1268                 binder.linkToDeath(record, 0);
1269             } catch (RemoteException ex) {
1270                 throw new RuntimeException(ex);
1271             }
1272             mTabletModeChangedListeners.put(callingPid, record);
1273         }
1274     }
1275 
onTabletModeChangedListenerDied(int pid)1276     private void onTabletModeChangedListenerDied(int pid) {
1277         synchronized (mTabletModeLock) {
1278             mTabletModeChangedListeners.remove(pid);
1279         }
1280     }
1281 
1282     // Must be called on handler
deliverTabletModeChanged(long whenNanos, boolean inTabletMode)1283     private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
1284         mTempTabletModeChangedListenersToNotify.clear();
1285         final int numListeners;
1286         synchronized (mTabletModeLock) {
1287             numListeners = mTabletModeChangedListeners.size();
1288             for (int i = 0; i < numListeners; i++) {
1289                 mTempTabletModeChangedListenersToNotify.add(
1290                         mTabletModeChangedListeners.valueAt(i));
1291             }
1292         }
1293         for (int i = 0; i < numListeners; i++) {
1294             mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
1295                     whenNanos, inTabletMode);
1296         }
1297     }
1298 
1299     // Must be called on handler.
showMissingKeyboardLayoutNotification(InputDevice device)1300     private void showMissingKeyboardLayoutNotification(InputDevice device) {
1301         if (!mKeyboardLayoutNotificationShown) {
1302             final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
1303             if (device != null) {
1304                 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
1305             }
1306             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1307                     | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
1308                     | Intent.FLAG_ACTIVITY_CLEAR_TOP);
1309             final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
1310                     intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
1311 
1312             Resources r = mContext.getResources();
1313             Notification notification =
1314                     new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
1315                             .setContentTitle(r.getString(
1316                                     R.string.select_keyboard_layout_notification_title))
1317                             .setContentText(r.getString(
1318                                     R.string.select_keyboard_layout_notification_message))
1319                             .setContentIntent(keyboardLayoutIntent)
1320                             .setSmallIcon(R.drawable.ic_settings_language)
1321                             .setColor(mContext.getColor(
1322                                     com.android.internal.R.color.system_notification_accent_color))
1323                             .build();
1324             mNotificationManager.notifyAsUser(null,
1325                     SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
1326                     notification, UserHandle.ALL);
1327             mKeyboardLayoutNotificationShown = true;
1328         }
1329     }
1330 
1331     // Must be called on handler.
hideMissingKeyboardLayoutNotification()1332     private void hideMissingKeyboardLayoutNotification() {
1333         if (mKeyboardLayoutNotificationShown) {
1334             mKeyboardLayoutNotificationShown = false;
1335             mNotificationManager.cancelAsUser(null,
1336                     SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
1337                     UserHandle.ALL);
1338         }
1339     }
1340 
1341     // Must be called on handler.
updateKeyboardLayouts()1342     private void updateKeyboardLayouts() {
1343         // Scan all input devices state for keyboard layouts that have been uninstalled.
1344         final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
1345         visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) ->
1346                 availableKeyboardLayouts.add(layout.getDescriptor()));
1347         synchronized (mDataStore) {
1348             try {
1349                 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
1350             } finally {
1351                 mDataStore.saveIfNeeded();
1352             }
1353         }
1354 
1355         // Reload keyboard layouts.
1356         reloadKeyboardLayouts();
1357     }
1358 
containsInputDeviceWithDescriptor(InputDevice[] inputDevices, String descriptor)1359     private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
1360             String descriptor) {
1361         final int numDevices = inputDevices.length;
1362         for (int i = 0; i < numDevices; i++) {
1363             final InputDevice inputDevice = inputDevices[i];
1364             if (inputDevice.getDescriptor().equals(descriptor)) {
1365                 return true;
1366             }
1367         }
1368         return false;
1369     }
1370 
1371     @Override // Binder call
getKeyboardLayouts()1372     public KeyboardLayout[] getKeyboardLayouts() {
1373         final ArrayList<KeyboardLayout> list = new ArrayList<>();
1374         visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> list.add(layout));
1375         return list.toArray(new KeyboardLayout[list.size()]);
1376     }
1377 
1378     @Override // Binder call
getKeyboardLayoutsForInputDevice( final InputDeviceIdentifier identifier)1379     public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1380             final InputDeviceIdentifier identifier) {
1381         final String[] enabledLayoutDescriptors =
1382                 getEnabledKeyboardLayoutsForInputDevice(identifier);
1383         final ArrayList<KeyboardLayout> enabledLayouts =
1384                 new ArrayList<>(enabledLayoutDescriptors.length);
1385         final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<>();
1386         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1387             boolean mHasSeenDeviceSpecificLayout;
1388 
1389             @Override
1390             public void visitKeyboardLayout(Resources resources,
1391                     int keyboardLayoutResId, KeyboardLayout layout) {
1392                 // First check if it's enabled. If the keyboard layout is enabled then we always
1393                 // want to return it as a possible layout for the device.
1394                 for (String s : enabledLayoutDescriptors) {
1395                     if (s != null && s.equals(layout.getDescriptor())) {
1396                         enabledLayouts.add(layout);
1397                         return;
1398                     }
1399                 }
1400                 // Next find any potential layouts that aren't yet enabled for the device. For
1401                 // devices that have special layouts we assume there's a reason that the generic
1402                 // layouts don't work for them so we don't want to return them since it's likely
1403                 // to result in a poor user experience.
1404                 if (layout.getVendorId() == identifier.getVendorId()
1405                         && layout.getProductId() == identifier.getProductId()) {
1406                     if (!mHasSeenDeviceSpecificLayout) {
1407                         mHasSeenDeviceSpecificLayout = true;
1408                         potentialLayouts.clear();
1409                     }
1410                     potentialLayouts.add(layout);
1411                 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
1412                         && !mHasSeenDeviceSpecificLayout) {
1413                     potentialLayouts.add(layout);
1414                 }
1415             }
1416         });
1417         final int enabledLayoutSize = enabledLayouts.size();
1418         final int potentialLayoutSize = potentialLayouts.size();
1419         KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
1420         enabledLayouts.toArray(layouts);
1421         for (int i = 0; i < potentialLayoutSize; i++) {
1422             layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
1423         }
1424         return layouts;
1425     }
1426 
1427     @Override // Binder call
getKeyboardLayout(String keyboardLayoutDescriptor)1428     public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
1429         Objects.requireNonNull(keyboardLayoutDescriptor,
1430                 "keyboardLayoutDescriptor must not be null");
1431 
1432         final KeyboardLayout[] result = new KeyboardLayout[1];
1433         visitKeyboardLayout(keyboardLayoutDescriptor,
1434                 (resources, keyboardLayoutResId, layout) -> result[0] = layout);
1435         if (result[0] == null) {
1436             Slog.w(TAG, "Could not get keyboard layout with descriptor '"
1437                     + keyboardLayoutDescriptor + "'.");
1438         }
1439         return result[0];
1440     }
1441 
visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor)1442     private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
1443         final PackageManager pm = mContext.getPackageManager();
1444         Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
1445         for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
1446                 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
1447                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
1448             final ActivityInfo activityInfo = resolveInfo.activityInfo;
1449             final int priority = resolveInfo.priority;
1450             visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
1451         }
1452     }
1453 
visitKeyboardLayout(String keyboardLayoutDescriptor, KeyboardLayoutVisitor visitor)1454     private void visitKeyboardLayout(String keyboardLayoutDescriptor,
1455             KeyboardLayoutVisitor visitor) {
1456         KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
1457         if (d != null) {
1458             final PackageManager pm = mContext.getPackageManager();
1459             try {
1460                 ActivityInfo receiver = pm.getReceiverInfo(
1461                         new ComponentName(d.packageName, d.receiverName),
1462                         PackageManager.GET_META_DATA
1463                                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1464                                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
1465                 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
1466             } catch (NameNotFoundException ignored) {
1467             }
1468         }
1469     }
1470 
visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor)1471     private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
1472             String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
1473         Bundle metaData = receiver.metaData;
1474         if (metaData == null) {
1475             return;
1476         }
1477 
1478         int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1479         if (configResId == 0) {
1480             Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
1481                     + "' on receiver " + receiver.packageName + "/" + receiver.name);
1482             return;
1483         }
1484 
1485         CharSequence receiverLabel = receiver.loadLabel(pm);
1486         String collection = receiverLabel != null ? receiverLabel.toString() : "";
1487         int priority;
1488         if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1489             priority = requestedPriority;
1490         } else {
1491             priority = 0;
1492         }
1493 
1494         try {
1495             Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1496             try (XmlResourceParser parser = resources.getXml(configResId)) {
1497                 XmlUtils.beginDocument(parser, "keyboard-layouts");
1498 
1499                 while (true) {
1500                     XmlUtils.nextElement(parser);
1501                     String element = parser.getName();
1502                     if (element == null) {
1503                         break;
1504                     }
1505                     if (element.equals("keyboard-layout")) {
1506                         TypedArray a = resources.obtainAttributes(
1507                                 parser, R.styleable.KeyboardLayout);
1508                         try {
1509                             String name = a.getString(
1510                                     R.styleable.KeyboardLayout_name);
1511                             String label = a.getString(
1512                                     R.styleable.KeyboardLayout_label);
1513                             int keyboardLayoutResId = a.getResourceId(
1514                                     R.styleable.KeyboardLayout_keyboardLayout,
1515                                     0);
1516                             String languageTags = a.getString(
1517                                     R.styleable.KeyboardLayout_locale);
1518                             LocaleList locales = getLocalesFromLanguageTags(languageTags);
1519                             int vid = a.getInt(
1520                                     R.styleable.KeyboardLayout_vendorId, -1);
1521                             int pid = a.getInt(
1522                                     R.styleable.KeyboardLayout_productId, -1);
1523 
1524                             if (name == null || label == null || keyboardLayoutResId == 0) {
1525                                 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
1526                                         + "attributes in keyboard layout "
1527                                         + "resource from receiver "
1528                                         + receiver.packageName + "/" + receiver.name);
1529                             } else {
1530                                 String descriptor = KeyboardLayoutDescriptor.format(
1531                                         receiver.packageName, receiver.name, name);
1532                                 if (keyboardName == null || name.equals(keyboardName)) {
1533                                     KeyboardLayout layout = new KeyboardLayout(
1534                                             descriptor, label, collection, priority,
1535                                             locales, vid, pid);
1536                                     visitor.visitKeyboardLayout(
1537                                             resources, keyboardLayoutResId, layout);
1538                                 }
1539                             }
1540                         } finally {
1541                             a.recycle();
1542                         }
1543                     } else {
1544                         Slog.w(TAG, "Skipping unrecognized element '" + element
1545                                 + "' in keyboard layout resource from receiver "
1546                                 + receiver.packageName + "/" + receiver.name);
1547                     }
1548                 }
1549             }
1550         } catch (Exception ex) {
1551             Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
1552                     + receiver.packageName + "/" + receiver.name, ex);
1553         }
1554     }
1555 
1556     @NonNull
getLocalesFromLanguageTags(String languageTags)1557     private static LocaleList getLocalesFromLanguageTags(String languageTags) {
1558         if (TextUtils.isEmpty(languageTags)) {
1559             return LocaleList.getEmptyLocaleList();
1560         }
1561         return LocaleList.forLanguageTags(languageTags.replace('|', ','));
1562     }
1563 
1564     /**
1565      * Builds a layout descriptor for the vendor/product. This returns the
1566      * descriptor for ids that aren't useful (such as the default 0, 0).
1567      */
getLayoutDescriptor(InputDeviceIdentifier identifier)1568     private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1569         Objects.requireNonNull(identifier, "identifier must not be null");
1570         Objects.requireNonNull(identifier.getDescriptor(), "descriptor must not be null");
1571 
1572         if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1573             return identifier.getDescriptor();
1574         }
1575         return "vendor:" + identifier.getVendorId() + ",product:" + identifier.getProductId();
1576     }
1577 
1578     @Override // Binder call
getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier)1579     public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1580 
1581         String key = getLayoutDescriptor(identifier);
1582         synchronized (mDataStore) {
1583             String layout;
1584             // try loading it using the layout descriptor if we have it
1585             layout = mDataStore.getCurrentKeyboardLayout(key);
1586             if (layout == null && !key.equals(identifier.getDescriptor())) {
1587                 // if it doesn't exist fall back to the device descriptor
1588                 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1589             }
1590             if (DEBUG) {
1591                 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1592                         + layout);
1593             }
1594             return layout;
1595         }
1596     }
1597 
1598     @Override // Binder call
setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1599     public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1600             String keyboardLayoutDescriptor) {
1601         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1602                 "setCurrentKeyboardLayoutForInputDevice()")) {
1603             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1604         }
1605 
1606         Objects.requireNonNull(keyboardLayoutDescriptor,
1607                 "keyboardLayoutDescriptor must not be null");
1608 
1609         String key = getLayoutDescriptor(identifier);
1610         synchronized (mDataStore) {
1611             try {
1612                 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1613                     if (DEBUG) {
1614                         Slog.d(TAG, "Saved keyboard layout using " + key);
1615                     }
1616                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1617                 }
1618             } finally {
1619                 mDataStore.saveIfNeeded();
1620             }
1621         }
1622     }
1623 
1624     @Override // Binder call
getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier)1625     public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
1626         String key = getLayoutDescriptor(identifier);
1627         synchronized (mDataStore) {
1628             String[] layouts = mDataStore.getKeyboardLayouts(key);
1629             if ((layouts == null || layouts.length == 0)
1630                     && !key.equals(identifier.getDescriptor())) {
1631                 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1632             }
1633             return layouts;
1634         }
1635     }
1636 
1637     @Override // Binder call
addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1638     public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1639             String keyboardLayoutDescriptor) {
1640         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1641                 "addKeyboardLayoutForInputDevice()")) {
1642             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1643         }
1644         Objects.requireNonNull(keyboardLayoutDescriptor,
1645                 "keyboardLayoutDescriptor must not be null");
1646 
1647         String key = getLayoutDescriptor(identifier);
1648         synchronized (mDataStore) {
1649             try {
1650                 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1651                 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1652                     oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1653                 }
1654                 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
1655                         && !Objects.equals(oldLayout,
1656                                 mDataStore.getCurrentKeyboardLayout(key))) {
1657                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1658                 }
1659             } finally {
1660                 mDataStore.saveIfNeeded();
1661             }
1662         }
1663     }
1664 
1665     @Override // Binder call
removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1666     public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1667             String keyboardLayoutDescriptor) {
1668         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1669                 "removeKeyboardLayoutForInputDevice()")) {
1670             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1671         }
1672         Objects.requireNonNull(keyboardLayoutDescriptor,
1673                 "keyboardLayoutDescriptor must not be null");
1674 
1675         String key = getLayoutDescriptor(identifier);
1676         synchronized (mDataStore) {
1677             try {
1678                 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1679                 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1680                     oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1681                 }
1682                 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1683                 if (!key.equals(identifier.getDescriptor())) {
1684                     // We need to remove from both places to ensure it is gone
1685                     removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1686                             keyboardLayoutDescriptor);
1687                 }
1688                 if (removed && !Objects.equals(oldLayout,
1689                                 mDataStore.getCurrentKeyboardLayout(key))) {
1690                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1691                 }
1692             } finally {
1693                 mDataStore.saveIfNeeded();
1694             }
1695         }
1696     }
1697 
switchKeyboardLayout(int deviceId, int direction)1698     public void switchKeyboardLayout(int deviceId, int direction) {
1699         mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
1700     }
1701 
1702     // Must be called on handler.
handleSwitchKeyboardLayout(int deviceId, int direction)1703     private void handleSwitchKeyboardLayout(int deviceId, int direction) {
1704         final InputDevice device = getInputDevice(deviceId);
1705         if (device != null) {
1706             final boolean changed;
1707             final String keyboardLayoutDescriptor;
1708 
1709             String key = getLayoutDescriptor(device.getIdentifier());
1710             synchronized (mDataStore) {
1711                 try {
1712                     changed = mDataStore.switchKeyboardLayout(key, direction);
1713                     keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
1714                             key);
1715                 } finally {
1716                     mDataStore.saveIfNeeded();
1717                 }
1718             }
1719 
1720             if (changed) {
1721                 if (mSwitchedKeyboardLayoutToast != null) {
1722                     mSwitchedKeyboardLayoutToast.cancel();
1723                     mSwitchedKeyboardLayoutToast = null;
1724                 }
1725                 if (keyboardLayoutDescriptor != null) {
1726                     KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
1727                     if (keyboardLayout != null) {
1728                         mSwitchedKeyboardLayoutToast = Toast.makeText(
1729                                 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
1730                         mSwitchedKeyboardLayoutToast.show();
1731                     }
1732                 }
1733 
1734                 reloadKeyboardLayouts();
1735             }
1736         }
1737     }
1738 
setFocusedApplication(int displayId, InputApplicationHandle application)1739     public void setFocusedApplication(int displayId, InputApplicationHandle application) {
1740         mNative.setFocusedApplication(displayId, application);
1741     }
1742 
setFocusedDisplay(int displayId)1743     public void setFocusedDisplay(int displayId) {
1744         mNative.setFocusedDisplay(displayId);
1745     }
1746 
1747     /** Clean up input window handles of the given display. */
onDisplayRemoved(int displayId)1748     public void onDisplayRemoved(int displayId) {
1749         if (mPointerIconDisplayContext != null
1750                 && mPointerIconDisplayContext.getDisplay().getDisplayId() == displayId) {
1751             mPointerIconDisplayContext = null;
1752         }
1753 
1754         updateAdditionalDisplayInputProperties(displayId, AdditionalDisplayInputProperties::reset);
1755 
1756         mNative.displayRemoved(displayId);
1757     }
1758 
1759     @Override
requestPointerCapture(IBinder inputChannelToken, boolean enabled)1760     public void requestPointerCapture(IBinder inputChannelToken, boolean enabled) {
1761         Objects.requireNonNull(inputChannelToken, "event must not be null");
1762 
1763         mNative.requestPointerCapture(inputChannelToken, enabled);
1764     }
1765 
setInputDispatchMode(boolean enabled, boolean frozen)1766     public void setInputDispatchMode(boolean enabled, boolean frozen) {
1767         mNative.setInputDispatchMode(enabled, frozen);
1768     }
1769 
setSystemUiLightsOut(boolean lightsOut)1770     public void setSystemUiLightsOut(boolean lightsOut) {
1771         mNative.setSystemUiLightsOut(lightsOut);
1772     }
1773 
1774     /**
1775      * Atomically transfers touch focus from one window to another as identified by
1776      * their input channels.  It is possible for multiple windows to have
1777      * touch focus if they support split touch dispatch
1778      * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1779      * method only transfers touch focus of the specified window without affecting
1780      * other windows that may also have touch focus at the same time.
1781      * @param fromChannel The channel of a window that currently has touch focus.
1782      * @param toChannel The channel of the window that should receive touch focus in
1783      * place of the first.
1784      * @param isDragDrop True if transfer touch focus for drag and drop.
1785      * @return True if the transfer was successful.  False if the window with the
1786      * specified channel did not actually have touch focus at the time of the request.
1787      */
transferTouchFocus(@onNull InputChannel fromChannel, @NonNull InputChannel toChannel, boolean isDragDrop)1788     public boolean transferTouchFocus(@NonNull InputChannel fromChannel,
1789             @NonNull InputChannel toChannel, boolean isDragDrop) {
1790         return mNative.transferTouchFocus(fromChannel.getToken(), toChannel.getToken(),
1791                 isDragDrop);
1792     }
1793 
1794     /**
1795      * Atomically transfers touch focus from one window to another as identified by
1796      * their input channels.  It is possible for multiple windows to have
1797      * touch focus if they support split touch dispatch
1798      * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1799      * method only transfers touch focus of the specified window without affecting
1800      * other windows that may also have touch focus at the same time.
1801      * @param fromChannelToken The channel token of a window that currently has touch focus.
1802      * @param toChannelToken The channel token of the window that should receive touch focus in
1803      * place of the first.
1804      * @return True if the transfer was successful.  False if the window with the
1805      * specified channel did not actually have touch focus at the time of the request.
1806      */
transferTouchFocus(@onNull IBinder fromChannelToken, @NonNull IBinder toChannelToken)1807     public boolean transferTouchFocus(@NonNull IBinder fromChannelToken,
1808             @NonNull IBinder toChannelToken) {
1809         Objects.nonNull(fromChannelToken);
1810         Objects.nonNull(toChannelToken);
1811         return mNative.transferTouchFocus(fromChannelToken, toChannelToken,
1812                 false /* isDragDrop */);
1813     }
1814 
1815     @Override // Binder call
tryPointerSpeed(int speed)1816     public void tryPointerSpeed(int speed) {
1817         if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1818                 "tryPointerSpeed()")) {
1819             throw new SecurityException("Requires SET_POINTER_SPEED permission");
1820         }
1821 
1822         if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1823             throw new IllegalArgumentException("speed out of range");
1824         }
1825 
1826         setPointerSpeedUnchecked(speed);
1827     }
1828 
updatePointerSpeedFromSettings()1829     private void updatePointerSpeedFromSettings() {
1830         int speed = getPointerSpeedSetting();
1831         setPointerSpeedUnchecked(speed);
1832     }
1833 
setPointerSpeedUnchecked(int speed)1834     private void setPointerSpeedUnchecked(int speed) {
1835         speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1836                 InputManager.MAX_POINTER_SPEED);
1837         mNative.setPointerSpeed(speed);
1838     }
1839 
setPointerAcceleration(float acceleration, int displayId)1840     private void setPointerAcceleration(float acceleration, int displayId) {
1841         updateAdditionalDisplayInputProperties(displayId,
1842                 properties -> properties.pointerAcceleration = acceleration);
1843     }
1844 
setPointerIconVisible(boolean visible, int displayId)1845     private void setPointerIconVisible(boolean visible, int displayId) {
1846         updateAdditionalDisplayInputProperties(displayId,
1847                 properties -> properties.pointerIconVisible = visible);
1848     }
1849 
registerPointerSpeedSettingObserver()1850     private void registerPointerSpeedSettingObserver() {
1851         mContext.getContentResolver().registerContentObserver(
1852                 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
1853                 new ContentObserver(mHandler) {
1854                     @Override
1855                     public void onChange(boolean selfChange) {
1856                         updatePointerSpeedFromSettings();
1857                     }
1858                 }, UserHandle.USER_ALL);
1859     }
1860 
getPointerSpeedSetting()1861     private int getPointerSpeedSetting() {
1862         int speed = InputManager.DEFAULT_POINTER_SPEED;
1863         try {
1864             speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1865                     Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
1866         } catch (SettingNotFoundException ignored) {
1867         }
1868         return speed;
1869     }
1870 
updateShowTouchesFromSettings()1871     private void updateShowTouchesFromSettings() {
1872         int setting = getShowTouchesSetting(0);
1873         mNative.setShowTouches(setting != 0);
1874     }
1875 
registerShowTouchesSettingObserver()1876     private void registerShowTouchesSettingObserver() {
1877         mContext.getContentResolver().registerContentObserver(
1878                 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
1879                 new ContentObserver(mHandler) {
1880                     @Override
1881                     public void onChange(boolean selfChange) {
1882                         updateShowTouchesFromSettings();
1883                     }
1884                 }, UserHandle.USER_ALL);
1885     }
1886 
updateAccessibilityLargePointerFromSettings()1887     private void updateAccessibilityLargePointerFromSettings() {
1888         final int accessibilityConfig = Settings.Secure.getIntForUser(
1889                 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1890                 0, UserHandle.USER_CURRENT);
1891         PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
1892         mNative.reloadPointerIcons();
1893     }
1894 
registerAccessibilityLargePointerSettingObserver()1895     private void registerAccessibilityLargePointerSettingObserver() {
1896         mContext.getContentResolver().registerContentObserver(
1897                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1898                 new ContentObserver(mHandler) {
1899                     @Override
1900                     public void onChange(boolean selfChange) {
1901                         updateAccessibilityLargePointerFromSettings();
1902                     }
1903                 }, UserHandle.USER_ALL);
1904     }
1905 
updateDeepPressStatusFromSettings(String reason)1906     private void updateDeepPressStatusFromSettings(String reason) {
1907         // Not using ViewConfiguration.getLongPressTimeout here because it may return a stale value
1908         final int timeout = Settings.Secure.getIntForUser(mContext.getContentResolver(),
1909                 Settings.Secure.LONG_PRESS_TIMEOUT, ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT,
1910                 UserHandle.USER_CURRENT);
1911         final boolean featureEnabledFlag =
1912                 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
1913                         DEEP_PRESS_ENABLED, true /* default */);
1914         final boolean enabled =
1915                 featureEnabledFlag && timeout <= ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT;
1916         Log.i(TAG,
1917                 (enabled ? "Enabling" : "Disabling") + " motion classifier because " + reason
1918                 + ": feature " + (featureEnabledFlag ? "enabled" : "disabled")
1919                 + ", long press timeout = " + timeout);
1920         mNative.setMotionClassifierEnabled(enabled);
1921     }
1922 
registerLongPressTimeoutObserver()1923     private void registerLongPressTimeoutObserver() {
1924         mContext.getContentResolver().registerContentObserver(
1925                 Settings.Secure.getUriFor(Settings.Secure.LONG_PRESS_TIMEOUT), true,
1926                 new ContentObserver(mHandler) {
1927                     @Override
1928                     public void onChange(boolean selfChange) {
1929                         updateDeepPressStatusFromSettings("timeout changed");
1930                     }
1931                 }, UserHandle.USER_ALL);
1932     }
1933 
registerBlockUntrustedTouchesModeSettingObserver()1934     private void registerBlockUntrustedTouchesModeSettingObserver() {
1935         mContext.getContentResolver().registerContentObserver(
1936                 Settings.Global.getUriFor(Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE),
1937                 /* notifyForDescendants */ true,
1938                 new ContentObserver(mHandler) {
1939                     @Override
1940                     public void onChange(boolean selfChange) {
1941                         updateBlockUntrustedTouchesModeFromSettings();
1942                     }
1943                 }, UserHandle.USER_ALL);
1944     }
1945 
updateBlockUntrustedTouchesModeFromSettings()1946     private void updateBlockUntrustedTouchesModeFromSettings() {
1947         final int mode = InputManager.getInstance().getBlockUntrustedTouchesMode(mContext);
1948         mNative.setBlockUntrustedTouchesMode(mode);
1949     }
1950 
registerMaximumObscuringOpacityForTouchSettingObserver()1951     private void registerMaximumObscuringOpacityForTouchSettingObserver() {
1952         mContext.getContentResolver().registerContentObserver(
1953                 Settings.Global.getUriFor(Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH),
1954                 /* notifyForDescendants */ true,
1955                 new ContentObserver(mHandler) {
1956                     @Override
1957                     public void onChange(boolean selfChange) {
1958                         updateMaximumObscuringOpacityForTouchFromSettings();
1959                     }
1960                 }, UserHandle.USER_ALL);
1961     }
1962 
updateMaximumObscuringOpacityForTouchFromSettings()1963     private void updateMaximumObscuringOpacityForTouchFromSettings() {
1964         final float opacity = InputManager.getInstance().getMaximumObscuringOpacityForTouch();
1965         if (opacity < 0 || opacity > 1) {
1966             Log.e(TAG, "Invalid maximum obscuring opacity " + opacity
1967                     + ", it should be >= 0 and <= 1, rejecting update.");
1968             return;
1969         }
1970         mNative.setMaximumObscuringOpacityForTouch(opacity);
1971     }
1972 
getShowTouchesSetting(int defaultValue)1973     private int getShowTouchesSetting(int defaultValue) {
1974         int result = defaultValue;
1975         try {
1976             result = Settings.System.getIntForUser(mContext.getContentResolver(),
1977                     Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
1978         } catch (SettingNotFoundException snfe) {
1979         }
1980         return result;
1981     }
1982 
1983     /**
1984      * Update the display on which the mouse pointer is shown.
1985      *
1986      * @return true if the pointer displayId changed, false otherwise.
1987      */
1988     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
updatePointerDisplayIdLocked(int pointerDisplayId)1989     private boolean updatePointerDisplayIdLocked(int pointerDisplayId) {
1990         if (mRequestedPointerDisplayId == pointerDisplayId) {
1991             return false;
1992         }
1993         mRequestedPointerDisplayId = pointerDisplayId;
1994         mNative.setPointerDisplayId(pointerDisplayId);
1995         applyAdditionalDisplayInputProperties();
1996         return true;
1997     }
1998 
handlePointerDisplayIdChanged(PointerDisplayIdChangedArgs args)1999     private void handlePointerDisplayIdChanged(PointerDisplayIdChangedArgs args) {
2000         synchronized (mAdditionalDisplayInputPropertiesLock) {
2001             mAcknowledgedPointerDisplayId = args.mPointerDisplayId;
2002             // Notify waiting threads that the display of the mouse pointer has changed.
2003             mAdditionalDisplayInputPropertiesLock.notifyAll();
2004         }
2005         mWindowManagerCallbacks.notifyPointerDisplayIdChanged(
2006                 args.mPointerDisplayId, args.mXPosition, args.mYPosition);
2007     }
2008 
setVirtualMousePointerDisplayIdBlocking(int overrideDisplayId)2009     private boolean setVirtualMousePointerDisplayIdBlocking(int overrideDisplayId) {
2010         final boolean isRemovingOverride = overrideDisplayId == Display.INVALID_DISPLAY;
2011 
2012         // Take care to not make calls to window manager while holding internal locks.
2013         final int resolvedDisplayId = isRemovingOverride
2014                 ? mWindowManagerCallbacks.getPointerDisplayId()
2015                 : overrideDisplayId;
2016 
2017         synchronized (mAdditionalDisplayInputPropertiesLock) {
2018             mOverriddenPointerDisplayId = overrideDisplayId;
2019 
2020             if (!updatePointerDisplayIdLocked(resolvedDisplayId)
2021                     && mAcknowledgedPointerDisplayId == resolvedDisplayId) {
2022                 // The requested pointer display is already set.
2023                 return true;
2024             }
2025             if (isRemovingOverride && mAcknowledgedPointerDisplayId == Display.INVALID_DISPLAY) {
2026                 // The pointer display override is being removed, but the current pointer display
2027                 // is already invalid. This can happen when the PointerController is destroyed as a
2028                 // result of the removal of all input devices that can control the pointer.
2029                 return true;
2030             }
2031             try {
2032                 // The pointer display changed, so wait until the change has propagated.
2033                 mAdditionalDisplayInputPropertiesLock.wait(5_000 /*mills*/);
2034             } catch (InterruptedException ignored) {
2035             }
2036             // This request succeeds in two cases:
2037             // - This request was to remove the override, in which case the new pointer display
2038             //   could be anything that WM has set.
2039             // - We are setting a new override, in which case the request only succeeds if the
2040             //   reported new displayId is the one we requested. This check ensures that if two
2041             //   competing overrides are requested in succession, the caller can be notified if one
2042             //   of them fails.
2043             return  isRemovingOverride || mAcknowledgedPointerDisplayId == overrideDisplayId;
2044         }
2045     }
2046 
getVirtualMousePointerDisplayId()2047     private int getVirtualMousePointerDisplayId() {
2048         synchronized (mAdditionalDisplayInputPropertiesLock) {
2049             return mOverriddenPointerDisplayId;
2050         }
2051     }
2052 
setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible)2053     private void setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible) {
2054         mNative.setDisplayEligibilityForPointerCapture(displayId, isEligible);
2055     }
2056 
2057     private static class VibrationInfo {
2058         private final long[] mPattern;
2059         private final int[] mAmplitudes;
2060         private final int mRepeat;
2061 
getPattern()2062         public long[] getPattern() {
2063             return mPattern;
2064         }
2065 
getAmplitudes()2066         public int[] getAmplitudes() {
2067             return mAmplitudes;
2068         }
2069 
getRepeatIndex()2070         public int getRepeatIndex() {
2071             return mRepeat;
2072         }
2073 
VibrationInfo(VibrationEffect effect)2074         VibrationInfo(VibrationEffect effect) {
2075             long[] pattern = null;
2076             int[] amplitudes = null;
2077             int patternRepeatIndex = -1;
2078             int amplitudeCount = -1;
2079 
2080             if (effect instanceof VibrationEffect.Composed) {
2081                 VibrationEffect.Composed composed = (VibrationEffect.Composed) effect;
2082                 int segmentCount = composed.getSegments().size();
2083                 pattern = new long[segmentCount];
2084                 amplitudes = new int[segmentCount];
2085                 patternRepeatIndex = composed.getRepeatIndex();
2086                 amplitudeCount = 0;
2087                 for (int i = 0; i < segmentCount; i++) {
2088                     VibrationEffectSegment segment = composed.getSegments().get(i);
2089                     if (composed.getRepeatIndex() == i) {
2090                         patternRepeatIndex = amplitudeCount;
2091                     }
2092                     if (!(segment instanceof StepSegment)) {
2093                         Slog.w(TAG, "Input devices don't support segment " + segment);
2094                         amplitudeCount = -1;
2095                         break;
2096                     }
2097                     float amplitude = ((StepSegment) segment).getAmplitude();
2098                     if (Float.compare(amplitude, VibrationEffect.DEFAULT_AMPLITUDE) == 0) {
2099                         amplitudes[amplitudeCount] = DEFAULT_VIBRATION_MAGNITUDE;
2100                     } else {
2101                         amplitudes[amplitudeCount] =
2102                                 (int) (amplitude * VibrationEffect.MAX_AMPLITUDE);
2103                     }
2104                     pattern[amplitudeCount++] = segment.getDuration();
2105                 }
2106             }
2107 
2108             if (amplitudeCount < 0) {
2109                 Slog.w(TAG, "Only oneshot and step waveforms are supported on input devices");
2110                 mPattern = new long[0];
2111                 mAmplitudes = new int[0];
2112                 mRepeat = -1;
2113             } else {
2114                 mRepeat = patternRepeatIndex;
2115                 mPattern = new long[amplitudeCount];
2116                 mAmplitudes = new int[amplitudeCount];
2117                 System.arraycopy(pattern, 0, mPattern, 0, amplitudeCount);
2118                 System.arraycopy(amplitudes, 0, mAmplitudes, 0, amplitudeCount);
2119                 if (mRepeat >= mPattern.length) {
2120                     throw new ArrayIndexOutOfBoundsException("Repeat index " + mRepeat
2121                             + " must be within the bounds of the pattern.length "
2122                             + mPattern.length);
2123                 }
2124             }
2125         }
2126     }
2127 
getVibratorToken(int deviceId, IBinder token)2128     private VibratorToken getVibratorToken(int deviceId, IBinder token) {
2129         VibratorToken v;
2130         synchronized (mVibratorLock) {
2131             v = mVibratorTokens.get(token);
2132             if (v == null) {
2133                 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
2134                 try {
2135                     token.linkToDeath(v, 0);
2136                 } catch (RemoteException ex) {
2137                     // give up
2138                     throw new RuntimeException(ex);
2139                 }
2140                 mVibratorTokens.put(token, v);
2141             }
2142         }
2143         return v;
2144     }
2145 
2146     // Binder call
2147     @Override
vibrate(int deviceId, VibrationEffect effect, IBinder token)2148     public void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
2149         VibrationInfo info = new VibrationInfo(effect);
2150         VibratorToken v = getVibratorToken(deviceId, token);
2151         synchronized (v) {
2152             v.mVibrating = true;
2153             mNative.vibrate(deviceId, info.getPattern(), info.getAmplitudes(),
2154                     info.getRepeatIndex(), v.mTokenValue);
2155         }
2156     }
2157 
2158     // Binder call
2159     @Override
getVibratorIds(int deviceId)2160     public int[] getVibratorIds(int deviceId) {
2161         return mNative.getVibratorIds(deviceId);
2162     }
2163 
2164     // Binder call
2165     @Override
isVibrating(int deviceId)2166     public boolean isVibrating(int deviceId) {
2167         return mNative.isVibrating(deviceId);
2168     }
2169 
2170     // Binder call
2171     @Override
vibrateCombined(int deviceId, CombinedVibration effect, IBinder token)2172     public void vibrateCombined(int deviceId, CombinedVibration effect, IBinder token) {
2173         VibratorToken v = getVibratorToken(deviceId, token);
2174         synchronized (v) {
2175             if (!(effect instanceof CombinedVibration.Mono)
2176                     && !(effect instanceof CombinedVibration.Stereo)) {
2177                 Slog.e(TAG, "Only Mono and Stereo effects are supported");
2178                 return;
2179             }
2180 
2181             v.mVibrating = true;
2182             if (effect instanceof CombinedVibration.Mono) {
2183                 CombinedVibration.Mono mono = (CombinedVibration.Mono) effect;
2184                 VibrationInfo info = new VibrationInfo(mono.getEffect());
2185                 mNative.vibrate(deviceId, info.getPattern(), info.getAmplitudes(),
2186                         info.getRepeatIndex(), v.mTokenValue);
2187             } else if (effect instanceof CombinedVibration.Stereo) {
2188                 CombinedVibration.Stereo stereo = (CombinedVibration.Stereo) effect;
2189                 SparseArray<VibrationEffect> effects = stereo.getEffects();
2190                 long[] pattern = new long[0];
2191                 int repeat = Integer.MIN_VALUE;
2192                 SparseArray<int[]> amplitudes = new SparseArray<>(effects.size());
2193                 for (int i = 0; i < effects.size(); i++) {
2194                     VibrationInfo info = new VibrationInfo(effects.valueAt(i));
2195                     // Pattern of all effects should be same
2196                     if (pattern.length == 0) {
2197                         pattern = info.getPattern();
2198                     }
2199                     if (repeat == Integer.MIN_VALUE) {
2200                         repeat = info.getRepeatIndex();
2201                     }
2202                     amplitudes.put(effects.keyAt(i), info.getAmplitudes());
2203                 }
2204                 mNative.vibrateCombined(deviceId, pattern, amplitudes, repeat,
2205                         v.mTokenValue);
2206             }
2207         }
2208     }
2209 
2210     // Binder call
2211     @Override
cancelVibrate(int deviceId, IBinder token)2212     public void cancelVibrate(int deviceId, IBinder token) {
2213         VibratorToken v;
2214         synchronized (mVibratorLock) {
2215             v = mVibratorTokens.get(token);
2216             if (v == null || v.mDeviceId != deviceId) {
2217                 return; // nothing to cancel
2218             }
2219         }
2220 
2221         cancelVibrateIfNeeded(v);
2222     }
2223 
onVibratorTokenDied(VibratorToken v)2224     void onVibratorTokenDied(VibratorToken v) {
2225         synchronized (mVibratorLock) {
2226             mVibratorTokens.remove(v.mToken);
2227         }
2228 
2229         cancelVibrateIfNeeded(v);
2230     }
2231 
cancelVibrateIfNeeded(VibratorToken v)2232     private void cancelVibrateIfNeeded(VibratorToken v) {
2233         synchronized (v) {
2234             if (v.mVibrating) {
2235                 mNative.cancelVibrate(v.mDeviceId, v.mTokenValue);
2236                 v.mVibrating = false;
2237             }
2238         }
2239     }
2240 
2241     // Native callback.
2242     @SuppressWarnings("unused")
notifyVibratorState(int deviceId, boolean isOn)2243     private void notifyVibratorState(int deviceId, boolean isOn) {
2244         if (DEBUG) {
2245             Slog.d(TAG, "notifyVibratorState: deviceId=" + deviceId + " isOn=" + isOn);
2246         }
2247         synchronized (mVibratorLock) {
2248             mIsVibrating.put(deviceId, isOn);
2249             notifyVibratorStateListenersLocked(deviceId);
2250         }
2251     }
2252 
2253     @GuardedBy("mVibratorLock")
notifyVibratorStateListenersLocked(int deviceId)2254     private void notifyVibratorStateListenersLocked(int deviceId) {
2255         if (!mVibratorStateListeners.contains(deviceId)) {
2256             if (DEBUG) {
2257                 Slog.v(TAG, "Device " + deviceId + " doesn't have vibrator state listener.");
2258             }
2259             return;
2260         }
2261         RemoteCallbackList<IVibratorStateListener> listeners =
2262                 mVibratorStateListeners.get(deviceId);
2263         final int length = listeners.beginBroadcast();
2264         try {
2265             for (int i = 0; i < length; i++) {
2266                 notifyVibratorStateListenerLocked(deviceId, listeners.getBroadcastItem(i));
2267             }
2268         } finally {
2269             listeners.finishBroadcast();
2270         }
2271     }
2272 
2273     @GuardedBy("mVibratorLock")
notifyVibratorStateListenerLocked(int deviceId, IVibratorStateListener listener)2274     private void notifyVibratorStateListenerLocked(int deviceId, IVibratorStateListener listener) {
2275         try {
2276             listener.onVibrating(mIsVibrating.get(deviceId));
2277         } catch (RemoteException | RuntimeException e) {
2278             Slog.e(TAG, "Vibrator state listener failed to call", e);
2279         }
2280     }
2281 
2282     @Override // Binder call
registerVibratorStateListener(int deviceId, IVibratorStateListener listener)2283     public boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
2284         Objects.requireNonNull(listener, "listener must not be null");
2285 
2286         RemoteCallbackList<IVibratorStateListener> listeners;
2287         synchronized (mVibratorLock) {
2288             if (!mVibratorStateListeners.contains(deviceId)) {
2289                 listeners = new RemoteCallbackList<>();
2290                 mVibratorStateListeners.put(deviceId, listeners);
2291             } else {
2292                 listeners = mVibratorStateListeners.get(deviceId);
2293             }
2294 
2295             final long token = Binder.clearCallingIdentity();
2296             try {
2297                 if (!listeners.register(listener)) {
2298                     Slog.e(TAG, "Could not register vibrator state listener " + listener);
2299                     return false;
2300                 }
2301                 // Notify its callback after new client registered.
2302                 notifyVibratorStateListenerLocked(deviceId, listener);
2303                 return true;
2304             } finally {
2305                 Binder.restoreCallingIdentity(token);
2306             }
2307         }
2308     }
2309 
2310     @Override // Binder call
unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener)2311     public boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
2312         synchronized (mVibratorLock) {
2313             final long token = Binder.clearCallingIdentity();
2314             try {
2315                 if (!mVibratorStateListeners.contains(deviceId)) {
2316                     Slog.w(TAG, "Vibrator state listener " + deviceId + " doesn't exist");
2317                     return false;
2318                 }
2319                 RemoteCallbackList<IVibratorStateListener> listeners =
2320                         mVibratorStateListeners.get(deviceId);
2321                 return listeners.unregister(listener);
2322             } finally {
2323                 Binder.restoreCallingIdentity(token);
2324             }
2325         }
2326     }
2327 
2328     // Binder call
2329     @Override
getBatteryStatus(int deviceId)2330     public int getBatteryStatus(int deviceId) {
2331         return mNative.getBatteryStatus(deviceId);
2332     }
2333 
2334     // Binder call
2335     @Override
getBatteryCapacity(int deviceId)2336     public int getBatteryCapacity(int deviceId) {
2337         return mNative.getBatteryCapacity(deviceId);
2338     }
2339 
2340     // Binder call
2341     @Override
setPointerIconType(int iconType)2342     public void setPointerIconType(int iconType) {
2343         if (iconType == PointerIcon.TYPE_CUSTOM) {
2344             throw new IllegalArgumentException("Use setCustomPointerIcon to set custom pointers");
2345         }
2346         synchronized (mAdditionalDisplayInputPropertiesLock) {
2347             mIcon = null;
2348             mIconType = iconType;
2349 
2350             if (!mCurrentDisplayProperties.pointerIconVisible) return;
2351 
2352             mNative.setPointerIconType(mIconType);
2353         }
2354     }
2355 
2356     // Binder call
2357     @Override
setCustomPointerIcon(PointerIcon icon)2358     public void setCustomPointerIcon(PointerIcon icon) {
2359         Objects.requireNonNull(icon);
2360         synchronized (mAdditionalDisplayInputPropertiesLock) {
2361             mIconType = PointerIcon.TYPE_CUSTOM;
2362             mIcon = icon;
2363 
2364             if (!mCurrentDisplayProperties.pointerIconVisible) return;
2365 
2366             mNative.setCustomPointerIcon(mIcon);
2367         }
2368     }
2369 
2370     /**
2371      * Add a runtime association between the input port and the display port. This overrides any
2372      * static associations.
2373      * @param inputPort The port of the input device.
2374      * @param displayPort The physical port of the associated display.
2375      */
2376     @Override // Binder call
addPortAssociation(@onNull String inputPort, int displayPort)2377     public void addPortAssociation(@NonNull String inputPort, int displayPort) {
2378         if (!checkCallingPermission(
2379                 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
2380                 "addPortAssociation()")) {
2381             throw new SecurityException(
2382                     "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
2383         }
2384 
2385         Objects.requireNonNull(inputPort);
2386         synchronized (mAssociationsLock) {
2387             mRuntimeAssociations.put(inputPort, displayPort);
2388         }
2389         mNative.notifyPortAssociationsChanged();
2390     }
2391 
2392     /**
2393      * Remove the runtime association between the input port and the display port. Any existing
2394      * static association for the cleared input port will be restored.
2395      * @param inputPort The port of the input device to be cleared.
2396      */
2397     @Override // Binder call
removePortAssociation(@onNull String inputPort)2398     public void removePortAssociation(@NonNull String inputPort) {
2399         if (!checkCallingPermission(
2400                 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
2401                 "clearPortAssociations()")) {
2402             throw new SecurityException(
2403                     "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
2404         }
2405 
2406         Objects.requireNonNull(inputPort);
2407         synchronized (mAssociationsLock) {
2408             mRuntimeAssociations.remove(inputPort);
2409         }
2410         mNative.notifyPortAssociationsChanged();
2411     }
2412 
2413     @Override // Binder call
addUniqueIdAssociation(@onNull String inputPort, @NonNull String displayUniqueId)2414     public void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) {
2415         if (!checkCallingPermission(
2416                 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
2417                 "addNameAssociation()")) {
2418             throw new SecurityException(
2419                     "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
2420         }
2421 
2422         Objects.requireNonNull(inputPort);
2423         Objects.requireNonNull(displayUniqueId);
2424         synchronized (mAssociationsLock) {
2425             mUniqueIdAssociations.put(inputPort, displayUniqueId);
2426         }
2427         mNative.changeUniqueIdAssociation();
2428     }
2429 
2430     @Override // Binder call
removeUniqueIdAssociation(@onNull String inputPort)2431     public void removeUniqueIdAssociation(@NonNull String inputPort) {
2432         if (!checkCallingPermission(
2433                 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
2434                 "removeUniqueIdAssociation()")) {
2435             throw new SecurityException(
2436                     "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
2437         }
2438 
2439         Objects.requireNonNull(inputPort);
2440         synchronized (mAssociationsLock) {
2441             mUniqueIdAssociations.remove(inputPort);
2442         }
2443         mNative.changeUniqueIdAssociation();
2444     }
2445 
2446     @Override // Binder call
getSensorList(int deviceId)2447     public InputSensorInfo[] getSensorList(int deviceId) {
2448         return mNative.getSensorList(deviceId);
2449     }
2450 
2451     @Override // Binder call
registerSensorListener(IInputSensorEventListener listener)2452     public boolean registerSensorListener(IInputSensorEventListener listener) {
2453         if (DEBUG) {
2454             Slog.d(TAG, "registerSensorListener: listener=" + listener + " callingPid="
2455                     + Binder.getCallingPid());
2456         }
2457         Objects.requireNonNull(listener, "listener must not be null");
2458 
2459         synchronized (mSensorEventLock) {
2460             int callingPid = Binder.getCallingPid();
2461             if (mSensorEventListeners.get(callingPid) != null) {
2462                 Slog.e(TAG, "The calling process " + callingPid + " has already "
2463                         + "registered an InputSensorEventListener.");
2464                 return false;
2465             }
2466 
2467             SensorEventListenerRecord record =
2468                     new SensorEventListenerRecord(callingPid, listener);
2469             try {
2470                 IBinder binder = listener.asBinder();
2471                 binder.linkToDeath(record, 0);
2472             } catch (RemoteException ex) {
2473                 // give up
2474                 throw new RuntimeException(ex);
2475             }
2476 
2477             mSensorEventListeners.put(callingPid, record);
2478         }
2479         return true;
2480     }
2481 
2482     @Override // Binder call
unregisterSensorListener(IInputSensorEventListener listener)2483     public void unregisterSensorListener(IInputSensorEventListener listener) {
2484         if (DEBUG) {
2485             Slog.d(TAG, "unregisterSensorListener: listener=" + listener + " callingPid="
2486                     + Binder.getCallingPid());
2487         }
2488 
2489         Objects.requireNonNull(listener, "listener must not be null");
2490 
2491         synchronized (mSensorEventLock) {
2492             int callingPid = Binder.getCallingPid();
2493             if (mSensorEventListeners.get(callingPid) != null) {
2494                 SensorEventListenerRecord record = mSensorEventListeners.get(callingPid);
2495                 if (record.getListener().asBinder() != listener.asBinder()) {
2496                     throw new IllegalArgumentException("listener is not registered");
2497                 }
2498                 mSensorEventListeners.remove(callingPid);
2499             }
2500         }
2501     }
2502 
2503     @Override // Binder call
flushSensor(int deviceId, int sensorType)2504     public boolean flushSensor(int deviceId, int sensorType) {
2505         synchronized (mSensorEventLock) {
2506             int callingPid = Binder.getCallingPid();
2507             SensorEventListenerRecord listener = mSensorEventListeners.get(callingPid);
2508             if (listener != null) {
2509                 return mNative.flushSensor(deviceId, sensorType);
2510             }
2511             return false;
2512         }
2513     }
2514 
2515     @Override // Binder call
enableSensor(int deviceId, int sensorType, int samplingPeriodUs, int maxBatchReportLatencyUs)2516     public boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs,
2517             int maxBatchReportLatencyUs) {
2518         synchronized (mInputDevicesLock) {
2519             return mNative.enableSensor(deviceId, sensorType, samplingPeriodUs,
2520                     maxBatchReportLatencyUs);
2521         }
2522     }
2523 
2524     @Override // Binder call
disableSensor(int deviceId, int sensorType)2525     public void disableSensor(int deviceId, int sensorType) {
2526         synchronized (mInputDevicesLock) {
2527             mNative.disableSensor(deviceId, sensorType);
2528         }
2529     }
2530 
2531     /**
2532      * LightSession represents a light session for lights manager.
2533      */
2534     private final class LightSession implements DeathRecipient {
2535         private final int mDeviceId;
2536         private final IBinder mToken;
2537         private final String mOpPkg;
2538         // The light ids and states that are requested by the light seesion
2539         private int[] mLightIds;
2540         private LightState[] mLightStates;
2541 
LightSession(int deviceId, String opPkg, IBinder token)2542         LightSession(int deviceId, String opPkg, IBinder token) {
2543             mDeviceId = deviceId;
2544             mOpPkg = opPkg;
2545             mToken = token;
2546         }
2547 
2548         @Override
binderDied()2549         public void binderDied() {
2550             if (DEBUG) {
2551                 Slog.d(TAG, "Light token died.");
2552             }
2553             synchronized (mLightLock) {
2554                 closeLightSession(mDeviceId, mToken);
2555                 mLightSessions.remove(mToken);
2556             }
2557         }
2558     }
2559 
2560     /**
2561      * Returns the lights available for apps to control on the specified input device.
2562      * Only lights that aren't reserved for system use are available to apps.
2563      */
2564     @Override // Binder call
getLights(int deviceId)2565     public List<Light> getLights(int deviceId) {
2566         return mNative.getLights(deviceId);
2567     }
2568 
2569     /**
2570      * Set specified light state with for a specific input device.
2571      */
setLightStateInternal(int deviceId, Light light, LightState lightState)2572     private void setLightStateInternal(int deviceId, Light light, LightState lightState) {
2573         Objects.requireNonNull(light, "light does not exist");
2574         if (DEBUG) {
2575             Slog.d(TAG, "setLightStateInternal device " + deviceId + " light " + light
2576                     + "lightState " + lightState);
2577         }
2578         if (light.getType() == Light.LIGHT_TYPE_PLAYER_ID) {
2579             mNative.setLightPlayerId(deviceId, light.getId(), lightState.getPlayerId());
2580         } else {
2581             // Set ARGB format color to input device light
2582             // Refer to https://developer.android.com/reference/kotlin/android/graphics/Color
2583             mNative.setLightColor(deviceId, light.getId(), lightState.getColor());
2584         }
2585     }
2586 
2587     /**
2588      * Set multiple light states with multiple light ids for a specific input device.
2589      */
setLightStatesInternal(int deviceId, int[] lightIds, LightState[] lightStates)2590     private void setLightStatesInternal(int deviceId, int[] lightIds, LightState[] lightStates) {
2591         final List<Light> lights = mNative.getLights(deviceId);
2592         SparseArray<Light> lightArray = new SparseArray<>();
2593         for (int i = 0; i < lights.size(); i++) {
2594             lightArray.put(lights.get(i).getId(), lights.get(i));
2595         }
2596         for (int i = 0; i < lightIds.length; i++) {
2597             if (lightArray.contains(lightIds[i])) {
2598                 setLightStateInternal(deviceId, lightArray.get(lightIds[i]), lightStates[i]);
2599             }
2600         }
2601     }
2602 
2603     /**
2604      * Set states for multiple lights for an opened light session.
2605      */
2606     @Override
setLightStates(int deviceId, int[] lightIds, LightState[] lightStates, IBinder token)2607     public void setLightStates(int deviceId, int[] lightIds, LightState[] lightStates,
2608             IBinder token) {
2609         Preconditions.checkArgument(lightIds.length == lightStates.length,
2610                 "lights and light states are not same length");
2611         synchronized (mLightLock) {
2612             LightSession lightSession = mLightSessions.get(token);
2613             Preconditions.checkArgument(lightSession != null, "not registered");
2614             Preconditions.checkState(lightSession.mDeviceId == deviceId, "Incorrect device ID");
2615             lightSession.mLightIds = lightIds.clone();
2616             lightSession.mLightStates = lightStates.clone();
2617             if (DEBUG) {
2618                 Slog.d(TAG, "setLightStates for " + lightSession.mOpPkg + " device " + deviceId);
2619             }
2620         }
2621         setLightStatesInternal(deviceId, lightIds, lightStates);
2622     }
2623 
2624     @Override
getLightState(int deviceId, int lightId)2625     public @Nullable LightState getLightState(int deviceId, int lightId) {
2626         synchronized (mLightLock) {
2627             int color = mNative.getLightColor(deviceId, lightId);
2628             int playerId = mNative.getLightPlayerId(deviceId, lightId);
2629 
2630             return new LightState(color, playerId);
2631         }
2632     }
2633 
2634     @Override
openLightSession(int deviceId, String opPkg, IBinder token)2635     public void openLightSession(int deviceId, String opPkg, IBinder token) {
2636         Objects.requireNonNull(token);
2637         synchronized (mLightLock) {
2638             Preconditions.checkState(mLightSessions.get(token) == null, "already registered");
2639             LightSession lightSession = new LightSession(deviceId, opPkg, token);
2640             try {
2641                 token.linkToDeath(lightSession, 0);
2642             } catch (RemoteException ex) {
2643                 // give up
2644                 ex.rethrowAsRuntimeException();
2645             }
2646             mLightSessions.put(token, lightSession);
2647             if (DEBUG) {
2648                 Slog.d(TAG, "Open light session for " + opPkg + " device " + deviceId);
2649             }
2650         }
2651     }
2652 
2653     @Override
closeLightSession(int deviceId, IBinder token)2654     public void closeLightSession(int deviceId, IBinder token) {
2655         Objects.requireNonNull(token);
2656         synchronized (mLightLock) {
2657             LightSession lightSession = mLightSessions.get(token);
2658             Preconditions.checkState(lightSession != null, "not registered");
2659             // Turn off the lights that were previously requested by the session to be closed.
2660             Arrays.fill(lightSession.mLightStates, new LightState(0));
2661             setLightStatesInternal(deviceId, lightSession.mLightIds,
2662                     lightSession.mLightStates);
2663             mLightSessions.remove(token);
2664             // If any other session is still pending with light request, apply the first session's
2665             // request.
2666             if (!mLightSessions.isEmpty()) {
2667                 LightSession nextSession = mLightSessions.valueAt(0);
2668                 setLightStatesInternal(deviceId, nextSession.mLightIds, nextSession.mLightStates);
2669             }
2670         }
2671     }
2672 
2673     @Override
cancelCurrentTouch()2674     public void cancelCurrentTouch() {
2675         if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT,
2676                 "cancelCurrentTouch()")) {
2677             throw new SecurityException("Requires MONITOR_INPUT permission");
2678         }
2679 
2680         mNative.cancelCurrentTouch();
2681     }
2682 
2683     @EnforcePermission(Manifest.permission.MONITOR_INPUT)
2684     @Override
pilferPointers(IBinder inputChannelToken)2685     public void pilferPointers(IBinder inputChannelToken) {
2686         Objects.requireNonNull(inputChannelToken);
2687         mNative.pilferPointers(inputChannelToken);
2688     }
2689 
2690     @Override
registerBatteryListener(int deviceId, IInputDeviceBatteryListener listener)2691     public void registerBatteryListener(int deviceId, IInputDeviceBatteryListener listener) {
2692         Objects.requireNonNull(listener);
2693         mBatteryController.registerBatteryListener(deviceId, listener, Binder.getCallingPid());
2694     }
2695 
2696     @Override
unregisterBatteryListener(int deviceId, IInputDeviceBatteryListener listener)2697     public void unregisterBatteryListener(int deviceId, IInputDeviceBatteryListener listener) {
2698         Objects.requireNonNull(listener);
2699         mBatteryController.unregisterBatteryListener(deviceId, listener, Binder.getCallingPid());
2700     }
2701 
2702     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2703     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2704         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
2705 
2706         pw.println("INPUT MANAGER (dumpsys input)\n");
2707         String dumpStr = mNative.dump();
2708         if (dumpStr != null) {
2709             pw.println(dumpStr);
2710         }
2711 
2712         pw.println("Input Manager Service (Java) State:");
2713         dumpAssociations(pw, "  " /*prefix*/);
2714         dumpSpyWindowGestureMonitors(pw, "  " /*prefix*/);
2715         dumpDisplayInputPropertiesValues(pw, "  " /*prefix*/);
2716         mBatteryController.dump(pw, "  " /*prefix*/);
2717     }
2718 
dumpAssociations(PrintWriter pw, String prefix)2719     private void dumpAssociations(PrintWriter pw, String prefix) {
2720         if (!mStaticAssociations.isEmpty()) {
2721             pw.println(prefix + "Static Associations:");
2722             mStaticAssociations.forEach((k, v) -> {
2723                 pw.print(prefix + "  port: " + k);
2724                 pw.println("  display: " + v);
2725             });
2726         }
2727 
2728         synchronized (mAssociationsLock) {
2729             if (!mRuntimeAssociations.isEmpty()) {
2730                 pw.println(prefix + "Runtime Associations:");
2731                 mRuntimeAssociations.forEach((k, v) -> {
2732                     pw.print(prefix + "  port: " + k);
2733                     pw.println("  display: " + v);
2734                 });
2735             }
2736             if (!mUniqueIdAssociations.isEmpty()) {
2737                 pw.println(prefix + "Unique Id Associations:");
2738                 mUniqueIdAssociations.forEach((k, v) -> {
2739                     pw.print(prefix + "  port: " + k);
2740                     pw.println("  uniqueId: " + v);
2741                 });
2742             }
2743         }
2744     }
2745 
dumpSpyWindowGestureMonitors(PrintWriter pw, String prefix)2746     private void dumpSpyWindowGestureMonitors(PrintWriter pw, String prefix) {
2747         synchronized (mInputMonitors) {
2748             if (mInputMonitors.isEmpty()) return;
2749             pw.println(prefix + "Gesture Monitors (implemented as spy windows):");
2750             int i = 0;
2751             for (final GestureMonitorSpyWindow monitor : mInputMonitors.values()) {
2752                 pw.append(prefix + "  " + i++ + ": ").println(monitor.dump());
2753             }
2754         }
2755     }
2756 
dumpDisplayInputPropertiesValues(PrintWriter pw, String prefix)2757     private void dumpDisplayInputPropertiesValues(PrintWriter pw, String prefix) {
2758         synchronized (mAdditionalDisplayInputPropertiesLock) {
2759             if (mAdditionalDisplayInputProperties.size() != 0) {
2760                 pw.println(prefix + "mAdditionalDisplayInputProperties:");
2761                 for (int i = 0; i < mAdditionalDisplayInputProperties.size(); i++) {
2762                     pw.println(prefix + "  displayId: "
2763                             + mAdditionalDisplayInputProperties.keyAt(i));
2764                     final AdditionalDisplayInputProperties properties =
2765                             mAdditionalDisplayInputProperties.valueAt(i);
2766                     pw.println(prefix + "  pointerAcceleration: " + properties.pointerAcceleration);
2767                     pw.println(prefix + "  pointerIconVisible: " + properties.pointerIconVisible);
2768                 }
2769             }
2770             if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
2771                 pw.println(prefix + "mOverriddenPointerDisplayId: " + mOverriddenPointerDisplayId);
2772             }
2773         }
2774     }
checkCallingPermission(String permission, String func)2775     private boolean checkCallingPermission(String permission, String func) {
2776         return checkCallingPermission(permission, func, false /*checkInstrumentationSource*/);
2777     }
2778 
checkCallingPermission(String permission, String func, boolean checkInstrumentationSource)2779     private boolean checkCallingPermission(String permission, String func,
2780             boolean checkInstrumentationSource) {
2781         // Quick check: if the calling permission is me, it's all okay.
2782         if (Binder.getCallingPid() == Process.myPid()) {
2783             return true;
2784         }
2785 
2786         if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
2787             return true;
2788         }
2789 
2790         if (checkInstrumentationSource) {
2791             final ActivityManagerInternal ami =
2792                     LocalServices.getService(ActivityManagerInternal.class);
2793             Objects.requireNonNull(ami, "ActivityManagerInternal should not be null.");
2794             final int instrumentationUid = ami.getInstrumentationSourceUid(Binder.getCallingUid());
2795             if (instrumentationUid != Process.INVALID_UID) {
2796                 // Clear the calling identity when checking if the instrumentation source has
2797                 // permission because PackageManager will deny all permissions to some callers,
2798                 // such as instant apps.
2799                 final long token = Binder.clearCallingIdentity();
2800                 try {
2801                     if (mContext.checkPermission(permission, -1 /*pid*/, instrumentationUid)
2802                             == PackageManager.PERMISSION_GRANTED) {
2803                         return true;
2804                     }
2805                 } finally {
2806                     Binder.restoreCallingIdentity(token);
2807                 }
2808             }
2809         }
2810 
2811         String msg = "Permission Denial: " + func + " from pid="
2812                 + Binder.getCallingPid()
2813                 + ", uid=" + Binder.getCallingUid()
2814                 + " requires " + permission;
2815         Slog.w(TAG, msg);
2816         return false;
2817     }
2818 
2819     // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
2820     @Override
monitor()2821     public void monitor() {
2822         synchronized (mInputFilterLock) { }
2823         synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
2824         synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
2825         synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ }
2826         synchronized (mAdditionalDisplayInputPropertiesLock) { /* Test if blocked by props lock */ }
2827         mBatteryController.monitor();
2828         mNative.monitor();
2829     }
2830 
2831     // Native callback.
2832     @SuppressWarnings("unused")
notifyConfigurationChanged(long whenNanos)2833     private void notifyConfigurationChanged(long whenNanos) {
2834         mWindowManagerCallbacks.notifyConfigurationChanged();
2835     }
2836 
2837     // Native callback.
2838     @SuppressWarnings("unused")
notifyInputDevicesChanged(InputDevice[] inputDevices)2839     private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
2840         synchronized (mInputDevicesLock) {
2841             if (!mInputDevicesChangedPending) {
2842                 mInputDevicesChangedPending = true;
2843                 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
2844                         mInputDevices).sendToTarget();
2845             }
2846 
2847             mInputDevices = inputDevices;
2848         }
2849     }
2850 
2851     // Native callback.
2852     @SuppressWarnings("unused")
notifySwitch(long whenNanos, int switchValues, int switchMask)2853     private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
2854         if (DEBUG) {
2855             Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
2856                     + ", mask=" + Integer.toHexString(switchMask));
2857         }
2858 
2859         if ((switchMask & SW_LID_BIT) != 0) {
2860             final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
2861             synchronized (mLidSwitchLock) {
2862                 if (mSystemReady) {
2863                     for (int i = 0; i < mLidSwitchCallbacks.size(); i++) {
2864                         LidSwitchCallback callbacks = mLidSwitchCallbacks.get(i);
2865                         callbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
2866                     }
2867                 }
2868             }
2869         }
2870 
2871         if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
2872             final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
2873             mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
2874             // Use SW_CAMERA_LENS_COVER code for camera privacy toggles
2875             setSensorPrivacy(Sensors.CAMERA, lensCovered);
2876         }
2877 
2878         if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
2879             mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
2880                     switchMask);
2881         }
2882 
2883         if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
2884             SomeArgs args = SomeArgs.obtain();
2885             args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
2886             args.argi2 = (int) (whenNanos >> 32);
2887             args.arg1 = (switchValues & SW_TABLET_MODE_BIT) != 0;
2888             mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
2889                     args).sendToTarget();
2890         }
2891 
2892         if ((switchMask & SW_MUTE_DEVICE_BIT) != 0) {
2893             final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0);
2894             AudioManager audioManager = mContext.getSystemService(AudioManager.class);
2895             audioManager.setMicrophoneMuteFromSwitch(micMute);
2896 
2897             setSensorPrivacy(Sensors.MICROPHONE, micMute);
2898         }
2899     }
2900 
2901     // Set the sensor privacy state based on the hardware toggles switch states
setSensorPrivacy(@ensorPrivacyManager.Sensors.Sensor int sensor, boolean enablePrivacy)2902     private void setSensorPrivacy(@SensorPrivacyManager.Sensors.Sensor int sensor,
2903             boolean enablePrivacy) {
2904         final SensorPrivacyManagerInternal sensorPrivacyManagerInternal =
2905                 LocalServices.getService(SensorPrivacyManagerInternal.class);
2906         sensorPrivacyManagerInternal.setPhysicalToggleSensorPrivacy(UserHandle.USER_CURRENT, sensor,
2907                 enablePrivacy);
2908     }
2909 
2910     // Native callback.
2911     @SuppressWarnings("unused")
notifyInputChannelBroken(IBinder token)2912     private void notifyInputChannelBroken(IBinder token) {
2913         synchronized (mInputMonitors) {
2914             if (mInputMonitors.containsKey(token)) {
2915                 removeSpyWindowGestureMonitor(token);
2916             }
2917         }
2918         mWindowManagerCallbacks.notifyInputChannelBroken(token);
2919     }
2920 
2921     // Native callback
2922     @SuppressWarnings("unused")
notifyFocusChanged(IBinder oldToken, IBinder newToken)2923     private void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
2924         mWindowManagerCallbacks.notifyFocusChanged(oldToken, newToken);
2925     }
2926 
2927     // Native callback
2928     @SuppressWarnings("unused")
notifyDropWindow(IBinder token, float x, float y)2929     private void notifyDropWindow(IBinder token, float x, float y) {
2930         mWindowManagerCallbacks.notifyDropWindow(token, x, y);
2931     }
2932 
2933     // Native callback
2934     @SuppressWarnings("unused")
notifyUntrustedTouch(String packageName)2935     private void notifyUntrustedTouch(String packageName) {
2936         // TODO(b/169067926): Remove toast after gathering feedback on dogfood.
2937         if (!UNTRUSTED_TOUCHES_TOAST || ArrayUtils.contains(
2938                 PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) {
2939             Log.i(TAG, "Suppressing untrusted touch toast for " + packageName);
2940             return;
2941         }
2942         DisplayThread.getHandler().post(() ->
2943                 Toast.makeText(mContext,
2944                         "Touch obscured by " + packageName
2945                                 + " will be blocked. Check go/untrusted-touches",
2946                         Toast.LENGTH_SHORT).show());
2947     }
2948 
2949     // Native callback.
2950     @SuppressWarnings("unused")
notifyNoFocusedWindowAnr(InputApplicationHandle inputApplicationHandle)2951     private void notifyNoFocusedWindowAnr(InputApplicationHandle inputApplicationHandle) {
2952         mWindowManagerCallbacks.notifyNoFocusedWindowAnr(inputApplicationHandle);
2953     }
2954 
2955     // Native callback
2956     @SuppressWarnings("unused")
notifyWindowUnresponsive(IBinder token, int pid, boolean isPidValid, String reason)2957     private void notifyWindowUnresponsive(IBinder token, int pid, boolean isPidValid,
2958             String reason) {
2959         mWindowManagerCallbacks.notifyWindowUnresponsive(token,
2960                 isPidValid ? OptionalInt.of(pid) : OptionalInt.empty(), reason);
2961     }
2962 
2963     // Native callback
2964     @SuppressWarnings("unused")
notifyWindowResponsive(IBinder token, int pid, boolean isPidValid)2965     private void notifyWindowResponsive(IBinder token, int pid, boolean isPidValid) {
2966         mWindowManagerCallbacks.notifyWindowResponsive(token,
2967                 isPidValid ? OptionalInt.of(pid) : OptionalInt.empty());
2968     }
2969 
2970     // Native callback.
2971     @SuppressWarnings("unused")
notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, float[] values)2972     private void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp,
2973             float[] values) {
2974         if (DEBUG) {
2975             Slog.d(TAG, "notifySensorEvent: deviceId=" + deviceId + " sensorType="
2976                     + sensorType + " values=" + Arrays.toString(values));
2977         }
2978         mSensorEventListenersToNotify.clear();
2979         final int numListeners;
2980         synchronized (mSensorEventLock) {
2981             numListeners = mSensorEventListeners.size();
2982             for (int i = 0; i < numListeners; i++) {
2983                 mSensorEventListenersToNotify.add(
2984                         mSensorEventListeners.valueAt(i));
2985             }
2986         }
2987         for (int i = 0; i < numListeners; i++) {
2988             mSensorEventListenersToNotify.get(i).notifySensorEvent(deviceId, sensorType,
2989                     accuracy, timestamp, values);
2990         }
2991         mSensorEventListenersToNotify.clear();
2992     }
2993 
2994     // Native callback.
2995     @SuppressWarnings("unused")
notifySensorAccuracy(int deviceId, int sensorType, int accuracy)2996     private void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) {
2997         mSensorAccuracyListenersToNotify.clear();
2998         final int numListeners;
2999         synchronized (mSensorEventLock) {
3000             numListeners = mSensorEventListeners.size();
3001             for (int i = 0; i < numListeners; i++) {
3002                 mSensorAccuracyListenersToNotify.add(mSensorEventListeners.valueAt(i));
3003             }
3004         }
3005         for (int i = 0; i < numListeners; i++) {
3006             mSensorAccuracyListenersToNotify.get(i).notifySensorAccuracy(
3007                     deviceId, sensorType, accuracy);
3008         }
3009         mSensorAccuracyListenersToNotify.clear();
3010     }
3011 
3012     // Native callback.
3013     @SuppressWarnings("unused")
filterInputEvent(InputEvent event, int policyFlags)3014     final boolean filterInputEvent(InputEvent event, int policyFlags) {
3015         synchronized (mInputFilterLock) {
3016             if (mInputFilter != null) {
3017                 try {
3018                     mInputFilter.filterInputEvent(event, policyFlags);
3019                 } catch (RemoteException e) {
3020                     /* ignore */
3021                 }
3022                 return false;
3023             }
3024         }
3025         event.recycle();
3026         return true;
3027     }
3028 
3029     // Native callback.
3030     @SuppressWarnings("unused")
interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)3031     private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
3032         return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
3033     }
3034 
3035     // Native callback.
3036     @SuppressWarnings("unused")
interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)3037     private int interceptMotionBeforeQueueingNonInteractive(int displayId,
3038             long whenNanos, int policyFlags) {
3039         return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
3040                 displayId, whenNanos, policyFlags);
3041     }
3042 
3043     // Native callback.
3044     @SuppressWarnings("unused")
interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags)3045     private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
3046         return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
3047     }
3048 
3049     // Native callback.
3050     @SuppressWarnings("unused")
dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags)3051     private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) {
3052         return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
3053     }
3054 
3055     // Native callback.
3056     @SuppressWarnings("unused")
onPointerDownOutsideFocus(IBinder touchedToken)3057     private void onPointerDownOutsideFocus(IBinder touchedToken) {
3058         mWindowManagerCallbacks.onPointerDownOutsideFocus(touchedToken);
3059     }
3060 
3061     // Native callback.
3062     @SuppressWarnings("unused")
getVirtualKeyQuietTimeMillis()3063     private int getVirtualKeyQuietTimeMillis() {
3064         return mContext.getResources().getInteger(
3065                 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
3066     }
3067 
3068     // Native callback.
3069     @SuppressWarnings("unused")
getExcludedDeviceNames()3070     private static String[] getExcludedDeviceNames() {
3071         List<String> names = new ArrayList<>();
3072         // Read partner-provided list of excluded input devices
3073         // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
3074         final File[] baseDirs = {
3075             Environment.getRootDirectory(),
3076             Environment.getVendorDirectory()
3077         };
3078         for (File baseDir: baseDirs) {
3079             File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH);
3080             try (InputStream stream = new FileInputStream(confFile)) {
3081                 names.addAll(ConfigurationProcessor.processExcludedDeviceNames(stream));
3082             } catch (FileNotFoundException e) {
3083                 // It's ok if the file does not exist.
3084             } catch (Exception e) {
3085                 Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
3086             }
3087         }
3088         return names.toArray(new String[0]);
3089     }
3090 
3091     /**
3092      * Flatten a map into a string list, with value positioned directly next to the
3093      * key.
3094      * @return Flattened list
3095      */
flatten(@onNull Map<String, T> map)3096     private static <T> String[] flatten(@NonNull Map<String, T> map) {
3097         final List<String> list = new ArrayList<>(map.size() * 2);
3098         map.forEach((k, v)-> {
3099             list.add(k);
3100             list.add(v.toString());
3101         });
3102         return list.toArray(new String[0]);
3103     }
3104 
3105     /**
3106      * Ports are highly platform-specific, so only allow these to be specified in the vendor
3107      * directory.
3108      */
loadStaticInputPortAssociations()3109     private static Map<String, Integer> loadStaticInputPortAssociations() {
3110         final File baseDir = Environment.getVendorDirectory();
3111         final File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
3112 
3113         try (final InputStream stream = new FileInputStream(confFile)) {
3114             return ConfigurationProcessor.processInputPortAssociations(stream);
3115         } catch (FileNotFoundException e) {
3116             // Most of the time, file will not exist, which is expected.
3117         } catch (Exception e) {
3118             Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
3119         }
3120 
3121         return new HashMap<>();
3122     }
3123 
3124     // Native callback
3125     @SuppressWarnings("unused")
getInputPortAssociations()3126     private String[] getInputPortAssociations() {
3127         final Map<String, Integer> associations = new HashMap<>(mStaticAssociations);
3128 
3129         // merge the runtime associations.
3130         synchronized (mAssociationsLock) {
3131             associations.putAll(mRuntimeAssociations);
3132         }
3133 
3134         return flatten(associations);
3135     }
3136 
3137     // Native callback
3138     @SuppressWarnings("unused")
getInputUniqueIdAssociations()3139     private String[] getInputUniqueIdAssociations() {
3140         final Map<String, String> associations;
3141         synchronized (mAssociationsLock) {
3142             associations = new HashMap<>(mUniqueIdAssociations);
3143         }
3144 
3145         return flatten(associations);
3146     }
3147 
3148     /**
3149      * Gets if an input device could dispatch to the given display".
3150      * @param deviceId The input device id.
3151      * @param displayId The specific display id.
3152      * @return True if the device could dispatch to the given display, false otherwise.
3153      */
canDispatchToDisplay(int deviceId, int displayId)3154     public boolean canDispatchToDisplay(int deviceId, int displayId) {
3155         return mNative.canDispatchToDisplay(deviceId, displayId);
3156     }
3157 
3158     // Native callback.
3159     @SuppressWarnings("unused")
getKeyRepeatTimeout()3160     private int getKeyRepeatTimeout() {
3161         return ViewConfiguration.getKeyRepeatTimeout();
3162     }
3163 
3164     // Native callback.
3165     @SuppressWarnings("unused")
getKeyRepeatDelay()3166     private int getKeyRepeatDelay() {
3167         return ViewConfiguration.getKeyRepeatDelay();
3168     }
3169 
3170     // Native callback.
3171     @SuppressWarnings("unused")
getHoverTapTimeout()3172     private int getHoverTapTimeout() {
3173         return ViewConfiguration.getHoverTapTimeout();
3174     }
3175 
3176     // Native callback.
3177     @SuppressWarnings("unused")
getHoverTapSlop()3178     private int getHoverTapSlop() {
3179         return ViewConfiguration.getHoverTapSlop();
3180     }
3181 
3182     // Native callback.
3183     @SuppressWarnings("unused")
getDoubleTapTimeout()3184     private int getDoubleTapTimeout() {
3185         return ViewConfiguration.getDoubleTapTimeout();
3186     }
3187 
3188     // Native callback.
3189     @SuppressWarnings("unused")
getLongPressTimeout()3190     private int getLongPressTimeout() {
3191         return ViewConfiguration.getLongPressTimeout();
3192     }
3193 
3194     // Native callback.
3195     @SuppressWarnings("unused")
getPointerLayer()3196     private int getPointerLayer() {
3197         return mWindowManagerCallbacks.getPointerLayer();
3198     }
3199 
3200     // Native callback.
3201     @SuppressWarnings("unused")
getPointerIcon(int displayId)3202     private PointerIcon getPointerIcon(int displayId) {
3203         return PointerIcon.getDefaultIcon(getContextForPointerIcon(displayId));
3204     }
3205 
3206     // Native callback.
3207     @SuppressWarnings("unused")
getParentSurfaceForPointers(int displayId)3208     private long getParentSurfaceForPointers(int displayId) {
3209         final SurfaceControl sc = mWindowManagerCallbacks.getParentSurfaceForPointers(displayId);
3210         if (sc == null) {
3211             return 0;
3212         }
3213         return sc.mNativeObject;
3214     }
3215 
3216     @NonNull
getContextForPointerIcon(int displayId)3217     private Context getContextForPointerIcon(int displayId) {
3218         if (mPointerIconDisplayContext != null
3219                 && mPointerIconDisplayContext.getDisplay().getDisplayId() == displayId) {
3220             return mPointerIconDisplayContext;
3221         }
3222 
3223         // Create and cache context for non-default display.
3224         mPointerIconDisplayContext = getContextForDisplay(displayId);
3225 
3226         // Fall back to default display if the requested displayId does not exist.
3227         if (mPointerIconDisplayContext == null) {
3228             mPointerIconDisplayContext = getContextForDisplay(Display.DEFAULT_DISPLAY);
3229         }
3230         return mPointerIconDisplayContext;
3231     }
3232 
3233     @Nullable
getContextForDisplay(int displayId)3234     private Context getContextForDisplay(int displayId) {
3235         if (displayId == Display.INVALID_DISPLAY) {
3236             return null;
3237         }
3238         if (mContext.getDisplay().getDisplayId() == displayId) {
3239             return mContext;
3240         }
3241 
3242         final DisplayManager displayManager = Objects.requireNonNull(
3243                 mContext.getSystemService(DisplayManager.class));
3244         final Display display = displayManager.getDisplay(displayId);
3245         if (display == null) {
3246             return null;
3247         }
3248 
3249         return mContext.createDisplayContext(display);
3250     }
3251 
3252     // Native callback.
3253     @SuppressWarnings("unused")
getKeyboardLayoutOverlay(InputDeviceIdentifier identifier)3254     private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
3255         if (!mSystemReady) {
3256             return null;
3257         }
3258 
3259         String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
3260         if (keyboardLayoutDescriptor == null) {
3261             return null;
3262         }
3263 
3264         final String[] result = new String[2];
3265         visitKeyboardLayout(keyboardLayoutDescriptor,
3266                 (resources, keyboardLayoutResId, layout) -> {
3267                     try (InputStreamReader stream = new InputStreamReader(
3268                             resources.openRawResource(keyboardLayoutResId))) {
3269                         result[0] = layout.getDescriptor();
3270                         result[1] = Streams.readFully(stream);
3271                     } catch (IOException | NotFoundException ignored) {
3272                     }
3273                 });
3274         if (result[0] == null) {
3275             Slog.w(TAG, "Could not get keyboard layout with descriptor '"
3276                     + keyboardLayoutDescriptor + "'.");
3277             return null;
3278         }
3279         return result;
3280     }
3281 
3282     // Native callback.
3283     @SuppressWarnings("unused")
getDeviceAlias(String uniqueId)3284     private String getDeviceAlias(String uniqueId) {
3285         if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
3286             // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
3287             return null;
3288         }
3289         return null;
3290     }
3291 
3292     private static class PointerDisplayIdChangedArgs {
3293         final int mPointerDisplayId;
3294         final float mXPosition;
3295         final float mYPosition;
PointerDisplayIdChangedArgs(int pointerDisplayId, float xPosition, float yPosition)3296         PointerDisplayIdChangedArgs(int pointerDisplayId, float xPosition, float yPosition) {
3297             mPointerDisplayId = pointerDisplayId;
3298             mXPosition = xPosition;
3299             mYPosition = yPosition;
3300         }
3301     }
3302 
3303     // Native callback.
3304     @SuppressWarnings("unused")
3305     @VisibleForTesting
onPointerDisplayIdChanged(int pointerDisplayId, float xPosition, float yPosition)3306     void onPointerDisplayIdChanged(int pointerDisplayId, float xPosition, float yPosition) {
3307         mHandler.obtainMessage(MSG_POINTER_DISPLAY_ID_CHANGED,
3308                 new PointerDisplayIdChangedArgs(pointerDisplayId, xPosition,
3309                         yPosition)).sendToTarget();
3310     }
3311 
3312     /**
3313      * Callback interface implemented by the Window Manager.
3314      */
3315     public interface WindowManagerCallbacks extends LidSwitchCallback {
3316         /**
3317          * This callback is invoked when the configuration changes.
3318          */
notifyConfigurationChanged()3319         void notifyConfigurationChanged();
3320 
3321         /**
3322          * This callback is invoked when the camera lens cover switch changes state.
3323          * @param whenNanos the time when the change occurred
3324          * @param lensCovered true is the lens is covered
3325          */
notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered)3326         void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
3327 
3328         /**
3329          * This callback is invoked when an input channel is closed unexpectedly.
3330          * @param token the connection token of the broken channel
3331          */
notifyInputChannelBroken(IBinder token)3332         void notifyInputChannelBroken(IBinder token);
3333 
3334         /**
3335          * Notify the window manager about the focused application that does not have any focused
3336          * window and is unable to respond to focused input events.
3337          */
notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle)3338         void notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle);
3339 
3340         /**
3341          * Notify the window manager about a window that is unresponsive.
3342          *
3343          * @param token the token that can be used to look up the window
3344          * @param pid the pid of the window owner, if known
3345          * @param reason the reason why this connection is unresponsive
3346          */
notifyWindowUnresponsive(@onNull IBinder token, @NonNull OptionalInt pid, @NonNull String reason)3347         void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
3348                 @NonNull String reason);
3349 
3350         /**
3351          * Notify the window manager about a window that has become responsive.
3352          *
3353          * @param token the token that can be used to look up the window
3354          * @param pid the pid of the window owner, if known
3355          */
notifyWindowResponsive(@onNull IBinder token, @NonNull OptionalInt pid)3356         void notifyWindowResponsive(@NonNull IBinder token, @NonNull OptionalInt pid);
3357 
3358         /**
3359          * This callback is invoked when an event first arrives to InputDispatcher and before it is
3360          * placed onto InputDispatcher's queue. If this event is intercepted, it will never be
3361          * processed by InputDispacher.
3362          * @param event The key event that's arriving to InputDispatcher
3363          * @param policyFlags The policy flags
3364          * @return the flags that tell InputDispatcher how to handle the event (for example, whether
3365          * to pass it to the user)
3366          */
interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)3367         int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
3368 
3369         /**
3370          * Provides an opportunity for the window manager policy to intercept early motion event
3371          * processing when the device is in a non-interactive state since these events are normally
3372          * dropped.
3373          */
interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)3374         int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
3375                 int policyFlags);
3376 
3377         /**
3378          * This callback is invoked just before the key is about to be sent to an application.
3379          * This allows the policy to make some last minute decisions on whether to intercept this
3380          * key.
3381          * @param token the window token that's about to receive this event
3382          * @param event the key event that's being dispatched
3383          * @param policyFlags the policy flags
3384          * @return negative value if the key should be skipped (not sent to the app). 0 if the key
3385          * should proceed getting dispatched to the app. positive value to indicate the additional
3386          * time delay, in nanoseconds, to wait before sending this key to the app.
3387          */
interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags)3388         long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags);
3389 
3390         /**
3391          * Dispatch unhandled key
3392          */
dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags)3393         KeyEvent dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags);
3394 
getPointerLayer()3395         int getPointerLayer();
3396 
getPointerDisplayId()3397         int getPointerDisplayId();
3398 
3399         /** Gets the x and y coordinates of the cursor's current position. */
getCursorPosition()3400         PointF getCursorPosition();
3401 
3402         /**
3403          * Notifies window manager that a {@link android.view.MotionEvent#ACTION_DOWN} pointer event
3404          * occurred on a window that did not have focus.
3405          *
3406          * @param touchedToken The token for the window that received the input event.
3407          */
onPointerDownOutsideFocus(IBinder touchedToken)3408         void onPointerDownOutsideFocus(IBinder touchedToken);
3409 
3410         /**
3411          * Called when the focused window has changed.
3412          */
notifyFocusChanged(IBinder oldToken, IBinder newToken)3413         void notifyFocusChanged(IBinder oldToken, IBinder newToken);
3414 
3415         /**
3416          * Called when the drag over window has changed.
3417          */
notifyDropWindow(IBinder token, float x, float y)3418         void notifyDropWindow(IBinder token, float x, float y);
3419 
3420         /**
3421          * Get the {@link SurfaceControl} that should be the parent for the surfaces created for
3422          * pointers such as the mouse cursor and touch spots for the given display.
3423          */
getParentSurfaceForPointers(int displayId)3424         SurfaceControl getParentSurfaceForPointers(int displayId);
3425 
3426         /**
3427          * Create a {@link SurfaceControl} that can be configured to receive input over the entire
3428          * display to implement a gesture monitor. The surface will not have a graphical buffer.
3429          * @param name the name of the gesture monitor
3430          * @param displayId the display to create the window in
3431          * @return the SurfaceControl of the new layer container surface
3432          */
3433         @Nullable
createSurfaceForGestureMonitor(String name, int displayId)3434         SurfaceControl createSurfaceForGestureMonitor(String name, int displayId);
3435 
3436         /**
3437          * Notify WindowManagerService when the display of the mouse pointer changes.
3438          * @param displayId The display on which the mouse pointer is shown.
3439          * @param x The x coordinate of the mouse pointer.
3440          * @param y The y coordinate of the mouse pointer.
3441          */
notifyPointerDisplayIdChanged(int displayId, float x, float y)3442         void notifyPointerDisplayIdChanged(int displayId, float x, float y);
3443     }
3444 
3445     /**
3446      * Callback interface implemented by WiredAccessoryObserver.
3447      */
3448     public interface WiredAccessoryCallbacks {
3449         /**
3450          * Notifies WiredAccessoryObserver that input state for wired accessories has changed
3451          * @param whenNanos When the wired accessories changed
3452          * @param switchValues The state of the switches
3453          * @param switchMask The mask of switches that changed
3454          */
notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask)3455         void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
3456 
3457         /**
3458          * Notifies WiredAccessoryObserver that the system is now ready.
3459          */
systemReady()3460         void systemReady();
3461     }
3462 
3463     /**
3464      * Private handler for the input manager.
3465      */
3466     private final class InputManagerHandler extends Handler {
InputManagerHandler(Looper looper)3467         public InputManagerHandler(Looper looper) {
3468             super(looper, null, true /*async*/);
3469         }
3470 
3471         @Override
handleMessage(Message msg)3472         public void handleMessage(Message msg) {
3473             switch (msg.what) {
3474                 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
3475                     deliverInputDevicesChanged((InputDevice[])msg.obj);
3476                     break;
3477                 case MSG_SWITCH_KEYBOARD_LAYOUT:
3478                     handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
3479                     break;
3480                 case MSG_RELOAD_KEYBOARD_LAYOUTS:
3481                     reloadKeyboardLayouts();
3482                     break;
3483                 case MSG_UPDATE_KEYBOARD_LAYOUTS:
3484                     updateKeyboardLayouts();
3485                     break;
3486                 case MSG_RELOAD_DEVICE_ALIASES:
3487                     reloadDeviceAliases();
3488                     break;
3489                 case MSG_DELIVER_TABLET_MODE_CHANGED:
3490                     SomeArgs args = (SomeArgs) msg.obj;
3491                     long whenNanos = (args.argi1 & 0xFFFFFFFFL) | ((long) args.argi2 << 32);
3492                     boolean inTabletMode = (boolean) args.arg1;
3493                     deliverTabletModeChanged(whenNanos, inTabletMode);
3494                     break;
3495                 case MSG_POINTER_DISPLAY_ID_CHANGED:
3496                     handlePointerDisplayIdChanged((PointerDisplayIdChangedArgs) msg.obj);
3497                     break;
3498             }
3499         }
3500     }
3501 
3502     /**
3503      * Hosting interface for input filters to call back into the input manager.
3504      */
3505     private final class InputFilterHost extends IInputFilterHost.Stub {
3506         @GuardedBy("mInputFilterLock")
3507         private boolean mDisconnected;
3508 
3509         @GuardedBy("mInputFilterLock")
disconnectLocked()3510         public void disconnectLocked() {
3511             mDisconnected = true;
3512         }
3513 
3514         @Override
sendInputEvent(InputEvent event, int policyFlags)3515         public void sendInputEvent(InputEvent event, int policyFlags) {
3516             if (!checkCallingPermission(android.Manifest.permission.INJECT_EVENTS,
3517                     "sendInputEvent()")) {
3518                 throw new SecurityException(
3519                         "The INJECT_EVENTS permission is required for injecting input events.");
3520             }
3521             Objects.requireNonNull(event, "event must not be null");
3522 
3523             synchronized (mInputFilterLock) {
3524                 if (!mDisconnected) {
3525                     mNative.injectInputEvent(event, false /* injectIntoUid */, -1 /* uid */,
3526                             InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0 /* timeout */,
3527                             policyFlags | WindowManagerPolicy.FLAG_FILTERED);
3528                 }
3529             }
3530         }
3531     }
3532 
3533     /**
3534      * Interface for the system to handle request from InputMonitors.
3535      */
3536     private final class InputMonitorHost extends IInputMonitorHost.Stub {
3537         private final IBinder mInputChannelToken;
3538 
InputMonitorHost(IBinder inputChannelToken)3539         InputMonitorHost(IBinder inputChannelToken) {
3540             mInputChannelToken = inputChannelToken;
3541         }
3542 
3543         @Override
pilferPointers()3544         public void pilferPointers() {
3545             mNative.pilferPointers(mInputChannelToken);
3546         }
3547 
3548         @Override
dispose()3549         public void dispose() {
3550             removeSpyWindowGestureMonitor(mInputChannelToken);
3551         }
3552     }
3553 
3554     private static final class KeyboardLayoutDescriptor {
3555         public String packageName;
3556         public String receiverName;
3557         public String keyboardLayoutName;
3558 
format(String packageName, String receiverName, String keyboardName)3559         public static String format(String packageName,
3560                 String receiverName, String keyboardName) {
3561             return packageName + "/" + receiverName + "/" + keyboardName;
3562         }
3563 
parse(String descriptor)3564         public static KeyboardLayoutDescriptor parse(String descriptor) {
3565             int pos = descriptor.indexOf('/');
3566             if (pos < 0 || pos + 1 == descriptor.length()) {
3567                 return null;
3568             }
3569             int pos2 = descriptor.indexOf('/', pos + 1);
3570             if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
3571                 return null;
3572             }
3573 
3574             KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
3575             result.packageName = descriptor.substring(0, pos);
3576             result.receiverName = descriptor.substring(pos + 1, pos2);
3577             result.keyboardLayoutName = descriptor.substring(pos2 + 1);
3578             return result;
3579         }
3580     }
3581 
3582     private interface KeyboardLayoutVisitor {
visitKeyboardLayout(Resources resources, int keyboardLayoutResId, KeyboardLayout layout)3583         void visitKeyboardLayout(Resources resources,
3584                 int keyboardLayoutResId, KeyboardLayout layout);
3585     }
3586 
3587     private final class InputDevicesChangedListenerRecord implements DeathRecipient {
3588         private final int mPid;
3589         private final IInputDevicesChangedListener mListener;
3590 
InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener)3591         public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
3592             mPid = pid;
3593             mListener = listener;
3594         }
3595 
3596         @Override
binderDied()3597         public void binderDied() {
3598             if (DEBUG) {
3599                 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
3600             }
3601             onInputDevicesChangedListenerDied(mPid);
3602         }
3603 
notifyInputDevicesChanged(int[] info)3604         public void notifyInputDevicesChanged(int[] info) {
3605             try {
3606                 mListener.onInputDevicesChanged(info);
3607             } catch (RemoteException ex) {
3608                 Slog.w(TAG, "Failed to notify process "
3609                         + mPid + " that input devices changed, assuming it died.", ex);
3610                 binderDied();
3611             }
3612         }
3613     }
3614 
3615     private final class TabletModeChangedListenerRecord implements DeathRecipient {
3616         private final int mPid;
3617         private final ITabletModeChangedListener mListener;
3618 
TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener)3619         public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
3620             mPid = pid;
3621             mListener = listener;
3622         }
3623 
3624         @Override
binderDied()3625         public void binderDied() {
3626             if (DEBUG) {
3627                 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
3628             }
3629             onTabletModeChangedListenerDied(mPid);
3630         }
3631 
notifyTabletModeChanged(long whenNanos, boolean inTabletMode)3632         public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
3633             try {
3634                 mListener.onTabletModeChanged(whenNanos, inTabletMode);
3635             } catch (RemoteException ex) {
3636                 Slog.w(TAG, "Failed to notify process " + mPid +
3637                         " that tablet mode changed, assuming it died.", ex);
3638                 binderDied();
3639             }
3640         }
3641     }
3642 
onSensorEventListenerDied(int pid)3643     private void onSensorEventListenerDied(int pid) {
3644         synchronized (mSensorEventLock) {
3645             mSensorEventListeners.remove(pid);
3646         }
3647     }
3648 
3649     private final class SensorEventListenerRecord implements DeathRecipient {
3650         private final int mPid;
3651         private final IInputSensorEventListener mListener;
3652 
SensorEventListenerRecord(int pid, IInputSensorEventListener listener)3653         SensorEventListenerRecord(int pid, IInputSensorEventListener listener) {
3654             mPid = pid;
3655             mListener = listener;
3656         }
3657 
3658         @Override
binderDied()3659         public void binderDied() {
3660             if (DEBUG) {
3661                 Slog.d(TAG, "Sensor event listener for pid " + mPid + " died.");
3662             }
3663             onSensorEventListenerDied(mPid);
3664         }
3665 
getListener()3666         public IInputSensorEventListener getListener() {
3667             return mListener;
3668         }
3669 
notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, float[] values)3670         public void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp,
3671                 float[] values) {
3672             try {
3673                 mListener.onInputSensorChanged(deviceId, sensorType, accuracy, timestamp,
3674                         values);
3675             } catch (RemoteException ex) {
3676                 Slog.w(TAG, "Failed to notify process " + mPid
3677                         + " that sensor event notified, assuming it died.", ex);
3678                 binderDied();
3679             }
3680         }
3681 
notifySensorAccuracy(int deviceId, int sensorType, int accuracy)3682         public void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) {
3683             try {
3684                 mListener.onInputSensorAccuracyChanged(deviceId, sensorType, accuracy);
3685             } catch (RemoteException ex) {
3686                 Slog.w(TAG, "Failed to notify process " + mPid
3687                         + " that sensor accuracy notified, assuming it died.", ex);
3688                 binderDied();
3689             }
3690         }
3691     }
3692 
3693     private final class VibratorToken implements DeathRecipient {
3694         public final int mDeviceId;
3695         public final IBinder mToken;
3696         public final int mTokenValue;
3697 
3698         public boolean mVibrating;
3699 
VibratorToken(int deviceId, IBinder token, int tokenValue)3700         public VibratorToken(int deviceId, IBinder token, int tokenValue) {
3701             mDeviceId = deviceId;
3702             mToken = token;
3703             mTokenValue = tokenValue;
3704         }
3705 
3706         @Override
binderDied()3707         public void binderDied() {
3708             if (DEBUG) {
3709                 Slog.d(TAG, "Vibrator token died.");
3710             }
3711             onVibratorTokenDied(this);
3712         }
3713     }
3714 
3715     private final class LocalService extends InputManagerInternal {
3716         @Override
setDisplayViewports(List<DisplayViewport> viewports)3717         public void setDisplayViewports(List<DisplayViewport> viewports) {
3718             setDisplayViewportsInternal(viewports);
3719         }
3720 
3721         @Override
setInteractive(boolean interactive)3722         public void setInteractive(boolean interactive) {
3723             mNative.setInteractive(interactive);
3724         }
3725 
3726         @Override
toggleCapsLock(int deviceId)3727         public void toggleCapsLock(int deviceId) {
3728             mNative.toggleCapsLock(deviceId);
3729         }
3730 
3731         @Override
setPulseGestureEnabled(boolean enabled)3732         public void setPulseGestureEnabled(boolean enabled) {
3733             if (mDoubleTouchGestureEnableFile != null) {
3734                 FileWriter writer = null;
3735                 try {
3736                     writer = new FileWriter(mDoubleTouchGestureEnableFile);
3737                     writer.write(enabled ? "1" : "0");
3738                 } catch (IOException e) {
3739                     Log.wtf(TAG, "Unable to setPulseGestureEnabled", e);
3740                 } finally {
3741                     IoUtils.closeQuietly(writer);
3742                 }
3743             }
3744         }
3745 
3746         @Override
transferTouchFocus(@onNull IBinder fromChannelToken, @NonNull IBinder toChannelToken)3747         public boolean transferTouchFocus(@NonNull IBinder fromChannelToken,
3748                 @NonNull IBinder toChannelToken) {
3749             return InputManagerService.this.transferTouchFocus(fromChannelToken, toChannelToken);
3750         }
3751 
3752         @Override
setVirtualMousePointerDisplayId(int pointerDisplayId)3753         public boolean setVirtualMousePointerDisplayId(int pointerDisplayId) {
3754             return InputManagerService.this
3755                     .setVirtualMousePointerDisplayIdBlocking(pointerDisplayId);
3756         }
3757 
3758         @Override
getVirtualMousePointerDisplayId()3759         public int getVirtualMousePointerDisplayId() {
3760             return InputManagerService.this.getVirtualMousePointerDisplayId();
3761         }
3762 
3763         @Override
getCursorPosition()3764         public PointF getCursorPosition() {
3765             return mWindowManagerCallbacks.getCursorPosition();
3766         }
3767 
3768         @Override
setPointerAcceleration(float acceleration, int displayId)3769         public void setPointerAcceleration(float acceleration, int displayId) {
3770             InputManagerService.this.setPointerAcceleration(acceleration, displayId);
3771         }
3772 
3773         @Override
setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible)3774         public void setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible) {
3775             InputManagerService.this.setDisplayEligibilityForPointerCapture(displayId, isEligible);
3776         }
3777 
3778         @Override
setPointerIconVisible(boolean visible, int displayId)3779         public void setPointerIconVisible(boolean visible, int displayId) {
3780             InputManagerService.this.setPointerIconVisible(visible, displayId);
3781         }
3782 
3783         @Override
registerLidSwitchCallback(LidSwitchCallback callbacks)3784         public void registerLidSwitchCallback(LidSwitchCallback callbacks) {
3785             registerLidSwitchCallbackInternal(callbacks);
3786         }
3787 
3788         @Override
unregisterLidSwitchCallback(LidSwitchCallback callbacks)3789         public void unregisterLidSwitchCallback(LidSwitchCallback callbacks) {
3790             unregisterLidSwitchCallbackInternal(callbacks);
3791         }
3792 
3793         @Override
createInputChannel(String inputChannelName)3794         public InputChannel createInputChannel(String inputChannelName) {
3795             return InputManagerService.this.createInputChannel(inputChannelName);
3796         }
3797 
3798         @Override
pilferPointers(IBinder token)3799         public void pilferPointers(IBinder token) {
3800             mNative.pilferPointers(token);
3801         }
3802     }
3803 
3804     @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)3805     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3806             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
3807         new InputShellCommand().exec(this, in, out, err, args, callback, resultReceiver);
3808     }
3809 
3810     private static class AdditionalDisplayInputProperties {
3811 
3812         static final boolean DEFAULT_POINTER_ICON_VISIBLE = true;
3813         static final float DEFAULT_POINTER_ACCELERATION =
3814                 (float) IInputConstants.DEFAULT_POINTER_ACCELERATION;
3815 
3816         // The pointer acceleration for this display.
3817         public float pointerAcceleration;
3818 
3819         // Whether the pointer icon should be visible or hidden on this display.
3820         public boolean pointerIconVisible;
3821 
AdditionalDisplayInputProperties()3822         AdditionalDisplayInputProperties() {
3823             reset();
3824         }
3825 
allDefaults()3826         public boolean allDefaults() {
3827             return Float.compare(pointerAcceleration, DEFAULT_POINTER_ACCELERATION) == 0
3828                     && pointerIconVisible == DEFAULT_POINTER_ICON_VISIBLE;
3829         }
3830 
reset()3831         public void reset() {
3832             pointerAcceleration = DEFAULT_POINTER_ACCELERATION;
3833             pointerIconVisible = DEFAULT_POINTER_ICON_VISIBLE;
3834         }
3835     }
3836 
applyAdditionalDisplayInputProperties()3837     private void applyAdditionalDisplayInputProperties() {
3838         synchronized (mAdditionalDisplayInputPropertiesLock) {
3839             AdditionalDisplayInputProperties properties =
3840                     mAdditionalDisplayInputProperties.get(mRequestedPointerDisplayId);
3841             if (properties == null) properties = DEFAULT_ADDITIONAL_DISPLAY_INPUT_PROPERTIES;
3842             applyAdditionalDisplayInputPropertiesLocked(properties);
3843         }
3844     }
3845 
3846     @GuardedBy("mAdditionalDisplayInputPropertiesLock")
applyAdditionalDisplayInputPropertiesLocked( AdditionalDisplayInputProperties properties)3847     private void applyAdditionalDisplayInputPropertiesLocked(
3848             AdditionalDisplayInputProperties properties) {
3849         // Handle changes to each of the individual properties.
3850         if (properties.pointerIconVisible != mCurrentDisplayProperties.pointerIconVisible) {
3851             mCurrentDisplayProperties.pointerIconVisible = properties.pointerIconVisible;
3852             if (properties.pointerIconVisible) {
3853                 if (mIconType == PointerIcon.TYPE_CUSTOM) {
3854                     Objects.requireNonNull(mIcon);
3855                     mNative.setCustomPointerIcon(mIcon);
3856                 } else {
3857                     mNative.setPointerIconType(mIconType);
3858                 }
3859             } else {
3860                 mNative.setPointerIconType(PointerIcon.TYPE_NULL);
3861             }
3862         }
3863 
3864         if (properties.pointerAcceleration != mCurrentDisplayProperties.pointerAcceleration) {
3865             mCurrentDisplayProperties.pointerAcceleration = properties.pointerAcceleration;
3866             mNative.setPointerAcceleration(properties.pointerAcceleration);
3867         }
3868     }
3869 
updateAdditionalDisplayInputProperties(int displayId, Consumer<AdditionalDisplayInputProperties> updater)3870     private void updateAdditionalDisplayInputProperties(int displayId,
3871             Consumer<AdditionalDisplayInputProperties> updater) {
3872         synchronized (mAdditionalDisplayInputPropertiesLock) {
3873             AdditionalDisplayInputProperties properties =
3874                     mAdditionalDisplayInputProperties.get(displayId);
3875             if (properties == null) {
3876                 properties = new AdditionalDisplayInputProperties();
3877                 mAdditionalDisplayInputProperties.put(displayId, properties);
3878             }
3879             updater.accept(properties);
3880             if (properties.allDefaults()) {
3881                 mAdditionalDisplayInputProperties.remove(displayId);
3882             }
3883             if (displayId != mRequestedPointerDisplayId) {
3884                 Log.i(TAG, "Not applying additional properties for display " + displayId
3885                         + " because the pointer is currently targeting display "
3886                         + mRequestedPointerDisplayId + ".");
3887                 return;
3888             }
3889             applyAdditionalDisplayInputPropertiesLocked(properties);
3890         }
3891     }
3892 }
3893