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