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