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