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