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