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 android.annotation.NonNull;
20 import android.app.Notification;
21 import android.app.NotificationManager;
22 import android.app.PendingIntent;
23 import android.bluetooth.BluetoothAdapter;
24 import android.bluetooth.BluetoothDevice;
25 import android.content.BroadcastReceiver;
26 import android.content.ComponentName;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.content.pm.ActivityInfo;
31 import android.content.pm.ApplicationInfo;
32 import android.content.pm.PackageManager;
33 import android.content.pm.PackageManager.NameNotFoundException;
34 import android.content.pm.ResolveInfo;
35 import android.content.res.Resources;
36 import android.content.res.Resources.NotFoundException;
37 import android.content.res.TypedArray;
38 import android.content.res.XmlResourceParser;
39 import android.database.ContentObserver;
40 import android.hardware.display.DisplayManager;
41 import android.hardware.display.DisplayViewport;
42 import android.hardware.input.IInputDevicesChangedListener;
43 import android.hardware.input.IInputManager;
44 import android.hardware.input.ITabletModeChangedListener;
45 import android.hardware.input.InputDeviceIdentifier;
46 import android.hardware.input.InputManager;
47 import android.hardware.input.InputManagerInternal;
48 import android.hardware.input.KeyboardLayout;
49 import android.hardware.input.TouchCalibration;
50 import android.media.AudioManager;
51 import android.os.Binder;
52 import android.os.Bundle;
53 import android.os.Environment;
54 import android.os.Handler;
55 import android.os.IBinder;
56 import android.os.LocaleList;
57 import android.os.Looper;
58 import android.os.Message;
59 import android.os.MessageQueue;
60 import android.os.Process;
61 import android.os.RemoteException;
62 import android.os.UserHandle;
63 import android.provider.DeviceConfig;
64 import android.provider.Settings;
65 import android.provider.Settings.SettingNotFoundException;
66 import android.text.TextUtils;
67 import android.util.Log;
68 import android.util.Slog;
69 import android.util.SparseArray;
70 import android.view.Display;
71 import android.view.IInputFilter;
72 import android.view.IInputFilterHost;
73 import android.view.IInputMonitorHost;
74 import android.view.InputApplicationHandle;
75 import android.view.InputChannel;
76 import android.view.InputDevice;
77 import android.view.InputEvent;
78 import android.view.InputMonitor;
79 import android.view.KeyEvent;
80 import android.view.PointerIcon;
81 import android.view.Surface;
82 import android.view.VerifiedInputEvent;
83 import android.view.ViewConfiguration;
84 import android.widget.Toast;
85 
86 import com.android.internal.R;
87 import com.android.internal.annotations.GuardedBy;
88 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
89 import com.android.internal.notification.SystemNotificationChannels;
90 import com.android.internal.os.SomeArgs;
91 import com.android.internal.util.DumpUtils;
92 import com.android.internal.util.XmlUtils;
93 import com.android.server.DisplayThread;
94 import com.android.server.LocalServices;
95 import com.android.server.Watchdog;
96 import com.android.server.policy.WindowManagerPolicy;
97 
98 import libcore.io.IoUtils;
99 import libcore.io.Streams;
100 
101 import java.io.File;
102 import java.io.FileDescriptor;
103 import java.io.FileInputStream;
104 import java.io.FileNotFoundException;
105 import java.io.FileWriter;
106 import java.io.IOException;
107 import java.io.InputStream;
108 import java.io.InputStreamReader;
109 import java.io.PrintWriter;
110 import java.util.ArrayList;
111 import java.util.Collections;
112 import java.util.HashMap;
113 import java.util.HashSet;
114 import java.util.List;
115 import java.util.Locale;
116 import java.util.Map;
117 import java.util.Objects;
118 /*
119  * Wraps the C++ InputManager and provides its callbacks.
120  */
121 public class InputManagerService extends IInputManager.Stub
122         implements Watchdog.Monitor {
123     static final String TAG = "InputManager";
124     static final boolean DEBUG = false;
125 
126     private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
127     private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml";
128 
129     // Feature flag name for the deep press feature
130     private static final String DEEP_PRESS_ENABLED = "deep_press_enabled";
131 
132     private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
133     private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
134     private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
135     private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
136     private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
137     private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
138 
139     // Pointer to native input manager service object.
140     private final long mPtr;
141 
142     private final Context mContext;
143     private final InputManagerHandler mHandler;
144 
145     // Context cache used for loading pointer resources.
146     private Context mDisplayContext;
147 
148     private final File mDoubleTouchGestureEnableFile;
149 
150     private WindowManagerCallbacks mWindowManagerCallbacks;
151     private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
152     private boolean mSystemReady;
153     private NotificationManager mNotificationManager;
154 
155     private final Object mTabletModeLock = new Object();
156     // List of currently registered tablet mode changed listeners by process id
157     private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
158             new SparseArray<>(); // guarded by mTabletModeLock
159     private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
160             new ArrayList<>();
161 
162     // Persistent data store.  Must be locked each time during use.
163     private final PersistentDataStore mDataStore = new PersistentDataStore();
164 
165     // List of currently registered input devices changed listeners by process id.
166     private Object mInputDevicesLock = new Object();
167     private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
168     private InputDevice[] mInputDevices = new InputDevice[0];
169     private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
170             new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
171     private final ArrayList<InputDevicesChangedListenerRecord>
172             mTempInputDevicesChangedListenersToNotify =
173                     new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
174     private final ArrayList<InputDevice>
175             mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
176     private boolean mKeyboardLayoutNotificationShown;
177     private Toast mSwitchedKeyboardLayoutToast;
178 
179     // State for vibrator tokens.
180     private Object mVibratorLock = new Object();
181     private HashMap<IBinder, VibratorToken> mVibratorTokens =
182             new HashMap<IBinder, VibratorToken>();
183     private int mNextVibratorTokenValue;
184 
185     // State for the currently installed input filter.
186     final Object mInputFilterLock = new Object();
187     IInputFilter mInputFilter; // guarded by mInputFilterLock
188     InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
189 
190     // The associations of input devices to displays by port. Maps from input device port (String)
191     // to display id (int). Currently only accessed by InputReader.
192     private final Map<String, Integer> mStaticAssociations;
193     private final Object mAssociationsLock = new Object();
194     @GuardedBy("mAssociationLock")
195     private final Map<String, Integer> mRuntimeAssociations = new HashMap<String, Integer>();
196 
nativeInit(InputManagerService service, Context context, MessageQueue messageQueue)197     private static native long nativeInit(InputManagerService service,
198             Context context, MessageQueue messageQueue);
nativeStart(long ptr)199     private static native void nativeStart(long ptr);
nativeSetDisplayViewports(long ptr, DisplayViewport[] viewports)200     private static native void nativeSetDisplayViewports(long ptr,
201             DisplayViewport[] viewports);
202 
nativeGetScanCodeState(long ptr, int deviceId, int sourceMask, int scanCode)203     private static native int nativeGetScanCodeState(long ptr,
204             int deviceId, int sourceMask, int scanCode);
nativeGetKeyCodeState(long ptr, int deviceId, int sourceMask, int keyCode)205     private static native int nativeGetKeyCodeState(long ptr,
206             int deviceId, int sourceMask, int keyCode);
nativeGetSwitchState(long ptr, int deviceId, int sourceMask, int sw)207     private static native int nativeGetSwitchState(long ptr,
208             int deviceId, int sourceMask, int sw);
nativeHasKeys(long ptr, int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists)209     private static native boolean nativeHasKeys(long ptr,
210             int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
nativeRegisterInputChannel(long ptr, InputChannel inputChannel)211     private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel);
nativeRegisterInputMonitor(long ptr, InputChannel inputChannel, int displayId, boolean isGestureMonitor)212     private static native void nativeRegisterInputMonitor(long ptr, InputChannel inputChannel,
213             int displayId, boolean isGestureMonitor);
nativeUnregisterInputChannel(long ptr, InputChannel inputChannel)214     private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
nativePilferPointers(long ptr, IBinder token)215     private static native void nativePilferPointers(long ptr, IBinder token);
nativeSetInputFilterEnabled(long ptr, boolean enable)216     private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
nativeSetInTouchMode(long ptr, boolean inTouchMode)217     private static native void nativeSetInTouchMode(long ptr, boolean inTouchMode);
nativeInjectInputEvent(long ptr, InputEvent event, int injectorPid, int injectorUid, int syncMode, int timeoutMillis, int policyFlags)218     private static native int nativeInjectInputEvent(long ptr, InputEvent event,
219             int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
220             int policyFlags);
nativeVerifyInputEvent(long ptr, InputEvent event)221     private static native VerifiedInputEvent nativeVerifyInputEvent(long ptr, InputEvent event);
nativeToggleCapsLock(long ptr, int deviceId)222     private static native void nativeToggleCapsLock(long ptr, int deviceId);
nativeDisplayRemoved(long ptr, int displayId)223     private static native void nativeDisplayRemoved(long ptr, int displayId);
nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen)224     private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
nativeSetSystemUiVisibility(long ptr, int visibility)225     private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
nativeSetFocusedApplication(long ptr, int displayId, InputApplicationHandle application)226     private static native void nativeSetFocusedApplication(long ptr,
227             int displayId, InputApplicationHandle application);
nativeSetFocusedDisplay(long ptr, int displayId)228     private static native void nativeSetFocusedDisplay(long ptr, int displayId);
nativeTransferTouchFocus(long ptr, IBinder fromChannelToken, IBinder toChannelToken)229     private static native boolean nativeTransferTouchFocus(long ptr,
230             IBinder fromChannelToken, IBinder toChannelToken);
nativeSetPointerSpeed(long ptr, int speed)231     private static native void nativeSetPointerSpeed(long ptr, int speed);
nativeSetShowTouches(long ptr, boolean enabled)232     private static native void nativeSetShowTouches(long ptr, boolean enabled);
nativeSetInteractive(long ptr, boolean interactive)233     private static native void nativeSetInteractive(long ptr, boolean interactive);
nativeReloadCalibration(long ptr)234     private static native void nativeReloadCalibration(long ptr);
nativeVibrate(long ptr, int deviceId, long[] pattern, int repeat, int token)235     private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
236             int repeat, int token);
nativeCancelVibrate(long ptr, int deviceId, int token)237     private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
nativeReloadKeyboardLayouts(long ptr)238     private static native void nativeReloadKeyboardLayouts(long ptr);
nativeReloadDeviceAliases(long ptr)239     private static native void nativeReloadDeviceAliases(long ptr);
nativeDump(long ptr)240     private static native String nativeDump(long ptr);
nativeMonitor(long ptr)241     private static native void nativeMonitor(long ptr);
nativeIsInputDeviceEnabled(long ptr, int deviceId)242     private static native boolean nativeIsInputDeviceEnabled(long ptr, int deviceId);
nativeEnableInputDevice(long ptr, int deviceId)243     private static native void nativeEnableInputDevice(long ptr, int deviceId);
nativeDisableInputDevice(long ptr, int deviceId)244     private static native void nativeDisableInputDevice(long ptr, int deviceId);
nativeSetPointerIconType(long ptr, int iconId)245     private static native void nativeSetPointerIconType(long ptr, int iconId);
nativeReloadPointerIcons(long ptr)246     private static native void nativeReloadPointerIcons(long ptr);
nativeSetCustomPointerIcon(long ptr, PointerIcon icon)247     private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
nativeSetPointerCapture(long ptr, boolean detached)248     private static native void nativeSetPointerCapture(long ptr, boolean detached);
nativeCanDispatchToDisplay(long ptr, int deviceId, int displayId)249     private static native boolean nativeCanDispatchToDisplay(long ptr, int deviceId, int displayId);
nativeNotifyPortAssociationsChanged(long ptr)250     private static native void nativeNotifyPortAssociationsChanged(long ptr);
nativeSetMotionClassifierEnabled(long ptr, boolean enabled)251     private static native void nativeSetMotionClassifierEnabled(long ptr, boolean enabled);
252 
253     // Input event injection constants defined in InputDispatcher.h.
254     private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
255     private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
256     private static final int INPUT_EVENT_INJECTION_FAILED = 2;
257     private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
258 
259     // Maximum number of milliseconds to wait for input event injection.
260     private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
261 
262     // Key states (may be returned by queries about the current state of a
263     // particular key code, scan code or switch).
264 
265     /** The key state is unknown or the requested key itself is not supported. */
266     public static final int KEY_STATE_UNKNOWN = -1;
267 
268     /** The key is up. /*/
269     public static final int KEY_STATE_UP = 0;
270 
271     /** The key is down. */
272     public static final int KEY_STATE_DOWN = 1;
273 
274     /** The key is down but is a virtual key press that is being emulated by the system. */
275     public static final int KEY_STATE_VIRTUAL = 2;
276 
277     /** Scan code: Mouse / trackball button. */
278     public static final int BTN_MOUSE = 0x110;
279 
280     // Switch code values must match bionic/libc/kernel/common/linux/input.h
281     /** Switch code: Lid switch.  When set, lid is shut. */
282     public static final int SW_LID = 0x00;
283 
284     /** Switch code: Tablet mode switch.
285      * When set, the device is in tablet mode (i.e. no keyboard is connected).
286      */
287     public static final int SW_TABLET_MODE = 0x01;
288 
289     /** Switch code: Keypad slide.  When set, keyboard is exposed. */
290     public static final int SW_KEYPAD_SLIDE = 0x0a;
291 
292     /** Switch code: Headphone.  When set, headphone is inserted. */
293     public static final int SW_HEADPHONE_INSERT = 0x02;
294 
295     /** Switch code: Microphone.  When set, microphone is inserted. */
296     public static final int SW_MICROPHONE_INSERT = 0x04;
297 
298     /** Switch code: Line out.  When set, Line out (hi-Z) is inserted. */
299     public static final int SW_LINEOUT_INSERT = 0x06;
300 
301     /** Switch code: Headphone/Microphone Jack.  When set, something is inserted. */
302     public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
303 
304     /** Switch code: Camera lens cover. When set the lens is covered. */
305     public static final int SW_CAMERA_LENS_COVER = 0x09;
306 
307     /** Switch code: Microphone. When set it is off. */
308     public static final int SW_MUTE_DEVICE = 0x0e;
309 
310     public static final int SW_LID_BIT = 1 << SW_LID;
311     public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
312     public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
313     public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
314     public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
315     public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
316     public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
317     public static final int SW_JACK_BITS =
318             SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
319     public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
320     public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE;
321 
322     /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
323     final boolean mUseDevInputEventForAudioJack;
324 
InputManagerService(Context context)325     public InputManagerService(Context context) {
326         this.mContext = context;
327         this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
328 
329         mStaticAssociations = loadStaticInputPortAssociations();
330         mUseDevInputEventForAudioJack =
331                 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
332         Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
333                 + mUseDevInputEventForAudioJack);
334         mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
335 
336         String doubleTouchGestureEnablePath = context.getResources().getString(
337                 R.string.config_doubleTouchGestureEnableFile);
338         mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
339             new File(doubleTouchGestureEnablePath);
340 
341         LocalServices.addService(InputManagerInternal.class, new LocalService());
342     }
343 
setWindowManagerCallbacks(WindowManagerCallbacks callbacks)344     public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
345         mWindowManagerCallbacks = callbacks;
346     }
347 
setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks)348     public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
349         mWiredAccessoryCallbacks = callbacks;
350     }
351 
start()352     public void start() {
353         Slog.i(TAG, "Starting input manager");
354         nativeStart(mPtr);
355 
356         // Add ourself to the Watchdog monitors.
357         Watchdog.getInstance().addMonitor(this);
358 
359         registerPointerSpeedSettingObserver();
360         registerShowTouchesSettingObserver();
361         registerAccessibilityLargePointerSettingObserver();
362         registerLongPressTimeoutObserver();
363 
364         mContext.registerReceiver(new BroadcastReceiver() {
365             @Override
366             public void onReceive(Context context, Intent intent) {
367                 updatePointerSpeedFromSettings();
368                 updateShowTouchesFromSettings();
369                 updateAccessibilityLargePointerFromSettings();
370                 updateDeepPressStatusFromSettings("user switched");
371             }
372         }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
373 
374         updatePointerSpeedFromSettings();
375         updateShowTouchesFromSettings();
376         updateAccessibilityLargePointerFromSettings();
377         updateDeepPressStatusFromSettings("just booted");
378     }
379 
380     // TODO(BT) Pass in parameter for bluetooth system
systemRunning()381     public void systemRunning() {
382         if (DEBUG) {
383             Slog.d(TAG, "System ready.");
384         }
385         mNotificationManager = (NotificationManager)mContext.getSystemService(
386                 Context.NOTIFICATION_SERVICE);
387         mSystemReady = true;
388 
389         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
390         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
391         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
392         filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
393         filter.addDataScheme("package");
394         mContext.registerReceiver(new BroadcastReceiver() {
395             @Override
396             public void onReceive(Context context, Intent intent) {
397                 updateKeyboardLayouts();
398             }
399         }, filter, null, mHandler);
400 
401         filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
402         mContext.registerReceiver(new BroadcastReceiver() {
403             @Override
404             public void onReceive(Context context, Intent intent) {
405                 reloadDeviceAliases();
406             }
407         }, filter, null, mHandler);
408 
409         mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
410         mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
411 
412         if (mWiredAccessoryCallbacks != null) {
413             mWiredAccessoryCallbacks.systemReady();
414         }
415     }
416 
reloadKeyboardLayouts()417     private void reloadKeyboardLayouts() {
418         if (DEBUG) {
419             Slog.d(TAG, "Reloading keyboard layouts.");
420         }
421         nativeReloadKeyboardLayouts(mPtr);
422     }
423 
reloadDeviceAliases()424     private void reloadDeviceAliases() {
425         if (DEBUG) {
426             Slog.d(TAG, "Reloading device names.");
427         }
428         nativeReloadDeviceAliases(mPtr);
429     }
430 
setDisplayViewportsInternal(List<DisplayViewport> viewports)431     private void setDisplayViewportsInternal(List<DisplayViewport> viewports) {
432         nativeSetDisplayViewports(mPtr, viewports.toArray(new DisplayViewport[0]));
433     }
434 
435     /**
436      * Gets the current state of a key or button by key code.
437      * @param deviceId The input device id, or -1 to consult all devices.
438      * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
439      * consider all input sources.  An input device is consulted if at least one of its
440      * non-class input source bits matches the specified source mask.
441      * @param keyCode The key code to check.
442      * @return The key state.
443      */
getKeyCodeState(int deviceId, int sourceMask, int keyCode)444     public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
445         return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
446     }
447 
448     /**
449      * Gets the current state of a key or button by scan code.
450      * @param deviceId The input device id, or -1 to consult all devices.
451      * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
452      * consider all input sources.  An input device is consulted if at least one of its
453      * non-class input source bits matches the specified source mask.
454      * @param scanCode The scan code to check.
455      * @return The key state.
456      */
getScanCodeState(int deviceId, int sourceMask, int scanCode)457     public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
458         return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
459     }
460 
461     /**
462      * Gets the current state of a switch by switch code.
463      * @param deviceId The input device id, or -1 to consult all devices.
464      * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
465      * consider all input sources.  An input device is consulted if at least one of its
466      * non-class input source bits matches the specified source mask.
467      * @param switchCode The switch code to check.
468      * @return The switch state.
469      */
getSwitchState(int deviceId, int sourceMask, int switchCode)470     public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
471         return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
472     }
473 
474     /**
475      * Determines whether the specified key codes are supported by a particular device.
476      * @param deviceId The input device id, or -1 to consult all devices.
477      * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
478      * consider all input sources.  An input device is consulted if at least one of its
479      * non-class input source bits matches the specified source mask.
480      * @param keyCodes The array of key codes to check.
481      * @param keyExists An array at least as large as keyCodes whose entries will be set
482      * to true or false based on the presence or absence of support for the corresponding
483      * key codes.
484      * @return True if the lookup was successful, false otherwise.
485      */
486     @Override // Binder call
hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists)487     public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
488         if (keyCodes == null) {
489             throw new IllegalArgumentException("keyCodes must not be null.");
490         }
491         if (keyExists == null || keyExists.length < keyCodes.length) {
492             throw new IllegalArgumentException("keyExists must not be null and must be at "
493                     + "least as large as keyCodes.");
494         }
495 
496         return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
497     }
498 
499     /**
500      * Creates an input channel that will receive all input from the input dispatcher.
501      * @param inputChannelName The input channel name.
502      * @param displayId Target display id.
503      * @return The input channel.
504      */
monitorInput(String inputChannelName, int displayId)505     public InputChannel monitorInput(String inputChannelName, int displayId) {
506         if (inputChannelName == null) {
507             throw new IllegalArgumentException("inputChannelName must not be null.");
508         }
509 
510         if (displayId < Display.DEFAULT_DISPLAY) {
511             throw new IllegalArgumentException("displayId must >= 0.");
512         }
513 
514         InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
515         nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId, false /*isGestureMonitor*/);
516         inputChannels[0].dispose(); // don't need to retain the Java object reference
517         return inputChannels[1];
518     }
519 
520     /**
521      * Creates an input monitor that will receive pointer events for the purposes of system-wide
522      * gesture interpretation.
523      *
524      * @param inputChannelName The input channel name.
525      * @param displayId Target display id.
526      * @return The input channel.
527      */
528     @Override // Binder call
monitorGestureInput(String inputChannelName, int displayId)529     public InputMonitor monitorGestureInput(String inputChannelName, int displayId) {
530         if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT,
531                 "monitorInputRegion()")) {
532             throw new SecurityException("Requires MONITOR_INPUT permission");
533         }
534 
535         Objects.requireNonNull(inputChannelName, "inputChannelName must not be null.");
536 
537         if (displayId < Display.DEFAULT_DISPLAY) {
538             throw new IllegalArgumentException("displayId must >= 0.");
539         }
540 
541         final long ident = Binder.clearCallingIdentity();
542         try {
543             InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
544             InputMonitorHost host = new InputMonitorHost(inputChannels[0]);
545             nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId,
546                     true /*isGestureMonitor*/);
547             return new InputMonitor(inputChannels[1], host);
548         } finally {
549             Binder.restoreCallingIdentity(ident);
550         }
551     }
552 
553     /**
554      * Registers an input channel so that it can be used as an input event target. The channel is
555      * registered with a generated token.
556      *
557      * @param inputChannel The input channel to register.
558      */
registerInputChannel(InputChannel inputChannel)559     public void registerInputChannel(InputChannel inputChannel) {
560         if (inputChannel == null) {
561             throw new IllegalArgumentException("inputChannel must not be null.");
562         }
563 
564         nativeRegisterInputChannel(mPtr, inputChannel);
565     }
566 
567     /**
568      * Unregisters an input channel.
569      * @param inputChannel The input channel to unregister.
570      */
unregisterInputChannel(InputChannel inputChannel)571     public void unregisterInputChannel(InputChannel inputChannel) {
572         if (inputChannel == null) {
573             throw new IllegalArgumentException("inputChannel must not be null.");
574         }
575 
576         nativeUnregisterInputChannel(mPtr, inputChannel);
577     }
578 
579     /**
580      * Sets an input filter that will receive all input events before they are dispatched.
581      * The input filter may then reinterpret input events or inject new ones.
582      *
583      * To ensure consistency, the input dispatcher automatically drops all events
584      * in progress whenever an input filter is installed or uninstalled.  After an input
585      * filter is uninstalled, it can no longer send input events unless it is reinstalled.
586      * Any events it attempts to send after it has been uninstalled will be dropped.
587      *
588      * @param filter The input filter, or null to remove the current filter.
589      */
setInputFilter(IInputFilter filter)590     public void setInputFilter(IInputFilter filter) {
591         synchronized (mInputFilterLock) {
592             final IInputFilter oldFilter = mInputFilter;
593             if (oldFilter == filter) {
594                 return; // nothing to do
595             }
596 
597             if (oldFilter != null) {
598                 mInputFilter = null;
599                 mInputFilterHost.disconnectLocked();
600                 mInputFilterHost = null;
601                 try {
602                     oldFilter.uninstall();
603                 } catch (RemoteException re) {
604                     /* ignore */
605                 }
606             }
607 
608             if (filter != null) {
609                 mInputFilter = filter;
610                 mInputFilterHost = new InputFilterHost();
611                 try {
612                     filter.install(mInputFilterHost);
613                 } catch (RemoteException re) {
614                     /* ignore */
615                 }
616             }
617 
618             nativeSetInputFilterEnabled(mPtr, filter != null);
619         }
620     }
621 
622     /**
623      * Set the state of the touch mode.
624      *
625      * WindowManager remains the source of truth of the touch mode state.
626      * However, we need to keep a copy of this state in input.
627      *
628      * The apps determine the touch mode state. Therefore, a single app will
629      * affect the global state. That state change needs to be propagated to
630      * other apps, when they become focused.
631      *
632      * When input dispatches focus to the apps, the touch mode state
633      * will be sent together with the focus change.
634      *
635      * @param inTouchMode true if the device is in touch mode.
636      */
setInTouchMode(boolean inTouchMode)637     public void setInTouchMode(boolean inTouchMode) {
638         nativeSetInTouchMode(mPtr, inTouchMode);
639     }
640 
641     @Override // Binder call
injectInputEvent(InputEvent event, int mode)642     public boolean injectInputEvent(InputEvent event, int mode) {
643         return injectInputEventInternal(event, mode);
644     }
645 
injectInputEventInternal(InputEvent event, int mode)646     private boolean injectInputEventInternal(InputEvent event, int mode) {
647         if (event == null) {
648             throw new IllegalArgumentException("event must not be null");
649         }
650         if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
651                 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
652                 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
653             throw new IllegalArgumentException("mode is invalid");
654         }
655 
656         final int pid = Binder.getCallingPid();
657         final int uid = Binder.getCallingUid();
658         final long ident = Binder.clearCallingIdentity();
659         final int result;
660         try {
661             result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
662                     INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
663         } finally {
664             Binder.restoreCallingIdentity(ident);
665         }
666         switch (result) {
667             case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
668                 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
669                 throw new SecurityException(
670                         "Injecting to another application requires INJECT_EVENTS permission");
671             case INPUT_EVENT_INJECTION_SUCCEEDED:
672                 return true;
673             case INPUT_EVENT_INJECTION_TIMED_OUT:
674                 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
675                 return false;
676             case INPUT_EVENT_INJECTION_FAILED:
677             default:
678                 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
679                 return false;
680         }
681     }
682 
683     @Override // Binder call
verifyInputEvent(InputEvent event)684     public VerifiedInputEvent verifyInputEvent(InputEvent event) {
685         return nativeVerifyInputEvent(mPtr, event);
686     }
687 
688     /**
689      * Gets information about the input device with the specified id.
690      * @param deviceId The device id.
691      * @return The input device or null if not found.
692      */
693     @Override // Binder call
getInputDevice(int deviceId)694     public InputDevice getInputDevice(int deviceId) {
695         synchronized (mInputDevicesLock) {
696             final int count = mInputDevices.length;
697             for (int i = 0; i < count; i++) {
698                 final InputDevice inputDevice = mInputDevices[i];
699                 if (inputDevice.getId() == deviceId) {
700                     return inputDevice;
701                 }
702             }
703         }
704         return null;
705     }
706 
707     // Binder call
708     @Override
isInputDeviceEnabled(int deviceId)709     public boolean isInputDeviceEnabled(int deviceId) {
710         return nativeIsInputDeviceEnabled(mPtr, deviceId);
711     }
712 
713     // Binder call
714     @Override
enableInputDevice(int deviceId)715     public void enableInputDevice(int deviceId) {
716         if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
717                 "enableInputDevice()")) {
718             throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
719         }
720         nativeEnableInputDevice(mPtr, deviceId);
721     }
722 
723     // Binder call
724     @Override
disableInputDevice(int deviceId)725     public void disableInputDevice(int deviceId) {
726         if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
727                 "disableInputDevice()")) {
728             throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
729         }
730         nativeDisableInputDevice(mPtr, deviceId);
731     }
732 
733     /**
734      * Gets the ids of all input devices in the system.
735      * @return The input device ids.
736      */
737     @Override // Binder call
getInputDeviceIds()738     public int[] getInputDeviceIds() {
739         synchronized (mInputDevicesLock) {
740             final int count = mInputDevices.length;
741             int[] ids = new int[count];
742             for (int i = 0; i < count; i++) {
743                 ids[i] = mInputDevices[i].getId();
744             }
745             return ids;
746         }
747     }
748 
749     /**
750      * Gets all input devices in the system.
751      * @return The array of input devices.
752      */
getInputDevices()753     public InputDevice[] getInputDevices() {
754         synchronized (mInputDevicesLock) {
755             return mInputDevices;
756         }
757     }
758 
759     @Override // Binder call
registerInputDevicesChangedListener(IInputDevicesChangedListener listener)760     public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
761         if (listener == null) {
762             throw new IllegalArgumentException("listener must not be null");
763         }
764 
765         synchronized (mInputDevicesLock) {
766             int callingPid = Binder.getCallingPid();
767             if (mInputDevicesChangedListeners.get(callingPid) != null) {
768                 throw new SecurityException("The calling process has already "
769                         + "registered an InputDevicesChangedListener.");
770             }
771 
772             InputDevicesChangedListenerRecord record =
773                     new InputDevicesChangedListenerRecord(callingPid, listener);
774             try {
775                 IBinder binder = listener.asBinder();
776                 binder.linkToDeath(record, 0);
777             } catch (RemoteException ex) {
778                 // give up
779                 throw new RuntimeException(ex);
780             }
781 
782             mInputDevicesChangedListeners.put(callingPid, record);
783         }
784     }
785 
onInputDevicesChangedListenerDied(int pid)786     private void onInputDevicesChangedListenerDied(int pid) {
787         synchronized (mInputDevicesLock) {
788             mInputDevicesChangedListeners.remove(pid);
789         }
790     }
791 
792     // Must be called on handler.
deliverInputDevicesChanged(InputDevice[] oldInputDevices)793     private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
794         // Scan for changes.
795         int numFullKeyboardsAdded = 0;
796         mTempInputDevicesChangedListenersToNotify.clear();
797         mTempFullKeyboards.clear();
798         final int numListeners;
799         final int[] deviceIdAndGeneration;
800         synchronized (mInputDevicesLock) {
801             if (!mInputDevicesChangedPending) {
802                 return;
803             }
804             mInputDevicesChangedPending = false;
805 
806             numListeners = mInputDevicesChangedListeners.size();
807             for (int i = 0; i < numListeners; i++) {
808                 mTempInputDevicesChangedListenersToNotify.add(
809                         mInputDevicesChangedListeners.valueAt(i));
810             }
811 
812             final int numDevices = mInputDevices.length;
813             deviceIdAndGeneration = new int[numDevices * 2];
814             for (int i = 0; i < numDevices; i++) {
815                 final InputDevice inputDevice = mInputDevices[i];
816                 deviceIdAndGeneration[i * 2] = inputDevice.getId();
817                 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
818 
819                 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
820                     if (!containsInputDeviceWithDescriptor(oldInputDevices,
821                             inputDevice.getDescriptor())) {
822                         mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
823                     } else {
824                         mTempFullKeyboards.add(inputDevice);
825                     }
826                 }
827             }
828         }
829 
830         // Notify listeners.
831         for (int i = 0; i < numListeners; i++) {
832             mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
833                     deviceIdAndGeneration);
834         }
835         mTempInputDevicesChangedListenersToNotify.clear();
836 
837         // Check for missing keyboard layouts.
838         List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
839         final int numFullKeyboards = mTempFullKeyboards.size();
840         synchronized (mDataStore) {
841             for (int i = 0; i < numFullKeyboards; i++) {
842                 final InputDevice inputDevice = mTempFullKeyboards.get(i);
843                 String layout =
844                     getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
845                 if (layout == null) {
846                     layout = getDefaultKeyboardLayout(inputDevice);
847                     if (layout != null) {
848                         setCurrentKeyboardLayoutForInputDevice(
849                                 inputDevice.getIdentifier(), layout);
850                     }
851                 }
852                 if (layout == null) {
853                     keyboardsMissingLayout.add(inputDevice);
854                 }
855             }
856         }
857 
858         if (mNotificationManager != null) {
859             if (!keyboardsMissingLayout.isEmpty()) {
860                 if (keyboardsMissingLayout.size() > 1) {
861                     // We have more than one keyboard missing a layout, so drop the
862                     // user at the generic input methods page so they can pick which
863                     // one to set.
864                     showMissingKeyboardLayoutNotification(null);
865                 } else {
866                     showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
867                 }
868             } else if (mKeyboardLayoutNotificationShown) {
869                 hideMissingKeyboardLayoutNotification();
870             }
871         }
872         mTempFullKeyboards.clear();
873     }
874 
getDefaultKeyboardLayout(final InputDevice d)875     private String getDefaultKeyboardLayout(final InputDevice d) {
876         final Locale systemLocale = mContext.getResources().getConfiguration().locale;
877         // If our locale doesn't have a language for some reason, then we don't really have a
878         // reasonable default.
879         if (TextUtils.isEmpty(systemLocale.getLanguage())) {
880             return null;
881         }
882         final List<KeyboardLayout> layouts = new ArrayList<>();
883         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
884             @Override
885             public void visitKeyboardLayout(Resources resources,
886                     int keyboardLayoutResId, KeyboardLayout layout) {
887                 // Only select a default when we know the layout is appropriate. For now, this
888                 // means its a custom layout for a specific keyboard.
889                 if (layout.getVendorId() != d.getVendorId()
890                         || layout.getProductId() != d.getProductId()) {
891                     return;
892                 }
893                 final LocaleList locales = layout.getLocales();
894                 final int numLocales = locales.size();
895                 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
896                     if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
897                         layouts.add(layout);
898                         break;
899                     }
900                 }
901             }
902         });
903 
904         if (layouts.isEmpty()) {
905             return null;
906         }
907 
908         // First sort so that ones with higher priority are listed at the top
909         Collections.sort(layouts);
910         // Next we want to try to find an exact match of language, country and variant.
911         final int N = layouts.size();
912         for (int i = 0; i < N; i++) {
913             KeyboardLayout layout = layouts.get(i);
914             final LocaleList locales = layout.getLocales();
915             final int numLocales = locales.size();
916             for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
917                 final Locale locale = locales.get(localeIndex);
918                 if (locale.getCountry().equals(systemLocale.getCountry())
919                         && locale.getVariant().equals(systemLocale.getVariant())) {
920                     return layout.getDescriptor();
921                 }
922             }
923         }
924         // Then try an exact match of language and country
925         for (int i = 0; i < N; i++) {
926             KeyboardLayout layout = layouts.get(i);
927             final LocaleList locales = layout.getLocales();
928             final int numLocales = locales.size();
929             for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
930                 final Locale locale = locales.get(localeIndex);
931                 if (locale.getCountry().equals(systemLocale.getCountry())) {
932                     return layout.getDescriptor();
933                 }
934             }
935         }
936 
937         // Give up and just use the highest priority layout with matching language
938         return layouts.get(0).getDescriptor();
939     }
940 
isCompatibleLocale(Locale systemLocale, Locale keyboardLocale)941     private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
942         // Different languages are never compatible
943         if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
944             return false;
945         }
946         // If both the system and the keyboard layout have a country specifier, they must be equal.
947         if (!TextUtils.isEmpty(systemLocale.getCountry())
948                 && !TextUtils.isEmpty(keyboardLocale.getCountry())
949                 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
950             return false;
951         }
952         return true;
953     }
954 
955     @Override // Binder call & native callback
getTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation)956     public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
957             int surfaceRotation) {
958         if (inputDeviceDescriptor == null) {
959             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
960         }
961 
962         synchronized (mDataStore) {
963             return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
964         }
965     }
966 
967     @Override // Binder call
setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation, TouchCalibration calibration)968     public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
969             TouchCalibration calibration) {
970         if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
971                 "setTouchCalibrationForInputDevice()")) {
972             throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
973         }
974         if (inputDeviceDescriptor == null) {
975             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
976         }
977         if (calibration == null) {
978             throw new IllegalArgumentException("calibration must not be null");
979         }
980         if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
981             throw new IllegalArgumentException("surfaceRotation value out of bounds");
982         }
983 
984         synchronized (mDataStore) {
985             try {
986                 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
987                         calibration)) {
988                     nativeReloadCalibration(mPtr);
989                 }
990             } finally {
991                 mDataStore.saveIfNeeded();
992             }
993         }
994     }
995 
996     @Override // Binder call
isInTabletMode()997     public int isInTabletMode() {
998         if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
999                 "isInTabletMode()")) {
1000             throw new SecurityException("Requires TABLET_MODE permission");
1001         }
1002         return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
1003     }
1004 
1005     @Override // Binder call
isMicMuted()1006     public int isMicMuted() {
1007         return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MUTE_DEVICE);
1008     }
1009 
1010     @Override // Binder call
registerTabletModeChangedListener(ITabletModeChangedListener listener)1011     public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
1012         if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
1013                 "registerTabletModeChangedListener()")) {
1014             throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
1015         }
1016         if (listener == null) {
1017             throw new IllegalArgumentException("listener must not be null");
1018         }
1019 
1020         synchronized (mTabletModeLock) {
1021             final int callingPid = Binder.getCallingPid();
1022             if (mTabletModeChangedListeners.get(callingPid) != null) {
1023                 throw new IllegalStateException("The calling process has already registered "
1024                         + "a TabletModeChangedListener.");
1025             }
1026             TabletModeChangedListenerRecord record =
1027                     new TabletModeChangedListenerRecord(callingPid, listener);
1028             try {
1029                 IBinder binder = listener.asBinder();
1030                 binder.linkToDeath(record, 0);
1031             } catch (RemoteException ex) {
1032                 throw new RuntimeException(ex);
1033             }
1034             mTabletModeChangedListeners.put(callingPid, record);
1035         }
1036     }
1037 
onTabletModeChangedListenerDied(int pid)1038     private void onTabletModeChangedListenerDied(int pid) {
1039         synchronized (mTabletModeLock) {
1040             mTabletModeChangedListeners.remove(pid);
1041         }
1042     }
1043 
1044     // Must be called on handler
deliverTabletModeChanged(long whenNanos, boolean inTabletMode)1045     private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
1046         mTempTabletModeChangedListenersToNotify.clear();
1047         final int numListeners;
1048         synchronized (mTabletModeLock) {
1049             numListeners = mTabletModeChangedListeners.size();
1050             for (int i = 0; i < numListeners; i++) {
1051                 mTempTabletModeChangedListenersToNotify.add(
1052                         mTabletModeChangedListeners.valueAt(i));
1053             }
1054         }
1055         for (int i = 0; i < numListeners; i++) {
1056             mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
1057                     whenNanos, inTabletMode);
1058         }
1059     }
1060 
1061     // Must be called on handler.
showMissingKeyboardLayoutNotification(InputDevice device)1062     private void showMissingKeyboardLayoutNotification(InputDevice device) {
1063         if (!mKeyboardLayoutNotificationShown) {
1064             final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
1065             if (device != null) {
1066                 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
1067             }
1068             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1069                     | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
1070                     | Intent.FLAG_ACTIVITY_CLEAR_TOP);
1071             final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
1072                     intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
1073 
1074             Resources r = mContext.getResources();
1075             Notification notification =
1076                     new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
1077                             .setContentTitle(r.getString(
1078                                     R.string.select_keyboard_layout_notification_title))
1079                             .setContentText(r.getString(
1080                                     R.string.select_keyboard_layout_notification_message))
1081                             .setContentIntent(keyboardLayoutIntent)
1082                             .setSmallIcon(R.drawable.ic_settings_language)
1083                             .setColor(mContext.getColor(
1084                                     com.android.internal.R.color.system_notification_accent_color))
1085                             .build();
1086             mNotificationManager.notifyAsUser(null,
1087                     SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
1088                     notification, UserHandle.ALL);
1089             mKeyboardLayoutNotificationShown = true;
1090         }
1091     }
1092 
1093     // Must be called on handler.
hideMissingKeyboardLayoutNotification()1094     private void hideMissingKeyboardLayoutNotification() {
1095         if (mKeyboardLayoutNotificationShown) {
1096             mKeyboardLayoutNotificationShown = false;
1097             mNotificationManager.cancelAsUser(null,
1098                     SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
1099                     UserHandle.ALL);
1100         }
1101     }
1102 
1103     // Must be called on handler.
updateKeyboardLayouts()1104     private void updateKeyboardLayouts() {
1105         // Scan all input devices state for keyboard layouts that have been uninstalled.
1106         final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
1107         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1108             @Override
1109             public void visitKeyboardLayout(Resources resources,
1110                     int keyboardLayoutResId, KeyboardLayout layout) {
1111                 availableKeyboardLayouts.add(layout.getDescriptor());
1112             }
1113         });
1114         synchronized (mDataStore) {
1115             try {
1116                 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
1117             } finally {
1118                 mDataStore.saveIfNeeded();
1119             }
1120         }
1121 
1122         // Reload keyboard layouts.
1123         reloadKeyboardLayouts();
1124     }
1125 
containsInputDeviceWithDescriptor(InputDevice[] inputDevices, String descriptor)1126     private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
1127             String descriptor) {
1128         final int numDevices = inputDevices.length;
1129         for (int i = 0; i < numDevices; i++) {
1130             final InputDevice inputDevice = inputDevices[i];
1131             if (inputDevice.getDescriptor().equals(descriptor)) {
1132                 return true;
1133             }
1134         }
1135         return false;
1136     }
1137 
1138     @Override // Binder call
getKeyboardLayouts()1139     public KeyboardLayout[] getKeyboardLayouts() {
1140         final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
1141         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1142             @Override
1143             public void visitKeyboardLayout(Resources resources,
1144                     int keyboardLayoutResId, KeyboardLayout layout) {
1145                 list.add(layout);
1146             }
1147         });
1148         return list.toArray(new KeyboardLayout[list.size()]);
1149     }
1150 
1151     @Override // Binder call
getKeyboardLayoutsForInputDevice( final InputDeviceIdentifier identifier)1152     public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1153             final InputDeviceIdentifier identifier) {
1154         final String[] enabledLayoutDescriptors =
1155             getEnabledKeyboardLayoutsForInputDevice(identifier);
1156         final ArrayList<KeyboardLayout> enabledLayouts =
1157             new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length);
1158         final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>();
1159         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1160             boolean mHasSeenDeviceSpecificLayout;
1161 
1162             @Override
1163             public void visitKeyboardLayout(Resources resources,
1164                     int keyboardLayoutResId, KeyboardLayout layout) {
1165                 // First check if it's enabled. If the keyboard layout is enabled then we always
1166                 // want to return it as a possible layout for the device.
1167                 for (String s : enabledLayoutDescriptors) {
1168                     if (s != null && s.equals(layout.getDescriptor())) {
1169                         enabledLayouts.add(layout);
1170                         return;
1171                     }
1172                 }
1173                 // Next find any potential layouts that aren't yet enabled for the device. For
1174                 // devices that have special layouts we assume there's a reason that the generic
1175                 // layouts don't work for them so we don't want to return them since it's likely
1176                 // to result in a poor user experience.
1177                 if (layout.getVendorId() == identifier.getVendorId()
1178                         && layout.getProductId() == identifier.getProductId()) {
1179                     if (!mHasSeenDeviceSpecificLayout) {
1180                         mHasSeenDeviceSpecificLayout = true;
1181                         potentialLayouts.clear();
1182                     }
1183                     potentialLayouts.add(layout);
1184                 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
1185                         && !mHasSeenDeviceSpecificLayout) {
1186                     potentialLayouts.add(layout);
1187                 }
1188             }
1189         });
1190         final int enabledLayoutSize = enabledLayouts.size();
1191         final int potentialLayoutSize = potentialLayouts.size();
1192         KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
1193         enabledLayouts.toArray(layouts);
1194         for (int i = 0; i < potentialLayoutSize; i++) {
1195             layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
1196         }
1197         return layouts;
1198     }
1199 
1200     @Override // Binder call
getKeyboardLayout(String keyboardLayoutDescriptor)1201     public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
1202         if (keyboardLayoutDescriptor == null) {
1203             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1204         }
1205 
1206         final KeyboardLayout[] result = new KeyboardLayout[1];
1207         visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1208             @Override
1209             public void visitKeyboardLayout(Resources resources,
1210                     int keyboardLayoutResId, KeyboardLayout layout) {
1211                 result[0] = layout;
1212             }
1213         });
1214         if (result[0] == null) {
1215             Slog.w(TAG, "Could not get keyboard layout with descriptor '"
1216                     + keyboardLayoutDescriptor + "'.");
1217         }
1218         return result[0];
1219     }
1220 
visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor)1221     private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
1222         final PackageManager pm = mContext.getPackageManager();
1223         Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
1224         for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
1225                 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
1226                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
1227             final ActivityInfo activityInfo = resolveInfo.activityInfo;
1228             final int priority = resolveInfo.priority;
1229             visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
1230         }
1231     }
1232 
visitKeyboardLayout(String keyboardLayoutDescriptor, KeyboardLayoutVisitor visitor)1233     private void visitKeyboardLayout(String keyboardLayoutDescriptor,
1234             KeyboardLayoutVisitor visitor) {
1235         KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
1236         if (d != null) {
1237             final PackageManager pm = mContext.getPackageManager();
1238             try {
1239                 ActivityInfo receiver = pm.getReceiverInfo(
1240                         new ComponentName(d.packageName, d.receiverName),
1241                         PackageManager.GET_META_DATA
1242                                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1243                                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
1244                 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
1245             } catch (NameNotFoundException ex) {
1246             }
1247         }
1248     }
1249 
visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor)1250     private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
1251             String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
1252         Bundle metaData = receiver.metaData;
1253         if (metaData == null) {
1254             return;
1255         }
1256 
1257         int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1258         if (configResId == 0) {
1259             Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
1260                     + "' on receiver " + receiver.packageName + "/" + receiver.name);
1261             return;
1262         }
1263 
1264         CharSequence receiverLabel = receiver.loadLabel(pm);
1265         String collection = receiverLabel != null ? receiverLabel.toString() : "";
1266         int priority;
1267         if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1268             priority = requestedPriority;
1269         } else {
1270             priority = 0;
1271         }
1272 
1273         try {
1274             Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1275             XmlResourceParser parser = resources.getXml(configResId);
1276             try {
1277                 XmlUtils.beginDocument(parser, "keyboard-layouts");
1278 
1279                 for (;;) {
1280                     XmlUtils.nextElement(parser);
1281                     String element = parser.getName();
1282                     if (element == null) {
1283                         break;
1284                     }
1285                     if (element.equals("keyboard-layout")) {
1286                         TypedArray a = resources.obtainAttributes(
1287                                 parser, com.android.internal.R.styleable.KeyboardLayout);
1288                         try {
1289                             String name = a.getString(
1290                                     com.android.internal.R.styleable.KeyboardLayout_name);
1291                             String label = a.getString(
1292                                     com.android.internal.R.styleable.KeyboardLayout_label);
1293                             int keyboardLayoutResId = a.getResourceId(
1294                                     com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1295                                     0);
1296                             String languageTags = a.getString(
1297                                     com.android.internal.R.styleable.KeyboardLayout_locale);
1298                             LocaleList locales = getLocalesFromLanguageTags(languageTags);
1299                             int vid = a.getInt(
1300                                     com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
1301                             int pid = a.getInt(
1302                                     com.android.internal.R.styleable.KeyboardLayout_productId, -1);
1303 
1304                             if (name == null || label == null || keyboardLayoutResId == 0) {
1305                                 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
1306                                         + "attributes in keyboard layout "
1307                                         + "resource from receiver "
1308                                         + receiver.packageName + "/" + receiver.name);
1309                             } else {
1310                                 String descriptor = KeyboardLayoutDescriptor.format(
1311                                         receiver.packageName, receiver.name, name);
1312                                 if (keyboardName == null || name.equals(keyboardName)) {
1313                                     KeyboardLayout layout = new KeyboardLayout(
1314                                             descriptor, label, collection, priority,
1315                                             locales, vid, pid);
1316                                     visitor.visitKeyboardLayout(
1317                                             resources, keyboardLayoutResId, layout);
1318                                 }
1319                             }
1320                         } finally {
1321                             a.recycle();
1322                         }
1323                     } else {
1324                         Slog.w(TAG, "Skipping unrecognized element '" + element
1325                                 + "' in keyboard layout resource from receiver "
1326                                 + receiver.packageName + "/" + receiver.name);
1327                     }
1328                 }
1329             } finally {
1330                 parser.close();
1331             }
1332         } catch (Exception ex) {
1333             Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
1334                     + receiver.packageName + "/" + receiver.name, ex);
1335         }
1336     }
1337 
1338     @NonNull
getLocalesFromLanguageTags(String languageTags)1339     private static LocaleList getLocalesFromLanguageTags(String languageTags) {
1340         if (TextUtils.isEmpty(languageTags)) {
1341             return LocaleList.getEmptyLocaleList();
1342         }
1343         return LocaleList.forLanguageTags(languageTags.replace('|', ','));
1344     }
1345 
1346     /**
1347      * Builds a layout descriptor for the vendor/product. This returns the
1348      * descriptor for ids that aren't useful (such as the default 0, 0).
1349      */
getLayoutDescriptor(InputDeviceIdentifier identifier)1350     private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1351         if (identifier == null || identifier.getDescriptor() == null) {
1352             throw new IllegalArgumentException("identifier and descriptor must not be null");
1353         }
1354 
1355         if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1356             return identifier.getDescriptor();
1357         }
1358         StringBuilder bob = new StringBuilder();
1359         bob.append("vendor:").append(identifier.getVendorId());
1360         bob.append(",product:").append(identifier.getProductId());
1361         return bob.toString();
1362     }
1363 
1364     @Override // Binder call
getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier)1365     public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1366 
1367         String key = getLayoutDescriptor(identifier);
1368         synchronized (mDataStore) {
1369             String layout = null;
1370             // try loading it using the layout descriptor if we have it
1371             layout = mDataStore.getCurrentKeyboardLayout(key);
1372             if (layout == null && !key.equals(identifier.getDescriptor())) {
1373                 // if it doesn't exist fall back to the device descriptor
1374                 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1375             }
1376             if (DEBUG) {
1377                 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1378                         + layout);
1379             }
1380             return layout;
1381         }
1382     }
1383 
1384     @Override // Binder call
setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1385     public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1386             String keyboardLayoutDescriptor) {
1387         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1388                 "setCurrentKeyboardLayoutForInputDevice()")) {
1389             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1390         }
1391         if (keyboardLayoutDescriptor == null) {
1392             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1393         }
1394 
1395         String key = getLayoutDescriptor(identifier);
1396         synchronized (mDataStore) {
1397             try {
1398                 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1399                     if (DEBUG) {
1400                         Slog.d(TAG, "Saved keyboard layout using " + key);
1401                     }
1402                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1403                 }
1404             } finally {
1405                 mDataStore.saveIfNeeded();
1406             }
1407         }
1408     }
1409 
1410     @Override // Binder call
getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier)1411     public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
1412         String key = getLayoutDescriptor(identifier);
1413         synchronized (mDataStore) {
1414             String[] layouts = mDataStore.getKeyboardLayouts(key);
1415             if ((layouts == null || layouts.length == 0)
1416                     && !key.equals(identifier.getDescriptor())) {
1417                 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1418             }
1419             return layouts;
1420         }
1421     }
1422 
1423     @Override // Binder call
addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1424     public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1425             String keyboardLayoutDescriptor) {
1426         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1427                 "addKeyboardLayoutForInputDevice()")) {
1428             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1429         }
1430         if (keyboardLayoutDescriptor == null) {
1431             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1432         }
1433 
1434         String key = getLayoutDescriptor(identifier);
1435         synchronized (mDataStore) {
1436             try {
1437                 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1438                 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1439                     oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1440                 }
1441                 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
1442                         && !Objects.equals(oldLayout,
1443                                 mDataStore.getCurrentKeyboardLayout(key))) {
1444                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1445                 }
1446             } finally {
1447                 mDataStore.saveIfNeeded();
1448             }
1449         }
1450     }
1451 
1452     @Override // Binder call
removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1453     public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1454             String keyboardLayoutDescriptor) {
1455         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1456                 "removeKeyboardLayoutForInputDevice()")) {
1457             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1458         }
1459         if (keyboardLayoutDescriptor == null) {
1460             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1461         }
1462 
1463         String key = getLayoutDescriptor(identifier);
1464         synchronized (mDataStore) {
1465             try {
1466                 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1467                 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1468                     oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1469                 }
1470                 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1471                 if (!key.equals(identifier.getDescriptor())) {
1472                     // We need to remove from both places to ensure it is gone
1473                     removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1474                             keyboardLayoutDescriptor);
1475                 }
1476                 if (removed && !Objects.equals(oldLayout,
1477                                 mDataStore.getCurrentKeyboardLayout(key))) {
1478                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1479                 }
1480             } finally {
1481                 mDataStore.saveIfNeeded();
1482             }
1483         }
1484     }
1485 
switchKeyboardLayout(int deviceId, int direction)1486     public void switchKeyboardLayout(int deviceId, int direction) {
1487         mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
1488     }
1489 
1490     // Must be called on handler.
handleSwitchKeyboardLayout(int deviceId, int direction)1491     private void handleSwitchKeyboardLayout(int deviceId, int direction) {
1492         final InputDevice device = getInputDevice(deviceId);
1493         if (device != null) {
1494             final boolean changed;
1495             final String keyboardLayoutDescriptor;
1496 
1497             String key = getLayoutDescriptor(device.getIdentifier());
1498             synchronized (mDataStore) {
1499                 try {
1500                     changed = mDataStore.switchKeyboardLayout(key, direction);
1501                     keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
1502                             key);
1503                 } finally {
1504                     mDataStore.saveIfNeeded();
1505                 }
1506             }
1507 
1508             if (changed) {
1509                 if (mSwitchedKeyboardLayoutToast != null) {
1510                     mSwitchedKeyboardLayoutToast.cancel();
1511                     mSwitchedKeyboardLayoutToast = null;
1512                 }
1513                 if (keyboardLayoutDescriptor != null) {
1514                     KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
1515                     if (keyboardLayout != null) {
1516                         mSwitchedKeyboardLayoutToast = Toast.makeText(
1517                                 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
1518                         mSwitchedKeyboardLayoutToast.show();
1519                     }
1520                 }
1521 
1522                 reloadKeyboardLayouts();
1523             }
1524         }
1525     }
1526 
setFocusedApplication(int displayId, InputApplicationHandle application)1527     public void setFocusedApplication(int displayId, InputApplicationHandle application) {
1528         nativeSetFocusedApplication(mPtr, displayId, application);
1529     }
1530 
setFocusedDisplay(int displayId)1531     public void setFocusedDisplay(int displayId) {
1532         nativeSetFocusedDisplay(mPtr, displayId);
1533     }
1534 
1535     /** Clean up input window handles of the given display. */
onDisplayRemoved(int displayId)1536     public void onDisplayRemoved(int displayId) {
1537         nativeDisplayRemoved(mPtr, displayId);
1538     }
1539 
1540     @Override
requestPointerCapture(IBinder windowToken, boolean enabled)1541     public void requestPointerCapture(IBinder windowToken, boolean enabled) {
1542         boolean requestConfigurationRefresh =
1543                 mWindowManagerCallbacks.requestPointerCapture(windowToken, enabled);
1544         if (requestConfigurationRefresh) {
1545             nativeSetPointerCapture(mPtr, enabled);
1546         }
1547     }
1548 
setInputDispatchMode(boolean enabled, boolean frozen)1549     public void setInputDispatchMode(boolean enabled, boolean frozen) {
1550         nativeSetInputDispatchMode(mPtr, enabled, frozen);
1551     }
1552 
setSystemUiVisibility(int visibility)1553     public void setSystemUiVisibility(int visibility) {
1554         nativeSetSystemUiVisibility(mPtr, visibility);
1555     }
1556 
1557     /**
1558      * Atomically transfers touch focus from one window to another as identified by
1559      * their input channels.  It is possible for multiple windows to have
1560      * touch focus if they support split touch dispatch
1561      * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1562      * method only transfers touch focus of the specified window without affecting
1563      * other windows that may also have touch focus at the same time.
1564      * @param fromChannel The channel of a window that currently has touch focus.
1565      * @param toChannel The channel of the window that should receive touch focus in
1566      * place of the first.
1567      * @return True if the transfer was successful.  False if the window with the
1568      * specified channel did not actually have touch focus at the time of the request.
1569      */
transferTouchFocus(@onNull InputChannel fromChannel, @NonNull InputChannel toChannel)1570     public boolean transferTouchFocus(@NonNull InputChannel fromChannel,
1571             @NonNull InputChannel toChannel) {
1572         return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken());
1573     }
1574 
1575     /**
1576      * Atomically transfers touch focus from one window to another as identified by
1577      * their input channels.  It is possible for multiple windows to have
1578      * touch focus if they support split touch dispatch
1579      * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1580      * method only transfers touch focus of the specified window without affecting
1581      * other windows that may also have touch focus at the same time.
1582      * @param fromChannelToken The channel token of a window that currently has touch focus.
1583      * @param toChannelToken The channel token of the window that should receive touch focus in
1584      * place of the first.
1585      * @return True if the transfer was successful.  False if the window with the
1586      * specified channel did not actually have touch focus at the time of the request.
1587      */
transferTouchFocus(@onNull IBinder fromChannelToken, @NonNull IBinder toChannelToken)1588     public boolean transferTouchFocus(@NonNull IBinder fromChannelToken,
1589             @NonNull IBinder toChannelToken) {
1590         Objects.nonNull(fromChannelToken);
1591         Objects.nonNull(toChannelToken);
1592         return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken);
1593     }
1594 
1595     @Override // Binder call
tryPointerSpeed(int speed)1596     public void tryPointerSpeed(int speed) {
1597         if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1598                 "tryPointerSpeed()")) {
1599             throw new SecurityException("Requires SET_POINTER_SPEED permission");
1600         }
1601 
1602         if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1603             throw new IllegalArgumentException("speed out of range");
1604         }
1605 
1606         setPointerSpeedUnchecked(speed);
1607     }
1608 
updatePointerSpeedFromSettings()1609     private void updatePointerSpeedFromSettings() {
1610         int speed = getPointerSpeedSetting();
1611         setPointerSpeedUnchecked(speed);
1612     }
1613 
setPointerSpeedUnchecked(int speed)1614     private void setPointerSpeedUnchecked(int speed) {
1615         speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1616                 InputManager.MAX_POINTER_SPEED);
1617         nativeSetPointerSpeed(mPtr, speed);
1618     }
1619 
registerPointerSpeedSettingObserver()1620     private void registerPointerSpeedSettingObserver() {
1621         mContext.getContentResolver().registerContentObserver(
1622                 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
1623                 new ContentObserver(mHandler) {
1624                     @Override
1625                     public void onChange(boolean selfChange) {
1626                         updatePointerSpeedFromSettings();
1627                     }
1628                 }, UserHandle.USER_ALL);
1629     }
1630 
getPointerSpeedSetting()1631     private int getPointerSpeedSetting() {
1632         int speed = InputManager.DEFAULT_POINTER_SPEED;
1633         try {
1634             speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1635                     Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
1636         } catch (SettingNotFoundException snfe) {
1637         }
1638         return speed;
1639     }
1640 
updateShowTouchesFromSettings()1641     private void updateShowTouchesFromSettings() {
1642         int setting = getShowTouchesSetting(0);
1643         nativeSetShowTouches(mPtr, setting != 0);
1644     }
1645 
registerShowTouchesSettingObserver()1646     private void registerShowTouchesSettingObserver() {
1647         mContext.getContentResolver().registerContentObserver(
1648                 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
1649                 new ContentObserver(mHandler) {
1650                     @Override
1651                     public void onChange(boolean selfChange) {
1652                         updateShowTouchesFromSettings();
1653                     }
1654                 }, UserHandle.USER_ALL);
1655     }
1656 
updateAccessibilityLargePointerFromSettings()1657     private void updateAccessibilityLargePointerFromSettings() {
1658         final int accessibilityConfig = Settings.Secure.getIntForUser(
1659                 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1660                 0, UserHandle.USER_CURRENT);
1661         PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
1662         nativeReloadPointerIcons(mPtr);
1663     }
1664 
registerAccessibilityLargePointerSettingObserver()1665     private void registerAccessibilityLargePointerSettingObserver() {
1666         mContext.getContentResolver().registerContentObserver(
1667                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1668                 new ContentObserver(mHandler) {
1669                     @Override
1670                     public void onChange(boolean selfChange) {
1671                         updateAccessibilityLargePointerFromSettings();
1672                     }
1673                 }, UserHandle.USER_ALL);
1674     }
1675 
updateDeepPressStatusFromSettings(String reason)1676     private void updateDeepPressStatusFromSettings(String reason) {
1677         // Not using ViewConfiguration.getLongPressTimeout here because it may return a stale value
1678         final int timeout = Settings.Secure.getIntForUser(mContext.getContentResolver(),
1679                 Settings.Secure.LONG_PRESS_TIMEOUT, ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT,
1680                 UserHandle.USER_CURRENT);
1681         final boolean featureEnabledFlag =
1682                 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
1683                         DEEP_PRESS_ENABLED, true /* default */);
1684         final boolean enabled =
1685                 featureEnabledFlag && timeout <= ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT;
1686         Log.i(TAG,
1687                 (enabled ? "Enabling" : "Disabling") + " motion classifier because " + reason
1688                 + ": feature " + (featureEnabledFlag ? "enabled" : "disabled")
1689                 + ", long press timeout = " + timeout);
1690         nativeSetMotionClassifierEnabled(mPtr, enabled);
1691     }
1692 
registerLongPressTimeoutObserver()1693     private void registerLongPressTimeoutObserver() {
1694         mContext.getContentResolver().registerContentObserver(
1695                 Settings.Secure.getUriFor(Settings.Secure.LONG_PRESS_TIMEOUT), true,
1696                 new ContentObserver(mHandler) {
1697                     @Override
1698                     public void onChange(boolean selfChange) {
1699                         updateDeepPressStatusFromSettings("timeout changed");
1700                     }
1701                 }, UserHandle.USER_ALL);
1702     }
1703 
getShowTouchesSetting(int defaultValue)1704     private int getShowTouchesSetting(int defaultValue) {
1705         int result = defaultValue;
1706         try {
1707             result = Settings.System.getIntForUser(mContext.getContentResolver(),
1708                     Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
1709         } catch (SettingNotFoundException snfe) {
1710         }
1711         return result;
1712     }
1713 
1714     // Binder call
1715     @Override
vibrate(int deviceId, long[] pattern, int repeat, IBinder token)1716     public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1717         if (repeat >= pattern.length) {
1718             throw new ArrayIndexOutOfBoundsException();
1719         }
1720 
1721         VibratorToken v;
1722         synchronized (mVibratorLock) {
1723             v = mVibratorTokens.get(token);
1724             if (v == null) {
1725                 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1726                 try {
1727                     token.linkToDeath(v, 0);
1728                 } catch (RemoteException ex) {
1729                     // give up
1730                     throw new RuntimeException(ex);
1731                 }
1732                 mVibratorTokens.put(token, v);
1733             }
1734         }
1735 
1736         synchronized (v) {
1737             v.mVibrating = true;
1738             nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1739         }
1740     }
1741 
1742     // Binder call
1743     @Override
cancelVibrate(int deviceId, IBinder token)1744     public void cancelVibrate(int deviceId, IBinder token) {
1745         VibratorToken v;
1746         synchronized (mVibratorLock) {
1747             v = mVibratorTokens.get(token);
1748             if (v == null || v.mDeviceId != deviceId) {
1749                 return; // nothing to cancel
1750             }
1751         }
1752 
1753         cancelVibrateIfNeeded(v);
1754     }
1755 
onVibratorTokenDied(VibratorToken v)1756     void onVibratorTokenDied(VibratorToken v) {
1757         synchronized (mVibratorLock) {
1758             mVibratorTokens.remove(v.mToken);
1759         }
1760 
1761         cancelVibrateIfNeeded(v);
1762     }
1763 
cancelVibrateIfNeeded(VibratorToken v)1764     private void cancelVibrateIfNeeded(VibratorToken v) {
1765         synchronized (v) {
1766             if (v.mVibrating) {
1767                 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1768                 v.mVibrating = false;
1769             }
1770         }
1771     }
1772 
1773     // Binder call
1774     @Override
setPointerIconType(int iconId)1775     public void setPointerIconType(int iconId) {
1776         nativeSetPointerIconType(mPtr, iconId);
1777     }
1778 
1779     // Binder call
1780     @Override
setCustomPointerIcon(PointerIcon icon)1781     public void setCustomPointerIcon(PointerIcon icon) {
1782         Objects.requireNonNull(icon);
1783         nativeSetCustomPointerIcon(mPtr, icon);
1784     }
1785 
1786     /**
1787      * Add a runtime association between the input port and the display port. This overrides any
1788      * static associations.
1789      * @param inputPort The port of the input device.
1790      * @param displayPort The physical port of the associated display.
1791      */
1792     @Override // Binder call
addPortAssociation(@onNull String inputPort, int displayPort)1793     public void addPortAssociation(@NonNull String inputPort, int displayPort) {
1794         if (!checkCallingPermission(
1795                 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT,
1796                 "addPortAssociation()")) {
1797             throw new SecurityException(
1798                     "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT permission");
1799         }
1800 
1801         Objects.requireNonNull(inputPort);
1802         synchronized (mAssociationsLock) {
1803             mRuntimeAssociations.put(inputPort, displayPort);
1804         }
1805         nativeNotifyPortAssociationsChanged(mPtr);
1806     }
1807 
1808     /**
1809      * Remove the runtime association between the input port and the display port. Any existing
1810      * static association for the cleared input port will be restored.
1811      * @param inputPort The port of the input device to be cleared.
1812      */
1813     @Override // Binder call
removePortAssociation(@onNull String inputPort)1814     public void removePortAssociation(@NonNull String inputPort) {
1815         if (!checkCallingPermission(
1816                 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT,
1817                 "clearPortAssociations()")) {
1818             throw new SecurityException(
1819                     "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT permission");
1820         }
1821 
1822         Objects.requireNonNull(inputPort);
1823         synchronized (mAssociationsLock) {
1824             mRuntimeAssociations.remove(inputPort);
1825         }
1826         nativeNotifyPortAssociationsChanged(mPtr);
1827     }
1828 
1829     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1830     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1831         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
1832 
1833         pw.println("INPUT MANAGER (dumpsys input)\n");
1834         String dumpStr = nativeDump(mPtr);
1835         if (dumpStr != null) {
1836             pw.println(dumpStr);
1837             dumpAssociations(pw);
1838         }
1839     }
1840 
dumpAssociations(PrintWriter pw)1841     private void dumpAssociations(PrintWriter pw) {
1842         if (!mStaticAssociations.isEmpty()) {
1843             pw.println("Static Associations:");
1844             mStaticAssociations.forEach((k, v) -> {
1845                 pw.print("  port: " + k);
1846                 pw.println("  display: " + v);
1847             });
1848         }
1849 
1850         synchronized (mAssociationsLock) {
1851             if (!mRuntimeAssociations.isEmpty()) {
1852                 pw.println("Runtime Associations:");
1853                 mRuntimeAssociations.forEach((k, v) -> {
1854                     pw.print("  port: " + k);
1855                     pw.println("  display: " + v);
1856                 });
1857             }
1858         }
1859     }
1860 
checkCallingPermission(String permission, String func)1861     private boolean checkCallingPermission(String permission, String func) {
1862         // Quick check: if the calling permission is me, it's all okay.
1863         if (Binder.getCallingPid() == Process.myPid()) {
1864             return true;
1865         }
1866 
1867         if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1868             return true;
1869         }
1870         String msg = "Permission Denial: " + func + " from pid="
1871                 + Binder.getCallingPid()
1872                 + ", uid=" + Binder.getCallingUid()
1873                 + " requires " + permission;
1874         Slog.w(TAG, msg);
1875         return false;
1876     }
1877 
1878     // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
1879     @Override
monitor()1880     public void monitor() {
1881         synchronized (mInputFilterLock) { }
1882         synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
1883         nativeMonitor(mPtr);
1884     }
1885 
1886     // Native callback.
notifyConfigurationChanged(long whenNanos)1887     private void notifyConfigurationChanged(long whenNanos) {
1888         mWindowManagerCallbacks.notifyConfigurationChanged();
1889     }
1890 
1891     // Native callback.
notifyInputDevicesChanged(InputDevice[] inputDevices)1892     private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1893         synchronized (mInputDevicesLock) {
1894             if (!mInputDevicesChangedPending) {
1895                 mInputDevicesChangedPending = true;
1896                 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1897                         mInputDevices).sendToTarget();
1898             }
1899 
1900             mInputDevices = inputDevices;
1901         }
1902     }
1903 
1904     // Native callback.
notifySwitch(long whenNanos, int switchValues, int switchMask)1905     private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1906         if (DEBUG) {
1907             Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1908                     + ", mask=" + Integer.toHexString(switchMask));
1909         }
1910 
1911         if ((switchMask & SW_LID_BIT) != 0) {
1912             final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
1913             mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
1914         }
1915 
1916         if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
1917             final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
1918             mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1919         }
1920 
1921         if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1922             mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1923                     switchMask);
1924         }
1925 
1926         if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
1927             SomeArgs args = SomeArgs.obtain();
1928             args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
1929             args.argi2 = (int) (whenNanos >> 32);
1930             args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
1931             mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
1932                     args).sendToTarget();
1933         }
1934 
1935         if ((switchMask & SW_MUTE_DEVICE_BIT) != 0) {
1936             final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0);
1937             AudioManager audioManager = mContext.getSystemService(AudioManager.class);
1938             audioManager.setMicrophoneMuteFromSwitch(micMute);
1939         }
1940     }
1941 
1942     // Native callback.
notifyInputChannelBroken(IBinder token)1943     private void notifyInputChannelBroken(IBinder token) {
1944         mWindowManagerCallbacks.notifyInputChannelBroken(token);
1945     }
1946 
1947     // Native callback
notifyFocusChanged(IBinder oldToken, IBinder newToken)1948     private void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
1949         final boolean requestConfigurationRefresh =
1950                 mWindowManagerCallbacks.notifyFocusChanged(oldToken, newToken);
1951         if (requestConfigurationRefresh) {
1952             nativeSetPointerCapture(mPtr, false);
1953         }
1954     }
1955 
1956     // Native callback.
notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token, String reason)1957     private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
1958             String reason) {
1959         return mWindowManagerCallbacks.notifyANR(inputApplicationHandle,
1960                 token, reason);
1961     }
1962 
1963     // Native callback.
filterInputEvent(InputEvent event, int policyFlags)1964     final boolean filterInputEvent(InputEvent event, int policyFlags) {
1965         synchronized (mInputFilterLock) {
1966             if (mInputFilter != null) {
1967                 try {
1968                     mInputFilter.filterInputEvent(event, policyFlags);
1969                 } catch (RemoteException e) {
1970                     /* ignore */
1971                 }
1972                 return false;
1973             }
1974         }
1975         event.recycle();
1976         return true;
1977     }
1978 
1979     // Native callback.
interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)1980     private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1981         return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
1982     }
1983 
1984     // Native callback.
interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)1985     private int interceptMotionBeforeQueueingNonInteractive(int displayId,
1986             long whenNanos, int policyFlags) {
1987         return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
1988                 displayId, whenNanos, policyFlags);
1989     }
1990 
1991     // Native callback.
interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags)1992     private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
1993         return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
1994     }
1995 
1996     // Native callback.
dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags)1997     private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) {
1998         return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
1999     }
2000 
2001     // Native callback.
checkInjectEventsPermission(int injectorPid, int injectorUid)2002     private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
2003         return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
2004                 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
2005     }
2006 
2007     // Native callback.
onPointerDownOutsideFocus(IBinder touchedToken)2008     private void onPointerDownOutsideFocus(IBinder touchedToken) {
2009         mWindowManagerCallbacks.onPointerDownOutsideFocus(touchedToken);
2010     }
2011 
2012     // Native callback.
getVirtualKeyQuietTimeMillis()2013     private int getVirtualKeyQuietTimeMillis() {
2014         return mContext.getResources().getInteger(
2015                 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
2016     }
2017 
2018     // Native callback.
getExcludedDeviceNames()2019     private static String[] getExcludedDeviceNames() {
2020         List<String> names = new ArrayList<>();
2021         // Read partner-provided list of excluded input devices
2022         // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
2023         final File[] baseDirs = {
2024             Environment.getRootDirectory(),
2025             Environment.getVendorDirectory()
2026         };
2027         for (File baseDir: baseDirs) {
2028             File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH);
2029             try {
2030                 InputStream stream = new FileInputStream(confFile);
2031                 names.addAll(ConfigurationProcessor.processExcludedDeviceNames(stream));
2032             } catch (FileNotFoundException e) {
2033                 // It's ok if the file does not exist.
2034             } catch (Exception e) {
2035                 Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
2036             }
2037         }
2038         return names.toArray(new String[0]);
2039     }
2040 
2041     /**
2042      * Flatten a map into a string list, with value positioned directly next to the
2043      * key.
2044      * @return Flattened list
2045      */
flatten(@onNull Map<String, Integer> map)2046     private static List<String> flatten(@NonNull Map<String, Integer> map) {
2047         final List<String> list = new ArrayList<>(map.size() * 2);
2048         map.forEach((k, v)-> {
2049             list.add(k);
2050             list.add(v.toString());
2051         });
2052         return list;
2053     }
2054 
2055     /**
2056      * Ports are highly platform-specific, so only allow these to be specified in the vendor
2057      * directory.
2058      */
loadStaticInputPortAssociations()2059     private static Map<String, Integer> loadStaticInputPortAssociations() {
2060         final File baseDir = Environment.getVendorDirectory();
2061         final File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
2062 
2063         try {
2064             final InputStream stream = new FileInputStream(confFile);
2065             return ConfigurationProcessor.processInputPortAssociations(stream);
2066         } catch (FileNotFoundException e) {
2067             // Most of the time, file will not exist, which is expected.
2068         } catch (Exception e) {
2069             Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
2070         }
2071 
2072         return new HashMap<>();
2073     }
2074 
2075     // Native callback
getInputPortAssociations()2076     private String[] getInputPortAssociations() {
2077         final Map<String, Integer> associations = new HashMap<>(mStaticAssociations);
2078 
2079         // merge the runtime associations.
2080         synchronized (mAssociationsLock) {
2081             associations.putAll(mRuntimeAssociations);
2082         }
2083 
2084         final List<String> associationList = flatten(associations);
2085         return associationList.toArray(new String[0]);
2086     }
2087 
2088     /**
2089      * Gets if an input device could dispatch to the given display".
2090      * @param deviceId The input device id.
2091      * @param displayId The specific display id.
2092      * @return True if the device could dispatch to the given display, false otherwise.
2093      */
canDispatchToDisplay(int deviceId, int displayId)2094     public boolean canDispatchToDisplay(int deviceId, int displayId) {
2095         return nativeCanDispatchToDisplay(mPtr, deviceId, displayId);
2096     }
2097 
2098     // Native callback.
getKeyRepeatTimeout()2099     private int getKeyRepeatTimeout() {
2100         return ViewConfiguration.getKeyRepeatTimeout();
2101     }
2102 
2103     // Native callback.
getKeyRepeatDelay()2104     private int getKeyRepeatDelay() {
2105         return ViewConfiguration.getKeyRepeatDelay();
2106     }
2107 
2108     // Native callback.
getHoverTapTimeout()2109     private int getHoverTapTimeout() {
2110         return ViewConfiguration.getHoverTapTimeout();
2111     }
2112 
2113     // Native callback.
getHoverTapSlop()2114     private int getHoverTapSlop() {
2115         return ViewConfiguration.getHoverTapSlop();
2116     }
2117 
2118     // Native callback.
getDoubleTapTimeout()2119     private int getDoubleTapTimeout() {
2120         return ViewConfiguration.getDoubleTapTimeout();
2121     }
2122 
2123     // Native callback.
getLongPressTimeout()2124     private int getLongPressTimeout() {
2125         return ViewConfiguration.getLongPressTimeout();
2126     }
2127 
2128     // Native callback.
getPointerLayer()2129     private int getPointerLayer() {
2130         return mWindowManagerCallbacks.getPointerLayer();
2131     }
2132 
2133     // Native callback.
getPointerIcon(int displayId)2134     private PointerIcon getPointerIcon(int displayId) {
2135         return PointerIcon.getDefaultIcon(getContextForDisplay(displayId));
2136     }
2137 
getContextForDisplay(int displayId)2138     private Context getContextForDisplay(int displayId) {
2139         if (mDisplayContext != null && mDisplayContext.getDisplay().getDisplayId() == displayId) {
2140             return mDisplayContext;
2141         }
2142 
2143         if (mContext.getDisplay().getDisplayId() == displayId) {
2144             mDisplayContext = mContext;
2145             return mDisplayContext;
2146         }
2147 
2148         // Create and cache context for non-default display.
2149         final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
2150         final Display display = displayManager.getDisplay(displayId);
2151         mDisplayContext = mContext.createDisplayContext(display);
2152         return mDisplayContext;
2153     }
2154 
2155     // Native callback.
getPointerDisplayId()2156     private int getPointerDisplayId() {
2157         return mWindowManagerCallbacks.getPointerDisplayId();
2158     }
2159 
2160     // Native callback.
getKeyboardLayoutOverlay(InputDeviceIdentifier identifier)2161     private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
2162         if (!mSystemReady) {
2163             return null;
2164         }
2165 
2166         String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
2167         if (keyboardLayoutDescriptor == null) {
2168             return null;
2169         }
2170 
2171         final String[] result = new String[2];
2172         visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
2173             @Override
2174             public void visitKeyboardLayout(Resources resources,
2175                     int keyboardLayoutResId, KeyboardLayout layout) {
2176                 try {
2177                     result[0] = layout.getDescriptor();
2178                     result[1] = Streams.readFully(new InputStreamReader(
2179                             resources.openRawResource(keyboardLayoutResId)));
2180                 } catch (IOException ex) {
2181                 } catch (NotFoundException ex) {
2182                 }
2183             }
2184         });
2185         if (result[0] == null) {
2186             Slog.w(TAG, "Could not get keyboard layout with descriptor '"
2187                     + keyboardLayoutDescriptor + "'.");
2188             return null;
2189         }
2190         return result;
2191     }
2192 
2193     // Native callback.
getDeviceAlias(String uniqueId)2194     private String getDeviceAlias(String uniqueId) {
2195         if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
2196             // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
2197             return null;
2198         }
2199         return null;
2200     }
2201 
2202     /**
2203      * Callback interface implemented by the Window Manager.
2204      */
2205     public interface WindowManagerCallbacks {
notifyConfigurationChanged()2206         public void notifyConfigurationChanged();
2207 
notifyLidSwitchChanged(long whenNanos, boolean lidOpen)2208         public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
2209 
notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered)2210         public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
2211 
notifyInputChannelBroken(IBinder token)2212         public void notifyInputChannelBroken(IBinder token);
2213 
2214         /**
2215          * Notifies the window manager about an application that is not responding.
2216          * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
2217          */
notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token, String reason)2218         long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
2219                 String reason);
2220 
interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)2221         public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
2222 
2223         /**
2224          * Provides an opportunity for the window manager policy to intercept early motion event
2225          * processing when the device is in a non-interactive state since these events are normally
2226          * dropped.
2227          */
interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)2228         int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
2229                 int policyFlags);
2230 
interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags)2231         public long interceptKeyBeforeDispatching(IBinder token,
2232                 KeyEvent event, int policyFlags);
2233 
dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags)2234         public KeyEvent dispatchUnhandledKey(IBinder token,
2235                 KeyEvent event, int policyFlags);
2236 
getPointerLayer()2237         public int getPointerLayer();
2238 
getPointerDisplayId()2239         public int getPointerDisplayId();
2240 
2241         /**
2242          * Notifies window manager that a {@link android.view.MotionEvent#ACTION_DOWN} pointer event
2243          * occurred on a window that did not have focus.
2244          *
2245          * @param touchedToken The token for the window that received the input event.
2246          */
onPointerDownOutsideFocus(IBinder touchedToken)2247         void onPointerDownOutsideFocus(IBinder touchedToken);
2248 
2249         /**
2250          * Called when the focused window has changed.
2251          *
2252          * @return true if we want to request a configuration refresh.
2253          */
notifyFocusChanged(IBinder oldToken, IBinder newToken)2254         boolean notifyFocusChanged(IBinder oldToken, IBinder newToken);
2255 
2256         /**
2257          * Called by the client to request pointer capture.
2258          *
2259          * @return true if we want to request a configuration refresh.
2260          */
requestPointerCapture(IBinder windowToken, boolean enabled)2261         boolean requestPointerCapture(IBinder windowToken, boolean enabled);
2262     }
2263 
2264     /**
2265      * Callback interface implemented by WiredAccessoryObserver.
2266      */
2267     public interface WiredAccessoryCallbacks {
notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask)2268         public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
systemReady()2269         public void systemReady();
2270     }
2271 
2272     /**
2273      * Private handler for the input manager.
2274      */
2275     private final class InputManagerHandler extends Handler {
InputManagerHandler(Looper looper)2276         public InputManagerHandler(Looper looper) {
2277             super(looper, null, true /*async*/);
2278         }
2279 
2280         @Override
handleMessage(Message msg)2281         public void handleMessage(Message msg) {
2282             switch (msg.what) {
2283                 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
2284                     deliverInputDevicesChanged((InputDevice[])msg.obj);
2285                     break;
2286                 case MSG_SWITCH_KEYBOARD_LAYOUT:
2287                     handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
2288                     break;
2289                 case MSG_RELOAD_KEYBOARD_LAYOUTS:
2290                     reloadKeyboardLayouts();
2291                     break;
2292                 case MSG_UPDATE_KEYBOARD_LAYOUTS:
2293                     updateKeyboardLayouts();
2294                     break;
2295                 case MSG_RELOAD_DEVICE_ALIASES:
2296                     reloadDeviceAliases();
2297                     break;
2298                 case MSG_DELIVER_TABLET_MODE_CHANGED:
2299                     SomeArgs args = (SomeArgs) msg.obj;
2300                     long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
2301                     boolean inTabletMode = (boolean) args.arg1;
2302                     deliverTabletModeChanged(whenNanos, inTabletMode);
2303                     break;
2304             }
2305         }
2306     }
2307 
2308     /**
2309      * Hosting interface for input filters to call back into the input manager.
2310      */
2311     private final class InputFilterHost extends IInputFilterHost.Stub {
2312         private boolean mDisconnected;
2313 
disconnectLocked()2314         public void disconnectLocked() {
2315             mDisconnected = true;
2316         }
2317 
2318         @Override
sendInputEvent(InputEvent event, int policyFlags)2319         public void sendInputEvent(InputEvent event, int policyFlags) {
2320             if (event == null) {
2321                 throw new IllegalArgumentException("event must not be null");
2322             }
2323 
2324             synchronized (mInputFilterLock) {
2325                 if (!mDisconnected) {
2326                     nativeInjectInputEvent(mPtr, event, 0, 0,
2327                             InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
2328                             policyFlags | WindowManagerPolicy.FLAG_FILTERED);
2329                 }
2330             }
2331         }
2332     }
2333 
2334     /**
2335      * Interface for the system to handle request from InputMonitors.
2336      */
2337     private final class InputMonitorHost extends IInputMonitorHost.Stub {
2338         private final InputChannel mInputChannel;
2339 
InputMonitorHost(InputChannel channel)2340         InputMonitorHost(InputChannel channel) {
2341             mInputChannel = channel;
2342         }
2343 
2344         @Override
pilferPointers()2345         public void pilferPointers() {
2346             nativePilferPointers(mPtr, mInputChannel.getToken());
2347         }
2348 
2349         @Override
dispose()2350         public void dispose() {
2351             nativeUnregisterInputChannel(mPtr, mInputChannel);
2352             mInputChannel.dispose();
2353         }
2354     }
2355 
2356     private static final class KeyboardLayoutDescriptor {
2357         public String packageName;
2358         public String receiverName;
2359         public String keyboardLayoutName;
2360 
format(String packageName, String receiverName, String keyboardName)2361         public static String format(String packageName,
2362                 String receiverName, String keyboardName) {
2363             return packageName + "/" + receiverName + "/" + keyboardName;
2364         }
2365 
parse(String descriptor)2366         public static KeyboardLayoutDescriptor parse(String descriptor) {
2367             int pos = descriptor.indexOf('/');
2368             if (pos < 0 || pos + 1 == descriptor.length()) {
2369                 return null;
2370             }
2371             int pos2 = descriptor.indexOf('/', pos + 1);
2372             if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
2373                 return null;
2374             }
2375 
2376             KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
2377             result.packageName = descriptor.substring(0, pos);
2378             result.receiverName = descriptor.substring(pos + 1, pos2);
2379             result.keyboardLayoutName = descriptor.substring(pos2 + 1);
2380             return result;
2381         }
2382     }
2383 
2384     private interface KeyboardLayoutVisitor {
visitKeyboardLayout(Resources resources, int keyboardLayoutResId, KeyboardLayout layout)2385         void visitKeyboardLayout(Resources resources,
2386                 int keyboardLayoutResId, KeyboardLayout layout);
2387     }
2388 
2389     private final class InputDevicesChangedListenerRecord implements DeathRecipient {
2390         private final int mPid;
2391         private final IInputDevicesChangedListener mListener;
2392 
InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener)2393         public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
2394             mPid = pid;
2395             mListener = listener;
2396         }
2397 
2398         @Override
binderDied()2399         public void binderDied() {
2400             if (DEBUG) {
2401                 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
2402             }
2403             onInputDevicesChangedListenerDied(mPid);
2404         }
2405 
notifyInputDevicesChanged(int[] info)2406         public void notifyInputDevicesChanged(int[] info) {
2407             try {
2408                 mListener.onInputDevicesChanged(info);
2409             } catch (RemoteException ex) {
2410                 Slog.w(TAG, "Failed to notify process "
2411                         + mPid + " that input devices changed, assuming it died.", ex);
2412                 binderDied();
2413             }
2414         }
2415     }
2416 
2417     private final class TabletModeChangedListenerRecord implements DeathRecipient {
2418         private final int mPid;
2419         private final ITabletModeChangedListener mListener;
2420 
TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener)2421         public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
2422             mPid = pid;
2423             mListener = listener;
2424         }
2425 
2426         @Override
binderDied()2427         public void binderDied() {
2428             if (DEBUG) {
2429                 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
2430             }
2431             onTabletModeChangedListenerDied(mPid);
2432         }
2433 
notifyTabletModeChanged(long whenNanos, boolean inTabletMode)2434         public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
2435             try {
2436                 mListener.onTabletModeChanged(whenNanos, inTabletMode);
2437             } catch (RemoteException ex) {
2438                 Slog.w(TAG, "Failed to notify process " + mPid +
2439                         " that tablet mode changed, assuming it died.", ex);
2440                 binderDied();
2441             }
2442         }
2443     }
2444 
2445     private final class VibratorToken implements DeathRecipient {
2446         public final int mDeviceId;
2447         public final IBinder mToken;
2448         public final int mTokenValue;
2449 
2450         public boolean mVibrating;
2451 
VibratorToken(int deviceId, IBinder token, int tokenValue)2452         public VibratorToken(int deviceId, IBinder token, int tokenValue) {
2453             mDeviceId = deviceId;
2454             mToken = token;
2455             mTokenValue = tokenValue;
2456         }
2457 
2458         @Override
binderDied()2459         public void binderDied() {
2460             if (DEBUG) {
2461                 Slog.d(TAG, "Vibrator token died.");
2462             }
2463             onVibratorTokenDied(this);
2464         }
2465     }
2466 
2467     private final class LocalService extends InputManagerInternal {
2468         @Override
setDisplayViewports(List<DisplayViewport> viewports)2469         public void setDisplayViewports(List<DisplayViewport> viewports) {
2470             setDisplayViewportsInternal(viewports);
2471         }
2472 
2473         @Override
injectInputEvent(InputEvent event, int mode)2474         public boolean injectInputEvent(InputEvent event, int mode) {
2475             return injectInputEventInternal(event, mode);
2476         }
2477 
2478         @Override
setInteractive(boolean interactive)2479         public void setInteractive(boolean interactive) {
2480             nativeSetInteractive(mPtr, interactive);
2481         }
2482 
2483         @Override
toggleCapsLock(int deviceId)2484         public void toggleCapsLock(int deviceId) {
2485             nativeToggleCapsLock(mPtr, deviceId);
2486         }
2487 
2488         @Override
setPulseGestureEnabled(boolean enabled)2489         public void setPulseGestureEnabled(boolean enabled) {
2490             if (mDoubleTouchGestureEnableFile != null) {
2491                 FileWriter writer = null;
2492                 try {
2493                     writer = new FileWriter(mDoubleTouchGestureEnableFile);
2494                     writer.write(enabled ? "1" : "0");
2495                 } catch (IOException e) {
2496                     Log.wtf(TAG, "Unable to setPulseGestureEnabled", e);
2497                 } finally {
2498                     IoUtils.closeQuietly(writer);
2499                 }
2500             }
2501         }
2502 
2503         @Override
transferTouchFocus(@onNull IBinder fromChannelToken, @NonNull IBinder toChannelToken)2504         public boolean transferTouchFocus(@NonNull IBinder fromChannelToken,
2505                 @NonNull IBinder toChannelToken) {
2506             return InputManagerService.this.transferTouchFocus(fromChannelToken, toChannelToken);
2507         }
2508     }
2509 }
2510