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