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