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