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