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