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