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