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