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