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.annotation.NonNull;
20import android.annotation.Nullable;
21import android.os.LocaleList;
22import android.os.ShellCallback;
23import android.util.Log;
24import android.view.Display;
25import com.android.internal.inputmethod.InputMethodSubtypeHandle;
26import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
27import com.android.internal.notification.SystemNotificationChannels;
28import com.android.internal.os.SomeArgs;
29import com.android.internal.R;
30import com.android.internal.util.DumpUtils;
31import com.android.internal.util.Preconditions;
32import com.android.internal.util.XmlUtils;
33import com.android.server.DisplayThread;
34import com.android.server.LocalServices;
35import com.android.server.Watchdog;
36
37import org.xmlpull.v1.XmlPullParser;
38
39import android.Manifest;
40import android.app.Notification;
41import android.app.NotificationManager;
42import android.app.PendingIntent;
43import android.bluetooth.BluetoothAdapter;
44import android.bluetooth.BluetoothDevice;
45import android.content.BroadcastReceiver;
46import android.content.ComponentName;
47import android.content.Context;
48import android.content.Intent;
49import android.content.IntentFilter;
50import android.content.pm.ActivityInfo;
51import android.content.pm.ApplicationInfo;
52import android.content.pm.PackageManager;
53import android.content.pm.ResolveInfo;
54import android.content.pm.PackageManager.NameNotFoundException;
55import android.content.res.Resources;
56import android.content.res.Resources.NotFoundException;
57import android.content.res.TypedArray;
58import android.content.res.XmlResourceParser;
59import android.database.ContentObserver;
60import android.hardware.display.DisplayViewport;
61import android.hardware.input.IInputDevicesChangedListener;
62import android.hardware.input.IInputManager;
63import android.hardware.input.InputDeviceIdentifier;
64import android.hardware.input.InputManager;
65import android.hardware.input.InputManagerInternal;
66import android.hardware.input.ITabletModeChangedListener;
67import android.hardware.input.KeyboardLayout;
68import android.hardware.input.TouchCalibration;
69import android.os.Binder;
70import android.os.Bundle;
71import android.os.Environment;
72import android.os.Handler;
73import android.os.IBinder;
74import android.os.Looper;
75import android.os.Message;
76import android.os.MessageQueue;
77import android.os.Process;
78import android.os.RemoteException;
79import android.os.ResultReceiver;
80import android.os.ShellCommand;
81import android.os.UserHandle;
82import android.provider.Settings;
83import android.provider.Settings.SettingNotFoundException;
84import android.text.TextUtils;
85import android.util.Slog;
86import android.util.SparseArray;
87import android.util.Xml;
88import android.view.IInputFilter;
89import android.view.IInputFilterHost;
90import android.view.IWindow;
91import android.view.InputChannel;
92import android.view.InputDevice;
93import android.view.InputEvent;
94import android.view.KeyEvent;
95import android.view.PointerIcon;
96import android.view.Surface;
97import android.view.ViewConfiguration;
98import android.view.WindowManagerPolicy;
99import android.view.inputmethod.InputMethodInfo;
100import android.view.inputmethod.InputMethodSubtype;
101
102import java.io.File;
103import java.io.FileDescriptor;
104import java.io.FileNotFoundException;
105import java.io.FileReader;
106import java.io.FileWriter;
107import java.io.IOException;
108import java.io.InputStreamReader;
109import java.io.PrintWriter;
110import java.util.ArrayList;
111import java.util.Collections;
112import java.util.HashMap;
113import java.util.HashSet;
114import java.util.List;
115import java.util.Locale;
116
117import libcore.io.IoUtils;
118import libcore.io.Streams;
119import libcore.util.Objects;
120
121/*
122 * Wraps the C++ InputManager and provides its callbacks.
123 */
124public class InputManagerService extends IInputManager.Stub
125        implements Watchdog.Monitor {
126    static final String TAG = "InputManager";
127    static final boolean DEBUG = false;
128
129    private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
130
131    private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
132    private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
133    private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
134    private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
135    private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
136    private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
137    private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7;
138
139    // Pointer to native input manager service object.
140    private final long mPtr;
141
142    private final Context mContext;
143    private final InputManagerHandler mHandler;
144
145    private final File mDoubleTouchGestureEnableFile;
146
147    private WindowManagerCallbacks mWindowManagerCallbacks;
148    private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
149    private boolean mSystemReady;
150    private NotificationManager mNotificationManager;
151
152    private final Object mTabletModeLock = new Object();
153    // List of currently registered tablet mode changed listeners by process id
154    private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
155            new SparseArray<>(); // guarded by mTabletModeLock
156    private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
157            new ArrayList<>();
158
159    // Persistent data store.  Must be locked each time during use.
160    private final PersistentDataStore mDataStore = new PersistentDataStore();
161
162    // List of currently registered input devices changed listeners by process id.
163    private Object mInputDevicesLock = new Object();
164    private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
165    private InputDevice[] mInputDevices = new InputDevice[0];
166    private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
167            new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
168    private final ArrayList<InputDevicesChangedListenerRecord>
169            mTempInputDevicesChangedListenersToNotify =
170                    new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
171    private final ArrayList<InputDevice>
172            mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
173    private boolean mKeyboardLayoutNotificationShown;
174    private InputMethodSubtypeHandle mCurrentImeHandle;
175
176    // State for vibrator tokens.
177    private Object mVibratorLock = new Object();
178    private HashMap<IBinder, VibratorToken> mVibratorTokens =
179            new HashMap<IBinder, VibratorToken>();
180    private int mNextVibratorTokenValue;
181
182    // State for the currently installed input filter.
183    final Object mInputFilterLock = new Object();
184    IInputFilter mInputFilter; // guarded by mInputFilterLock
185    InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
186
187    private IWindow mFocusedWindow;
188    private boolean mFocusedWindowHasCapture;
189
190    private static native long nativeInit(InputManagerService service,
191            Context context, MessageQueue messageQueue);
192    private static native void nativeStart(long ptr);
193    private static native void nativeSetVirtualDisplayViewports(long ptr,
194            DisplayViewport[] viewports);
195    private static native void nativeSetDisplayViewport(long ptr, int viewportType,
196            int displayId, int rotation,
197            int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
198            int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
199            int deviceWidth, int deviceHeight, String uniqueId);
200
201    private static native int nativeGetScanCodeState(long ptr,
202            int deviceId, int sourceMask, int scanCode);
203    private static native int nativeGetKeyCodeState(long ptr,
204            int deviceId, int sourceMask, int keyCode);
205    private static native int nativeGetSwitchState(long ptr,
206            int deviceId, int sourceMask, int sw);
207    private static native boolean nativeHasKeys(long ptr,
208            int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
209    private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
210            InputWindowHandle inputWindowHandle, boolean monitor);
211    private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
212    private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
213    private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId,
214            int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
215            int policyFlags);
216    private static native void nativeToggleCapsLock(long ptr, int deviceId);
217    private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
218    private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
219    private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
220    private static native void nativeSetFocusedApplication(long ptr,
221            InputApplicationHandle application);
222    private static native boolean nativeTransferTouchFocus(long ptr,
223            InputChannel fromChannel, InputChannel toChannel);
224    private static native void nativeSetPointerSpeed(long ptr, int speed);
225    private static native void nativeSetShowTouches(long ptr, boolean enabled);
226    private static native void nativeSetInteractive(long ptr, boolean interactive);
227    private static native void nativeReloadCalibration(long ptr);
228    private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
229            int repeat, int token);
230    private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
231    private static native void nativeReloadKeyboardLayouts(long ptr);
232    private static native void nativeReloadDeviceAliases(long ptr);
233    private static native String nativeDump(long ptr);
234    private static native void nativeMonitor(long ptr);
235    private static native void nativeSetPointerIconType(long ptr, int iconId);
236    private static native void nativeReloadPointerIcons(long ptr);
237    private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
238    private static native void nativeSetPointerCapture(long ptr, boolean detached);
239
240    // Input event injection constants defined in InputDispatcher.h.
241    private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
242    private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
243    private static final int INPUT_EVENT_INJECTION_FAILED = 2;
244    private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
245
246    // Maximum number of milliseconds to wait for input event injection.
247    private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
248
249    // Key states (may be returned by queries about the current state of a
250    // particular key code, scan code or switch).
251
252    /** The key state is unknown or the requested key itself is not supported. */
253    public static final int KEY_STATE_UNKNOWN = -1;
254
255    /** The key is up. /*/
256    public static final int KEY_STATE_UP = 0;
257
258    /** The key is down. */
259    public static final int KEY_STATE_DOWN = 1;
260
261    /** The key is down but is a virtual key press that is being emulated by the system. */
262    public static final int KEY_STATE_VIRTUAL = 2;
263
264    /** Scan code: Mouse / trackball button. */
265    public static final int BTN_MOUSE = 0x110;
266
267    // Switch code values must match bionic/libc/kernel/common/linux/input.h
268    /** Switch code: Lid switch.  When set, lid is shut. */
269    public static final int SW_LID = 0x00;
270
271    /** Switch code: Tablet mode switch.
272     * When set, the device is in tablet mode (i.e. no keyboard is connected).
273     */
274    public static final int SW_TABLET_MODE = 0x01;
275
276    /** Switch code: Keypad slide.  When set, keyboard is exposed. */
277    public static final int SW_KEYPAD_SLIDE = 0x0a;
278
279    /** Switch code: Headphone.  When set, headphone is inserted. */
280    public static final int SW_HEADPHONE_INSERT = 0x02;
281
282    /** Switch code: Microphone.  When set, microphone is inserted. */
283    public static final int SW_MICROPHONE_INSERT = 0x04;
284
285    /** Switch code: Line out.  When set, Line out (hi-Z) is inserted. */
286    public static final int SW_LINEOUT_INSERT = 0x06;
287
288    /** Switch code: Headphone/Microphone Jack.  When set, something is inserted. */
289    public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
290
291    /** Switch code: Camera lens cover. When set the lens is covered. */
292    public static final int SW_CAMERA_LENS_COVER = 0x09;
293
294    // Viewport constants defined in InputReader.h.
295    public static final int VIEWPORT_DEFAULT = 1;
296    public static final int VIEWPORT_EXTERNAL = 2;
297    public static final int VIEWPORT_VIRTUAL = 3;
298
299    public static final int SW_LID_BIT = 1 << SW_LID;
300    public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
301    public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
302    public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
303    public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
304    public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
305    public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
306    public static final int SW_JACK_BITS =
307            SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
308    public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
309
310    /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
311    final boolean mUseDevInputEventForAudioJack;
312
313    public InputManagerService(Context context) {
314        this.mContext = context;
315        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
316
317        mUseDevInputEventForAudioJack =
318                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
319        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
320                + mUseDevInputEventForAudioJack);
321        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
322
323        String doubleTouchGestureEnablePath = context.getResources().getString(
324                R.string.config_doubleTouchGestureEnableFile);
325        mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
326            new File(doubleTouchGestureEnablePath);
327
328        LocalServices.addService(InputManagerInternal.class, new LocalService());
329    }
330
331    public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
332        mWindowManagerCallbacks = callbacks;
333    }
334
335    public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
336        mWiredAccessoryCallbacks = callbacks;
337    }
338
339    public void start() {
340        Slog.i(TAG, "Starting input manager");
341        nativeStart(mPtr);
342
343        // Add ourself to the Watchdog monitors.
344        Watchdog.getInstance().addMonitor(this);
345
346        registerPointerSpeedSettingObserver();
347        registerShowTouchesSettingObserver();
348        registerAccessibilityLargePointerSettingObserver();
349
350        mContext.registerReceiver(new BroadcastReceiver() {
351            @Override
352            public void onReceive(Context context, Intent intent) {
353                updatePointerSpeedFromSettings();
354                updateShowTouchesFromSettings();
355                updateAccessibilityLargePointerFromSettings();
356            }
357        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
358
359        updatePointerSpeedFromSettings();
360        updateShowTouchesFromSettings();
361        updateAccessibilityLargePointerFromSettings();
362    }
363
364    // TODO(BT) Pass in paramter for bluetooth system
365    public void systemRunning() {
366        if (DEBUG) {
367            Slog.d(TAG, "System ready.");
368        }
369        mNotificationManager = (NotificationManager)mContext.getSystemService(
370                Context.NOTIFICATION_SERVICE);
371        mSystemReady = true;
372
373        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
374        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
375        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
376        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
377        filter.addDataScheme("package");
378        mContext.registerReceiver(new BroadcastReceiver() {
379            @Override
380            public void onReceive(Context context, Intent intent) {
381                updateKeyboardLayouts();
382            }
383        }, filter, null, mHandler);
384
385        filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
386        mContext.registerReceiver(new BroadcastReceiver() {
387            @Override
388            public void onReceive(Context context, Intent intent) {
389                reloadDeviceAliases();
390            }
391        }, filter, null, mHandler);
392
393        mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
394        mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
395
396        if (mWiredAccessoryCallbacks != null) {
397            mWiredAccessoryCallbacks.systemReady();
398        }
399    }
400
401    private void reloadKeyboardLayouts() {
402        if (DEBUG) {
403            Slog.d(TAG, "Reloading keyboard layouts.");
404        }
405        nativeReloadKeyboardLayouts(mPtr);
406    }
407
408    private void reloadDeviceAliases() {
409        if (DEBUG) {
410            Slog.d(TAG, "Reloading device names.");
411        }
412        nativeReloadDeviceAliases(mPtr);
413    }
414
415    private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
416            DisplayViewport externalTouchViewport,
417            List<DisplayViewport> virtualTouchViewports) {
418        if (defaultViewport.valid) {
419            setDisplayViewport(VIEWPORT_DEFAULT, defaultViewport);
420        }
421
422        if (externalTouchViewport.valid) {
423            setDisplayViewport(VIEWPORT_EXTERNAL, externalTouchViewport);
424        } else if (defaultViewport.valid) {
425            setDisplayViewport(VIEWPORT_EXTERNAL, defaultViewport);
426        }
427
428        nativeSetVirtualDisplayViewports(mPtr,
429                virtualTouchViewports.toArray(new DisplayViewport[0]));
430    }
431
432    private void setDisplayViewport(int viewportType, DisplayViewport viewport) {
433        nativeSetDisplayViewport(mPtr, viewportType,
434                viewport.displayId, viewport.orientation,
435                viewport.logicalFrame.left, viewport.logicalFrame.top,
436                viewport.logicalFrame.right, viewport.logicalFrame.bottom,
437                viewport.physicalFrame.left, viewport.physicalFrame.top,
438                viewport.physicalFrame.right, viewport.physicalFrame.bottom,
439                viewport.deviceWidth, viewport.deviceHeight, viewport.uniqueId);
440    }
441
442    /**
443     * Gets the current state of a key or button by key code.
444     * @param deviceId The input device id, or -1 to consult all devices.
445     * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
446     * consider all input sources.  An input device is consulted if at least one of its
447     * non-class input source bits matches the specified source mask.
448     * @param keyCode The key code to check.
449     * @return The key state.
450     */
451    public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
452        return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
453    }
454
455    /**
456     * Gets the current state of a key or button by scan code.
457     * @param deviceId The input device id, or -1 to consult all devices.
458     * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
459     * consider all input sources.  An input device is consulted if at least one of its
460     * non-class input source bits matches the specified source mask.
461     * @param scanCode The scan code to check.
462     * @return The key state.
463     */
464    public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
465        return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
466    }
467
468    /**
469     * Gets the current state of a switch by switch code.
470     * @param deviceId The input device id, or -1 to consult all devices.
471     * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
472     * consider all input sources.  An input device is consulted if at least one of its
473     * non-class input source bits matches the specified source mask.
474     * @param switchCode The switch code to check.
475     * @return The switch state.
476     */
477    public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
478        return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
479    }
480
481    /**
482     * Determines whether the specified key codes are supported by a particular device.
483     * @param deviceId The input device id, or -1 to consult all devices.
484     * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
485     * consider all input sources.  An input device is consulted if at least one of its
486     * non-class input source bits matches the specified source mask.
487     * @param keyCodes The array of key codes to check.
488     * @param keyExists An array at least as large as keyCodes whose entries will be set
489     * to true or false based on the presence or absence of support for the corresponding
490     * key codes.
491     * @return True if the lookup was successful, false otherwise.
492     */
493    @Override // Binder call
494    public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
495        if (keyCodes == null) {
496            throw new IllegalArgumentException("keyCodes must not be null.");
497        }
498        if (keyExists == null || keyExists.length < keyCodes.length) {
499            throw new IllegalArgumentException("keyExists must not be null and must be at "
500                    + "least as large as keyCodes.");
501        }
502
503        return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
504    }
505
506    /**
507     * Creates an input channel that will receive all input from the input dispatcher.
508     * @param inputChannelName The input channel name.
509     * @return The input channel.
510     */
511    public InputChannel monitorInput(String inputChannelName) {
512        if (inputChannelName == null) {
513            throw new IllegalArgumentException("inputChannelName must not be null.");
514        }
515
516        InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
517        nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
518        inputChannels[0].dispose(); // don't need to retain the Java object reference
519        return inputChannels[1];
520    }
521
522    /**
523     * Registers an input channel so that it can be used as an input event target.
524     * @param inputChannel The input channel to register.
525     * @param inputWindowHandle The handle of the input window associated with the
526     * input channel, or null if none.
527     */
528    public void registerInputChannel(InputChannel inputChannel,
529            InputWindowHandle inputWindowHandle) {
530        if (inputChannel == null) {
531            throw new IllegalArgumentException("inputChannel must not be null.");
532        }
533
534        nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
535    }
536
537    /**
538     * Unregisters an input channel.
539     * @param inputChannel The input channel to unregister.
540     */
541    public void unregisterInputChannel(InputChannel inputChannel) {
542        if (inputChannel == null) {
543            throw new IllegalArgumentException("inputChannel must not be null.");
544        }
545
546        nativeUnregisterInputChannel(mPtr, inputChannel);
547    }
548
549    /**
550     * Sets an input filter that will receive all input events before they are dispatched.
551     * The input filter may then reinterpret input events or inject new ones.
552     *
553     * To ensure consistency, the input dispatcher automatically drops all events
554     * in progress whenever an input filter is installed or uninstalled.  After an input
555     * filter is uninstalled, it can no longer send input events unless it is reinstalled.
556     * Any events it attempts to send after it has been uninstalled will be dropped.
557     *
558     * @param filter The input filter, or null to remove the current filter.
559     */
560    public void setInputFilter(IInputFilter filter) {
561        synchronized (mInputFilterLock) {
562            final IInputFilter oldFilter = mInputFilter;
563            if (oldFilter == filter) {
564                return; // nothing to do
565            }
566
567            if (oldFilter != null) {
568                mInputFilter = null;
569                mInputFilterHost.disconnectLocked();
570                mInputFilterHost = null;
571                try {
572                    oldFilter.uninstall();
573                } catch (RemoteException re) {
574                    /* ignore */
575                }
576            }
577
578            if (filter != null) {
579                mInputFilter = filter;
580                mInputFilterHost = new InputFilterHost();
581                try {
582                    filter.install(mInputFilterHost);
583                } catch (RemoteException re) {
584                    /* ignore */
585                }
586            }
587
588            nativeSetInputFilterEnabled(mPtr, filter != null);
589        }
590    }
591
592    @Override // Binder call
593    public boolean injectInputEvent(InputEvent event, int mode) {
594        return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
595    }
596
597    private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
598        if (event == null) {
599            throw new IllegalArgumentException("event must not be null");
600        }
601        if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
602                && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
603                && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
604            throw new IllegalArgumentException("mode is invalid");
605        }
606
607        final int pid = Binder.getCallingPid();
608        final int uid = Binder.getCallingUid();
609        final long ident = Binder.clearCallingIdentity();
610        final int result;
611        try {
612            result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
613                    INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
614        } finally {
615            Binder.restoreCallingIdentity(ident);
616        }
617        switch (result) {
618            case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
619                Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
620                throw new SecurityException(
621                        "Injecting to another application requires INJECT_EVENTS permission");
622            case INPUT_EVENT_INJECTION_SUCCEEDED:
623                return true;
624            case INPUT_EVENT_INJECTION_TIMED_OUT:
625                Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
626                return false;
627            case INPUT_EVENT_INJECTION_FAILED:
628            default:
629                Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
630                return false;
631        }
632    }
633
634    /**
635     * Gets information about the input device with the specified id.
636     * @param deviceId The device id.
637     * @return The input device or null if not found.
638     */
639    @Override // Binder call
640    public InputDevice getInputDevice(int deviceId) {
641        synchronized (mInputDevicesLock) {
642            final int count = mInputDevices.length;
643            for (int i = 0; i < count; i++) {
644                final InputDevice inputDevice = mInputDevices[i];
645                if (inputDevice.getId() == deviceId) {
646                    return inputDevice;
647                }
648            }
649        }
650        return null;
651    }
652
653    /**
654     * Gets the ids of all input devices in the system.
655     * @return The input device ids.
656     */
657    @Override // Binder call
658    public int[] getInputDeviceIds() {
659        synchronized (mInputDevicesLock) {
660            final int count = mInputDevices.length;
661            int[] ids = new int[count];
662            for (int i = 0; i < count; i++) {
663                ids[i] = mInputDevices[i].getId();
664            }
665            return ids;
666        }
667    }
668
669    /**
670     * Gets all input devices in the system.
671     * @return The array of input devices.
672     */
673    public InputDevice[] getInputDevices() {
674        synchronized (mInputDevicesLock) {
675            return mInputDevices;
676        }
677    }
678
679    @Override // Binder call
680    public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
681        if (listener == null) {
682            throw new IllegalArgumentException("listener must not be null");
683        }
684
685        synchronized (mInputDevicesLock) {
686            int callingPid = Binder.getCallingPid();
687            if (mInputDevicesChangedListeners.get(callingPid) != null) {
688                throw new SecurityException("The calling process has already "
689                        + "registered an InputDevicesChangedListener.");
690            }
691
692            InputDevicesChangedListenerRecord record =
693                    new InputDevicesChangedListenerRecord(callingPid, listener);
694            try {
695                IBinder binder = listener.asBinder();
696                binder.linkToDeath(record, 0);
697            } catch (RemoteException ex) {
698                // give up
699                throw new RuntimeException(ex);
700            }
701
702            mInputDevicesChangedListeners.put(callingPid, record);
703        }
704    }
705
706    private void onInputDevicesChangedListenerDied(int pid) {
707        synchronized (mInputDevicesLock) {
708            mInputDevicesChangedListeners.remove(pid);
709        }
710    }
711
712    // Must be called on handler.
713    private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
714        // Scan for changes.
715        int numFullKeyboardsAdded = 0;
716        mTempInputDevicesChangedListenersToNotify.clear();
717        mTempFullKeyboards.clear();
718        final int numListeners;
719        final int[] deviceIdAndGeneration;
720        synchronized (mInputDevicesLock) {
721            if (!mInputDevicesChangedPending) {
722                return;
723            }
724            mInputDevicesChangedPending = false;
725
726            numListeners = mInputDevicesChangedListeners.size();
727            for (int i = 0; i < numListeners; i++) {
728                mTempInputDevicesChangedListenersToNotify.add(
729                        mInputDevicesChangedListeners.valueAt(i));
730            }
731
732            final int numDevices = mInputDevices.length;
733            deviceIdAndGeneration = new int[numDevices * 2];
734            for (int i = 0; i < numDevices; i++) {
735                final InputDevice inputDevice = mInputDevices[i];
736                deviceIdAndGeneration[i * 2] = inputDevice.getId();
737                deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
738
739                if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
740                    if (!containsInputDeviceWithDescriptor(oldInputDevices,
741                            inputDevice.getDescriptor())) {
742                        mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
743                    } else {
744                        mTempFullKeyboards.add(inputDevice);
745                    }
746                }
747            }
748        }
749
750        // Notify listeners.
751        for (int i = 0; i < numListeners; i++) {
752            mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
753                    deviceIdAndGeneration);
754        }
755        mTempInputDevicesChangedListenersToNotify.clear();
756
757        // Check for missing keyboard layouts.
758        List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
759        final int numFullKeyboards = mTempFullKeyboards.size();
760        synchronized (mDataStore) {
761            for (int i = 0; i < numFullKeyboards; i++) {
762                final InputDevice inputDevice = mTempFullKeyboards.get(i);
763                String layout =
764                    getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
765                if (layout == null) {
766                    layout = getDefaultKeyboardLayout(inputDevice);
767                    if (layout != null) {
768                        setCurrentKeyboardLayoutForInputDevice(
769                                inputDevice.getIdentifier(), layout);
770                    }
771                }
772                if (layout == null) {
773                    keyboardsMissingLayout.add(inputDevice);
774                }
775            }
776        }
777
778        if (mNotificationManager != null) {
779            if (!keyboardsMissingLayout.isEmpty()) {
780                if (keyboardsMissingLayout.size() > 1) {
781                    // We have more than one keyboard missing a layout, so drop the
782                    // user at the generic input methods page so they can pick which
783                    // one to set.
784                    showMissingKeyboardLayoutNotification(null);
785                } else {
786                    showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
787                }
788            } else if (mKeyboardLayoutNotificationShown) {
789                hideMissingKeyboardLayoutNotification();
790            }
791        }
792        mTempFullKeyboards.clear();
793    }
794
795    private String getDefaultKeyboardLayout(final InputDevice d) {
796        final Locale systemLocale = mContext.getResources().getConfiguration().locale;
797        // If our locale doesn't have a language for some reason, then we don't really have a
798        // reasonable default.
799        if (TextUtils.isEmpty(systemLocale.getLanguage())) {
800            return null;
801        }
802        final List<KeyboardLayout> layouts = new ArrayList<>();
803        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
804            @Override
805            public void visitKeyboardLayout(Resources resources,
806                    int keyboardLayoutResId, KeyboardLayout layout) {
807                // Only select a default when we know the layout is appropriate. For now, this
808                // means its a custom layout for a specific keyboard.
809                if (layout.getVendorId() != d.getVendorId()
810                        || layout.getProductId() != d.getProductId()) {
811                    return;
812                }
813                final LocaleList locales = layout.getLocales();
814                final int numLocales = locales.size();
815                for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
816                    if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
817                        layouts.add(layout);
818                        break;
819                    }
820                }
821            }
822        });
823
824        if (layouts.isEmpty()) {
825            return null;
826        }
827
828        // First sort so that ones with higher priority are listed at the top
829        Collections.sort(layouts);
830        // Next we want to try to find an exact match of language, country and variant.
831        final int N = layouts.size();
832        for (int i = 0; i < N; i++) {
833            KeyboardLayout layout = layouts.get(i);
834            final LocaleList locales = layout.getLocales();
835            final int numLocales = locales.size();
836            for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
837                final Locale locale = locales.get(localeIndex);
838                if (locale.getCountry().equals(systemLocale.getCountry())
839                        && locale.getVariant().equals(systemLocale.getVariant())) {
840                    return layout.getDescriptor();
841                }
842            }
843        }
844        // Then try an exact match of language and country
845        for (int i = 0; i < N; i++) {
846            KeyboardLayout layout = layouts.get(i);
847            final LocaleList locales = layout.getLocales();
848            final int numLocales = locales.size();
849            for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
850                final Locale locale = locales.get(localeIndex);
851                if (locale.getCountry().equals(systemLocale.getCountry())) {
852                    return layout.getDescriptor();
853                }
854            }
855        }
856
857        // Give up and just use the highest priority layout with matching language
858        return layouts.get(0).getDescriptor();
859    }
860
861    private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
862        // Different languages are never compatible
863        if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
864            return false;
865        }
866        // If both the system and the keyboard layout have a country specifier, they must be equal.
867        if (!TextUtils.isEmpty(systemLocale.getCountry())
868                && !TextUtils.isEmpty(keyboardLocale.getCountry())
869                && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
870            return false;
871        }
872        return true;
873    }
874
875    @Override // Binder call & native callback
876    public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
877            int surfaceRotation) {
878        if (inputDeviceDescriptor == null) {
879            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
880        }
881
882        synchronized (mDataStore) {
883            return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
884        }
885    }
886
887    @Override // Binder call
888    public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
889            TouchCalibration calibration) {
890        if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
891                "setTouchCalibrationForInputDevice()")) {
892            throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
893        }
894        if (inputDeviceDescriptor == null) {
895            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
896        }
897        if (calibration == null) {
898            throw new IllegalArgumentException("calibration must not be null");
899        }
900        if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
901            throw new IllegalArgumentException("surfaceRotation value out of bounds");
902        }
903
904        synchronized (mDataStore) {
905            try {
906                if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
907                        calibration)) {
908                    nativeReloadCalibration(mPtr);
909                }
910            } finally {
911                mDataStore.saveIfNeeded();
912            }
913        }
914    }
915
916    @Override // Binder call
917    public int isInTabletMode() {
918        if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
919                "isInTabletMode()")) {
920            throw new SecurityException("Requires TABLET_MODE permission");
921        }
922        return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
923    }
924
925    @Override // Binder call
926    public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
927        if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
928                "registerTabletModeChangedListener()")) {
929            throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
930        }
931        if (listener == null) {
932            throw new IllegalArgumentException("listener must not be null");
933        }
934
935        synchronized (mTabletModeLock) {
936            final int callingPid = Binder.getCallingPid();
937            if (mTabletModeChangedListeners.get(callingPid) != null) {
938                throw new IllegalStateException("The calling process has already registered "
939                        + "a TabletModeChangedListener.");
940            }
941            TabletModeChangedListenerRecord record =
942                    new TabletModeChangedListenerRecord(callingPid, listener);
943            try {
944                IBinder binder = listener.asBinder();
945                binder.linkToDeath(record, 0);
946            } catch (RemoteException ex) {
947                throw new RuntimeException(ex);
948            }
949            mTabletModeChangedListeners.put(callingPid, record);
950        }
951    }
952
953    private void onTabletModeChangedListenerDied(int pid) {
954        synchronized (mTabletModeLock) {
955            mTabletModeChangedListeners.remove(pid);
956        }
957    }
958
959    // Must be called on handler
960    private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
961        mTempTabletModeChangedListenersToNotify.clear();
962        final int numListeners;
963        synchronized (mTabletModeLock) {
964            numListeners = mTabletModeChangedListeners.size();
965            for (int i = 0; i < numListeners; i++) {
966                mTempTabletModeChangedListenersToNotify.add(
967                        mTabletModeChangedListeners.valueAt(i));
968            }
969        }
970        for (int i = 0; i < numListeners; i++) {
971            mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
972                    whenNanos, inTabletMode);
973        }
974    }
975
976    // Must be called on handler.
977    private void showMissingKeyboardLayoutNotification(InputDevice device) {
978        if (!mKeyboardLayoutNotificationShown) {
979            final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
980            if (device != null) {
981                intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
982            }
983            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
984                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
985                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
986            final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
987                    intent, 0, null, UserHandle.CURRENT);
988
989            Resources r = mContext.getResources();
990            Notification notification =
991                    new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
992                            .setContentTitle(r.getString(
993                                    R.string.select_keyboard_layout_notification_title))
994                            .setContentText(r.getString(
995                                    R.string.select_keyboard_layout_notification_message))
996                            .setContentIntent(keyboardLayoutIntent)
997                            .setSmallIcon(R.drawable.ic_settings_language)
998                            .setColor(mContext.getColor(
999                                    com.android.internal.R.color.system_notification_accent_color))
1000                            .build();
1001            mNotificationManager.notifyAsUser(null,
1002                    SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
1003                    notification, UserHandle.ALL);
1004            mKeyboardLayoutNotificationShown = true;
1005        }
1006    }
1007
1008    // Must be called on handler.
1009    private void hideMissingKeyboardLayoutNotification() {
1010        if (mKeyboardLayoutNotificationShown) {
1011            mKeyboardLayoutNotificationShown = false;
1012            mNotificationManager.cancelAsUser(null,
1013                    SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
1014                    UserHandle.ALL);
1015        }
1016    }
1017
1018    // Must be called on handler.
1019    private void updateKeyboardLayouts() {
1020        // Scan all input devices state for keyboard layouts that have been uninstalled.
1021        final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
1022        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1023            @Override
1024            public void visitKeyboardLayout(Resources resources,
1025                    int keyboardLayoutResId, KeyboardLayout layout) {
1026                availableKeyboardLayouts.add(layout.getDescriptor());
1027            }
1028        });
1029        synchronized (mDataStore) {
1030            try {
1031                mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
1032            } finally {
1033                mDataStore.saveIfNeeded();
1034            }
1035        }
1036
1037        // Reload keyboard layouts.
1038        reloadKeyboardLayouts();
1039    }
1040
1041    private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
1042            String descriptor) {
1043        final int numDevices = inputDevices.length;
1044        for (int i = 0; i < numDevices; i++) {
1045            final InputDevice inputDevice = inputDevices[i];
1046            if (inputDevice.getDescriptor().equals(descriptor)) {
1047                return true;
1048            }
1049        }
1050        return false;
1051    }
1052
1053    @Override // Binder call
1054    public KeyboardLayout[] getKeyboardLayouts() {
1055        final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
1056        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1057            @Override
1058            public void visitKeyboardLayout(Resources resources,
1059                    int keyboardLayoutResId, KeyboardLayout layout) {
1060                list.add(layout);
1061            }
1062        });
1063        return list.toArray(new KeyboardLayout[list.size()]);
1064    }
1065
1066    @Override // Binder call
1067    public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1068            final InputDeviceIdentifier identifier) {
1069        final String[] enabledLayoutDescriptors =
1070            getEnabledKeyboardLayoutsForInputDevice(identifier);
1071        final ArrayList<KeyboardLayout> enabledLayouts =
1072            new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length);
1073        final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>();
1074        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1075            boolean mHasSeenDeviceSpecificLayout;
1076
1077            @Override
1078            public void visitKeyboardLayout(Resources resources,
1079                    int keyboardLayoutResId, KeyboardLayout layout) {
1080                // First check if it's enabled. If the keyboard layout is enabled then we always
1081                // want to return it as a possible layout for the device.
1082                for (String s : enabledLayoutDescriptors) {
1083                    if (s != null && s.equals(layout.getDescriptor())) {
1084                        enabledLayouts.add(layout);
1085                        return;
1086                    }
1087                }
1088                // Next find any potential layouts that aren't yet enabled for the device. For
1089                // devices that have special layouts we assume there's a reason that the generic
1090                // layouts don't work for them so we don't want to return them since it's likely
1091                // to result in a poor user experience.
1092                if (layout.getVendorId() == identifier.getVendorId()
1093                        && layout.getProductId() == identifier.getProductId()) {
1094                    if (!mHasSeenDeviceSpecificLayout) {
1095                        mHasSeenDeviceSpecificLayout = true;
1096                        potentialLayouts.clear();
1097                    }
1098                    potentialLayouts.add(layout);
1099                } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
1100                        && !mHasSeenDeviceSpecificLayout) {
1101                    potentialLayouts.add(layout);
1102                }
1103            }
1104        });
1105        final int enabledLayoutSize = enabledLayouts.size();
1106        final int potentialLayoutSize = potentialLayouts.size();
1107        KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
1108        enabledLayouts.toArray(layouts);
1109        for (int i = 0; i < potentialLayoutSize; i++) {
1110            layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
1111        }
1112        return layouts;
1113    }
1114
1115    @Override // Binder call
1116    public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
1117        if (keyboardLayoutDescriptor == null) {
1118            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1119        }
1120
1121        final KeyboardLayout[] result = new KeyboardLayout[1];
1122        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1123            @Override
1124            public void visitKeyboardLayout(Resources resources,
1125                    int keyboardLayoutResId, KeyboardLayout layout) {
1126                result[0] = layout;
1127            }
1128        });
1129        if (result[0] == null) {
1130            Slog.w(TAG, "Could not get keyboard layout with descriptor '"
1131                    + keyboardLayoutDescriptor + "'.");
1132        }
1133        return result[0];
1134    }
1135
1136    private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
1137        final PackageManager pm = mContext.getPackageManager();
1138        Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
1139        for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
1140                PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
1141                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
1142            final ActivityInfo activityInfo = resolveInfo.activityInfo;
1143            final int priority = resolveInfo.priority;
1144            visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
1145        }
1146    }
1147
1148    private void visitKeyboardLayout(String keyboardLayoutDescriptor,
1149            KeyboardLayoutVisitor visitor) {
1150        KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
1151        if (d != null) {
1152            final PackageManager pm = mContext.getPackageManager();
1153            try {
1154                ActivityInfo receiver = pm.getReceiverInfo(
1155                        new ComponentName(d.packageName, d.receiverName),
1156                        PackageManager.GET_META_DATA
1157                                | PackageManager.MATCH_DIRECT_BOOT_AWARE
1158                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
1159                visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
1160            } catch (NameNotFoundException ex) {
1161            }
1162        }
1163    }
1164
1165    private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
1166            String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
1167        Bundle metaData = receiver.metaData;
1168        if (metaData == null) {
1169            return;
1170        }
1171
1172        int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1173        if (configResId == 0) {
1174            Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
1175                    + "' on receiver " + receiver.packageName + "/" + receiver.name);
1176            return;
1177        }
1178
1179        CharSequence receiverLabel = receiver.loadLabel(pm);
1180        String collection = receiverLabel != null ? receiverLabel.toString() : "";
1181        int priority;
1182        if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1183            priority = requestedPriority;
1184        } else {
1185            priority = 0;
1186        }
1187
1188        try {
1189            Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1190            XmlResourceParser parser = resources.getXml(configResId);
1191            try {
1192                XmlUtils.beginDocument(parser, "keyboard-layouts");
1193
1194                for (;;) {
1195                    XmlUtils.nextElement(parser);
1196                    String element = parser.getName();
1197                    if (element == null) {
1198                        break;
1199                    }
1200                    if (element.equals("keyboard-layout")) {
1201                        TypedArray a = resources.obtainAttributes(
1202                                parser, com.android.internal.R.styleable.KeyboardLayout);
1203                        try {
1204                            String name = a.getString(
1205                                    com.android.internal.R.styleable.KeyboardLayout_name);
1206                            String label = a.getString(
1207                                    com.android.internal.R.styleable.KeyboardLayout_label);
1208                            int keyboardLayoutResId = a.getResourceId(
1209                                    com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1210                                    0);
1211                            String languageTags = a.getString(
1212                                    com.android.internal.R.styleable.KeyboardLayout_locale);
1213                            LocaleList locales = getLocalesFromLanguageTags(languageTags);
1214                            int vid = a.getInt(
1215                                    com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
1216                            int pid = a.getInt(
1217                                    com.android.internal.R.styleable.KeyboardLayout_productId, -1);
1218
1219                            if (name == null || label == null || keyboardLayoutResId == 0) {
1220                                Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
1221                                        + "attributes in keyboard layout "
1222                                        + "resource from receiver "
1223                                        + receiver.packageName + "/" + receiver.name);
1224                            } else {
1225                                String descriptor = KeyboardLayoutDescriptor.format(
1226                                        receiver.packageName, receiver.name, name);
1227                                if (keyboardName == null || name.equals(keyboardName)) {
1228                                    KeyboardLayout layout = new KeyboardLayout(
1229                                            descriptor, label, collection, priority,
1230                                            locales, vid, pid);
1231                                    visitor.visitKeyboardLayout(
1232                                            resources, keyboardLayoutResId, layout);
1233                                }
1234                            }
1235                        } finally {
1236                            a.recycle();
1237                        }
1238                    } else {
1239                        Slog.w(TAG, "Skipping unrecognized element '" + element
1240                                + "' in keyboard layout resource from receiver "
1241                                + receiver.packageName + "/" + receiver.name);
1242                    }
1243                }
1244            } finally {
1245                parser.close();
1246            }
1247        } catch (Exception ex) {
1248            Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
1249                    + receiver.packageName + "/" + receiver.name, ex);
1250        }
1251    }
1252
1253    @NonNull
1254    private static LocaleList getLocalesFromLanguageTags(String languageTags) {
1255        if (TextUtils.isEmpty(languageTags)) {
1256            return LocaleList.getEmptyLocaleList();
1257        }
1258        return LocaleList.forLanguageTags(languageTags.replace('|', ','));
1259    }
1260
1261    /**
1262     * Builds a layout descriptor for the vendor/product. This returns the
1263     * descriptor for ids that aren't useful (such as the default 0, 0).
1264     */
1265    private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1266        if (identifier == null || identifier.getDescriptor() == null) {
1267            throw new IllegalArgumentException("identifier and descriptor must not be null");
1268        }
1269
1270        if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1271            return identifier.getDescriptor();
1272        }
1273        StringBuilder bob = new StringBuilder();
1274        bob.append("vendor:").append(identifier.getVendorId());
1275        bob.append(",product:").append(identifier.getProductId());
1276        return bob.toString();
1277    }
1278
1279    @Override // Binder call
1280    public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1281
1282        String key = getLayoutDescriptor(identifier);
1283        synchronized (mDataStore) {
1284            String layout = null;
1285            // try loading it using the layout descriptor if we have it
1286            layout = mDataStore.getCurrentKeyboardLayout(key);
1287            if (layout == null && !key.equals(identifier.getDescriptor())) {
1288                // if it doesn't exist fall back to the device descriptor
1289                layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1290            }
1291            if (DEBUG) {
1292                Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1293                        + layout);
1294            }
1295            return layout;
1296        }
1297    }
1298
1299    @Override // Binder call
1300    public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1301            String keyboardLayoutDescriptor) {
1302        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1303                "setCurrentKeyboardLayoutForInputDevice()")) {
1304            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1305        }
1306        if (keyboardLayoutDescriptor == null) {
1307            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1308        }
1309
1310        String key = getLayoutDescriptor(identifier);
1311        synchronized (mDataStore) {
1312            try {
1313                if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1314                    if (DEBUG) {
1315                        Slog.d(TAG, "Saved keyboard layout using " + key);
1316                    }
1317                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1318                }
1319            } finally {
1320                mDataStore.saveIfNeeded();
1321            }
1322        }
1323    }
1324
1325    @Override // Binder call
1326    public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
1327        String key = getLayoutDescriptor(identifier);
1328        synchronized (mDataStore) {
1329            String[] layouts = mDataStore.getKeyboardLayouts(key);
1330            if ((layouts == null || layouts.length == 0)
1331                    && !key.equals(identifier.getDescriptor())) {
1332                layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1333            }
1334            return layouts;
1335        }
1336    }
1337
1338    @Override // Binder call
1339    @Nullable
1340    public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1341            InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) {
1342        InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
1343        String key = getLayoutDescriptor(identifier);
1344        final String keyboardLayoutDescriptor;
1345        synchronized (mDataStore) {
1346            keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle);
1347        }
1348
1349        if (keyboardLayoutDescriptor == null) {
1350            return null;
1351        }
1352
1353        final KeyboardLayout[] result = new KeyboardLayout[1];
1354        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1355            @Override
1356            public void visitKeyboardLayout(Resources resources,
1357                    int keyboardLayoutResId, KeyboardLayout layout) {
1358                result[0] = layout;
1359            }
1360        });
1361        if (result[0] == null) {
1362            Slog.w(TAG, "Could not get keyboard layout with descriptor '"
1363                    + keyboardLayoutDescriptor + "'.");
1364        }
1365        return result[0];
1366    }
1367
1368    @Override
1369    public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1370            InputMethodInfo imeInfo, InputMethodSubtype imeSubtype,
1371            String keyboardLayoutDescriptor) {
1372        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1373                "setKeyboardLayoutForInputDevice()")) {
1374            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1375        }
1376        if (keyboardLayoutDescriptor == null) {
1377            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1378        }
1379        if (imeInfo == null) {
1380            throw new IllegalArgumentException("imeInfo must not be null");
1381        }
1382        InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
1383        setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
1384    }
1385
1386    private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier,
1387            InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
1388        String key = getLayoutDescriptor(identifier);
1389        synchronized (mDataStore) {
1390            try {
1391                if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) {
1392                    if (DEBUG) {
1393                        Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor +
1394                                " for subtype " + imeHandle + " and device " + identifier +
1395                                " using key " + key);
1396                    }
1397                    if (imeHandle.equals(mCurrentImeHandle)) {
1398                        if (DEBUG) {
1399                            Slog.d(TAG, "Layout for current subtype changed, switching layout");
1400                        }
1401                        SomeArgs args = SomeArgs.obtain();
1402                        args.arg1 = identifier;
1403                        args.arg2 = imeHandle;
1404                        mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget();
1405                    }
1406                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1407                }
1408            } finally {
1409                mDataStore.saveIfNeeded();
1410            }
1411        }
1412    }
1413
1414    @Override // Binder call
1415    public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1416            String keyboardLayoutDescriptor) {
1417        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1418                "addKeyboardLayoutForInputDevice()")) {
1419            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1420        }
1421        if (keyboardLayoutDescriptor == null) {
1422            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1423        }
1424
1425        String key = getLayoutDescriptor(identifier);
1426        synchronized (mDataStore) {
1427            try {
1428                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1429                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1430                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1431                }
1432                if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
1433                        && !Objects.equal(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) {
1434                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1435                }
1436            } finally {
1437                mDataStore.saveIfNeeded();
1438            }
1439        }
1440    }
1441
1442    @Override // Binder call
1443    public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1444            String keyboardLayoutDescriptor) {
1445        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1446                "removeKeyboardLayoutForInputDevice()")) {
1447            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1448        }
1449        if (keyboardLayoutDescriptor == null) {
1450            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1451        }
1452
1453        String key = getLayoutDescriptor(identifier);
1454        synchronized (mDataStore) {
1455            try {
1456                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1457                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1458                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1459                }
1460                boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1461                if (!key.equals(identifier.getDescriptor())) {
1462                    // We need to remove from both places to ensure it is gone
1463                    removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1464                            keyboardLayoutDescriptor);
1465                }
1466                if (removed && !Objects.equal(oldLayout,
1467                                mDataStore.getCurrentKeyboardLayout(key))) {
1468                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1469                }
1470            } finally {
1471                mDataStore.saveIfNeeded();
1472            }
1473        }
1474    }
1475
1476    // Must be called on handler.
1477    private void handleSwitchInputMethodSubtype(int userId,
1478            @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
1479        if (DEBUG) {
1480            Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
1481                    + " ime=" + inputMethodInfo + " subtype=" + subtype);
1482        }
1483        if (inputMethodInfo == null) {
1484            Slog.d(TAG, "No InputMethod is running, ignoring change");
1485            return;
1486        }
1487        if (subtype != null && !"keyboard".equals(subtype.getMode())) {
1488            Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change");
1489            return;
1490        }
1491        InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype);
1492        if (!handle.equals(mCurrentImeHandle)) {
1493            mCurrentImeHandle = handle;
1494            handleSwitchKeyboardLayout(null, handle);
1495        }
1496    }
1497
1498    // Must be called on handler.
1499    private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier,
1500            InputMethodSubtypeHandle handle) {
1501        synchronized (mInputDevicesLock) {
1502            for (InputDevice device : mInputDevices) {
1503                if (identifier != null && !device.getIdentifier().equals(identifier) ||
1504                        !device.isFullKeyboard()) {
1505                    continue;
1506                }
1507                String key = getLayoutDescriptor(device.getIdentifier());
1508                boolean changed = false;
1509                synchronized (mDataStore) {
1510                    try {
1511                        if (mDataStore.switchKeyboardLayout(key, handle)) {
1512                            changed = true;
1513                        }
1514                    } finally {
1515                        mDataStore.saveIfNeeded();
1516                    }
1517                }
1518                if (changed) {
1519                    reloadKeyboardLayouts();
1520                }
1521            }
1522        }
1523    }
1524
1525    public void setInputWindows(InputWindowHandle[] windowHandles,
1526            InputWindowHandle focusedWindowHandle) {
1527        final IWindow newFocusedWindow =
1528            focusedWindowHandle != null ? focusedWindowHandle.clientWindow : null;
1529        if (mFocusedWindow != newFocusedWindow) {
1530            mFocusedWindow = newFocusedWindow;
1531            if (mFocusedWindowHasCapture) {
1532                setPointerCapture(false);
1533            }
1534        }
1535        nativeSetInputWindows(mPtr, windowHandles);
1536    }
1537
1538    public void setFocusedApplication(InputApplicationHandle application) {
1539        nativeSetFocusedApplication(mPtr, application);
1540    }
1541
1542    @Override
1543    public void requestPointerCapture(IBinder windowToken, boolean enabled) {
1544        if (mFocusedWindow == null || mFocusedWindow.asBinder() != windowToken) {
1545            Slog.e(TAG, "requestPointerCapture called for a window that has no focus: "
1546                    + windowToken);
1547            return;
1548        }
1549        if (mFocusedWindowHasCapture == enabled) {
1550            Slog.i(TAG, "requestPointerCapture: already " + (enabled ? "enabled" : "disabled"));
1551            return;
1552        }
1553        setPointerCapture(enabled);
1554        try {
1555            mFocusedWindow.dispatchPointerCaptureChanged(enabled);
1556        } catch (RemoteException ex) {
1557            /* ignore */
1558        }
1559    }
1560
1561    private void setPointerCapture(boolean enabled) {
1562        mFocusedWindowHasCapture = enabled;
1563        nativeSetPointerCapture(mPtr, enabled);
1564    }
1565
1566    public void setInputDispatchMode(boolean enabled, boolean frozen) {
1567        nativeSetInputDispatchMode(mPtr, enabled, frozen);
1568    }
1569
1570    public void setSystemUiVisibility(int visibility) {
1571        nativeSetSystemUiVisibility(mPtr, visibility);
1572    }
1573
1574    /**
1575     * Atomically transfers touch focus from one window to another as identified by
1576     * their input channels.  It is possible for multiple windows to have
1577     * touch focus if they support split touch dispatch
1578     * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1579     * method only transfers touch focus of the specified window without affecting
1580     * other windows that may also have touch focus at the same time.
1581     * @param fromChannel The channel of a window that currently has touch focus.
1582     * @param toChannel The channel of the window that should receive touch focus in
1583     * place of the first.
1584     * @return True if the transfer was successful.  False if the window with the
1585     * specified channel did not actually have touch focus at the time of the request.
1586     */
1587    public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1588        if (fromChannel == null) {
1589            throw new IllegalArgumentException("fromChannel must not be null.");
1590        }
1591        if (toChannel == null) {
1592            throw new IllegalArgumentException("toChannel must not be null.");
1593        }
1594        return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
1595    }
1596
1597    @Override // Binder call
1598    public void tryPointerSpeed(int speed) {
1599        if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1600                "tryPointerSpeed()")) {
1601            throw new SecurityException("Requires SET_POINTER_SPEED permission");
1602        }
1603
1604        if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1605            throw new IllegalArgumentException("speed out of range");
1606        }
1607
1608        setPointerSpeedUnchecked(speed);
1609    }
1610
1611    public void updatePointerSpeedFromSettings() {
1612        int speed = getPointerSpeedSetting();
1613        setPointerSpeedUnchecked(speed);
1614    }
1615
1616    private void setPointerSpeedUnchecked(int speed) {
1617        speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1618                InputManager.MAX_POINTER_SPEED);
1619        nativeSetPointerSpeed(mPtr, speed);
1620    }
1621
1622    private void registerPointerSpeedSettingObserver() {
1623        mContext.getContentResolver().registerContentObserver(
1624                Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
1625                new ContentObserver(mHandler) {
1626                    @Override
1627                    public void onChange(boolean selfChange) {
1628                        updatePointerSpeedFromSettings();
1629                    }
1630                }, UserHandle.USER_ALL);
1631    }
1632
1633    private int getPointerSpeedSetting() {
1634        int speed = InputManager.DEFAULT_POINTER_SPEED;
1635        try {
1636            speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1637                    Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
1638        } catch (SettingNotFoundException snfe) {
1639        }
1640        return speed;
1641    }
1642
1643    public void updateShowTouchesFromSettings() {
1644        int setting = getShowTouchesSetting(0);
1645        nativeSetShowTouches(mPtr, setting != 0);
1646    }
1647
1648    private void registerShowTouchesSettingObserver() {
1649        mContext.getContentResolver().registerContentObserver(
1650                Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
1651                new ContentObserver(mHandler) {
1652                    @Override
1653                    public void onChange(boolean selfChange) {
1654                        updateShowTouchesFromSettings();
1655                    }
1656                }, UserHandle.USER_ALL);
1657    }
1658
1659    public void updateAccessibilityLargePointerFromSettings() {
1660        final int accessibilityConfig = Settings.Secure.getIntForUser(
1661                mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1662                0, UserHandle.USER_CURRENT);
1663        PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
1664        nativeReloadPointerIcons(mPtr);
1665    }
1666
1667    private void registerAccessibilityLargePointerSettingObserver() {
1668        mContext.getContentResolver().registerContentObserver(
1669                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1670                new ContentObserver(mHandler) {
1671                    @Override
1672                    public void onChange(boolean selfChange) {
1673                        updateAccessibilityLargePointerFromSettings();
1674                    }
1675                }, UserHandle.USER_ALL);
1676    }
1677
1678    private int getShowTouchesSetting(int defaultValue) {
1679        int result = defaultValue;
1680        try {
1681            result = Settings.System.getIntForUser(mContext.getContentResolver(),
1682                    Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
1683        } catch (SettingNotFoundException snfe) {
1684        }
1685        return result;
1686    }
1687
1688    // Binder call
1689    @Override
1690    public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1691        if (repeat >= pattern.length) {
1692            throw new ArrayIndexOutOfBoundsException();
1693        }
1694
1695        VibratorToken v;
1696        synchronized (mVibratorLock) {
1697            v = mVibratorTokens.get(token);
1698            if (v == null) {
1699                v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1700                try {
1701                    token.linkToDeath(v, 0);
1702                } catch (RemoteException ex) {
1703                    // give up
1704                    throw new RuntimeException(ex);
1705                }
1706                mVibratorTokens.put(token, v);
1707            }
1708        }
1709
1710        synchronized (v) {
1711            v.mVibrating = true;
1712            nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1713        }
1714    }
1715
1716    // Binder call
1717    @Override
1718    public void cancelVibrate(int deviceId, IBinder token) {
1719        VibratorToken v;
1720        synchronized (mVibratorLock) {
1721            v = mVibratorTokens.get(token);
1722            if (v == null || v.mDeviceId != deviceId) {
1723                return; // nothing to cancel
1724            }
1725        }
1726
1727        cancelVibrateIfNeeded(v);
1728    }
1729
1730    void onVibratorTokenDied(VibratorToken v) {
1731        synchronized (mVibratorLock) {
1732            mVibratorTokens.remove(v.mToken);
1733        }
1734
1735        cancelVibrateIfNeeded(v);
1736    }
1737
1738    private void cancelVibrateIfNeeded(VibratorToken v) {
1739        synchronized (v) {
1740            if (v.mVibrating) {
1741                nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1742                v.mVibrating = false;
1743            }
1744        }
1745    }
1746
1747    // Binder call
1748    @Override
1749    public void setPointerIconType(int iconId) {
1750        nativeSetPointerIconType(mPtr, iconId);
1751    }
1752
1753    // Binder call
1754    @Override
1755    public void setCustomPointerIcon(PointerIcon icon) {
1756        Preconditions.checkNotNull(icon);
1757        nativeSetCustomPointerIcon(mPtr, icon);
1758    }
1759
1760    @Override
1761    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
1762        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
1763
1764        pw.println("INPUT MANAGER (dumpsys input)\n");
1765        String dumpStr = nativeDump(mPtr);
1766        if (dumpStr != null) {
1767            pw.println(dumpStr);
1768        }
1769        pw.println("  Keyboard Layouts:");
1770        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1771            @Override
1772            public void visitKeyboardLayout(Resources resources,
1773                    int keyboardLayoutResId, KeyboardLayout layout) {
1774                pw.println("    \"" + layout + "\": " + layout.getDescriptor());
1775            }
1776        });
1777        pw.println();
1778        synchronized(mDataStore) {
1779            mDataStore.dump(pw, "  ");
1780        }
1781    }
1782
1783    @Override
1784    public void onShellCommand(FileDescriptor in, FileDescriptor out,
1785            FileDescriptor err, String[] args, ShellCallback callback,
1786            ResultReceiver resultReceiver) {
1787        (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
1788    }
1789
1790    public int onShellCommand(Shell shell, String cmd) {
1791        if (TextUtils.isEmpty(cmd)) {
1792            shell.onHelp();
1793            return 1;
1794        }
1795        if (cmd.equals("setlayout")) {
1796            if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1797                    "onShellCommand()")) {
1798                throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1799            }
1800            InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
1801                    shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired()));
1802            String descriptor = shell.getNextArgRequired();
1803            int vid = Integer.decode(shell.getNextArgRequired());
1804            int pid = Integer.decode(shell.getNextArgRequired());
1805            InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid);
1806            setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired());
1807        }
1808        return 0;
1809    }
1810
1811
1812    private boolean checkCallingPermission(String permission, String func) {
1813        // Quick check: if the calling permission is me, it's all okay.
1814        if (Binder.getCallingPid() == Process.myPid()) {
1815            return true;
1816        }
1817
1818        if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1819            return true;
1820        }
1821        String msg = "Permission Denial: " + func + " from pid="
1822                + Binder.getCallingPid()
1823                + ", uid=" + Binder.getCallingUid()
1824                + " requires " + permission;
1825        Slog.w(TAG, msg);
1826        return false;
1827    }
1828
1829    // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
1830    @Override
1831    public void monitor() {
1832        synchronized (mInputFilterLock) { }
1833        nativeMonitor(mPtr);
1834    }
1835
1836    // Native callback.
1837    private void notifyConfigurationChanged(long whenNanos) {
1838        mWindowManagerCallbacks.notifyConfigurationChanged();
1839    }
1840
1841    // Native callback.
1842    private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1843        synchronized (mInputDevicesLock) {
1844            if (!mInputDevicesChangedPending) {
1845                mInputDevicesChangedPending = true;
1846                mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1847                        mInputDevices).sendToTarget();
1848            }
1849
1850            mInputDevices = inputDevices;
1851        }
1852    }
1853
1854    // Native callback.
1855    private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1856        if (DEBUG) {
1857            Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1858                    + ", mask=" + Integer.toHexString(switchMask));
1859        }
1860
1861        if ((switchMask & SW_LID_BIT) != 0) {
1862            final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
1863            mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
1864        }
1865
1866        if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
1867            final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
1868            mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1869        }
1870
1871        if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1872            mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1873                    switchMask);
1874        }
1875
1876        if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
1877            SomeArgs args = SomeArgs.obtain();
1878            args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
1879            args.argi2 = (int) (whenNanos >> 32);
1880            args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
1881            mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
1882                    args).sendToTarget();
1883        }
1884    }
1885
1886    // Native callback.
1887    private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
1888        mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
1889    }
1890
1891    // Native callback.
1892    private long notifyANR(InputApplicationHandle inputApplicationHandle,
1893            InputWindowHandle inputWindowHandle, String reason) {
1894        return mWindowManagerCallbacks.notifyANR(
1895                inputApplicationHandle, inputWindowHandle, reason);
1896    }
1897
1898    // Native callback.
1899    final boolean filterInputEvent(InputEvent event, int policyFlags) {
1900        synchronized (mInputFilterLock) {
1901            if (mInputFilter != null) {
1902                try {
1903                    mInputFilter.filterInputEvent(event, policyFlags);
1904                } catch (RemoteException e) {
1905                    /* ignore */
1906                }
1907                return false;
1908            }
1909        }
1910        event.recycle();
1911        return true;
1912    }
1913
1914    // Native callback.
1915    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1916        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
1917    }
1918
1919    // Native callback.
1920    private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
1921        return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
1922                whenNanos, policyFlags);
1923    }
1924
1925    // Native callback.
1926    private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1927            KeyEvent event, int policyFlags) {
1928        return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
1929    }
1930
1931    // Native callback.
1932    private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1933            KeyEvent event, int policyFlags) {
1934        return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
1935    }
1936
1937    // Native callback.
1938    private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1939        return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1940                injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1941    }
1942
1943    // Native callback.
1944    private int getVirtualKeyQuietTimeMillis() {
1945        return mContext.getResources().getInteger(
1946                com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1947    }
1948
1949    // Native callback.
1950    private String[] getExcludedDeviceNames() {
1951        ArrayList<String> names = new ArrayList<String>();
1952
1953        // Read partner-provided list of excluded input devices
1954        XmlPullParser parser = null;
1955        // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1956        File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1957        FileReader confreader = null;
1958        try {
1959            confreader = new FileReader(confFile);
1960            parser = Xml.newPullParser();
1961            parser.setInput(confreader);
1962            XmlUtils.beginDocument(parser, "devices");
1963
1964            while (true) {
1965                XmlUtils.nextElement(parser);
1966                if (!"device".equals(parser.getName())) {
1967                    break;
1968                }
1969                String name = parser.getAttributeValue(null, "name");
1970                if (name != null) {
1971                    names.add(name);
1972                }
1973            }
1974        } catch (FileNotFoundException e) {
1975            // It's ok if the file does not exist.
1976        } catch (Exception e) {
1977            Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1978        } finally {
1979            try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1980        }
1981
1982        return names.toArray(new String[names.size()]);
1983    }
1984
1985    // Native callback.
1986    private int getKeyRepeatTimeout() {
1987        return ViewConfiguration.getKeyRepeatTimeout();
1988    }
1989
1990    // Native callback.
1991    private int getKeyRepeatDelay() {
1992        return ViewConfiguration.getKeyRepeatDelay();
1993    }
1994
1995    // Native callback.
1996    private int getHoverTapTimeout() {
1997        return ViewConfiguration.getHoverTapTimeout();
1998    }
1999
2000    // Native callback.
2001    private int getHoverTapSlop() {
2002        return ViewConfiguration.getHoverTapSlop();
2003    }
2004
2005    // Native callback.
2006    private int getDoubleTapTimeout() {
2007        return ViewConfiguration.getDoubleTapTimeout();
2008    }
2009
2010    // Native callback.
2011    private int getLongPressTimeout() {
2012        return ViewConfiguration.getLongPressTimeout();
2013    }
2014
2015    // Native callback.
2016    private int getPointerLayer() {
2017        return mWindowManagerCallbacks.getPointerLayer();
2018    }
2019
2020    // Native callback.
2021    private PointerIcon getPointerIcon() {
2022        return PointerIcon.getDefaultIcon(mContext);
2023    }
2024
2025    // Native callback.
2026    private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
2027        if (!mSystemReady) {
2028            return null;
2029        }
2030
2031        String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
2032        if (keyboardLayoutDescriptor == null) {
2033            return null;
2034        }
2035
2036        final String[] result = new String[2];
2037        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
2038            @Override
2039            public void visitKeyboardLayout(Resources resources,
2040                    int keyboardLayoutResId, KeyboardLayout layout) {
2041                try {
2042                    result[0] = layout.getDescriptor();
2043                    result[1] = Streams.readFully(new InputStreamReader(
2044                            resources.openRawResource(keyboardLayoutResId)));
2045                } catch (IOException ex) {
2046                } catch (NotFoundException ex) {
2047                }
2048            }
2049        });
2050        if (result[0] == null) {
2051            Slog.w(TAG, "Could not get keyboard layout with descriptor '"
2052                    + keyboardLayoutDescriptor + "'.");
2053            return null;
2054        }
2055        return result;
2056    }
2057
2058    // Native callback.
2059    private String getDeviceAlias(String uniqueId) {
2060        if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
2061            // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
2062            return null;
2063        }
2064        return null;
2065    }
2066
2067    /**
2068     * Callback interface implemented by the Window Manager.
2069     */
2070    public interface WindowManagerCallbacks {
2071        public void notifyConfigurationChanged();
2072
2073        public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
2074
2075        public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
2076
2077        public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
2078
2079        public long notifyANR(InputApplicationHandle inputApplicationHandle,
2080                InputWindowHandle inputWindowHandle, String reason);
2081
2082        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
2083
2084        public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
2085
2086        public long interceptKeyBeforeDispatching(InputWindowHandle focus,
2087                KeyEvent event, int policyFlags);
2088
2089        public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
2090                KeyEvent event, int policyFlags);
2091
2092        public int getPointerLayer();
2093    }
2094
2095    /**
2096     * Callback interface implemented by WiredAccessoryObserver.
2097     */
2098    public interface WiredAccessoryCallbacks {
2099        public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
2100        public void systemReady();
2101    }
2102
2103    /**
2104     * Private handler for the input manager.
2105     */
2106    private final class InputManagerHandler extends Handler {
2107        public InputManagerHandler(Looper looper) {
2108            super(looper, null, true /*async*/);
2109        }
2110
2111        @Override
2112        public void handleMessage(Message msg) {
2113            switch (msg.what) {
2114                case MSG_DELIVER_INPUT_DEVICES_CHANGED:
2115                    deliverInputDevicesChanged((InputDevice[])msg.obj);
2116                    break;
2117                case MSG_SWITCH_KEYBOARD_LAYOUT: {
2118                    SomeArgs args = (SomeArgs)msg.obj;
2119                    handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1,
2120                            (InputMethodSubtypeHandle)args.arg2);
2121                    break;
2122                }
2123                case MSG_RELOAD_KEYBOARD_LAYOUTS:
2124                    reloadKeyboardLayouts();
2125                    break;
2126                case MSG_UPDATE_KEYBOARD_LAYOUTS:
2127                    updateKeyboardLayouts();
2128                    break;
2129                case MSG_RELOAD_DEVICE_ALIASES:
2130                    reloadDeviceAliases();
2131                    break;
2132                case MSG_DELIVER_TABLET_MODE_CHANGED: {
2133                    SomeArgs args = (SomeArgs) msg.obj;
2134                    long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
2135                    boolean inTabletMode = (boolean) args.arg1;
2136                    deliverTabletModeChanged(whenNanos, inTabletMode);
2137                    break;
2138                }
2139                case MSG_INPUT_METHOD_SUBTYPE_CHANGED: {
2140                    final int userId = msg.arg1;
2141                    final SomeArgs args = (SomeArgs) msg.obj;
2142                    final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1;
2143                    final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2;
2144                    args.recycle();
2145                    handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype);
2146                    break;
2147                }
2148            }
2149        }
2150    }
2151
2152    /**
2153     * Hosting interface for input filters to call back into the input manager.
2154     */
2155    private final class InputFilterHost extends IInputFilterHost.Stub {
2156        private boolean mDisconnected;
2157
2158        public void disconnectLocked() {
2159            mDisconnected = true;
2160        }
2161
2162        @Override
2163        public void sendInputEvent(InputEvent event, int policyFlags) {
2164            if (event == null) {
2165                throw new IllegalArgumentException("event must not be null");
2166            }
2167
2168            synchronized (mInputFilterLock) {
2169                if (!mDisconnected) {
2170                    nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
2171                            InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
2172                            policyFlags | WindowManagerPolicy.FLAG_FILTERED);
2173                }
2174            }
2175        }
2176    }
2177
2178    private static final class KeyboardLayoutDescriptor {
2179        public String packageName;
2180        public String receiverName;
2181        public String keyboardLayoutName;
2182
2183        public static String format(String packageName,
2184                String receiverName, String keyboardName) {
2185            return packageName + "/" + receiverName + "/" + keyboardName;
2186        }
2187
2188        public static KeyboardLayoutDescriptor parse(String descriptor) {
2189            int pos = descriptor.indexOf('/');
2190            if (pos < 0 || pos + 1 == descriptor.length()) {
2191                return null;
2192            }
2193            int pos2 = descriptor.indexOf('/', pos + 1);
2194            if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
2195                return null;
2196            }
2197
2198            KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
2199            result.packageName = descriptor.substring(0, pos);
2200            result.receiverName = descriptor.substring(pos + 1, pos2);
2201            result.keyboardLayoutName = descriptor.substring(pos2 + 1);
2202            return result;
2203        }
2204    }
2205
2206    private interface KeyboardLayoutVisitor {
2207        void visitKeyboardLayout(Resources resources,
2208                int keyboardLayoutResId, KeyboardLayout layout);
2209    }
2210
2211    private final class InputDevicesChangedListenerRecord implements DeathRecipient {
2212        private final int mPid;
2213        private final IInputDevicesChangedListener mListener;
2214
2215        public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
2216            mPid = pid;
2217            mListener = listener;
2218        }
2219
2220        @Override
2221        public void binderDied() {
2222            if (DEBUG) {
2223                Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
2224            }
2225            onInputDevicesChangedListenerDied(mPid);
2226        }
2227
2228        public void notifyInputDevicesChanged(int[] info) {
2229            try {
2230                mListener.onInputDevicesChanged(info);
2231            } catch (RemoteException ex) {
2232                Slog.w(TAG, "Failed to notify process "
2233                        + mPid + " that input devices changed, assuming it died.", ex);
2234                binderDied();
2235            }
2236        }
2237    }
2238
2239    private final class TabletModeChangedListenerRecord implements DeathRecipient {
2240        private final int mPid;
2241        private final ITabletModeChangedListener mListener;
2242
2243        public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
2244            mPid = pid;
2245            mListener = listener;
2246        }
2247
2248        @Override
2249        public void binderDied() {
2250            if (DEBUG) {
2251                Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
2252            }
2253            onTabletModeChangedListenerDied(mPid);
2254        }
2255
2256        public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
2257            try {
2258                mListener.onTabletModeChanged(whenNanos, inTabletMode);
2259            } catch (RemoteException ex) {
2260                Slog.w(TAG, "Failed to notify process " + mPid +
2261                        " that tablet mode changed, assuming it died.", ex);
2262                binderDied();
2263            }
2264        }
2265    }
2266
2267    private final class VibratorToken implements DeathRecipient {
2268        public final int mDeviceId;
2269        public final IBinder mToken;
2270        public final int mTokenValue;
2271
2272        public boolean mVibrating;
2273
2274        public VibratorToken(int deviceId, IBinder token, int tokenValue) {
2275            mDeviceId = deviceId;
2276            mToken = token;
2277            mTokenValue = tokenValue;
2278        }
2279
2280        @Override
2281        public void binderDied() {
2282            if (DEBUG) {
2283                Slog.d(TAG, "Vibrator token died.");
2284            }
2285            onVibratorTokenDied(this);
2286        }
2287    }
2288
2289    private class Shell extends ShellCommand {
2290        @Override
2291        public int onCommand(String cmd) {
2292            return onShellCommand(this, cmd);
2293        }
2294
2295        @Override
2296        public void onHelp() {
2297            final PrintWriter pw = getOutPrintWriter();
2298            pw.println("Input manager commands:");
2299            pw.println("  help");
2300            pw.println("    Print this help text.");
2301            pw.println("");
2302            pw.println("  setlayout IME_ID IME_SUPTYPE_HASH_CODE"
2303                    + " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR");
2304            pw.println("    Sets a keyboard layout for a given IME subtype and input device pair");
2305        }
2306    }
2307
2308    private final class LocalService extends InputManagerInternal {
2309        @Override
2310        public void setDisplayViewports(DisplayViewport defaultViewport,
2311                DisplayViewport externalTouchViewport,
2312                List<DisplayViewport> virtualTouchViewports) {
2313            setDisplayViewportsInternal(defaultViewport, externalTouchViewport,
2314                    virtualTouchViewports);
2315        }
2316
2317        @Override
2318        public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
2319            return injectInputEventInternal(event, displayId, mode);
2320        }
2321
2322        @Override
2323        public void setInteractive(boolean interactive) {
2324            nativeSetInteractive(mPtr, interactive);
2325        }
2326
2327        @Override
2328        public void onInputMethodSubtypeChanged(int userId,
2329                @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
2330            final SomeArgs someArgs = SomeArgs.obtain();
2331            someArgs.arg1 = inputMethodInfo;
2332            someArgs.arg2 = subtype;
2333            mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs)
2334                    .sendToTarget();
2335        }
2336
2337        @Override
2338        public void toggleCapsLock(int deviceId) {
2339            nativeToggleCapsLock(mPtr, deviceId);
2340        }
2341
2342        @Override
2343        public void setPulseGestureEnabled(boolean enabled) {
2344            if (mDoubleTouchGestureEnableFile != null) {
2345                FileWriter writer = null;
2346                try {
2347                    writer = new FileWriter(mDoubleTouchGestureEnableFile);
2348                    writer.write(enabled ? "1" : "0");
2349                } catch (IOException e) {
2350                    Log.wtf(TAG, "Unable to setPulseGestureEnabled", e);
2351                } finally {
2352                    IoUtils.closeQuietly(writer);
2353                }
2354            }
2355        }
2356    }
2357}
2358