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