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