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