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