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