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