• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.input;
18 
19 import static android.view.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 mDisplayContext;
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             if (event instanceof MotionEvent) {
843                 final Context dispCtx = getContextForDisplay(event.getDisplayId());
844                 final Display display = dispCtx.getDisplay();
845                 final int rotation = display.getRotation();
846                 if (rotation != ROTATION_0) {
847                     final MotionEvent motion = (MotionEvent) event;
848                     // Injections are currently expected to be in the space of the injector (ie.
849                     // usually assumed to be post-rotated). Thus we need to unrotate into raw
850                     // input coordinates for dispatch.
851                     final Point sz = new Point();
852                     display.getRealSize(sz);
853                     if ((rotation % 2) != 0) {
854                         final int tmpX = sz.x;
855                         sz.x = sz.y;
856                         sz.y = tmpX;
857                     }
858                     motion.applyTransform(MotionEvent.createRotateMatrix(
859                             (4 - rotation), sz.x, sz.y));
860                 }
861             }
862         }
863 
864         final int pid = Binder.getCallingPid();
865         final int uid = Binder.getCallingUid();
866         final long ident = Binder.clearCallingIdentity();
867         final int result;
868         try {
869             result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
870                     INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
871         } finally {
872             Binder.restoreCallingIdentity(ident);
873         }
874         switch (result) {
875             case InputEventInjectionResult.PERMISSION_DENIED:
876                 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
877                 throw new SecurityException(
878                         "Injecting to another application requires INJECT_EVENTS permission");
879             case InputEventInjectionResult.SUCCEEDED:
880                 return true;
881             case InputEventInjectionResult.TIMED_OUT:
882                 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
883                 return false;
884             case InputEventInjectionResult.FAILED:
885             default:
886                 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
887                 return false;
888         }
889     }
890 
891     @Override // Binder call
verifyInputEvent(InputEvent event)892     public VerifiedInputEvent verifyInputEvent(InputEvent event) {
893         return nativeVerifyInputEvent(mPtr, event);
894     }
895 
896     /**
897      * Gets information about the input device with the specified id.
898      * @param deviceId The device id.
899      * @return The input device or null if not found.
900      */
901     @Override // Binder call
getInputDevice(int deviceId)902     public InputDevice getInputDevice(int deviceId) {
903         synchronized (mInputDevicesLock) {
904             final int count = mInputDevices.length;
905             for (int i = 0; i < count; i++) {
906                 final InputDevice inputDevice = mInputDevices[i];
907                 if (inputDevice.getId() == deviceId) {
908                     return inputDevice;
909                 }
910             }
911         }
912         return null;
913     }
914 
915     // Binder call
916     @Override
isInputDeviceEnabled(int deviceId)917     public boolean isInputDeviceEnabled(int deviceId) {
918         return nativeIsInputDeviceEnabled(mPtr, deviceId);
919     }
920 
921     // Binder call
922     @Override
enableInputDevice(int deviceId)923     public void enableInputDevice(int deviceId) {
924         if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
925                 "enableInputDevice()")) {
926             throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
927         }
928         nativeEnableInputDevice(mPtr, deviceId);
929     }
930 
931     // Binder call
932     @Override
disableInputDevice(int deviceId)933     public void disableInputDevice(int deviceId) {
934         if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
935                 "disableInputDevice()")) {
936             throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
937         }
938         nativeDisableInputDevice(mPtr, deviceId);
939     }
940 
941     /**
942      * Gets the ids of all input devices in the system.
943      * @return The input device ids.
944      */
945     @Override // Binder call
getInputDeviceIds()946     public int[] getInputDeviceIds() {
947         synchronized (mInputDevicesLock) {
948             final int count = mInputDevices.length;
949             int[] ids = new int[count];
950             for (int i = 0; i < count; i++) {
951                 ids[i] = mInputDevices[i].getId();
952             }
953             return ids;
954         }
955     }
956 
957     /**
958      * Gets all input devices in the system.
959      * @return The array of input devices.
960      */
getInputDevices()961     public InputDevice[] getInputDevices() {
962         synchronized (mInputDevicesLock) {
963             return mInputDevices;
964         }
965     }
966 
967     @Override // Binder call
registerInputDevicesChangedListener(IInputDevicesChangedListener listener)968     public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
969         if (listener == null) {
970             throw new IllegalArgumentException("listener must not be null");
971         }
972 
973         synchronized (mInputDevicesLock) {
974             int callingPid = Binder.getCallingPid();
975             if (mInputDevicesChangedListeners.get(callingPid) != null) {
976                 throw new SecurityException("The calling process has already "
977                         + "registered an InputDevicesChangedListener.");
978             }
979 
980             InputDevicesChangedListenerRecord record =
981                     new InputDevicesChangedListenerRecord(callingPid, listener);
982             try {
983                 IBinder binder = listener.asBinder();
984                 binder.linkToDeath(record, 0);
985             } catch (RemoteException ex) {
986                 // give up
987                 throw new RuntimeException(ex);
988             }
989 
990             mInputDevicesChangedListeners.put(callingPid, record);
991         }
992     }
993 
onInputDevicesChangedListenerDied(int pid)994     private void onInputDevicesChangedListenerDied(int pid) {
995         synchronized (mInputDevicesLock) {
996             mInputDevicesChangedListeners.remove(pid);
997         }
998     }
999 
1000     // Must be called on handler.
deliverInputDevicesChanged(InputDevice[] oldInputDevices)1001     private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
1002         // Scan for changes.
1003         int numFullKeyboardsAdded = 0;
1004         mTempInputDevicesChangedListenersToNotify.clear();
1005         mTempFullKeyboards.clear();
1006         final int numListeners;
1007         final int[] deviceIdAndGeneration;
1008         synchronized (mInputDevicesLock) {
1009             if (!mInputDevicesChangedPending) {
1010                 return;
1011             }
1012             mInputDevicesChangedPending = false;
1013 
1014             numListeners = mInputDevicesChangedListeners.size();
1015             for (int i = 0; i < numListeners; i++) {
1016                 mTempInputDevicesChangedListenersToNotify.add(
1017                         mInputDevicesChangedListeners.valueAt(i));
1018             }
1019 
1020             final int numDevices = mInputDevices.length;
1021             deviceIdAndGeneration = new int[numDevices * 2];
1022             for (int i = 0; i < numDevices; i++) {
1023                 final InputDevice inputDevice = mInputDevices[i];
1024                 deviceIdAndGeneration[i * 2] = inputDevice.getId();
1025                 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
1026 
1027                 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
1028                     if (!containsInputDeviceWithDescriptor(oldInputDevices,
1029                             inputDevice.getDescriptor())) {
1030                         mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
1031                     } else {
1032                         mTempFullKeyboards.add(inputDevice);
1033                     }
1034                 }
1035             }
1036         }
1037 
1038         // Notify listeners.
1039         for (int i = 0; i < numListeners; i++) {
1040             mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
1041                     deviceIdAndGeneration);
1042         }
1043         mTempInputDevicesChangedListenersToNotify.clear();
1044 
1045         // Check for missing keyboard layouts.
1046         List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
1047         final int numFullKeyboards = mTempFullKeyboards.size();
1048         synchronized (mDataStore) {
1049             for (int i = 0; i < numFullKeyboards; i++) {
1050                 final InputDevice inputDevice = mTempFullKeyboards.get(i);
1051                 String layout =
1052                     getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
1053                 if (layout == null) {
1054                     layout = getDefaultKeyboardLayout(inputDevice);
1055                     if (layout != null) {
1056                         setCurrentKeyboardLayoutForInputDevice(
1057                                 inputDevice.getIdentifier(), layout);
1058                     }
1059                 }
1060                 if (layout == null) {
1061                     keyboardsMissingLayout.add(inputDevice);
1062                 }
1063             }
1064         }
1065 
1066         if (mNotificationManager != null) {
1067             if (!keyboardsMissingLayout.isEmpty()) {
1068                 if (keyboardsMissingLayout.size() > 1) {
1069                     // We have more than one keyboard missing a layout, so drop the
1070                     // user at the generic input methods page so they can pick which
1071                     // one to set.
1072                     showMissingKeyboardLayoutNotification(null);
1073                 } else {
1074                     showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
1075                 }
1076             } else if (mKeyboardLayoutNotificationShown) {
1077                 hideMissingKeyboardLayoutNotification();
1078             }
1079         }
1080         mTempFullKeyboards.clear();
1081     }
1082 
getDefaultKeyboardLayout(final InputDevice d)1083     private String getDefaultKeyboardLayout(final InputDevice d) {
1084         final Locale systemLocale = mContext.getResources().getConfiguration().locale;
1085         // If our locale doesn't have a language for some reason, then we don't really have a
1086         // reasonable default.
1087         if (TextUtils.isEmpty(systemLocale.getLanguage())) {
1088             return null;
1089         }
1090         final List<KeyboardLayout> layouts = new ArrayList<>();
1091         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1092             @Override
1093             public void visitKeyboardLayout(Resources resources,
1094                     int keyboardLayoutResId, KeyboardLayout layout) {
1095                 // Only select a default when we know the layout is appropriate. For now, this
1096                 // means its a custom layout for a specific keyboard.
1097                 if (layout.getVendorId() != d.getVendorId()
1098                         || layout.getProductId() != d.getProductId()) {
1099                     return;
1100                 }
1101                 final LocaleList locales = layout.getLocales();
1102                 final int numLocales = locales.size();
1103                 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
1104                     if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
1105                         layouts.add(layout);
1106                         break;
1107                     }
1108                 }
1109             }
1110         });
1111 
1112         if (layouts.isEmpty()) {
1113             return null;
1114         }
1115 
1116         // First sort so that ones with higher priority are listed at the top
1117         Collections.sort(layouts);
1118         // Next we want to try to find an exact match of language, country and variant.
1119         final int N = layouts.size();
1120         for (int i = 0; i < N; i++) {
1121             KeyboardLayout layout = layouts.get(i);
1122             final LocaleList locales = layout.getLocales();
1123             final int numLocales = locales.size();
1124             for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
1125                 final Locale locale = locales.get(localeIndex);
1126                 if (locale.getCountry().equals(systemLocale.getCountry())
1127                         && locale.getVariant().equals(systemLocale.getVariant())) {
1128                     return layout.getDescriptor();
1129                 }
1130             }
1131         }
1132         // Then try an exact match of language and country
1133         for (int i = 0; i < N; i++) {
1134             KeyboardLayout layout = layouts.get(i);
1135             final LocaleList locales = layout.getLocales();
1136             final int numLocales = locales.size();
1137             for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
1138                 final Locale locale = locales.get(localeIndex);
1139                 if (locale.getCountry().equals(systemLocale.getCountry())) {
1140                     return layout.getDescriptor();
1141                 }
1142             }
1143         }
1144 
1145         // Give up and just use the highest priority layout with matching language
1146         return layouts.get(0).getDescriptor();
1147     }
1148 
isCompatibleLocale(Locale systemLocale, Locale keyboardLocale)1149     private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
1150         // Different languages are never compatible
1151         if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
1152             return false;
1153         }
1154         // If both the system and the keyboard layout have a country specifier, they must be equal.
1155         if (!TextUtils.isEmpty(systemLocale.getCountry())
1156                 && !TextUtils.isEmpty(keyboardLocale.getCountry())
1157                 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
1158             return false;
1159         }
1160         return true;
1161     }
1162 
1163     @Override // Binder call & native callback
getTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation)1164     public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
1165             int surfaceRotation) {
1166         if (inputDeviceDescriptor == null) {
1167             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
1168         }
1169 
1170         synchronized (mDataStore) {
1171             return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
1172         }
1173     }
1174 
1175     @Override // Binder call
setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation, TouchCalibration calibration)1176     public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
1177             TouchCalibration calibration) {
1178         if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
1179                 "setTouchCalibrationForInputDevice()")) {
1180             throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
1181         }
1182         if (inputDeviceDescriptor == null) {
1183             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
1184         }
1185         if (calibration == null) {
1186             throw new IllegalArgumentException("calibration must not be null");
1187         }
1188         if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
1189             throw new IllegalArgumentException("surfaceRotation value out of bounds");
1190         }
1191 
1192         synchronized (mDataStore) {
1193             try {
1194                 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
1195                         calibration)) {
1196                     nativeReloadCalibration(mPtr);
1197                 }
1198             } finally {
1199                 mDataStore.saveIfNeeded();
1200             }
1201         }
1202     }
1203 
1204     @Override // Binder call
isInTabletMode()1205     public int isInTabletMode() {
1206         if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
1207                 "isInTabletMode()")) {
1208             throw new SecurityException("Requires TABLET_MODE permission");
1209         }
1210         return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
1211     }
1212 
1213     @Override // Binder call
isMicMuted()1214     public int isMicMuted() {
1215         return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MUTE_DEVICE);
1216     }
1217 
1218     @Override // Binder call
registerTabletModeChangedListener(ITabletModeChangedListener listener)1219     public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
1220         if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
1221                 "registerTabletModeChangedListener()")) {
1222             throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
1223         }
1224         if (listener == null) {
1225             throw new IllegalArgumentException("listener must not be null");
1226         }
1227 
1228         synchronized (mTabletModeLock) {
1229             final int callingPid = Binder.getCallingPid();
1230             if (mTabletModeChangedListeners.get(callingPid) != null) {
1231                 throw new IllegalStateException("The calling process has already registered "
1232                         + "a TabletModeChangedListener.");
1233             }
1234             TabletModeChangedListenerRecord record =
1235                     new TabletModeChangedListenerRecord(callingPid, listener);
1236             try {
1237                 IBinder binder = listener.asBinder();
1238                 binder.linkToDeath(record, 0);
1239             } catch (RemoteException ex) {
1240                 throw new RuntimeException(ex);
1241             }
1242             mTabletModeChangedListeners.put(callingPid, record);
1243         }
1244     }
1245 
onTabletModeChangedListenerDied(int pid)1246     private void onTabletModeChangedListenerDied(int pid) {
1247         synchronized (mTabletModeLock) {
1248             mTabletModeChangedListeners.remove(pid);
1249         }
1250     }
1251 
1252     // Must be called on handler
deliverTabletModeChanged(long whenNanos, boolean inTabletMode)1253     private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
1254         mTempTabletModeChangedListenersToNotify.clear();
1255         final int numListeners;
1256         synchronized (mTabletModeLock) {
1257             numListeners = mTabletModeChangedListeners.size();
1258             for (int i = 0; i < numListeners; i++) {
1259                 mTempTabletModeChangedListenersToNotify.add(
1260                         mTabletModeChangedListeners.valueAt(i));
1261             }
1262         }
1263         for (int i = 0; i < numListeners; i++) {
1264             mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
1265                     whenNanos, inTabletMode);
1266         }
1267     }
1268 
1269     // Must be called on handler.
showMissingKeyboardLayoutNotification(InputDevice device)1270     private void showMissingKeyboardLayoutNotification(InputDevice device) {
1271         if (!mKeyboardLayoutNotificationShown) {
1272             final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
1273             if (device != null) {
1274                 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
1275             }
1276             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1277                     | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
1278                     | Intent.FLAG_ACTIVITY_CLEAR_TOP);
1279             final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
1280                     intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
1281 
1282             Resources r = mContext.getResources();
1283             Notification notification =
1284                     new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
1285                             .setContentTitle(r.getString(
1286                                     R.string.select_keyboard_layout_notification_title))
1287                             .setContentText(r.getString(
1288                                     R.string.select_keyboard_layout_notification_message))
1289                             .setContentIntent(keyboardLayoutIntent)
1290                             .setSmallIcon(R.drawable.ic_settings_language)
1291                             .setColor(mContext.getColor(
1292                                     com.android.internal.R.color.system_notification_accent_color))
1293                             .build();
1294             mNotificationManager.notifyAsUser(null,
1295                     SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
1296                     notification, UserHandle.ALL);
1297             mKeyboardLayoutNotificationShown = true;
1298         }
1299     }
1300 
1301     // Must be called on handler.
hideMissingKeyboardLayoutNotification()1302     private void hideMissingKeyboardLayoutNotification() {
1303         if (mKeyboardLayoutNotificationShown) {
1304             mKeyboardLayoutNotificationShown = false;
1305             mNotificationManager.cancelAsUser(null,
1306                     SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
1307                     UserHandle.ALL);
1308         }
1309     }
1310 
1311     // Must be called on handler.
updateKeyboardLayouts()1312     private void updateKeyboardLayouts() {
1313         // Scan all input devices state for keyboard layouts that have been uninstalled.
1314         final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
1315         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1316             @Override
1317             public void visitKeyboardLayout(Resources resources,
1318                     int keyboardLayoutResId, KeyboardLayout layout) {
1319                 availableKeyboardLayouts.add(layout.getDescriptor());
1320             }
1321         });
1322         synchronized (mDataStore) {
1323             try {
1324                 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
1325             } finally {
1326                 mDataStore.saveIfNeeded();
1327             }
1328         }
1329 
1330         // Reload keyboard layouts.
1331         reloadKeyboardLayouts();
1332     }
1333 
containsInputDeviceWithDescriptor(InputDevice[] inputDevices, String descriptor)1334     private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
1335             String descriptor) {
1336         final int numDevices = inputDevices.length;
1337         for (int i = 0; i < numDevices; i++) {
1338             final InputDevice inputDevice = inputDevices[i];
1339             if (inputDevice.getDescriptor().equals(descriptor)) {
1340                 return true;
1341             }
1342         }
1343         return false;
1344     }
1345 
1346     @Override // Binder call
getKeyboardLayouts()1347     public KeyboardLayout[] getKeyboardLayouts() {
1348         final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
1349         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1350             @Override
1351             public void visitKeyboardLayout(Resources resources,
1352                     int keyboardLayoutResId, KeyboardLayout layout) {
1353                 list.add(layout);
1354             }
1355         });
1356         return list.toArray(new KeyboardLayout[list.size()]);
1357     }
1358 
1359     @Override // Binder call
getKeyboardLayoutsForInputDevice( final InputDeviceIdentifier identifier)1360     public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1361             final InputDeviceIdentifier identifier) {
1362         final String[] enabledLayoutDescriptors =
1363             getEnabledKeyboardLayoutsForInputDevice(identifier);
1364         final ArrayList<KeyboardLayout> enabledLayouts =
1365             new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length);
1366         final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>();
1367         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1368             boolean mHasSeenDeviceSpecificLayout;
1369 
1370             @Override
1371             public void visitKeyboardLayout(Resources resources,
1372                     int keyboardLayoutResId, KeyboardLayout layout) {
1373                 // First check if it's enabled. If the keyboard layout is enabled then we always
1374                 // want to return it as a possible layout for the device.
1375                 for (String s : enabledLayoutDescriptors) {
1376                     if (s != null && s.equals(layout.getDescriptor())) {
1377                         enabledLayouts.add(layout);
1378                         return;
1379                     }
1380                 }
1381                 // Next find any potential layouts that aren't yet enabled for the device. For
1382                 // devices that have special layouts we assume there's a reason that the generic
1383                 // layouts don't work for them so we don't want to return them since it's likely
1384                 // to result in a poor user experience.
1385                 if (layout.getVendorId() == identifier.getVendorId()
1386                         && layout.getProductId() == identifier.getProductId()) {
1387                     if (!mHasSeenDeviceSpecificLayout) {
1388                         mHasSeenDeviceSpecificLayout = true;
1389                         potentialLayouts.clear();
1390                     }
1391                     potentialLayouts.add(layout);
1392                 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
1393                         && !mHasSeenDeviceSpecificLayout) {
1394                     potentialLayouts.add(layout);
1395                 }
1396             }
1397         });
1398         final int enabledLayoutSize = enabledLayouts.size();
1399         final int potentialLayoutSize = potentialLayouts.size();
1400         KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
1401         enabledLayouts.toArray(layouts);
1402         for (int i = 0; i < potentialLayoutSize; i++) {
1403             layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
1404         }
1405         return layouts;
1406     }
1407 
1408     @Override // Binder call
getKeyboardLayout(String keyboardLayoutDescriptor)1409     public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
1410         if (keyboardLayoutDescriptor == null) {
1411             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1412         }
1413 
1414         final KeyboardLayout[] result = new KeyboardLayout[1];
1415         visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1416             @Override
1417             public void visitKeyboardLayout(Resources resources,
1418                     int keyboardLayoutResId, KeyboardLayout layout) {
1419                 result[0] = layout;
1420             }
1421         });
1422         if (result[0] == null) {
1423             Slog.w(TAG, "Could not get keyboard layout with descriptor '"
1424                     + keyboardLayoutDescriptor + "'.");
1425         }
1426         return result[0];
1427     }
1428 
visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor)1429     private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
1430         final PackageManager pm = mContext.getPackageManager();
1431         Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
1432         for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
1433                 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
1434                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
1435             final ActivityInfo activityInfo = resolveInfo.activityInfo;
1436             final int priority = resolveInfo.priority;
1437             visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
1438         }
1439     }
1440 
visitKeyboardLayout(String keyboardLayoutDescriptor, KeyboardLayoutVisitor visitor)1441     private void visitKeyboardLayout(String keyboardLayoutDescriptor,
1442             KeyboardLayoutVisitor visitor) {
1443         KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
1444         if (d != null) {
1445             final PackageManager pm = mContext.getPackageManager();
1446             try {
1447                 ActivityInfo receiver = pm.getReceiverInfo(
1448                         new ComponentName(d.packageName, d.receiverName),
1449                         PackageManager.GET_META_DATA
1450                                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1451                                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
1452                 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
1453             } catch (NameNotFoundException ex) {
1454             }
1455         }
1456     }
1457 
visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor)1458     private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
1459             String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
1460         Bundle metaData = receiver.metaData;
1461         if (metaData == null) {
1462             return;
1463         }
1464 
1465         int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1466         if (configResId == 0) {
1467             Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
1468                     + "' on receiver " + receiver.packageName + "/" + receiver.name);
1469             return;
1470         }
1471 
1472         CharSequence receiverLabel = receiver.loadLabel(pm);
1473         String collection = receiverLabel != null ? receiverLabel.toString() : "";
1474         int priority;
1475         if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1476             priority = requestedPriority;
1477         } else {
1478             priority = 0;
1479         }
1480 
1481         try {
1482             Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1483             XmlResourceParser parser = resources.getXml(configResId);
1484             try {
1485                 XmlUtils.beginDocument(parser, "keyboard-layouts");
1486 
1487                 for (;;) {
1488                     XmlUtils.nextElement(parser);
1489                     String element = parser.getName();
1490                     if (element == null) {
1491                         break;
1492                     }
1493                     if (element.equals("keyboard-layout")) {
1494                         TypedArray a = resources.obtainAttributes(
1495                                 parser, com.android.internal.R.styleable.KeyboardLayout);
1496                         try {
1497                             String name = a.getString(
1498                                     com.android.internal.R.styleable.KeyboardLayout_name);
1499                             String label = a.getString(
1500                                     com.android.internal.R.styleable.KeyboardLayout_label);
1501                             int keyboardLayoutResId = a.getResourceId(
1502                                     com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1503                                     0);
1504                             String languageTags = a.getString(
1505                                     com.android.internal.R.styleable.KeyboardLayout_locale);
1506                             LocaleList locales = getLocalesFromLanguageTags(languageTags);
1507                             int vid = a.getInt(
1508                                     com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
1509                             int pid = a.getInt(
1510                                     com.android.internal.R.styleable.KeyboardLayout_productId, -1);
1511 
1512                             if (name == null || label == null || keyboardLayoutResId == 0) {
1513                                 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
1514                                         + "attributes in keyboard layout "
1515                                         + "resource from receiver "
1516                                         + receiver.packageName + "/" + receiver.name);
1517                             } else {
1518                                 String descriptor = KeyboardLayoutDescriptor.format(
1519                                         receiver.packageName, receiver.name, name);
1520                                 if (keyboardName == null || name.equals(keyboardName)) {
1521                                     KeyboardLayout layout = new KeyboardLayout(
1522                                             descriptor, label, collection, priority,
1523                                             locales, vid, pid);
1524                                     visitor.visitKeyboardLayout(
1525                                             resources, keyboardLayoutResId, layout);
1526                                 }
1527                             }
1528                         } finally {
1529                             a.recycle();
1530                         }
1531                     } else {
1532                         Slog.w(TAG, "Skipping unrecognized element '" + element
1533                                 + "' in keyboard layout resource from receiver "
1534                                 + receiver.packageName + "/" + receiver.name);
1535                     }
1536                 }
1537             } finally {
1538                 parser.close();
1539             }
1540         } catch (Exception ex) {
1541             Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
1542                     + receiver.packageName + "/" + receiver.name, ex);
1543         }
1544     }
1545 
1546     @NonNull
getLocalesFromLanguageTags(String languageTags)1547     private static LocaleList getLocalesFromLanguageTags(String languageTags) {
1548         if (TextUtils.isEmpty(languageTags)) {
1549             return LocaleList.getEmptyLocaleList();
1550         }
1551         return LocaleList.forLanguageTags(languageTags.replace('|', ','));
1552     }
1553 
1554     /**
1555      * Builds a layout descriptor for the vendor/product. This returns the
1556      * descriptor for ids that aren't useful (such as the default 0, 0).
1557      */
getLayoutDescriptor(InputDeviceIdentifier identifier)1558     private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1559         if (identifier == null || identifier.getDescriptor() == null) {
1560             throw new IllegalArgumentException("identifier and descriptor must not be null");
1561         }
1562 
1563         if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1564             return identifier.getDescriptor();
1565         }
1566         StringBuilder bob = new StringBuilder();
1567         bob.append("vendor:").append(identifier.getVendorId());
1568         bob.append(",product:").append(identifier.getProductId());
1569         return bob.toString();
1570     }
1571 
1572     @Override // Binder call
getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier)1573     public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1574 
1575         String key = getLayoutDescriptor(identifier);
1576         synchronized (mDataStore) {
1577             String layout = null;
1578             // try loading it using the layout descriptor if we have it
1579             layout = mDataStore.getCurrentKeyboardLayout(key);
1580             if (layout == null && !key.equals(identifier.getDescriptor())) {
1581                 // if it doesn't exist fall back to the device descriptor
1582                 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1583             }
1584             if (DEBUG) {
1585                 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1586                         + layout);
1587             }
1588             return layout;
1589         }
1590     }
1591 
1592     @Override // Binder call
setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1593     public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1594             String keyboardLayoutDescriptor) {
1595         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1596                 "setCurrentKeyboardLayoutForInputDevice()")) {
1597             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1598         }
1599         if (keyboardLayoutDescriptor == null) {
1600             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1601         }
1602 
1603         String key = getLayoutDescriptor(identifier);
1604         synchronized (mDataStore) {
1605             try {
1606                 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1607                     if (DEBUG) {
1608                         Slog.d(TAG, "Saved keyboard layout using " + key);
1609                     }
1610                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1611                 }
1612             } finally {
1613                 mDataStore.saveIfNeeded();
1614             }
1615         }
1616     }
1617 
1618     @Override // Binder call
getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier)1619     public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
1620         String key = getLayoutDescriptor(identifier);
1621         synchronized (mDataStore) {
1622             String[] layouts = mDataStore.getKeyboardLayouts(key);
1623             if ((layouts == null || layouts.length == 0)
1624                     && !key.equals(identifier.getDescriptor())) {
1625                 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1626             }
1627             return layouts;
1628         }
1629     }
1630 
1631     @Override // Binder call
addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1632     public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1633             String keyboardLayoutDescriptor) {
1634         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1635                 "addKeyboardLayoutForInputDevice()")) {
1636             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1637         }
1638         if (keyboardLayoutDescriptor == null) {
1639             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1640         }
1641 
1642         String key = getLayoutDescriptor(identifier);
1643         synchronized (mDataStore) {
1644             try {
1645                 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1646                 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1647                     oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1648                 }
1649                 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
1650                         && !Objects.equals(oldLayout,
1651                                 mDataStore.getCurrentKeyboardLayout(key))) {
1652                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1653                 }
1654             } finally {
1655                 mDataStore.saveIfNeeded();
1656             }
1657         }
1658     }
1659 
1660     @Override // Binder call
removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1661     public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1662             String keyboardLayoutDescriptor) {
1663         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1664                 "removeKeyboardLayoutForInputDevice()")) {
1665             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1666         }
1667         if (keyboardLayoutDescriptor == null) {
1668             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1669         }
1670 
1671         String key = getLayoutDescriptor(identifier);
1672         synchronized (mDataStore) {
1673             try {
1674                 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1675                 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1676                     oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1677                 }
1678                 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1679                 if (!key.equals(identifier.getDescriptor())) {
1680                     // We need to remove from both places to ensure it is gone
1681                     removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1682                             keyboardLayoutDescriptor);
1683                 }
1684                 if (removed && !Objects.equals(oldLayout,
1685                                 mDataStore.getCurrentKeyboardLayout(key))) {
1686                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1687                 }
1688             } finally {
1689                 mDataStore.saveIfNeeded();
1690             }
1691         }
1692     }
1693 
switchKeyboardLayout(int deviceId, int direction)1694     public void switchKeyboardLayout(int deviceId, int direction) {
1695         mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
1696     }
1697 
1698     // Must be called on handler.
handleSwitchKeyboardLayout(int deviceId, int direction)1699     private void handleSwitchKeyboardLayout(int deviceId, int direction) {
1700         final InputDevice device = getInputDevice(deviceId);
1701         if (device != null) {
1702             final boolean changed;
1703             final String keyboardLayoutDescriptor;
1704 
1705             String key = getLayoutDescriptor(device.getIdentifier());
1706             synchronized (mDataStore) {
1707                 try {
1708                     changed = mDataStore.switchKeyboardLayout(key, direction);
1709                     keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
1710                             key);
1711                 } finally {
1712                     mDataStore.saveIfNeeded();
1713                 }
1714             }
1715 
1716             if (changed) {
1717                 if (mSwitchedKeyboardLayoutToast != null) {
1718                     mSwitchedKeyboardLayoutToast.cancel();
1719                     mSwitchedKeyboardLayoutToast = null;
1720                 }
1721                 if (keyboardLayoutDescriptor != null) {
1722                     KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
1723                     if (keyboardLayout != null) {
1724                         mSwitchedKeyboardLayoutToast = Toast.makeText(
1725                                 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
1726                         mSwitchedKeyboardLayoutToast.show();
1727                     }
1728                 }
1729 
1730                 reloadKeyboardLayouts();
1731             }
1732         }
1733     }
1734 
setFocusedApplication(int displayId, InputApplicationHandle application)1735     public void setFocusedApplication(int displayId, InputApplicationHandle application) {
1736         nativeSetFocusedApplication(mPtr, displayId, application);
1737     }
1738 
setFocusedDisplay(int displayId)1739     public void setFocusedDisplay(int displayId) {
1740         nativeSetFocusedDisplay(mPtr, displayId);
1741     }
1742 
1743     /** Clean up input window handles of the given display. */
onDisplayRemoved(int displayId)1744     public void onDisplayRemoved(int displayId) {
1745         nativeDisplayRemoved(mPtr, displayId);
1746     }
1747 
1748     @Override
requestPointerCapture(IBinder inputChannelToken, boolean enabled)1749     public void requestPointerCapture(IBinder inputChannelToken, boolean enabled) {
1750         if (inputChannelToken == null) {
1751             return;
1752         }
1753 
1754         nativeRequestPointerCapture(mPtr, inputChannelToken, enabled);
1755     }
1756 
setInputDispatchMode(boolean enabled, boolean frozen)1757     public void setInputDispatchMode(boolean enabled, boolean frozen) {
1758         nativeSetInputDispatchMode(mPtr, enabled, frozen);
1759     }
1760 
setSystemUiLightsOut(boolean lightsOut)1761     public void setSystemUiLightsOut(boolean lightsOut) {
1762         nativeSetSystemUiLightsOut(mPtr, lightsOut);
1763     }
1764 
1765     /**
1766      * Atomically transfers touch focus from one window to another as identified by
1767      * their input channels.  It is possible for multiple windows to have
1768      * touch focus if they support split touch dispatch
1769      * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1770      * method only transfers touch focus of the specified window without affecting
1771      * other windows that may also have touch focus at the same time.
1772      * @param fromChannel The channel of a window that currently has touch focus.
1773      * @param toChannel The channel of the window that should receive touch focus in
1774      * place of the first.
1775      * @param isDragDrop True if transfer touch focus for drag and drop.
1776      * @return True if the transfer was successful.  False if the window with the
1777      * specified channel did not actually have touch focus at the time of the request.
1778      */
transferTouchFocus(@onNull InputChannel fromChannel, @NonNull InputChannel toChannel, boolean isDragDrop)1779     public boolean transferTouchFocus(@NonNull InputChannel fromChannel,
1780             @NonNull InputChannel toChannel, boolean isDragDrop) {
1781         return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken(),
1782                 isDragDrop);
1783     }
1784 
1785     /**
1786      * Atomically transfers touch focus from one window to another as identified by
1787      * their input channels.  It is possible for multiple windows to have
1788      * touch focus if they support split touch dispatch
1789      * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1790      * method only transfers touch focus of the specified window without affecting
1791      * other windows that may also have touch focus at the same time.
1792      * @param fromChannelToken The channel token of a window that currently has touch focus.
1793      * @param toChannelToken The channel token of the window that should receive touch focus in
1794      * place of the first.
1795      * @return True if the transfer was successful.  False if the window with the
1796      * specified channel did not actually have touch focus at the time of the request.
1797      */
transferTouchFocus(@onNull IBinder fromChannelToken, @NonNull IBinder toChannelToken)1798     public boolean transferTouchFocus(@NonNull IBinder fromChannelToken,
1799             @NonNull IBinder toChannelToken) {
1800         Objects.nonNull(fromChannelToken);
1801         Objects.nonNull(toChannelToken);
1802         return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken,
1803                 false /* isDragDrop */);
1804     }
1805 
1806     @Override // Binder call
tryPointerSpeed(int speed)1807     public void tryPointerSpeed(int speed) {
1808         if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1809                 "tryPointerSpeed()")) {
1810             throw new SecurityException("Requires SET_POINTER_SPEED permission");
1811         }
1812 
1813         if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1814             throw new IllegalArgumentException("speed out of range");
1815         }
1816 
1817         setPointerSpeedUnchecked(speed);
1818     }
1819 
updatePointerSpeedFromSettings()1820     private void updatePointerSpeedFromSettings() {
1821         int speed = getPointerSpeedSetting();
1822         setPointerSpeedUnchecked(speed);
1823     }
1824 
setPointerSpeedUnchecked(int speed)1825     private void setPointerSpeedUnchecked(int speed) {
1826         speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1827                 InputManager.MAX_POINTER_SPEED);
1828         nativeSetPointerSpeed(mPtr, speed);
1829     }
1830 
registerPointerSpeedSettingObserver()1831     private void registerPointerSpeedSettingObserver() {
1832         mContext.getContentResolver().registerContentObserver(
1833                 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
1834                 new ContentObserver(mHandler) {
1835                     @Override
1836                     public void onChange(boolean selfChange) {
1837                         updatePointerSpeedFromSettings();
1838                     }
1839                 }, UserHandle.USER_ALL);
1840     }
1841 
getPointerSpeedSetting()1842     private int getPointerSpeedSetting() {
1843         int speed = InputManager.DEFAULT_POINTER_SPEED;
1844         try {
1845             speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1846                     Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
1847         } catch (SettingNotFoundException snfe) {
1848         }
1849         return speed;
1850     }
1851 
updateShowTouchesFromSettings()1852     private void updateShowTouchesFromSettings() {
1853         int setting = getShowTouchesSetting(0);
1854         nativeSetShowTouches(mPtr, setting != 0);
1855     }
1856 
registerShowTouchesSettingObserver()1857     private void registerShowTouchesSettingObserver() {
1858         mContext.getContentResolver().registerContentObserver(
1859                 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
1860                 new ContentObserver(mHandler) {
1861                     @Override
1862                     public void onChange(boolean selfChange) {
1863                         updateShowTouchesFromSettings();
1864                     }
1865                 }, UserHandle.USER_ALL);
1866     }
1867 
updateAccessibilityLargePointerFromSettings()1868     private void updateAccessibilityLargePointerFromSettings() {
1869         final int accessibilityConfig = Settings.Secure.getIntForUser(
1870                 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1871                 0, UserHandle.USER_CURRENT);
1872         PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
1873         nativeReloadPointerIcons(mPtr);
1874     }
1875 
registerAccessibilityLargePointerSettingObserver()1876     private void registerAccessibilityLargePointerSettingObserver() {
1877         mContext.getContentResolver().registerContentObserver(
1878                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1879                 new ContentObserver(mHandler) {
1880                     @Override
1881                     public void onChange(boolean selfChange) {
1882                         updateAccessibilityLargePointerFromSettings();
1883                     }
1884                 }, UserHandle.USER_ALL);
1885     }
1886 
updateDeepPressStatusFromSettings(String reason)1887     private void updateDeepPressStatusFromSettings(String reason) {
1888         // Not using ViewConfiguration.getLongPressTimeout here because it may return a stale value
1889         final int timeout = Settings.Secure.getIntForUser(mContext.getContentResolver(),
1890                 Settings.Secure.LONG_PRESS_TIMEOUT, ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT,
1891                 UserHandle.USER_CURRENT);
1892         final boolean featureEnabledFlag =
1893                 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
1894                         DEEP_PRESS_ENABLED, true /* default */);
1895         final boolean enabled =
1896                 featureEnabledFlag && timeout <= ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT;
1897         Log.i(TAG,
1898                 (enabled ? "Enabling" : "Disabling") + " motion classifier because " + reason
1899                 + ": feature " + (featureEnabledFlag ? "enabled" : "disabled")
1900                 + ", long press timeout = " + timeout);
1901         nativeSetMotionClassifierEnabled(mPtr, enabled);
1902     }
1903 
registerLongPressTimeoutObserver()1904     private void registerLongPressTimeoutObserver() {
1905         mContext.getContentResolver().registerContentObserver(
1906                 Settings.Secure.getUriFor(Settings.Secure.LONG_PRESS_TIMEOUT), true,
1907                 new ContentObserver(mHandler) {
1908                     @Override
1909                     public void onChange(boolean selfChange) {
1910                         updateDeepPressStatusFromSettings("timeout changed");
1911                     }
1912                 }, UserHandle.USER_ALL);
1913     }
1914 
registerBlockUntrustedTouchesModeSettingObserver()1915     private void registerBlockUntrustedTouchesModeSettingObserver() {
1916         mContext.getContentResolver().registerContentObserver(
1917                 Settings.Global.getUriFor(Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE),
1918                 /* notifyForDescendants */ true,
1919                 new ContentObserver(mHandler) {
1920                     @Override
1921                     public void onChange(boolean selfChange) {
1922                         updateBlockUntrustedTouchesModeFromSettings();
1923                     }
1924                 }, UserHandle.USER_ALL);
1925     }
1926 
updateBlockUntrustedTouchesModeFromSettings()1927     private void updateBlockUntrustedTouchesModeFromSettings() {
1928         final int mode = InputManager.getInstance().getBlockUntrustedTouchesMode(mContext);
1929         nativeSetBlockUntrustedTouchesMode(mPtr, mode);
1930     }
1931 
registerMaximumObscuringOpacityForTouchSettingObserver()1932     private void registerMaximumObscuringOpacityForTouchSettingObserver() {
1933         mContext.getContentResolver().registerContentObserver(
1934                 Settings.Global.getUriFor(Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH),
1935                 /* notifyForDescendants */ true,
1936                 new ContentObserver(mHandler) {
1937                     @Override
1938                     public void onChange(boolean selfChange) {
1939                         updateMaximumObscuringOpacityForTouchFromSettings();
1940                     }
1941                 }, UserHandle.USER_ALL);
1942     }
1943 
updateMaximumObscuringOpacityForTouchFromSettings()1944     private void updateMaximumObscuringOpacityForTouchFromSettings() {
1945         final float opacity = InputManager.getInstance().getMaximumObscuringOpacityForTouch();
1946         if (opacity < 0 || opacity > 1) {
1947             Log.e(TAG, "Invalid maximum obscuring opacity " + opacity
1948                     + ", it should be >= 0 and <= 1, rejecting update.");
1949             return;
1950         }
1951         nativeSetMaximumObscuringOpacityForTouch(mPtr, opacity);
1952     }
1953 
getShowTouchesSetting(int defaultValue)1954     private int getShowTouchesSetting(int defaultValue) {
1955         int result = defaultValue;
1956         try {
1957             result = Settings.System.getIntForUser(mContext.getContentResolver(),
1958                     Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
1959         } catch (SettingNotFoundException snfe) {
1960         }
1961         return result;
1962     }
1963 
1964     private static class VibrationInfo {
1965         private final long[] mPattern;
1966         private final int[] mAmplitudes;
1967         private final int mRepeat;
1968 
getPattern()1969         public long[] getPattern() {
1970             return mPattern;
1971         }
1972 
getAmplitudes()1973         public int[] getAmplitudes() {
1974             return mAmplitudes;
1975         }
1976 
getRepeatIndex()1977         public int getRepeatIndex() {
1978             return mRepeat;
1979         }
1980 
VibrationInfo(VibrationEffect effect)1981         VibrationInfo(VibrationEffect effect) {
1982             long[] pattern = null;
1983             int[] amplitudes = null;
1984             int patternRepeatIndex = -1;
1985             int amplitudeCount = -1;
1986 
1987             if (effect instanceof VibrationEffect.Composed) {
1988                 VibrationEffect.Composed composed = (VibrationEffect.Composed) effect;
1989                 int segmentCount = composed.getSegments().size();
1990                 pattern = new long[segmentCount];
1991                 amplitudes = new int[segmentCount];
1992                 patternRepeatIndex = composed.getRepeatIndex();
1993                 amplitudeCount = 0;
1994                 for (int i = 0; i < segmentCount; i++) {
1995                     VibrationEffectSegment segment = composed.getSegments().get(i);
1996                     if (composed.getRepeatIndex() == i) {
1997                         patternRepeatIndex = amplitudeCount;
1998                     }
1999                     if (!(segment instanceof StepSegment)) {
2000                         Slog.w(TAG, "Input devices don't support segment " + segment);
2001                         amplitudeCount = -1;
2002                         break;
2003                     }
2004                     float amplitude = ((StepSegment) segment).getAmplitude();
2005                     if (Float.compare(amplitude, VibrationEffect.DEFAULT_AMPLITUDE) == 0) {
2006                         amplitudes[amplitudeCount] = DEFAULT_VIBRATION_MAGNITUDE;
2007                     } else {
2008                         amplitudes[amplitudeCount] =
2009                                 (int) (amplitude * VibrationEffect.MAX_AMPLITUDE);
2010                     }
2011                     pattern[amplitudeCount++] = segment.getDuration();
2012                 }
2013             }
2014 
2015             if (amplitudeCount < 0) {
2016                 Slog.w(TAG, "Only oneshot and step waveforms are supported on input devices");
2017                 mPattern = new long[0];
2018                 mAmplitudes = new int[0];
2019                 mRepeat = -1;
2020             } else {
2021                 mRepeat = patternRepeatIndex;
2022                 mPattern = new long[amplitudeCount];
2023                 mAmplitudes = new int[amplitudeCount];
2024                 System.arraycopy(pattern, 0, mPattern, 0, amplitudeCount);
2025                 System.arraycopy(amplitudes, 0, mAmplitudes, 0, amplitudeCount);
2026                 if (mRepeat >= mPattern.length) {
2027                     throw new ArrayIndexOutOfBoundsException("Repeat index " + mRepeat
2028                             + " must be within the bounds of the pattern.length "
2029                             + mPattern.length);
2030                 }
2031             }
2032         }
2033     }
2034 
getVibratorToken(int deviceId, IBinder token)2035     private VibratorToken getVibratorToken(int deviceId, IBinder token) {
2036         VibratorToken v;
2037         synchronized (mVibratorLock) {
2038             v = mVibratorTokens.get(token);
2039             if (v == null) {
2040                 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
2041                 try {
2042                     token.linkToDeath(v, 0);
2043                 } catch (RemoteException ex) {
2044                     // give up
2045                     throw new RuntimeException(ex);
2046                 }
2047                 mVibratorTokens.put(token, v);
2048             }
2049         }
2050         return v;
2051     }
2052 
2053     // Binder call
2054     @Override
vibrate(int deviceId, VibrationEffect effect, IBinder token)2055     public void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
2056         VibrationInfo info = new VibrationInfo(effect);
2057         VibratorToken v = getVibratorToken(deviceId, token);
2058         synchronized (v) {
2059             v.mVibrating = true;
2060             nativeVibrate(mPtr, deviceId, info.getPattern(), info.getAmplitudes(),
2061                     info.getRepeatIndex(), v.mTokenValue);
2062         }
2063     }
2064 
2065     // Binder call
2066     @Override
getVibratorIds(int deviceId)2067     public int[] getVibratorIds(int deviceId) {
2068         return nativeGetVibratorIds(mPtr, deviceId);
2069     }
2070 
2071     // Binder call
2072     @Override
isVibrating(int deviceId)2073     public boolean isVibrating(int deviceId) {
2074         return nativeIsVibrating(mPtr, deviceId);
2075     }
2076 
2077     // Binder call
2078     @Override
vibrateCombined(int deviceId, CombinedVibration effect, IBinder token)2079     public void vibrateCombined(int deviceId, CombinedVibration effect, IBinder token) {
2080         VibratorToken v = getVibratorToken(deviceId, token);
2081         synchronized (v) {
2082             if (!(effect instanceof CombinedVibration.Mono)
2083                     && !(effect instanceof CombinedVibration.Stereo)) {
2084                 Slog.e(TAG, "Only Mono and Stereo effects are supported");
2085                 return;
2086             }
2087 
2088             v.mVibrating = true;
2089             if (effect instanceof CombinedVibration.Mono) {
2090                 CombinedVibration.Mono mono = (CombinedVibration.Mono) effect;
2091                 VibrationInfo info = new VibrationInfo(mono.getEffect());
2092                 nativeVibrate(mPtr, deviceId, info.getPattern(), info.getAmplitudes(),
2093                         info.getRepeatIndex(), v.mTokenValue);
2094             } else if (effect instanceof CombinedVibration.Stereo) {
2095                 CombinedVibration.Stereo stereo = (CombinedVibration.Stereo) effect;
2096                 SparseArray<VibrationEffect> effects = stereo.getEffects();
2097                 long[] pattern = new long[0];
2098                 int repeat = Integer.MIN_VALUE;
2099                 SparseArray<int[]> amplitudes = new SparseArray<int[]>(effects.size());
2100                 for (int i = 0; i < effects.size(); i++) {
2101                     VibrationInfo info = new VibrationInfo(effects.valueAt(i));
2102                     // Pattern of all effects should be same
2103                     if (pattern.length == 0) {
2104                         pattern = info.getPattern();
2105                     }
2106                     if (repeat == Integer.MIN_VALUE) {
2107                         repeat = info.getRepeatIndex();
2108                     }
2109                     amplitudes.put(effects.keyAt(i), info.getAmplitudes());
2110                 }
2111                 nativeVibrateCombined(mPtr, deviceId, pattern, amplitudes, repeat,
2112                         v.mTokenValue);
2113             }
2114         }
2115     }
2116 
2117     // Binder call
2118     @Override
cancelVibrate(int deviceId, IBinder token)2119     public void cancelVibrate(int deviceId, IBinder token) {
2120         VibratorToken v;
2121         synchronized (mVibratorLock) {
2122             v = mVibratorTokens.get(token);
2123             if (v == null || v.mDeviceId != deviceId) {
2124                 return; // nothing to cancel
2125             }
2126         }
2127 
2128         cancelVibrateIfNeeded(v);
2129     }
2130 
onVibratorTokenDied(VibratorToken v)2131     void onVibratorTokenDied(VibratorToken v) {
2132         synchronized (mVibratorLock) {
2133             mVibratorTokens.remove(v.mToken);
2134         }
2135 
2136         cancelVibrateIfNeeded(v);
2137     }
2138 
cancelVibrateIfNeeded(VibratorToken v)2139     private void cancelVibrateIfNeeded(VibratorToken v) {
2140         synchronized (v) {
2141             if (v.mVibrating) {
2142                 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
2143                 v.mVibrating = false;
2144             }
2145         }
2146     }
2147 
2148     // Native callback.
notifyVibratorState(int deviceId, boolean isOn)2149     private void notifyVibratorState(int deviceId, boolean isOn) {
2150         if (DEBUG) {
2151             Slog.d(TAG, "notifyVibratorState: deviceId=" + deviceId + " isOn=" + isOn);
2152         }
2153         synchronized (mVibratorLock) {
2154             mIsVibrating.put(deviceId, isOn);
2155             notifyVibratorStateListenersLocked(deviceId);
2156         }
2157     }
2158 
2159     @GuardedBy("mVibratorLock")
notifyVibratorStateListenersLocked(int deviceId)2160     private void notifyVibratorStateListenersLocked(int deviceId) {
2161         if (!mVibratorStateListeners.contains(deviceId)) {
2162             if (DEBUG) {
2163                 Slog.v(TAG, "Device " + deviceId + " doesn't have vibrator state listener.");
2164             }
2165             return;
2166         }
2167         RemoteCallbackList<IVibratorStateListener> listeners =
2168                 mVibratorStateListeners.get(deviceId);
2169         final int length = listeners.beginBroadcast();
2170         try {
2171             for (int i = 0; i < length; i++) {
2172                 notifyVibratorStateListenerLocked(deviceId, listeners.getBroadcastItem(i));
2173             }
2174         } finally {
2175             listeners.finishBroadcast();
2176         }
2177     }
2178 
2179     @GuardedBy("mVibratorLock")
notifyVibratorStateListenerLocked(int deviceId, IVibratorStateListener listener)2180     private void notifyVibratorStateListenerLocked(int deviceId, IVibratorStateListener listener) {
2181         try {
2182             listener.onVibrating(mIsVibrating.get(deviceId));
2183         } catch (RemoteException | RuntimeException e) {
2184             Slog.e(TAG, "Vibrator state listener failed to call", e);
2185         }
2186     }
2187 
2188     @Override // Binder call
registerVibratorStateListener(int deviceId, IVibratorStateListener listener)2189     public boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
2190         Preconditions.checkNotNull(listener, "listener must not be null");
2191 
2192         RemoteCallbackList<IVibratorStateListener> listeners;
2193         synchronized (mVibratorLock) {
2194             if (!mVibratorStateListeners.contains(deviceId)) {
2195                 listeners = new RemoteCallbackList<>();
2196                 mVibratorStateListeners.put(deviceId, listeners);
2197             } else {
2198                 listeners = mVibratorStateListeners.get(deviceId);
2199             }
2200 
2201             final long token = Binder.clearCallingIdentity();
2202             try {
2203                 if (!listeners.register(listener)) {
2204                     Slog.e(TAG, "Could not register vibrator state listener " + listener);
2205                     return false;
2206                 }
2207                 // Notify its callback after new client registered.
2208                 notifyVibratorStateListenerLocked(deviceId, listener);
2209                 return true;
2210             } finally {
2211                 Binder.restoreCallingIdentity(token);
2212             }
2213         }
2214     }
2215 
2216     @Override // Binder call
unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener)2217     public boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
2218         synchronized (mVibratorLock) {
2219             final long token = Binder.clearCallingIdentity();
2220             try {
2221                 if (!mVibratorStateListeners.contains(deviceId)) {
2222                     Slog.w(TAG, "Vibrator state listener " + deviceId + " doesn't exist");
2223                     return false;
2224                 }
2225                 RemoteCallbackList<IVibratorStateListener> listeners =
2226                         mVibratorStateListeners.get(deviceId);
2227                 return listeners.unregister(listener);
2228             } finally {
2229                 Binder.restoreCallingIdentity(token);
2230             }
2231         }
2232     }
2233 
2234     // Binder call
2235     @Override
getBatteryStatus(int deviceId)2236     public int getBatteryStatus(int deviceId) {
2237         return nativeGetBatteryStatus(mPtr, deviceId);
2238     }
2239 
2240     // Binder call
2241     @Override
getBatteryCapacity(int deviceId)2242     public int getBatteryCapacity(int deviceId) {
2243         return nativeGetBatteryCapacity(mPtr, deviceId);
2244     }
2245 
2246     // Binder call
2247     @Override
setPointerIconType(int iconId)2248     public void setPointerIconType(int iconId) {
2249         nativeSetPointerIconType(mPtr, iconId);
2250     }
2251 
2252     // Binder call
2253     @Override
setCustomPointerIcon(PointerIcon icon)2254     public void setCustomPointerIcon(PointerIcon icon) {
2255         Objects.requireNonNull(icon);
2256         nativeSetCustomPointerIcon(mPtr, icon);
2257     }
2258 
2259     /**
2260      * Add a runtime association between the input port and the display port. This overrides any
2261      * static associations.
2262      * @param inputPort The port of the input device.
2263      * @param displayPort The physical port of the associated display.
2264      */
2265     @Override // Binder call
addPortAssociation(@onNull String inputPort, int displayPort)2266     public void addPortAssociation(@NonNull String inputPort, int displayPort) {
2267         if (!checkCallingPermission(
2268                 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
2269                 "addPortAssociation()")) {
2270             throw new SecurityException(
2271                     "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
2272         }
2273 
2274         Objects.requireNonNull(inputPort);
2275         synchronized (mAssociationsLock) {
2276             mRuntimeAssociations.put(inputPort, displayPort);
2277         }
2278         nativeNotifyPortAssociationsChanged(mPtr);
2279     }
2280 
2281     /**
2282      * Remove the runtime association between the input port and the display port. Any existing
2283      * static association for the cleared input port will be restored.
2284      * @param inputPort The port of the input device to be cleared.
2285      */
2286     @Override // Binder call
removePortAssociation(@onNull String inputPort)2287     public void removePortAssociation(@NonNull String inputPort) {
2288         if (!checkCallingPermission(
2289                 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
2290                 "clearPortAssociations()")) {
2291             throw new SecurityException(
2292                     "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
2293         }
2294 
2295         Objects.requireNonNull(inputPort);
2296         synchronized (mAssociationsLock) {
2297             mRuntimeAssociations.remove(inputPort);
2298         }
2299         nativeNotifyPortAssociationsChanged(mPtr);
2300     }
2301 
2302     /**
2303      * Add a runtime association between the input device name and the display unique id.
2304      * @param inputDeviceName The name of the input device.
2305      * @param displayUniqueId The unique id of the associated display.
2306      */
2307     @Override // Binder call
addUniqueIdAssociation(@onNull String inputDeviceName, @NonNull String displayUniqueId)2308     public void addUniqueIdAssociation(@NonNull String inputDeviceName,
2309             @NonNull String displayUniqueId) {
2310         if (!checkCallingPermission(
2311                 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
2312                 "addNameAssociation()")) {
2313             throw new SecurityException(
2314                     "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
2315         }
2316 
2317         Objects.requireNonNull(inputDeviceName);
2318         Objects.requireNonNull(displayUniqueId);
2319         synchronized (mAssociationsLock) {
2320             mUniqueIdAssociations.put(inputDeviceName, displayUniqueId);
2321         }
2322         nativeChangeUniqueIdAssociation(mPtr);
2323     }
2324 
2325     /**
2326      * Remove the runtime association between the input device and the display.
2327      * @param inputDeviceName The port of the input device to be cleared.
2328      */
2329     @Override // Binder call
removeUniqueIdAssociation(@onNull String inputDeviceName)2330     public void removeUniqueIdAssociation(@NonNull String inputDeviceName) {
2331         if (!checkCallingPermission(
2332                 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
2333                 "removeUniqueIdAssociation()")) {
2334             throw new SecurityException(
2335                     "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
2336         }
2337 
2338         Objects.requireNonNull(inputDeviceName);
2339         synchronized (mAssociationsLock) {
2340             mUniqueIdAssociations.remove(inputDeviceName);
2341         }
2342         nativeChangeUniqueIdAssociation(mPtr);
2343     }
2344 
2345     @Override // Binder call
getSensorList(int deviceId)2346     public InputSensorInfo[] getSensorList(int deviceId) {
2347         return nativeGetSensorList(mPtr, deviceId);
2348     }
2349 
2350     @Override // Binder call
registerSensorListener(IInputSensorEventListener listener)2351     public boolean registerSensorListener(IInputSensorEventListener listener) {
2352         if (DEBUG) {
2353             Slog.d(TAG, "registerSensorListener: listener=" + listener + " callingPid="
2354                     + Binder.getCallingPid());
2355         }
2356         if (listener == null) {
2357             Slog.e(TAG, "listener must not be null");
2358             return false;
2359         }
2360 
2361         synchronized (mInputDevicesLock) {
2362             int callingPid = Binder.getCallingPid();
2363             if (mSensorEventListeners.get(callingPid) != null) {
2364                 Slog.e(TAG, "The calling process " + callingPid + " has already "
2365                         + "registered an InputSensorEventListener.");
2366                 return false;
2367             }
2368 
2369             SensorEventListenerRecord record =
2370                     new SensorEventListenerRecord(callingPid, listener);
2371             try {
2372                 IBinder binder = listener.asBinder();
2373                 binder.linkToDeath(record, 0);
2374             } catch (RemoteException ex) {
2375                 // give up
2376                 throw new RuntimeException(ex);
2377             }
2378 
2379             mSensorEventListeners.put(callingPid, record);
2380         }
2381         return true;
2382     }
2383 
2384     @Override // Binder call
unregisterSensorListener(IInputSensorEventListener listener)2385     public void unregisterSensorListener(IInputSensorEventListener listener) {
2386         if (DEBUG) {
2387             Slog.d(TAG, "unregisterSensorListener: listener=" + listener + " callingPid="
2388                     + Binder.getCallingPid());
2389         }
2390 
2391         if (listener == null) {
2392             throw new IllegalArgumentException("listener must not be null");
2393         }
2394 
2395         synchronized (mInputDevicesLock) {
2396             int callingPid = Binder.getCallingPid();
2397             if (mSensorEventListeners.get(callingPid) != null) {
2398                 SensorEventListenerRecord record = mSensorEventListeners.get(callingPid);
2399                 if (record.getListener().asBinder() != listener.asBinder()) {
2400                     throw new IllegalArgumentException("listener is not registered");
2401                 }
2402                 mSensorEventListeners.remove(callingPid);
2403             }
2404         }
2405     }
2406 
2407     @Override // Binder call
flushSensor(int deviceId, int sensorType)2408     public boolean flushSensor(int deviceId, int sensorType) {
2409         synchronized (mInputDevicesLock) {
2410             int callingPid = Binder.getCallingPid();
2411             SensorEventListenerRecord listener = mSensorEventListeners.get(callingPid);
2412             if (listener != null) {
2413                 return nativeFlushSensor(mPtr, deviceId, sensorType);
2414             }
2415             return false;
2416         }
2417     }
2418 
2419     @Override // Binder call
enableSensor(int deviceId, int sensorType, int samplingPeriodUs, int maxBatchReportLatencyUs)2420     public boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs,
2421             int maxBatchReportLatencyUs) {
2422         synchronized (mInputDevicesLock) {
2423             return nativeEnableSensor(mPtr, deviceId, sensorType, samplingPeriodUs,
2424                     maxBatchReportLatencyUs);
2425         }
2426     }
2427 
2428     @Override // Binder call
disableSensor(int deviceId, int sensorType)2429     public void disableSensor(int deviceId, int sensorType) {
2430         synchronized (mInputDevicesLock) {
2431             nativeDisableSensor(mPtr, deviceId, sensorType);
2432         }
2433     }
2434 
2435     /**
2436      * LightSession represents a light session for lights manager.
2437      */
2438     private final class LightSession implements DeathRecipient {
2439         private final int mDeviceId;
2440         private final IBinder mToken;
2441         private final String mOpPkg;
2442         // The light ids and states that are requested by the light seesion
2443         private int[] mLightIds;
2444         private LightState[] mLightStates;
2445 
LightSession(int deviceId, String opPkg, IBinder token)2446         LightSession(int deviceId, String opPkg, IBinder token) {
2447             mDeviceId = deviceId;
2448             mOpPkg = opPkg;
2449             mToken = token;
2450         }
2451 
2452         @Override
binderDied()2453         public void binderDied() {
2454             if (DEBUG) {
2455                 Slog.d(TAG, "Light token died.");
2456             }
2457             synchronized (mLightLock) {
2458                 closeLightSession(mDeviceId, mToken);
2459                 mLightSessions.remove(mToken);
2460             }
2461         }
2462     }
2463 
2464     /**
2465      * Returns the lights available for apps to control on the specified input device.
2466      * Only lights that aren't reserved for system use are available to apps.
2467      */
2468     @Override // Binder call
getLights(int deviceId)2469     public List<Light> getLights(int deviceId) {
2470         return nativeGetLights(mPtr, deviceId);
2471     }
2472 
2473     /**
2474      * Set specified light state with for a specific input device.
2475      */
setLightStateInternal(int deviceId, Light light, LightState lightState)2476     private void setLightStateInternal(int deviceId, Light light, LightState lightState) {
2477         Preconditions.checkNotNull(light, "light does not exist");
2478         if (DEBUG) {
2479             Slog.d(TAG, "setLightStateInternal device " + deviceId + " light " + light
2480                     + "lightState " + lightState);
2481         }
2482         if (light.getType() == Light.LIGHT_TYPE_PLAYER_ID) {
2483             nativeSetLightPlayerId(mPtr, deviceId, light.getId(), lightState.getPlayerId());
2484         } else {
2485             // Set ARGB format color to input device light
2486             // Refer to https://developer.android.com/reference/kotlin/android/graphics/Color
2487             nativeSetLightColor(mPtr, deviceId, light.getId(), lightState.getColor());
2488         }
2489     }
2490 
2491     /**
2492      * Set multiple light states with multiple light ids for a specific input device.
2493      */
setLightStatesInternal(int deviceId, int[] lightIds, LightState[] lightStates)2494     private void setLightStatesInternal(int deviceId, int[] lightIds, LightState[] lightStates) {
2495         final List<Light> lights = nativeGetLights(mPtr, deviceId);
2496         SparseArray<Light> lightArray = new SparseArray<>();
2497         for (int i = 0; i < lights.size(); i++) {
2498             lightArray.put(lights.get(i).getId(), lights.get(i));
2499         }
2500         for (int i = 0; i < lightIds.length; i++) {
2501             if (lightArray.contains(lightIds[i])) {
2502                 setLightStateInternal(deviceId, lightArray.get(lightIds[i]), lightStates[i]);
2503             }
2504         }
2505     }
2506 
2507     /**
2508      * Set states for multiple lights for an opened light session.
2509      */
2510     @Override
setLightStates(int deviceId, int[] lightIds, LightState[] lightStates, IBinder token)2511     public void setLightStates(int deviceId, int[] lightIds, LightState[] lightStates,
2512             IBinder token) {
2513         Preconditions.checkArgument(lightIds.length == lightStates.length,
2514                 "lights and light states are not same length");
2515         synchronized (mLightLock) {
2516             LightSession lightSession = mLightSessions.get(token);
2517             Preconditions.checkArgument(lightSession != null, "not registered");
2518             Preconditions.checkState(lightSession.mDeviceId == deviceId, "Incorrect device ID");
2519             lightSession.mLightIds = lightIds.clone();
2520             lightSession.mLightStates = lightStates.clone();
2521             if (DEBUG) {
2522                 Slog.d(TAG, "setLightStates for " + lightSession.mOpPkg + " device " + deviceId);
2523             }
2524         }
2525         setLightStatesInternal(deviceId, lightIds, lightStates);
2526     }
2527 
2528     @Override
getLightState(int deviceId, int lightId)2529     public @Nullable LightState getLightState(int deviceId, int lightId) {
2530         synchronized (mLightLock) {
2531             int color = nativeGetLightColor(mPtr, deviceId, lightId);
2532             int playerId = nativeGetLightPlayerId(mPtr, deviceId, lightId);
2533 
2534             return new LightState(color, playerId);
2535         }
2536     }
2537 
2538     @Override
openLightSession(int deviceId, String opPkg, IBinder token)2539     public void openLightSession(int deviceId, String opPkg, IBinder token) {
2540         Preconditions.checkNotNull(token);
2541         synchronized (mLightLock) {
2542             Preconditions.checkState(mLightSessions.get(token) == null, "already registered");
2543             LightSession lightSession = new LightSession(deviceId, opPkg, token);
2544             try {
2545                 token.linkToDeath(lightSession, 0);
2546             } catch (RemoteException ex) {
2547                 // give up
2548                 ex.rethrowAsRuntimeException();
2549             }
2550             mLightSessions.put(token, lightSession);
2551             if (DEBUG) {
2552                 Slog.d(TAG, "Open light session for " + opPkg + " device " + deviceId);
2553             }
2554         }
2555     }
2556 
2557     @Override
closeLightSession(int deviceId, IBinder token)2558     public void closeLightSession(int deviceId, IBinder token) {
2559         Preconditions.checkNotNull(token);
2560         synchronized (mLightLock) {
2561             LightSession lightSession = mLightSessions.get(token);
2562             Preconditions.checkState(lightSession != null, "not registered");
2563             // Turn off the lights that were previously requested by the session to be closed.
2564             Arrays.fill(lightSession.mLightStates, new LightState(0));
2565             setLightStatesInternal(deviceId, lightSession.mLightIds,
2566                     lightSession.mLightStates);
2567             mLightSessions.remove(token);
2568             // If any other session is still pending with light request, apply the first session's
2569             // request.
2570             if (!mLightSessions.isEmpty()) {
2571                 LightSession nextSession = mLightSessions.valueAt(0);
2572                 setLightStatesInternal(deviceId, nextSession.mLightIds, nextSession.mLightStates);
2573             }
2574         }
2575     }
2576 
2577     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2578     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2579         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
2580 
2581         pw.println("INPUT MANAGER (dumpsys input)\n");
2582         String dumpStr = nativeDump(mPtr);
2583         if (dumpStr != null) {
2584             pw.println(dumpStr);
2585             dumpAssociations(pw);
2586         }
2587     }
2588 
dumpAssociations(PrintWriter pw)2589     private void dumpAssociations(PrintWriter pw) {
2590         if (!mStaticAssociations.isEmpty()) {
2591             pw.println("Static Associations:");
2592             mStaticAssociations.forEach((k, v) -> {
2593                 pw.print("  port: " + k);
2594                 pw.println("  display: " + v);
2595             });
2596         }
2597 
2598         synchronized (mAssociationsLock) {
2599             if (!mRuntimeAssociations.isEmpty()) {
2600                 pw.println("Runtime Associations:");
2601                 mRuntimeAssociations.forEach((k, v) -> {
2602                     pw.print("  port: " + k);
2603                     pw.println("  display: " + v);
2604                 });
2605             }
2606         }
2607     }
2608 
checkCallingPermission(String permission, String func)2609     private boolean checkCallingPermission(String permission, String func) {
2610         // Quick check: if the calling permission is me, it's all okay.
2611         if (Binder.getCallingPid() == Process.myPid()) {
2612             return true;
2613         }
2614 
2615         if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
2616             return true;
2617         }
2618         String msg = "Permission Denial: " + func + " from pid="
2619                 + Binder.getCallingPid()
2620                 + ", uid=" + Binder.getCallingUid()
2621                 + " requires " + permission;
2622         Slog.w(TAG, msg);
2623         return false;
2624     }
2625 
2626     // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
2627     @Override
monitor()2628     public void monitor() {
2629         synchronized (mInputFilterLock) { }
2630         synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
2631         synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
2632         nativeMonitor(mPtr);
2633     }
2634 
2635     // Native callback.
notifyConfigurationChanged(long whenNanos)2636     private void notifyConfigurationChanged(long whenNanos) {
2637         mWindowManagerCallbacks.notifyConfigurationChanged();
2638     }
2639 
2640     // Native callback.
notifyInputDevicesChanged(InputDevice[] inputDevices)2641     private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
2642         synchronized (mInputDevicesLock) {
2643             if (!mInputDevicesChangedPending) {
2644                 mInputDevicesChangedPending = true;
2645                 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
2646                         mInputDevices).sendToTarget();
2647             }
2648 
2649             mInputDevices = inputDevices;
2650         }
2651     }
2652 
2653     // Native callback.
notifySwitch(long whenNanos, int switchValues, int switchMask)2654     private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
2655         if (DEBUG) {
2656             Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
2657                     + ", mask=" + Integer.toHexString(switchMask));
2658         }
2659 
2660         if ((switchMask & SW_LID_BIT) != 0) {
2661             final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
2662             synchronized (mLidSwitchLock) {
2663                 if (mSystemReady) {
2664                     for (int i = 0; i < mLidSwitchCallbacks.size(); i++) {
2665                         LidSwitchCallback callbacks = mLidSwitchCallbacks.get(i);
2666                         callbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
2667                     }
2668                 }
2669             }
2670         }
2671 
2672         if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
2673             final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
2674             mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
2675         }
2676 
2677         if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
2678             mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
2679                     switchMask);
2680         }
2681 
2682         if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
2683             SomeArgs args = SomeArgs.obtain();
2684             args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
2685             args.argi2 = (int) (whenNanos >> 32);
2686             args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
2687             mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
2688                     args).sendToTarget();
2689         }
2690 
2691         if ((switchMask & SW_MUTE_DEVICE_BIT) != 0) {
2692             final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0);
2693             AudioManager audioManager = mContext.getSystemService(AudioManager.class);
2694             audioManager.setMicrophoneMuteFromSwitch(micMute);
2695         }
2696     }
2697 
2698     // Native callback.
notifyInputChannelBroken(IBinder token)2699     private void notifyInputChannelBroken(IBinder token) {
2700         mWindowManagerCallbacks.notifyInputChannelBroken(token);
2701     }
2702 
2703     // Native callback
notifyFocusChanged(IBinder oldToken, IBinder newToken)2704     private void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
2705         mWindowManagerCallbacks.notifyFocusChanged(oldToken, newToken);
2706     }
2707 
2708     // Native callback
notifyDropWindow(IBinder token, float x, float y)2709     private void notifyDropWindow(IBinder token, float x, float y) {
2710         mWindowManagerCallbacks.notifyDropWindow(token, x, y);
2711     }
2712 
2713     // Native callback
notifyUntrustedTouch(String packageName)2714     private void notifyUntrustedTouch(String packageName) {
2715         // TODO(b/169067926): Remove toast after gathering feedback on dogfood.
2716         if (!UNTRUSTED_TOUCHES_TOAST || ArrayUtils.contains(
2717                 PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) {
2718             Log.i(TAG, "Suppressing untrusted touch toast for " + packageName);
2719             return;
2720         }
2721         DisplayThread.getHandler().post(() ->
2722                 Toast.makeText(mContext,
2723                         "Touch obscured by " + packageName
2724                                 + " will be blocked. Check go/untrusted-touches",
2725                         Toast.LENGTH_SHORT).show());
2726     }
2727 
2728     // Native callback.
notifyNoFocusedWindowAnr(InputApplicationHandle inputApplicationHandle)2729     private void notifyNoFocusedWindowAnr(InputApplicationHandle inputApplicationHandle) {
2730         mWindowManagerCallbacks.notifyNoFocusedWindowAnr(inputApplicationHandle);
2731     }
2732 
2733     // Native callback
notifyWindowUnresponsive(IBinder token, String reason)2734     private void notifyWindowUnresponsive(IBinder token, String reason) {
2735         mWindowManagerCallbacks.notifyWindowUnresponsive(token, reason);
2736     }
2737 
2738     // Native callback
notifyMonitorUnresponsive(int pid, String reason)2739     private void notifyMonitorUnresponsive(int pid, String reason) {
2740         mWindowManagerCallbacks.notifyGestureMonitorUnresponsive(pid, reason);
2741     }
2742 
2743     // Native callback
notifyWindowResponsive(IBinder token)2744     private void notifyWindowResponsive(IBinder token) {
2745         mWindowManagerCallbacks.notifyWindowResponsive(token);
2746     }
2747 
2748     // Native callback
notifyMonitorResponsive(int pid)2749     private void notifyMonitorResponsive(int pid) {
2750         mWindowManagerCallbacks.notifyGestureMonitorResponsive(pid);
2751     }
2752 
2753     // Native callback.
notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, float[] values)2754     private void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp,
2755             float[] values) {
2756         if (DEBUG) {
2757             Slog.d(TAG, "notifySensorEvent: deviceId=" + deviceId + " sensorType="
2758                     + sensorType + " values=" + Arrays.toString(values));
2759         }
2760         mSensorEventListenersToNotify.clear();
2761         final int numListeners;
2762         synchronized (mSensorEventLock) {
2763             numListeners = mSensorEventListeners.size();
2764             for (int i = 0; i < numListeners; i++) {
2765                 mSensorEventListenersToNotify.add(
2766                         mSensorEventListeners.valueAt(i));
2767             }
2768         }
2769         for (int i = 0; i < numListeners; i++) {
2770             mSensorEventListenersToNotify.get(i).notifySensorEvent(deviceId, sensorType,
2771                     accuracy, timestamp, values);
2772         }
2773         mSensorEventListenersToNotify.clear();
2774     }
2775 
2776     // Native callback.
notifySensorAccuracy(int deviceId, int sensorType, int accuracy)2777     private void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) {
2778         mSensorAccuracyListenersToNotify.clear();
2779         final int numListeners;
2780         synchronized (mSensorEventLock) {
2781             numListeners = mSensorEventListeners.size();
2782             for (int i = 0; i < numListeners; i++) {
2783                 mSensorAccuracyListenersToNotify.add(mSensorEventListeners.valueAt(i));
2784             }
2785         }
2786         for (int i = 0; i < numListeners; i++) {
2787             mSensorAccuracyListenersToNotify.get(i).notifySensorAccuracy(
2788                     deviceId, sensorType, accuracy);
2789         }
2790         mSensorAccuracyListenersToNotify.clear();
2791     }
2792 
2793     // Native callback.
filterInputEvent(InputEvent event, int policyFlags)2794     final boolean filterInputEvent(InputEvent event, int policyFlags) {
2795         synchronized (mInputFilterLock) {
2796             if (mInputFilter != null) {
2797                 try {
2798                     mInputFilter.filterInputEvent(event, policyFlags);
2799                 } catch (RemoteException e) {
2800                     /* ignore */
2801                 }
2802                 return false;
2803             }
2804         }
2805         event.recycle();
2806         return true;
2807     }
2808 
2809     // Native callback.
interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)2810     private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
2811         return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
2812     }
2813 
2814     // Native callback.
interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)2815     private int interceptMotionBeforeQueueingNonInteractive(int displayId,
2816             long whenNanos, int policyFlags) {
2817         return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
2818                 displayId, whenNanos, policyFlags);
2819     }
2820 
2821     // Native callback.
interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags)2822     private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
2823         return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
2824     }
2825 
2826     // Native callback.
dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags)2827     private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) {
2828         return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
2829     }
2830 
2831     // Native callback.
checkInjectEventsPermission(int injectorPid, int injectorUid)2832     private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
2833         return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
2834                 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
2835     }
2836 
2837     // Native callback.
onPointerDownOutsideFocus(IBinder touchedToken)2838     private void onPointerDownOutsideFocus(IBinder touchedToken) {
2839         mWindowManagerCallbacks.onPointerDownOutsideFocus(touchedToken);
2840     }
2841 
2842     // Native callback.
getVirtualKeyQuietTimeMillis()2843     private int getVirtualKeyQuietTimeMillis() {
2844         return mContext.getResources().getInteger(
2845                 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
2846     }
2847 
2848     // Native callback.
getExcludedDeviceNames()2849     private static String[] getExcludedDeviceNames() {
2850         List<String> names = new ArrayList<>();
2851         // Read partner-provided list of excluded input devices
2852         // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
2853         final File[] baseDirs = {
2854             Environment.getRootDirectory(),
2855             Environment.getVendorDirectory()
2856         };
2857         for (File baseDir: baseDirs) {
2858             File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH);
2859             try {
2860                 InputStream stream = new FileInputStream(confFile);
2861                 names.addAll(ConfigurationProcessor.processExcludedDeviceNames(stream));
2862             } catch (FileNotFoundException e) {
2863                 // It's ok if the file does not exist.
2864             } catch (Exception e) {
2865                 Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
2866             }
2867         }
2868         return names.toArray(new String[0]);
2869     }
2870 
2871     /**
2872      * Flatten a map into a string list, with value positioned directly next to the
2873      * key.
2874      * @return Flattened list
2875      */
flatten(@onNull Map<String, T> map)2876     private static <T> String[] flatten(@NonNull Map<String, T> map) {
2877         final List<String> list = new ArrayList<>(map.size() * 2);
2878         map.forEach((k, v)-> {
2879             list.add(k);
2880             list.add(v.toString());
2881         });
2882         return list.toArray(new String[0]);
2883     }
2884 
2885     /**
2886      * Ports are highly platform-specific, so only allow these to be specified in the vendor
2887      * directory.
2888      */
loadStaticInputPortAssociations()2889     private static Map<String, Integer> loadStaticInputPortAssociations() {
2890         final File baseDir = Environment.getVendorDirectory();
2891         final File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
2892 
2893         try {
2894             final InputStream stream = new FileInputStream(confFile);
2895             return ConfigurationProcessor.processInputPortAssociations(stream);
2896         } catch (FileNotFoundException e) {
2897             // Most of the time, file will not exist, which is expected.
2898         } catch (Exception e) {
2899             Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
2900         }
2901 
2902         return new HashMap<>();
2903     }
2904 
2905     // Native callback
getInputPortAssociations()2906     private String[] getInputPortAssociations() {
2907         final Map<String, Integer> associations = new HashMap<>(mStaticAssociations);
2908 
2909         // merge the runtime associations.
2910         synchronized (mAssociationsLock) {
2911             associations.putAll(mRuntimeAssociations);
2912         }
2913 
2914         return flatten(associations);
2915     }
2916 
2917     // Native callback
getInputUniqueIdAssociations()2918     private String[] getInputUniqueIdAssociations() {
2919         final Map<String, String> associations;
2920         synchronized (mAssociationsLock) {
2921             associations = new HashMap<>(mUniqueIdAssociations);
2922         }
2923 
2924         return flatten(associations);
2925     }
2926 
2927     /**
2928      * Gets if an input device could dispatch to the given display".
2929      * @param deviceId The input device id.
2930      * @param displayId The specific display id.
2931      * @return True if the device could dispatch to the given display, false otherwise.
2932      */
canDispatchToDisplay(int deviceId, int displayId)2933     public boolean canDispatchToDisplay(int deviceId, int displayId) {
2934         return nativeCanDispatchToDisplay(mPtr, deviceId, displayId);
2935     }
2936 
2937     // Native callback.
getKeyRepeatTimeout()2938     private int getKeyRepeatTimeout() {
2939         return ViewConfiguration.getKeyRepeatTimeout();
2940     }
2941 
2942     // Native callback.
getKeyRepeatDelay()2943     private int getKeyRepeatDelay() {
2944         return ViewConfiguration.getKeyRepeatDelay();
2945     }
2946 
2947     // Native callback.
getHoverTapTimeout()2948     private int getHoverTapTimeout() {
2949         return ViewConfiguration.getHoverTapTimeout();
2950     }
2951 
2952     // Native callback.
getHoverTapSlop()2953     private int getHoverTapSlop() {
2954         return ViewConfiguration.getHoverTapSlop();
2955     }
2956 
2957     // Native callback.
getDoubleTapTimeout()2958     private int getDoubleTapTimeout() {
2959         return ViewConfiguration.getDoubleTapTimeout();
2960     }
2961 
2962     // Native callback.
getLongPressTimeout()2963     private int getLongPressTimeout() {
2964         return ViewConfiguration.getLongPressTimeout();
2965     }
2966 
2967     // Native callback.
getPointerLayer()2968     private int getPointerLayer() {
2969         return mWindowManagerCallbacks.getPointerLayer();
2970     }
2971 
2972     // Native callback.
getPointerIcon(int displayId)2973     private PointerIcon getPointerIcon(int displayId) {
2974         return PointerIcon.getDefaultIcon(getContextForDisplay(displayId));
2975     }
2976 
getContextForDisplay(int displayId)2977     private Context getContextForDisplay(int displayId) {
2978         if (mDisplayContext != null && mDisplayContext.getDisplay().getDisplayId() == displayId) {
2979             return mDisplayContext;
2980         }
2981 
2982         if (mContext.getDisplay().getDisplayId() == displayId) {
2983             mDisplayContext = mContext;
2984             return mDisplayContext;
2985         }
2986 
2987         // Create and cache context for non-default display.
2988         final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
2989         final Display display = displayManager.getDisplay(displayId);
2990         mDisplayContext = mContext.createDisplayContext(display);
2991         return mDisplayContext;
2992     }
2993 
2994     // Native callback.
getPointerDisplayId()2995     private int getPointerDisplayId() {
2996         return mWindowManagerCallbacks.getPointerDisplayId();
2997     }
2998 
2999     // Native callback.
getKeyboardLayoutOverlay(InputDeviceIdentifier identifier)3000     private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
3001         if (!mSystemReady) {
3002             return null;
3003         }
3004 
3005         String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
3006         if (keyboardLayoutDescriptor == null) {
3007             return null;
3008         }
3009 
3010         final String[] result = new String[2];
3011         visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
3012             @Override
3013             public void visitKeyboardLayout(Resources resources,
3014                     int keyboardLayoutResId, KeyboardLayout layout) {
3015                 try {
3016                     result[0] = layout.getDescriptor();
3017                     result[1] = Streams.readFully(new InputStreamReader(
3018                             resources.openRawResource(keyboardLayoutResId)));
3019                 } catch (IOException ex) {
3020                 } catch (NotFoundException ex) {
3021                 }
3022             }
3023         });
3024         if (result[0] == null) {
3025             Slog.w(TAG, "Could not get keyboard layout with descriptor '"
3026                     + keyboardLayoutDescriptor + "'.");
3027             return null;
3028         }
3029         return result;
3030     }
3031 
3032     // Native callback.
getDeviceAlias(String uniqueId)3033     private String getDeviceAlias(String uniqueId) {
3034         if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
3035             // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
3036             return null;
3037         }
3038         return null;
3039     }
3040 
3041     /**
3042      * Callback interface implemented by the Window Manager.
3043      */
3044     public interface WindowManagerCallbacks extends LidSwitchCallback {
3045         /**
3046          * This callback is invoked when the configuration changes.
3047          */
notifyConfigurationChanged()3048         void notifyConfigurationChanged();
3049 
3050         /**
3051          * This callback is invoked when the camera lens cover switch changes state.
3052          * @param whenNanos the time when the change occurred
3053          * @param lensCovered true is the lens is covered
3054          */
notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered)3055         void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
3056 
3057         /**
3058          * This callback is invoked when an input channel is closed unexpectedly.
3059          * @param token the connection token of the broken channel
3060          */
notifyInputChannelBroken(IBinder token)3061         void notifyInputChannelBroken(IBinder token);
3062 
3063         /**
3064          * Notify the window manager about the focused application that does not have any focused
3065          * window and is unable to respond to focused input events.
3066          */
notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle)3067         void notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle);
3068 
3069         /**
3070          * Notify the window manager about a gesture monitor that is unresponsive.
3071          *
3072          * @param pid the pid of the gesture monitor process
3073          * @param reason the reason why this connection is unresponsive
3074          */
notifyGestureMonitorUnresponsive(int pid, @NonNull String reason)3075         void notifyGestureMonitorUnresponsive(int pid, @NonNull String reason);
3076 
3077         /**
3078          * Notify the window manager about a window that is unresponsive.
3079          *
3080          * @param token the token that can be used to look up the window
3081          * @param reason the reason why this connection is unresponsive
3082          */
notifyWindowUnresponsive(@onNull IBinder token, @NonNull String reason)3083         void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull String reason);
3084 
3085         /**
3086          * Notify the window manager about a gesture monitor that has become responsive.
3087          *
3088          * @param pid the pid of the gesture monitor process
3089          */
notifyGestureMonitorResponsive(int pid)3090         void notifyGestureMonitorResponsive(int pid);
3091 
3092         /**
3093          * Notify the window manager about a window that has become responsive.
3094          *
3095          * @param token the token that can be used to look up the window
3096          */
notifyWindowResponsive(@onNull IBinder token)3097         void notifyWindowResponsive(@NonNull IBinder token);
3098 
3099         /**
3100          * This callback is invoked when an event first arrives to InputDispatcher and before it is
3101          * placed onto InputDispatcher's queue. If this event is intercepted, it will never be
3102          * processed by InputDispacher.
3103          * @param event The key event that's arriving to InputDispatcher
3104          * @param policyFlags The policy flags
3105          * @return the flags that tell InputDispatcher how to handle the event (for example, whether
3106          * to pass it to the user)
3107          */
interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)3108         int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
3109 
3110         /**
3111          * Provides an opportunity for the window manager policy to intercept early motion event
3112          * processing when the device is in a non-interactive state since these events are normally
3113          * dropped.
3114          */
interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)3115         int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
3116                 int policyFlags);
3117 
3118         /**
3119          * This callback is invoked just before the key is about to be sent to an application.
3120          * This allows the policy to make some last minute decisions on whether to intercept this
3121          * key.
3122          * @param token the window token that's about to receive this event
3123          * @param event the key event that's being dispatched
3124          * @param policyFlags the policy flags
3125          * @return negative value if the key should be skipped (not sent to the app). 0 if the key
3126          * should proceed getting dispatched to the app. positive value to indicate the additional
3127          * time delay, in nanoseconds, to wait before sending this key to the app.
3128          */
interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags)3129         long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags);
3130 
3131         /**
3132          * Dispatch unhandled key
3133          */
dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags)3134         KeyEvent dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags);
3135 
getPointerLayer()3136         int getPointerLayer();
3137 
getPointerDisplayId()3138         int getPointerDisplayId();
3139 
3140         /**
3141          * Notifies window manager that a {@link android.view.MotionEvent#ACTION_DOWN} pointer event
3142          * occurred on a window that did not have focus.
3143          *
3144          * @param touchedToken The token for the window that received the input event.
3145          */
onPointerDownOutsideFocus(IBinder touchedToken)3146         void onPointerDownOutsideFocus(IBinder touchedToken);
3147 
3148         /**
3149          * Called when the focused window has changed.
3150          */
notifyFocusChanged(IBinder oldToken, IBinder newToken)3151         void notifyFocusChanged(IBinder oldToken, IBinder newToken);
3152 
3153         /**
3154          * Called when the drag over window has changed.
3155          */
notifyDropWindow(IBinder token, float x, float y)3156         void notifyDropWindow(IBinder token, float x, float y);
3157     }
3158 
3159     /**
3160      * Callback interface implemented by WiredAccessoryObserver.
3161      */
3162     public interface WiredAccessoryCallbacks {
notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask)3163         public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
systemReady()3164         public void systemReady();
3165     }
3166 
3167     /**
3168      * Private handler for the input manager.
3169      */
3170     private final class InputManagerHandler extends Handler {
InputManagerHandler(Looper looper)3171         public InputManagerHandler(Looper looper) {
3172             super(looper, null, true /*async*/);
3173         }
3174 
3175         @Override
handleMessage(Message msg)3176         public void handleMessage(Message msg) {
3177             switch (msg.what) {
3178                 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
3179                     deliverInputDevicesChanged((InputDevice[])msg.obj);
3180                     break;
3181                 case MSG_SWITCH_KEYBOARD_LAYOUT:
3182                     handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
3183                     break;
3184                 case MSG_RELOAD_KEYBOARD_LAYOUTS:
3185                     reloadKeyboardLayouts();
3186                     break;
3187                 case MSG_UPDATE_KEYBOARD_LAYOUTS:
3188                     updateKeyboardLayouts();
3189                     break;
3190                 case MSG_RELOAD_DEVICE_ALIASES:
3191                     reloadDeviceAliases();
3192                     break;
3193                 case MSG_DELIVER_TABLET_MODE_CHANGED:
3194                     SomeArgs args = (SomeArgs) msg.obj;
3195                     long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
3196                     boolean inTabletMode = (boolean) args.arg1;
3197                     deliverTabletModeChanged(whenNanos, inTabletMode);
3198                     break;
3199             }
3200         }
3201     }
3202 
3203     /**
3204      * Hosting interface for input filters to call back into the input manager.
3205      */
3206     private final class InputFilterHost extends IInputFilterHost.Stub {
3207         private boolean mDisconnected;
3208 
disconnectLocked()3209         public void disconnectLocked() {
3210             mDisconnected = true;
3211         }
3212 
3213         @Override
sendInputEvent(InputEvent event, int policyFlags)3214         public void sendInputEvent(InputEvent event, int policyFlags) {
3215             if (event == null) {
3216                 throw new IllegalArgumentException("event must not be null");
3217             }
3218 
3219             synchronized (mInputFilterLock) {
3220                 if (!mDisconnected) {
3221                     nativeInjectInputEvent(mPtr, event, 0, 0,
3222                             InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
3223                             policyFlags | WindowManagerPolicy.FLAG_FILTERED);
3224                 }
3225             }
3226         }
3227     }
3228 
3229     /**
3230      * Interface for the system to handle request from InputMonitors.
3231      */
3232     private final class InputMonitorHost extends IInputMonitorHost.Stub {
3233         private IBinder mToken;
3234 
InputMonitorHost(IBinder token)3235         InputMonitorHost(IBinder token) {
3236             mToken = token;
3237         }
3238 
3239         @Override
pilferPointers()3240         public void pilferPointers() {
3241             if (mToken == null) {
3242                 throw new IllegalStateException(
3243                         "Illegal call to pilferPointers after InputMonitorHost is disposed.");
3244             }
3245             nativePilferPointers(mPtr, mToken);
3246         }
3247 
3248         @Override
dispose()3249         public void dispose() {
3250             // We do not remove the input monitor here by calling nativeRemoveInputChannel because
3251             // it causes a race in InputDispatcher between the removal of the InputChannel through
3252             // that call and the InputChannel#dispose call (which causes an FD hangup) from the
3253             // client (b/189135695).
3254             //
3255             // NOTE: This means the client is responsible for properly closing the InputMonitor by
3256             // disposing the InputChannel and all its duplicates.
3257             mToken = null;
3258         }
3259     }
3260 
3261     private static final class KeyboardLayoutDescriptor {
3262         public String packageName;
3263         public String receiverName;
3264         public String keyboardLayoutName;
3265 
format(String packageName, String receiverName, String keyboardName)3266         public static String format(String packageName,
3267                 String receiverName, String keyboardName) {
3268             return packageName + "/" + receiverName + "/" + keyboardName;
3269         }
3270 
parse(String descriptor)3271         public static KeyboardLayoutDescriptor parse(String descriptor) {
3272             int pos = descriptor.indexOf('/');
3273             if (pos < 0 || pos + 1 == descriptor.length()) {
3274                 return null;
3275             }
3276             int pos2 = descriptor.indexOf('/', pos + 1);
3277             if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
3278                 return null;
3279             }
3280 
3281             KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
3282             result.packageName = descriptor.substring(0, pos);
3283             result.receiverName = descriptor.substring(pos + 1, pos2);
3284             result.keyboardLayoutName = descriptor.substring(pos2 + 1);
3285             return result;
3286         }
3287     }
3288 
3289     private interface KeyboardLayoutVisitor {
visitKeyboardLayout(Resources resources, int keyboardLayoutResId, KeyboardLayout layout)3290         void visitKeyboardLayout(Resources resources,
3291                 int keyboardLayoutResId, KeyboardLayout layout);
3292     }
3293 
3294     private final class InputDevicesChangedListenerRecord implements DeathRecipient {
3295         private final int mPid;
3296         private final IInputDevicesChangedListener mListener;
3297 
InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener)3298         public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
3299             mPid = pid;
3300             mListener = listener;
3301         }
3302 
3303         @Override
binderDied()3304         public void binderDied() {
3305             if (DEBUG) {
3306                 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
3307             }
3308             onInputDevicesChangedListenerDied(mPid);
3309         }
3310 
notifyInputDevicesChanged(int[] info)3311         public void notifyInputDevicesChanged(int[] info) {
3312             try {
3313                 mListener.onInputDevicesChanged(info);
3314             } catch (RemoteException ex) {
3315                 Slog.w(TAG, "Failed to notify process "
3316                         + mPid + " that input devices changed, assuming it died.", ex);
3317                 binderDied();
3318             }
3319         }
3320     }
3321 
3322     private final class TabletModeChangedListenerRecord implements DeathRecipient {
3323         private final int mPid;
3324         private final ITabletModeChangedListener mListener;
3325 
TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener)3326         public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
3327             mPid = pid;
3328             mListener = listener;
3329         }
3330 
3331         @Override
binderDied()3332         public void binderDied() {
3333             if (DEBUG) {
3334                 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
3335             }
3336             onTabletModeChangedListenerDied(mPid);
3337         }
3338 
notifyTabletModeChanged(long whenNanos, boolean inTabletMode)3339         public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
3340             try {
3341                 mListener.onTabletModeChanged(whenNanos, inTabletMode);
3342             } catch (RemoteException ex) {
3343                 Slog.w(TAG, "Failed to notify process " + mPid +
3344                         " that tablet mode changed, assuming it died.", ex);
3345                 binderDied();
3346             }
3347         }
3348     }
3349 
onSensorEventListenerDied(int pid)3350     private void onSensorEventListenerDied(int pid) {
3351         synchronized (mSensorEventLock) {
3352             mSensorEventListeners.remove(pid);
3353         }
3354     }
3355 
3356     private final class SensorEventListenerRecord implements DeathRecipient {
3357         private final int mPid;
3358         private final IInputSensorEventListener mListener;
3359 
SensorEventListenerRecord(int pid, IInputSensorEventListener listener)3360         SensorEventListenerRecord(int pid, IInputSensorEventListener listener) {
3361             mPid = pid;
3362             mListener = listener;
3363         }
3364 
3365         @Override
binderDied()3366         public void binderDied() {
3367             if (DEBUG) {
3368                 Slog.d(TAG, "Sensor event listener for pid " + mPid + " died.");
3369             }
3370             onSensorEventListenerDied(mPid);
3371         }
3372 
getListener()3373         public IInputSensorEventListener getListener() {
3374             return mListener;
3375         }
3376 
notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, float[] values)3377         public void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp,
3378                 float[] values) {
3379             try {
3380                 mListener.onInputSensorChanged(deviceId, sensorType, accuracy, timestamp,
3381                         values);
3382             } catch (RemoteException ex) {
3383                 Slog.w(TAG, "Failed to notify process " + mPid
3384                         + " that sensor event notified, assuming it died.", ex);
3385                 binderDied();
3386             }
3387         }
3388 
notifySensorAccuracy(int deviceId, int sensorType, int accuracy)3389         public void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) {
3390             try {
3391                 mListener.onInputSensorAccuracyChanged(deviceId, sensorType, accuracy);
3392             } catch (RemoteException ex) {
3393                 Slog.w(TAG, "Failed to notify process " + mPid
3394                         + " that sensor accuracy notified, assuming it died.", ex);
3395                 binderDied();
3396             }
3397         }
3398     }
3399 
3400     private final class VibratorToken implements DeathRecipient {
3401         public final int mDeviceId;
3402         public final IBinder mToken;
3403         public final int mTokenValue;
3404 
3405         public boolean mVibrating;
3406 
VibratorToken(int deviceId, IBinder token, int tokenValue)3407         public VibratorToken(int deviceId, IBinder token, int tokenValue) {
3408             mDeviceId = deviceId;
3409             mToken = token;
3410             mTokenValue = tokenValue;
3411         }
3412 
3413         @Override
binderDied()3414         public void binderDied() {
3415             if (DEBUG) {
3416                 Slog.d(TAG, "Vibrator token died.");
3417             }
3418             onVibratorTokenDied(this);
3419         }
3420     }
3421 
3422     private final class LocalService extends InputManagerInternal {
3423         @Override
setDisplayViewports(List<DisplayViewport> viewports)3424         public void setDisplayViewports(List<DisplayViewport> viewports) {
3425             setDisplayViewportsInternal(viewports);
3426         }
3427 
3428         @Override
injectInputEvent(InputEvent event, int mode)3429         public boolean injectInputEvent(InputEvent event, int mode) {
3430             return injectInputEventInternal(event, mode);
3431         }
3432 
3433         @Override
setInteractive(boolean interactive)3434         public void setInteractive(boolean interactive) {
3435             nativeSetInteractive(mPtr, interactive);
3436         }
3437 
3438         @Override
toggleCapsLock(int deviceId)3439         public void toggleCapsLock(int deviceId) {
3440             nativeToggleCapsLock(mPtr, deviceId);
3441         }
3442 
3443         @Override
setPulseGestureEnabled(boolean enabled)3444         public void setPulseGestureEnabled(boolean enabled) {
3445             if (mDoubleTouchGestureEnableFile != null) {
3446                 FileWriter writer = null;
3447                 try {
3448                     writer = new FileWriter(mDoubleTouchGestureEnableFile);
3449                     writer.write(enabled ? "1" : "0");
3450                 } catch (IOException e) {
3451                     Log.wtf(TAG, "Unable to setPulseGestureEnabled", e);
3452                 } finally {
3453                     IoUtils.closeQuietly(writer);
3454                 }
3455             }
3456         }
3457 
3458         @Override
transferTouchFocus(@onNull IBinder fromChannelToken, @NonNull IBinder toChannelToken)3459         public boolean transferTouchFocus(@NonNull IBinder fromChannelToken,
3460                 @NonNull IBinder toChannelToken) {
3461             return InputManagerService.this.transferTouchFocus(fromChannelToken, toChannelToken);
3462         }
3463 
3464         @Override
registerLidSwitchCallback(LidSwitchCallback callbacks)3465         public void registerLidSwitchCallback(LidSwitchCallback callbacks) {
3466             registerLidSwitchCallbackInternal(callbacks);
3467         }
3468 
3469         @Override
unregisterLidSwitchCallback(LidSwitchCallback callbacks)3470         public void unregisterLidSwitchCallback(LidSwitchCallback callbacks) {
3471             unregisterLidSwitchCallbackInternal(callbacks);
3472         }
3473     }
3474 
3475     @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)3476     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3477             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
3478         new InputShellCommand().exec(this, in, out, err, args, callback, resultReceiver);
3479     }
3480 
3481 }
3482