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