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