InputManagerService.java revision 255dd04271088590fedc46c8e22b2fd4ab142d39
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                    .setColor(mContext.getResources().getColor(
778                            com.android.internal.R.color.system_notification_accent_color))
779                    .build();
780            mNotificationManager.notifyAsUser(null,
781                    R.string.select_keyboard_layout_notification_title,
782                    notification, UserHandle.ALL);
783            mKeyboardLayoutNotificationShown = true;
784        }
785    }
786
787    // Must be called on handler.
788    private void hideMissingKeyboardLayoutNotification() {
789        if (mKeyboardLayoutNotificationShown) {
790            mKeyboardLayoutNotificationShown = false;
791            mNotificationManager.cancelAsUser(null,
792                    R.string.select_keyboard_layout_notification_title,
793                    UserHandle.ALL);
794        }
795    }
796
797    // Must be called on handler.
798    private void updateKeyboardLayouts() {
799        // Scan all input devices state for keyboard layouts that have been uninstalled.
800        final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
801        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
802            @Override
803            public void visitKeyboardLayout(Resources resources,
804                    String descriptor, String label, String collection, int keyboardLayoutResId) {
805                availableKeyboardLayouts.add(descriptor);
806            }
807        });
808        synchronized (mDataStore) {
809            try {
810                mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
811            } finally {
812                mDataStore.saveIfNeeded();
813            }
814        }
815
816        // Reload keyboard layouts.
817        reloadKeyboardLayouts();
818    }
819
820    private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
821            String descriptor) {
822        final int numDevices = inputDevices.length;
823        for (int i = 0; i < numDevices; i++) {
824            final InputDevice inputDevice = inputDevices[i];
825            if (inputDevice.getDescriptor().equals(descriptor)) {
826                return true;
827            }
828        }
829        return false;
830    }
831
832    @Override // Binder call
833    public KeyboardLayout[] getKeyboardLayouts() {
834        final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
835        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
836            @Override
837            public void visitKeyboardLayout(Resources resources,
838                    String descriptor, String label, String collection, int keyboardLayoutResId) {
839                list.add(new KeyboardLayout(descriptor, label, collection));
840            }
841        });
842        return list.toArray(new KeyboardLayout[list.size()]);
843    }
844
845    @Override // Binder call
846    public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
847        if (keyboardLayoutDescriptor == null) {
848            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
849        }
850
851        final KeyboardLayout[] result = new KeyboardLayout[1];
852        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
853            @Override
854            public void visitKeyboardLayout(Resources resources,
855                    String descriptor, String label, String collection, int keyboardLayoutResId) {
856                result[0] = new KeyboardLayout(descriptor, label, collection);
857            }
858        });
859        if (result[0] == null) {
860            Log.w(TAG, "Could not get keyboard layout with descriptor '"
861                    + keyboardLayoutDescriptor + "'.");
862        }
863        return result[0];
864    }
865
866    private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
867        final PackageManager pm = mContext.getPackageManager();
868        Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
869        for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
870                PackageManager.GET_META_DATA)) {
871            visitKeyboardLayoutsInPackage(pm, resolveInfo.activityInfo, null, visitor);
872        }
873    }
874
875    private void visitKeyboardLayout(String keyboardLayoutDescriptor,
876            KeyboardLayoutVisitor visitor) {
877        KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
878        if (d != null) {
879            final PackageManager pm = mContext.getPackageManager();
880            try {
881                ActivityInfo receiver = pm.getReceiverInfo(
882                        new ComponentName(d.packageName, d.receiverName),
883                        PackageManager.GET_META_DATA);
884                visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, visitor);
885            } catch (NameNotFoundException ex) {
886            }
887        }
888    }
889
890    private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
891            String keyboardName, KeyboardLayoutVisitor visitor) {
892        Bundle metaData = receiver.metaData;
893        if (metaData == null) {
894            return;
895        }
896
897        int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
898        if (configResId == 0) {
899            Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
900                    + "' on receiver " + receiver.packageName + "/" + receiver.name);
901            return;
902        }
903
904        CharSequence receiverLabel = receiver.loadLabel(pm);
905        String collection = receiverLabel != null ? receiverLabel.toString() : "";
906
907        try {
908            Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
909            XmlResourceParser parser = resources.getXml(configResId);
910            try {
911                XmlUtils.beginDocument(parser, "keyboard-layouts");
912
913                for (;;) {
914                    XmlUtils.nextElement(parser);
915                    String element = parser.getName();
916                    if (element == null) {
917                        break;
918                    }
919                    if (element.equals("keyboard-layout")) {
920                        TypedArray a = resources.obtainAttributes(
921                                parser, com.android.internal.R.styleable.KeyboardLayout);
922                        try {
923                            String name = a.getString(
924                                    com.android.internal.R.styleable.KeyboardLayout_name);
925                            String label = a.getString(
926                                    com.android.internal.R.styleable.KeyboardLayout_label);
927                            int keyboardLayoutResId = a.getResourceId(
928                                    com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
929                                    0);
930                            if (name == null || label == null || keyboardLayoutResId == 0) {
931                                Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
932                                        + "attributes in keyboard layout "
933                                        + "resource from receiver "
934                                        + receiver.packageName + "/" + receiver.name);
935                            } else {
936                                String descriptor = KeyboardLayoutDescriptor.format(
937                                        receiver.packageName, receiver.name, name);
938                                if (keyboardName == null || name.equals(keyboardName)) {
939                                    visitor.visitKeyboardLayout(resources, descriptor,
940                                            label, collection, keyboardLayoutResId);
941                                }
942                            }
943                        } finally {
944                            a.recycle();
945                        }
946                    } else {
947                        Log.w(TAG, "Skipping unrecognized element '" + element
948                                + "' in keyboard layout resource from receiver "
949                                + receiver.packageName + "/" + receiver.name);
950                    }
951                }
952            } finally {
953                parser.close();
954            }
955        } catch (Exception ex) {
956            Log.w(TAG, "Could not parse keyboard layout resource from receiver "
957                    + receiver.packageName + "/" + receiver.name, ex);
958        }
959    }
960
961    /**
962     * Builds a layout descriptor for the vendor/product. This returns the
963     * descriptor for ids that aren't useful (such as the default 0, 0).
964     */
965    private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
966        if (identifier == null || identifier.getDescriptor() == null) {
967            throw new IllegalArgumentException("identifier and descriptor must not be null");
968        }
969
970        if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
971            return identifier.getDescriptor();
972        }
973        StringBuilder bob = new StringBuilder();
974        bob.append("vendor:").append(identifier.getVendorId());
975        bob.append(",product:").append(identifier.getProductId());
976        return bob.toString();
977    }
978
979    @Override // Binder call
980    public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
981
982        String key = getLayoutDescriptor(identifier);
983        synchronized (mDataStore) {
984            String layout = null;
985            // try loading it using the layout descriptor if we have it
986            layout = mDataStore.getCurrentKeyboardLayout(key);
987            if (layout == null && !key.equals(identifier.getDescriptor())) {
988                // if it doesn't exist fall back to the device descriptor
989                layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
990            }
991            if (DEBUG) {
992                Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
993                        + layout);
994            }
995            return layout;
996        }
997    }
998
999    @Override // Binder call
1000    public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1001            String keyboardLayoutDescriptor) {
1002        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1003                "setCurrentKeyboardLayoutForInputDevice()")) {
1004            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1005        }
1006        if (keyboardLayoutDescriptor == null) {
1007            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1008        }
1009
1010        String key = getLayoutDescriptor(identifier);
1011        synchronized (mDataStore) {
1012            try {
1013                if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1014                    if (DEBUG) {
1015                        Slog.d(TAG, "Saved keyboard layout using " + key);
1016                    }
1017                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1018                }
1019            } finally {
1020                mDataStore.saveIfNeeded();
1021            }
1022        }
1023    }
1024
1025    @Override // Binder call
1026    public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
1027        String key = getLayoutDescriptor(identifier);
1028        synchronized (mDataStore) {
1029            String[] layouts = mDataStore.getKeyboardLayouts(key);
1030            if ((layouts == null || layouts.length == 0)
1031                    && !key.equals(identifier.getDescriptor())) {
1032                layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1033            }
1034            return layouts;
1035        }
1036    }
1037
1038    @Override // Binder call
1039    public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1040            String keyboardLayoutDescriptor) {
1041        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1042                "addKeyboardLayoutForInputDevice()")) {
1043            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1044        }
1045        if (keyboardLayoutDescriptor == null) {
1046            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1047        }
1048
1049        String key = getLayoutDescriptor(identifier);
1050        synchronized (mDataStore) {
1051            try {
1052                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1053                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1054                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1055                }
1056                if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
1057                        && !Objects.equal(oldLayout,
1058                                mDataStore.getCurrentKeyboardLayout(key))) {
1059                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1060                }
1061            } finally {
1062                mDataStore.saveIfNeeded();
1063            }
1064        }
1065    }
1066
1067    @Override // Binder call
1068    public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1069            String keyboardLayoutDescriptor) {
1070        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1071                "removeKeyboardLayoutForInputDevice()")) {
1072            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1073        }
1074        if (keyboardLayoutDescriptor == null) {
1075            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1076        }
1077
1078        String key = getLayoutDescriptor(identifier);
1079        synchronized (mDataStore) {
1080            try {
1081                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1082                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1083                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1084                }
1085                boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1086                if (!key.equals(identifier.getDescriptor())) {
1087                    // We need to remove from both places to ensure it is gone
1088                    removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1089                            keyboardLayoutDescriptor);
1090                }
1091                if (removed && !Objects.equal(oldLayout,
1092                                mDataStore.getCurrentKeyboardLayout(key))) {
1093                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1094                }
1095            } finally {
1096                mDataStore.saveIfNeeded();
1097            }
1098        }
1099    }
1100
1101    public void switchKeyboardLayout(int deviceId, int direction) {
1102        mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
1103    }
1104
1105    // Must be called on handler.
1106    private void handleSwitchKeyboardLayout(int deviceId, int direction) {
1107        final InputDevice device = getInputDevice(deviceId);
1108        if (device != null) {
1109            final boolean changed;
1110            final String keyboardLayoutDescriptor;
1111
1112            String key = getLayoutDescriptor(device.getIdentifier());
1113            synchronized (mDataStore) {
1114                try {
1115                    changed = mDataStore.switchKeyboardLayout(key, direction);
1116                    keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
1117                            key);
1118                } finally {
1119                    mDataStore.saveIfNeeded();
1120                }
1121            }
1122
1123            if (changed) {
1124                if (mSwitchedKeyboardLayoutToast != null) {
1125                    mSwitchedKeyboardLayoutToast.cancel();
1126                    mSwitchedKeyboardLayoutToast = null;
1127                }
1128                if (keyboardLayoutDescriptor != null) {
1129                    KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
1130                    if (keyboardLayout != null) {
1131                        mSwitchedKeyboardLayoutToast = Toast.makeText(
1132                                mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
1133                        mSwitchedKeyboardLayoutToast.show();
1134                    }
1135                }
1136
1137                reloadKeyboardLayouts();
1138            }
1139        }
1140    }
1141
1142    public void setInputWindows(InputWindowHandle[] windowHandles) {
1143        nativeSetInputWindows(mPtr, windowHandles);
1144    }
1145
1146    public void setFocusedApplication(InputApplicationHandle application) {
1147        nativeSetFocusedApplication(mPtr, application);
1148    }
1149
1150    public void setInputDispatchMode(boolean enabled, boolean frozen) {
1151        nativeSetInputDispatchMode(mPtr, enabled, frozen);
1152    }
1153
1154    public void setSystemUiVisibility(int visibility) {
1155        nativeSetSystemUiVisibility(mPtr, visibility);
1156    }
1157
1158    /**
1159     * Atomically transfers touch focus from one window to another as identified by
1160     * their input channels.  It is possible for multiple windows to have
1161     * touch focus if they support split touch dispatch
1162     * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1163     * method only transfers touch focus of the specified window without affecting
1164     * other windows that may also have touch focus at the same time.
1165     * @param fromChannel The channel of a window that currently has touch focus.
1166     * @param toChannel The channel of the window that should receive touch focus in
1167     * place of the first.
1168     * @return True if the transfer was successful.  False if the window with the
1169     * specified channel did not actually have touch focus at the time of the request.
1170     */
1171    public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1172        if (fromChannel == null) {
1173            throw new IllegalArgumentException("fromChannel must not be null.");
1174        }
1175        if (toChannel == null) {
1176            throw new IllegalArgumentException("toChannel must not be null.");
1177        }
1178        return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
1179    }
1180
1181    @Override // Binder call
1182    public void tryPointerSpeed(int speed) {
1183        if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1184                "tryPointerSpeed()")) {
1185            throw new SecurityException("Requires SET_POINTER_SPEED permission");
1186        }
1187
1188        if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1189            throw new IllegalArgumentException("speed out of range");
1190        }
1191
1192        setPointerSpeedUnchecked(speed);
1193    }
1194
1195    public void updatePointerSpeedFromSettings() {
1196        int speed = getPointerSpeedSetting();
1197        setPointerSpeedUnchecked(speed);
1198    }
1199
1200    private void setPointerSpeedUnchecked(int speed) {
1201        speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1202                InputManager.MAX_POINTER_SPEED);
1203        nativeSetPointerSpeed(mPtr, speed);
1204    }
1205
1206    private void registerPointerSpeedSettingObserver() {
1207        mContext.getContentResolver().registerContentObserver(
1208                Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
1209                new ContentObserver(mHandler) {
1210                    @Override
1211                    public void onChange(boolean selfChange) {
1212                        updatePointerSpeedFromSettings();
1213                    }
1214                }, UserHandle.USER_ALL);
1215    }
1216
1217    private int getPointerSpeedSetting() {
1218        int speed = InputManager.DEFAULT_POINTER_SPEED;
1219        try {
1220            speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1221                    Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
1222        } catch (SettingNotFoundException snfe) {
1223        }
1224        return speed;
1225    }
1226
1227    public void updateShowTouchesFromSettings() {
1228        int setting = getShowTouchesSetting(0);
1229        nativeSetShowTouches(mPtr, setting != 0);
1230    }
1231
1232    private void registerShowTouchesSettingObserver() {
1233        mContext.getContentResolver().registerContentObserver(
1234                Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
1235                new ContentObserver(mHandler) {
1236                    @Override
1237                    public void onChange(boolean selfChange) {
1238                        updateShowTouchesFromSettings();
1239                    }
1240                }, UserHandle.USER_ALL);
1241    }
1242
1243    private int getShowTouchesSetting(int defaultValue) {
1244        int result = defaultValue;
1245        try {
1246            result = Settings.System.getIntForUser(mContext.getContentResolver(),
1247                    Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
1248        } catch (SettingNotFoundException snfe) {
1249        }
1250        return result;
1251    }
1252
1253    // Binder call
1254    @Override
1255    public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1256        if (repeat >= pattern.length) {
1257            throw new ArrayIndexOutOfBoundsException();
1258        }
1259
1260        VibratorToken v;
1261        synchronized (mVibratorLock) {
1262            v = mVibratorTokens.get(token);
1263            if (v == null) {
1264                v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1265                try {
1266                    token.linkToDeath(v, 0);
1267                } catch (RemoteException ex) {
1268                    // give up
1269                    throw new RuntimeException(ex);
1270                }
1271                mVibratorTokens.put(token, v);
1272            }
1273        }
1274
1275        synchronized (v) {
1276            v.mVibrating = true;
1277            nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1278        }
1279    }
1280
1281    // Binder call
1282    @Override
1283    public void cancelVibrate(int deviceId, IBinder token) {
1284        VibratorToken v;
1285        synchronized (mVibratorLock) {
1286            v = mVibratorTokens.get(token);
1287            if (v == null || v.mDeviceId != deviceId) {
1288                return; // nothing to cancel
1289            }
1290        }
1291
1292        cancelVibrateIfNeeded(v);
1293    }
1294
1295    void onVibratorTokenDied(VibratorToken v) {
1296        synchronized (mVibratorLock) {
1297            mVibratorTokens.remove(v.mToken);
1298        }
1299
1300        cancelVibrateIfNeeded(v);
1301    }
1302
1303    private void cancelVibrateIfNeeded(VibratorToken v) {
1304        synchronized (v) {
1305            if (v.mVibrating) {
1306                nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1307                v.mVibrating = false;
1308            }
1309        }
1310    }
1311
1312    @Override
1313    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1314        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
1315                != PackageManager.PERMISSION_GRANTED) {
1316            pw.println("Permission Denial: can't dump InputManager from from pid="
1317                    + Binder.getCallingPid()
1318                    + ", uid=" + Binder.getCallingUid());
1319            return;
1320        }
1321
1322        pw.println("INPUT MANAGER (dumpsys input)\n");
1323        String dumpStr = nativeDump(mPtr);
1324        if (dumpStr != null) {
1325            pw.println(dumpStr);
1326        }
1327    }
1328
1329    private boolean checkCallingPermission(String permission, String func) {
1330        // Quick check: if the calling permission is me, it's all okay.
1331        if (Binder.getCallingPid() == Process.myPid()) {
1332            return true;
1333        }
1334
1335        if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1336            return true;
1337        }
1338        String msg = "Permission Denial: " + func + " from pid="
1339                + Binder.getCallingPid()
1340                + ", uid=" + Binder.getCallingUid()
1341                + " requires " + permission;
1342        Slog.w(TAG, msg);
1343        return false;
1344    }
1345
1346    // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
1347    @Override
1348    public void monitor() {
1349        synchronized (mInputFilterLock) { }
1350        nativeMonitor(mPtr);
1351    }
1352
1353    // Native callback.
1354    private void notifyConfigurationChanged(long whenNanos) {
1355        mWindowManagerCallbacks.notifyConfigurationChanged();
1356    }
1357
1358    // Native callback.
1359    private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1360        synchronized (mInputDevicesLock) {
1361            if (!mInputDevicesChangedPending) {
1362                mInputDevicesChangedPending = true;
1363                mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1364                        mInputDevices).sendToTarget();
1365            }
1366
1367            mInputDevices = inputDevices;
1368        }
1369    }
1370
1371    // Native callback.
1372    private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1373        if (DEBUG) {
1374            Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1375                    + ", mask=" + Integer.toHexString(switchMask));
1376        }
1377
1378        if ((switchMask & SW_LID_BIT) != 0) {
1379            final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
1380            mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
1381        }
1382
1383        if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1384            mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1385                    switchMask);
1386        }
1387    }
1388
1389    // Native callback.
1390    private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
1391        mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
1392    }
1393
1394    // Native callback.
1395    private long notifyANR(InputApplicationHandle inputApplicationHandle,
1396            InputWindowHandle inputWindowHandle, String reason) {
1397        return mWindowManagerCallbacks.notifyANR(
1398                inputApplicationHandle, inputWindowHandle, reason);
1399    }
1400
1401    // Native callback.
1402    final boolean filterInputEvent(InputEvent event, int policyFlags) {
1403        synchronized (mInputFilterLock) {
1404            if (mInputFilter != null) {
1405                try {
1406                    mInputFilter.filterInputEvent(event, policyFlags);
1407                } catch (RemoteException e) {
1408                    /* ignore */
1409                }
1410                return false;
1411            }
1412        }
1413        event.recycle();
1414        return true;
1415    }
1416
1417    // Native callback.
1418    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1419        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
1420    }
1421
1422    // Native callback.
1423    private int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
1424        return mWindowManagerCallbacks.interceptWakeMotionBeforeQueueing(
1425                whenNanos, policyFlags);
1426    }
1427
1428    // Native callback.
1429    private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1430            KeyEvent event, int policyFlags) {
1431        return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
1432    }
1433
1434    // Native callback.
1435    private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1436            KeyEvent event, int policyFlags) {
1437        return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
1438    }
1439
1440    // Native callback.
1441    private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1442        return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1443                injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1444    }
1445
1446    // Native callback.
1447    private int getVirtualKeyQuietTimeMillis() {
1448        return mContext.getResources().getInteger(
1449                com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1450    }
1451
1452    // Native callback.
1453    private String[] getExcludedDeviceNames() {
1454        ArrayList<String> names = new ArrayList<String>();
1455
1456        // Read partner-provided list of excluded input devices
1457        XmlPullParser parser = null;
1458        // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1459        File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1460        FileReader confreader = null;
1461        try {
1462            confreader = new FileReader(confFile);
1463            parser = Xml.newPullParser();
1464            parser.setInput(confreader);
1465            XmlUtils.beginDocument(parser, "devices");
1466
1467            while (true) {
1468                XmlUtils.nextElement(parser);
1469                if (!"device".equals(parser.getName())) {
1470                    break;
1471                }
1472                String name = parser.getAttributeValue(null, "name");
1473                if (name != null) {
1474                    names.add(name);
1475                }
1476            }
1477        } catch (FileNotFoundException e) {
1478            // It's ok if the file does not exist.
1479        } catch (Exception e) {
1480            Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1481        } finally {
1482            try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1483        }
1484
1485        return names.toArray(new String[names.size()]);
1486    }
1487
1488    // Native callback.
1489    private int getKeyRepeatTimeout() {
1490        return ViewConfiguration.getKeyRepeatTimeout();
1491    }
1492
1493    // Native callback.
1494    private int getKeyRepeatDelay() {
1495        return ViewConfiguration.getKeyRepeatDelay();
1496    }
1497
1498    // Native callback.
1499    private int getHoverTapTimeout() {
1500        return ViewConfiguration.getHoverTapTimeout();
1501    }
1502
1503    // Native callback.
1504    private int getHoverTapSlop() {
1505        return ViewConfiguration.getHoverTapSlop();
1506    }
1507
1508    // Native callback.
1509    private int getDoubleTapTimeout() {
1510        return ViewConfiguration.getDoubleTapTimeout();
1511    }
1512
1513    // Native callback.
1514    private int getLongPressTimeout() {
1515        return ViewConfiguration.getLongPressTimeout();
1516    }
1517
1518    // Native callback.
1519    private int getPointerLayer() {
1520        return mWindowManagerCallbacks.getPointerLayer();
1521    }
1522
1523    // Native callback.
1524    private PointerIcon getPointerIcon() {
1525        return PointerIcon.getDefaultIcon(mContext);
1526    }
1527
1528    // Native callback.
1529    private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
1530        if (!mSystemReady) {
1531            return null;
1532        }
1533
1534        String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
1535        if (keyboardLayoutDescriptor == null) {
1536            return null;
1537        }
1538
1539        final String[] result = new String[2];
1540        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1541            @Override
1542            public void visitKeyboardLayout(Resources resources,
1543                    String descriptor, String label, String collection, int keyboardLayoutResId) {
1544                try {
1545                    result[0] = descriptor;
1546                    result[1] = Streams.readFully(new InputStreamReader(
1547                            resources.openRawResource(keyboardLayoutResId)));
1548                } catch (IOException ex) {
1549                } catch (NotFoundException ex) {
1550                }
1551            }
1552        });
1553        if (result[0] == null) {
1554            Log.w(TAG, "Could not get keyboard layout with descriptor '"
1555                    + keyboardLayoutDescriptor + "'.");
1556            return null;
1557        }
1558        return result;
1559    }
1560
1561    // Native callback.
1562    private String getDeviceAlias(String uniqueId) {
1563        if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
1564            // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
1565            return null;
1566        }
1567        return null;
1568    }
1569
1570    /**
1571     * Callback interface implemented by the Window Manager.
1572     */
1573    public interface WindowManagerCallbacks {
1574        public void notifyConfigurationChanged();
1575
1576        public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
1577
1578        public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
1579
1580        public long notifyANR(InputApplicationHandle inputApplicationHandle,
1581                InputWindowHandle inputWindowHandle, String reason);
1582
1583        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
1584
1585        public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags);
1586
1587        public long interceptKeyBeforeDispatching(InputWindowHandle focus,
1588                KeyEvent event, int policyFlags);
1589
1590        public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1591                KeyEvent event, int policyFlags);
1592
1593        public int getPointerLayer();
1594    }
1595
1596    /**
1597     * Callback interface implemented by WiredAccessoryObserver.
1598     */
1599    public interface WiredAccessoryCallbacks {
1600        public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
1601        public void systemReady();
1602    }
1603
1604    /**
1605     * Private handler for the input manager.
1606     */
1607    private final class InputManagerHandler extends Handler {
1608        public InputManagerHandler(Looper looper) {
1609            super(looper, null, true /*async*/);
1610        }
1611
1612        @Override
1613        public void handleMessage(Message msg) {
1614            switch (msg.what) {
1615                case MSG_DELIVER_INPUT_DEVICES_CHANGED:
1616                    deliverInputDevicesChanged((InputDevice[])msg.obj);
1617                    break;
1618                case MSG_SWITCH_KEYBOARD_LAYOUT:
1619                    handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
1620                    break;
1621                case MSG_RELOAD_KEYBOARD_LAYOUTS:
1622                    reloadKeyboardLayouts();
1623                    break;
1624                case MSG_UPDATE_KEYBOARD_LAYOUTS:
1625                    updateKeyboardLayouts();
1626                    break;
1627                case MSG_RELOAD_DEVICE_ALIASES:
1628                    reloadDeviceAliases();
1629                    break;
1630            }
1631        }
1632    }
1633
1634    /**
1635     * Hosting interface for input filters to call back into the input manager.
1636     */
1637    private final class InputFilterHost extends IInputFilterHost.Stub {
1638        private boolean mDisconnected;
1639
1640        public void disconnectLocked() {
1641            mDisconnected = true;
1642        }
1643
1644        @Override
1645        public void sendInputEvent(InputEvent event, int policyFlags) {
1646            if (event == null) {
1647                throw new IllegalArgumentException("event must not be null");
1648            }
1649
1650            synchronized (mInputFilterLock) {
1651                if (!mDisconnected) {
1652                    nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
1653                            InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
1654                            policyFlags | WindowManagerPolicy.FLAG_FILTERED);
1655                }
1656            }
1657        }
1658    }
1659
1660    private static final class KeyboardLayoutDescriptor {
1661        public String packageName;
1662        public String receiverName;
1663        public String keyboardLayoutName;
1664
1665        public static String format(String packageName,
1666                String receiverName, String keyboardName) {
1667            return packageName + "/" + receiverName + "/" + keyboardName;
1668        }
1669
1670        public static KeyboardLayoutDescriptor parse(String descriptor) {
1671            int pos = descriptor.indexOf('/');
1672            if (pos < 0 || pos + 1 == descriptor.length()) {
1673                return null;
1674            }
1675            int pos2 = descriptor.indexOf('/', pos + 1);
1676            if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
1677                return null;
1678            }
1679
1680            KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
1681            result.packageName = descriptor.substring(0, pos);
1682            result.receiverName = descriptor.substring(pos + 1, pos2);
1683            result.keyboardLayoutName = descriptor.substring(pos2 + 1);
1684            return result;
1685        }
1686    }
1687
1688    private interface KeyboardLayoutVisitor {
1689        void visitKeyboardLayout(Resources resources,
1690                String descriptor, String label, String collection, int keyboardLayoutResId);
1691    }
1692
1693    private final class InputDevicesChangedListenerRecord implements DeathRecipient {
1694        private final int mPid;
1695        private final IInputDevicesChangedListener mListener;
1696
1697        public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
1698            mPid = pid;
1699            mListener = listener;
1700        }
1701
1702        @Override
1703        public void binderDied() {
1704            if (DEBUG) {
1705                Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
1706            }
1707            onInputDevicesChangedListenerDied(mPid);
1708        }
1709
1710        public void notifyInputDevicesChanged(int[] info) {
1711            try {
1712                mListener.onInputDevicesChanged(info);
1713            } catch (RemoteException ex) {
1714                Slog.w(TAG, "Failed to notify process "
1715                        + mPid + " that input devices changed, assuming it died.", ex);
1716                binderDied();
1717            }
1718        }
1719    }
1720
1721    private final class VibratorToken implements DeathRecipient {
1722        public final int mDeviceId;
1723        public final IBinder mToken;
1724        public final int mTokenValue;
1725
1726        public boolean mVibrating;
1727
1728        public VibratorToken(int deviceId, IBinder token, int tokenValue) {
1729            mDeviceId = deviceId;
1730            mToken = token;
1731            mTokenValue = tokenValue;
1732        }
1733
1734        @Override
1735        public void binderDied() {
1736            if (DEBUG) {
1737                Slog.d(TAG, "Vibrator token died.");
1738            }
1739            onVibratorTokenDied(this);
1740        }
1741    }
1742
1743    private final class LocalService extends InputManagerInternal {
1744        @Override
1745        public void setDisplayViewports(
1746                DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
1747            setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
1748        }
1749
1750        @Override
1751        public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
1752            return injectInputEventInternal(event, displayId, mode);
1753        }
1754
1755        @Override
1756        public void setInteractive(boolean interactive) {
1757            nativeSetInteractive(mPtr, interactive);
1758        }
1759    }
1760}
1761