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