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