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