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