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