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