blob: 68b38179e26d18687f5a4d2f48ed96b91934874d [file] [log] [blame]
Jeff Brown46b9ac02010-04-22 18:58:52 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jeff Brown4532e612012-04-05 14:27:12 -070017package com.android.server.input;
Jeff Brown46b9ac02010-04-22 18:58:52 -070018
Yohei Yukawab097b822015-12-01 10:43:08 -080019import android.annotation.Nullable;
Jeff Brownca9bc702014-02-11 14:32:56 -080020import android.view.Display;
Michael Wright39e5e942015-08-19 22:52:47 +010021import com.android.internal.os.SomeArgs;
Jeff Browncf39bdf2012-05-18 14:41:19 -070022import com.android.internal.R;
Jeff Brown46b9ac02010-04-22 18:58:52 -070023import com.android.internal.util.XmlUtils;
Jeff Brown4ccb8232014-01-16 22:16:42 -080024import com.android.server.DisplayThread;
25import com.android.server.LocalServices;
Jeff Brown89ef0722011-08-10 16:25:21 -070026import com.android.server.Watchdog;
Jeff Brown46b9ac02010-04-22 18:58:52 -070027
28import org.xmlpull.v1.XmlPullParser;
29
Jeff Browna3bc5652012-04-17 11:42:25 -070030import android.Manifest;
Jeff Browncf39bdf2012-05-18 14:41:19 -070031import android.app.Notification;
32import android.app.NotificationManager;
33import android.app.PendingIntent;
Jeff Brown5bbd4b42012-04-20 19:28:00 -070034import android.bluetooth.BluetoothAdapter;
35import android.bluetooth.BluetoothDevice;
Jeff Brown6ec6f792012-04-17 16:52:41 -070036import android.content.BroadcastReceiver;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070037import android.content.ComponentName;
Jeff Brown46b9ac02010-04-22 18:58:52 -070038import android.content.Context;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070039import android.content.Intent;
Jeff Brown6ec6f792012-04-17 16:52:41 -070040import android.content.IntentFilter;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070041import android.content.pm.ActivityInfo;
Michael Wright8ebac232014-09-18 18:29:49 -070042import android.content.pm.ApplicationInfo;
Jeff Brown349703e2010-06-22 01:27:15 -070043import android.content.pm.PackageManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070044import android.content.pm.ResolveInfo;
45import android.content.pm.PackageManager.NameNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070046import android.content.res.Resources;
Jeff Brown6ec6f792012-04-17 16:52:41 -070047import android.content.res.Resources.NotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070048import android.content.res.TypedArray;
49import android.content.res.XmlResourceParser;
Jeff Brown1a84fd12011-06-02 01:26:32 -070050import android.database.ContentObserver;
Jeff Brown4ccb8232014-01-16 22:16:42 -080051import android.hardware.display.DisplayViewport;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070052import android.hardware.input.IInputDevicesChangedListener;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070053import android.hardware.input.IInputManager;
RoboErikfb290df2013-12-16 11:27:55 -080054import android.hardware.input.InputDeviceIdentifier;
Jeff Brownac143512012-04-05 18:57:33 -070055import android.hardware.input.InputManager;
Jeff Brown4ccb8232014-01-16 22:16:42 -080056import android.hardware.input.InputManagerInternal;
Michael Wright39e5e942015-08-19 22:52:47 +010057import android.hardware.input.ITabletModeChangedListener;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070058import android.hardware.input.KeyboardLayout;
Jason Gerecked6396d62014-01-27 18:30:37 -080059import android.hardware.input.TouchCalibration;
Jeff Brown4532e612012-04-05 14:27:12 -070060import android.os.Binder;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070061import android.os.Bundle;
Jeff Brown46b9ac02010-04-22 18:58:52 -070062import android.os.Environment;
Jeff Brown4532e612012-04-05 14:27:12 -070063import android.os.Handler;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070064import android.os.IBinder;
Jeff Browna9d131c2012-09-20 16:48:17 -070065import android.os.Looper;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070066import android.os.Message;
Jeff Brown05dc66a2011-03-02 14:41:58 -080067import android.os.MessageQueue;
Jeff Brownac143512012-04-05 18:57:33 -070068import android.os.Process;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070069import android.os.RemoteException;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070070import android.os.UserHandle;
Jeff Brown1a84fd12011-06-02 01:26:32 -070071import android.provider.Settings;
72import android.provider.Settings.SettingNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070073import android.util.Log;
Jeff Brown46b9ac02010-04-22 18:58:52 -070074import android.util.Slog;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070075import android.util.SparseArray;
Jeff Brown46b9ac02010-04-22 18:58:52 -070076import android.util.Xml;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070077import android.view.IInputFilter;
78import android.view.IInputFilterHost;
Jeff Brown46b9ac02010-04-22 18:58:52 -070079import android.view.InputChannel;
Jeff Brown8d608662010-08-30 03:02:23 -070080import android.view.InputDevice;
Jeff Brown6ec402b2010-07-28 15:48:59 -070081import android.view.InputEvent;
Jeff Brown1f245102010-11-18 20:53:46 -080082import android.view.KeyEvent;
Jeff Brown2352b972011-04-12 22:39:53 -070083import android.view.PointerIcon;
Jason Gerecked5220742014-03-10 09:47:59 -070084import android.view.Surface;
Jeff Browna4547672011-03-02 21:38:11 -080085import android.view.ViewConfiguration;
Jeff Brown0029c662011-03-30 02:25:18 -070086import android.view.WindowManagerPolicy;
Yohei Yukawab097b822015-12-01 10:43:08 -080087import android.view.inputmethod.InputMethod;
88import android.view.inputmethod.InputMethodInfo;
89import android.view.inputmethod.InputMethodSubtype;
Jeff Browncf39bdf2012-05-18 14:41:19 -070090import android.widget.Toast;
Jeff Brown46b9ac02010-04-22 18:58:52 -070091
Jeff Brown46b9ac02010-04-22 18:58:52 -070092import java.io.File;
Jeff Brown4532e612012-04-05 14:27:12 -070093import java.io.FileDescriptor;
Jeff Brown46b9ac02010-04-22 18:58:52 -070094import java.io.FileNotFoundException;
95import java.io.FileReader;
96import java.io.IOException;
Jeff Brown6ec6f792012-04-17 16:52:41 -070097import java.io.InputStreamReader;
Jeff Brown46b9ac02010-04-22 18:58:52 -070098import java.io.PrintWriter;
99import java.util.ArrayList;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700100import java.util.HashMap;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700101import java.util.HashSet;
Michael Wright39e5e942015-08-19 22:52:47 +0100102import java.util.List;
Jeff Browna3bc5652012-04-17 11:42:25 -0700103
Jeff Brown6ec6f792012-04-17 16:52:41 -0700104import libcore.io.Streams;
Jeff Browna3bc5652012-04-17 11:42:25 -0700105import libcore.util.Objects;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700106
107/*
108 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -0700109 */
Jeff Brownd728bf52012-09-08 18:05:28 -0700110public class InputManagerService extends IInputManager.Stub
Jeff Brown4ccb8232014-01-16 22:16:42 -0800111 implements Watchdog.Monitor {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700112 static final String TAG = "InputManager";
Jeff Brown1b9ba572012-05-21 10:54:18 -0700113 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -0700114
Jeff Brown4532e612012-04-05 14:27:12 -0700115 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
116
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700117 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700118 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
119 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
120 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
121 private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
Michael Wright39e5e942015-08-19 22:52:47 +0100122 private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
Yohei Yukawab097b822015-12-01 10:43:08 -0800123 private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700124
Jeff Brown4532e612012-04-05 14:27:12 -0700125 // Pointer to native input manager service object.
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000126 private final long mPtr;
Jeff Brown4532e612012-04-05 14:27:12 -0700127
Jeff Brown46b9ac02010-04-22 18:58:52 -0700128 private final Context mContext;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700129 private final InputManagerHandler mHandler;
Jeff Browna9d131c2012-09-20 16:48:17 -0700130
131 private WindowManagerCallbacks mWindowManagerCallbacks;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700132 private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700133 private boolean mSystemReady;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700134 private NotificationManager mNotificationManager;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700135
Michael Wright39e5e942015-08-19 22:52:47 +0100136 private final Object mTabletModeLock = new Object();
137 // List of currently registered tablet mode changed listeners by process id
138 private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
139 new SparseArray<>(); // guarded by mTabletModeLock
140 private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
141 new ArrayList<>();
142
Jeff Browna3bc5652012-04-17 11:42:25 -0700143 // Persistent data store. Must be locked each time during use.
144 private final PersistentDataStore mDataStore = new PersistentDataStore();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700145
146 // List of currently registered input devices changed listeners by process id.
147 private Object mInputDevicesLock = new Object();
148 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
149 private InputDevice[] mInputDevices = new InputDevice[0];
150 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
151 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
152 private final ArrayList<InputDevicesChangedListenerRecord>
153 mTempInputDevicesChangedListenersToNotify =
154 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
Jeff Browncf39bdf2012-05-18 14:41:19 -0700155 private final ArrayList<InputDevice>
156 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
157 private boolean mKeyboardLayoutNotificationShown;
158 private PendingIntent mKeyboardLayoutIntent;
159 private Toast mSwitchedKeyboardLayoutToast;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700160
Jeff Browna47425a2012-04-13 04:09:27 -0700161 // State for vibrator tokens.
162 private Object mVibratorLock = new Object();
163 private HashMap<IBinder, VibratorToken> mVibratorTokens =
164 new HashMap<IBinder, VibratorToken>();
165 private int mNextVibratorTokenValue;
166
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700167 // State for the currently installed input filter.
168 final Object mInputFilterLock = new Object();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700169 IInputFilter mInputFilter; // guarded by mInputFilterLock
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700170 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
Jeff Brown1a84fd12011-06-02 01:26:32 -0700171
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000172 private static native long nativeInit(InputManagerService service,
Jeff Brown4532e612012-04-05 14:27:12 -0700173 Context context, MessageQueue messageQueue);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000174 private static native void nativeStart(long ptr);
175 private static native void nativeSetDisplayViewport(long ptr, boolean external,
Jeff Brownd728bf52012-09-08 18:05:28 -0700176 int displayId, int rotation,
177 int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
Jeff Brown83d616a2012-09-09 20:33:43 -0700178 int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
179 int deviceWidth, int deviceHeight);
Jeff Brownd728bf52012-09-08 18:05:28 -0700180
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000181 private static native int nativeGetScanCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700182 int deviceId, int sourceMask, int scanCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000183 private static native int nativeGetKeyCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700184 int deviceId, int sourceMask, int keyCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000185 private static native int nativeGetSwitchState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700186 int deviceId, int sourceMask, int sw);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000187 private static native boolean nativeHasKeys(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700188 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000189 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
Jeff Brown928e0542011-01-10 11:17:36 -0800190 InputWindowHandle inputWindowHandle, boolean monitor);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000191 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
192 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
Jeff Brownca9bc702014-02-11 14:32:56 -0800193 private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId,
Jeff Brown0029c662011-03-30 02:25:18 -0700194 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
195 int policyFlags);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000196 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
197 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
198 private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
199 private static native void nativeSetFocusedApplication(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700200 InputApplicationHandle application);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000201 private static native boolean nativeTransferTouchFocus(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700202 InputChannel fromChannel, InputChannel toChannel);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000203 private static native void nativeSetPointerSpeed(long ptr, int speed);
204 private static native void nativeSetShowTouches(long ptr, boolean enabled);
Jeff Brown037c33e2014-04-09 00:31:55 -0700205 private static native void nativeSetInteractive(long ptr, boolean interactive);
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800206 private static native void nativeReloadCalibration(long ptr);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000207 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
Jeff Browna47425a2012-04-13 04:09:27 -0700208 int repeat, int token);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000209 private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
210 private static native void nativeReloadKeyboardLayouts(long ptr);
211 private static native void nativeReloadDeviceAliases(long ptr);
212 private static native String nativeDump(long ptr);
213 private static native void nativeMonitor(long ptr);
Jun Mukai1db53972015-09-11 18:08:31 -0700214 private static native void nativeSetPointerIconShape(long ptr, int iconId);
Jun Mukai19a56012015-11-24 11:25:52 -0800215 private static native void nativeReloadPointerIcons(long ptr);
Jun Mukaid4eaef72015-10-30 15:54:33 -0700216 private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
Jeff Brown4532e612012-04-05 14:27:12 -0700217
Jeff Brownac143512012-04-05 18:57:33 -0700218 // Input event injection constants defined in InputDispatcher.h.
219 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
220 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
221 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
222 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
223
224 // Maximum number of milliseconds to wait for input event injection.
225 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
226
Jeff Brown6d0fec22010-07-23 21:28:06 -0700227 // Key states (may be returned by queries about the current state of a
228 // particular key code, scan code or switch).
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700229
Jeff Brown6d0fec22010-07-23 21:28:06 -0700230 /** The key state is unknown or the requested key itself is not supported. */
231 public static final int KEY_STATE_UNKNOWN = -1;
232
233 /** The key is up. /*/
234 public static final int KEY_STATE_UP = 0;
235
236 /** The key is down. */
237 public static final int KEY_STATE_DOWN = 1;
238
239 /** The key is down but is a virtual key press that is being emulated by the system. */
240 public static final int KEY_STATE_VIRTUAL = 2;
241
Jeff Brownc458ce92012-04-30 14:58:40 -0700242 /** Scan code: Mouse / trackball button. */
243 public static final int BTN_MOUSE = 0x110;
244
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700245 // Switch code values must match bionic/libc/kernel/common/linux/input.h
Jeff Brownc458ce92012-04-30 14:58:40 -0700246 /** Switch code: Lid switch. When set, lid is shut. */
247 public static final int SW_LID = 0x00;
248
Michael Wright39e5e942015-08-19 22:52:47 +0100249 /** Switch code: Tablet mode switch.
250 * When set, the device is in tablet mode (i.e. no keyboard is connected).
251 */
252 public static final int SW_TABLET_MODE = 0x01;
253
Jeff Brownc458ce92012-04-30 14:58:40 -0700254 /** Switch code: Keypad slide. When set, keyboard is exposed. */
255 public static final int SW_KEYPAD_SLIDE = 0x0a;
256
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700257 /** Switch code: Headphone. When set, headphone is inserted. */
258 public static final int SW_HEADPHONE_INSERT = 0x02;
259
260 /** Switch code: Microphone. When set, microphone is inserted. */
261 public static final int SW_MICROPHONE_INSERT = 0x04;
262
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500263 /** Switch code: Line out. When set, Line out (hi-Z) is inserted. */
264 public static final int SW_LINEOUT_INSERT = 0x06;
265
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700266 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */
267 public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
268
Michael Wright3818c922014-09-02 13:59:07 -0700269 /** Switch code: Camera lens cover. When set the lens is covered. */
270 public static final int SW_CAMERA_LENS_COVER = 0x09;
271
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700272 public static final int SW_LID_BIT = 1 << SW_LID;
Michael Wright39e5e942015-08-19 22:52:47 +0100273 public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700274 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
275 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
276 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500277 public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700278 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
279 public static final int SW_JACK_BITS =
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500280 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
Michael Wright3818c922014-09-02 13:59:07 -0700281 public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700282
283 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
284 final boolean mUseDevInputEventForAudioJack;
285
Jeff Brown4ccb8232014-01-16 22:16:42 -0800286 public InputManagerService(Context context) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700287 this.mContext = context;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800288 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
Jeff Brown05dc66a2011-03-02 14:41:58 -0800289
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700290 mUseDevInputEventForAudioJack =
291 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
292 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
293 + mUseDevInputEventForAudioJack);
Jeff Brown4532e612012-04-05 14:27:12 -0700294 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown4ccb8232014-01-16 22:16:42 -0800295
296 LocalServices.addService(InputManagerInternal.class, new LocalService());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700297 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700298
Jeff Browna9d131c2012-09-20 16:48:17 -0700299 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
300 mWindowManagerCallbacks = callbacks;
301 }
302
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700303 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
304 mWiredAccessoryCallbacks = callbacks;
305 }
306
Jeff Brown46b9ac02010-04-22 18:58:52 -0700307 public void start() {
308 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700309 nativeStart(mPtr);
310
311 // Add ourself to the Watchdog monitors.
312 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700313
314 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700315 registerShowTouchesSettingObserver();
Jun Mukai19a56012015-11-24 11:25:52 -0800316 registerAccessibilityLargePointerSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700317
Jeff Brownd4935962012-09-25 13:27:20 -0700318 mContext.registerReceiver(new BroadcastReceiver() {
319 @Override
320 public void onReceive(Context context, Intent intent) {
321 updatePointerSpeedFromSettings();
322 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800323 updateAccessibilityLargePointerFromSettings();
Jeff Brownd4935962012-09-25 13:27:20 -0700324 }
325 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
326
Jeff Brown1a84fd12011-06-02 01:26:32 -0700327 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700328 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800329 updateAccessibilityLargePointerFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700330 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700331
Matthew Xie96313142012-06-29 16:57:31 -0700332 // TODO(BT) Pass in paramter for bluetooth system
Svetoslav Ganova0027152013-06-25 14:59:53 -0700333 public void systemRunning() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700334 if (DEBUG) {
335 Slog.d(TAG, "System ready.");
336 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700337 mNotificationManager = (NotificationManager)mContext.getSystemService(
338 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700339 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700340
341 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
342 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
343 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Jeff Brown69b07162013-11-07 00:30:16 -0800344 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700345 filter.addDataScheme("package");
346 mContext.registerReceiver(new BroadcastReceiver() {
347 @Override
348 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700349 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700350 }
351 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700352
353 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
354 mContext.registerReceiver(new BroadcastReceiver() {
355 @Override
356 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700357 reloadDeviceAliases();
358 }
359 }, filter, null, mHandler);
360
Jeff Browncf39bdf2012-05-18 14:41:19 -0700361 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
362 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700363
364 if (mWiredAccessoryCallbacks != null) {
365 mWiredAccessoryCallbacks.systemReady();
366 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700367 }
368
369 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700370 if (DEBUG) {
371 Slog.d(TAG, "Reloading keyboard layouts.");
372 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700373 nativeReloadKeyboardLayouts(mPtr);
374 }
375
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700376 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700377 if (DEBUG) {
378 Slog.d(TAG, "Reloading device names.");
379 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700380 nativeReloadDeviceAliases(mPtr);
381 }
382
Jeff Brown4ccb8232014-01-16 22:16:42 -0800383 private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
Jeff Brownd728bf52012-09-08 18:05:28 -0700384 DisplayViewport externalTouchViewport) {
385 if (defaultViewport.valid) {
386 setDisplayViewport(false, defaultViewport);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700387 }
Jeff Brownd728bf52012-09-08 18:05:28 -0700388
389 if (externalTouchViewport.valid) {
390 setDisplayViewport(true, externalTouchViewport);
391 } else if (defaultViewport.valid) {
392 setDisplayViewport(true, defaultViewport);
Jeff Brownb6997262010-10-08 22:31:17 -0700393 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700394 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700395
Jeff Brownd728bf52012-09-08 18:05:28 -0700396 private void setDisplayViewport(boolean external, DisplayViewport viewport) {
397 nativeSetDisplayViewport(mPtr, external,
398 viewport.displayId, viewport.orientation,
399 viewport.logicalFrame.left, viewport.logicalFrame.top,
400 viewport.logicalFrame.right, viewport.logicalFrame.bottom,
401 viewport.physicalFrame.left, viewport.physicalFrame.top,
Jeff Brown83d616a2012-09-09 20:33:43 -0700402 viewport.physicalFrame.right, viewport.physicalFrame.bottom,
403 viewport.deviceWidth, viewport.deviceHeight);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700404 }
Jeff Brownac143512012-04-05 18:57:33 -0700405
Jeff Brown6d0fec22010-07-23 21:28:06 -0700406 /**
407 * Gets the current state of a key or button by key code.
408 * @param deviceId The input device id, or -1 to consult all devices.
409 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
410 * consider all input sources. An input device is consulted if at least one of its
411 * non-class input source bits matches the specified source mask.
412 * @param keyCode The key code to check.
413 * @return The key state.
414 */
415 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700416 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700417 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700418
Jeff Brown6d0fec22010-07-23 21:28:06 -0700419 /**
420 * Gets the current state of a key or button by scan code.
421 * @param deviceId The input device id, or -1 to consult all devices.
422 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
423 * consider all input sources. An input device is consulted if at least one of its
424 * non-class input source bits matches the specified source mask.
425 * @param scanCode The scan code to check.
426 * @return The key state.
427 */
428 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700429 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700430 }
RoboErikfb290df2013-12-16 11:27:55 -0800431
Jeff Brown6d0fec22010-07-23 21:28:06 -0700432 /**
433 * Gets the current state of a switch by switch code.
434 * @param deviceId The input device id, or -1 to consult all devices.
435 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
436 * consider all input sources. An input device is consulted if at least one of its
437 * non-class input source bits matches the specified source mask.
438 * @param switchCode The switch code to check.
439 * @return The switch state.
440 */
441 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700442 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700443 }
444
Jeff Brown6d0fec22010-07-23 21:28:06 -0700445 /**
446 * Determines whether the specified key codes are supported by a particular device.
447 * @param deviceId The input device id, or -1 to consult all devices.
448 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
449 * consider all input sources. An input device is consulted if at least one of its
450 * non-class input source bits matches the specified source mask.
451 * @param keyCodes The array of key codes to check.
452 * @param keyExists An array at least as large as keyCodes whose entries will be set
453 * to true or false based on the presence or absence of support for the corresponding
454 * key codes.
455 * @return True if the lookup was successful, false otherwise.
456 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700457 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700458 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700459 if (keyCodes == null) {
460 throw new IllegalArgumentException("keyCodes must not be null.");
461 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700462 if (keyExists == null || keyExists.length < keyCodes.length) {
463 throw new IllegalArgumentException("keyExists must not be null and must be at "
464 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700465 }
RoboErikfb290df2013-12-16 11:27:55 -0800466
Jeff Brown4532e612012-04-05 14:27:12 -0700467 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700468 }
RoboErikfb290df2013-12-16 11:27:55 -0800469
Jeff Browna41ca772010-08-11 14:46:32 -0700470 /**
471 * Creates an input channel that will receive all input from the input dispatcher.
472 * @param inputChannelName The input channel name.
473 * @return The input channel.
474 */
475 public InputChannel monitorInput(String inputChannelName) {
476 if (inputChannelName == null) {
477 throw new IllegalArgumentException("inputChannelName must not be null.");
478 }
RoboErikfb290df2013-12-16 11:27:55 -0800479
Jeff Browna41ca772010-08-11 14:46:32 -0700480 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700481 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700482 inputChannels[0].dispose(); // don't need to retain the Java object reference
483 return inputChannels[1];
484 }
485
486 /**
487 * Registers an input channel so that it can be used as an input event target.
488 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800489 * @param inputWindowHandle The handle of the input window associated with the
490 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700491 */
Jeff Brown928e0542011-01-10 11:17:36 -0800492 public void registerInputChannel(InputChannel inputChannel,
493 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700494 if (inputChannel == null) {
495 throw new IllegalArgumentException("inputChannel must not be null.");
496 }
RoboErikfb290df2013-12-16 11:27:55 -0800497
Jeff Brown4532e612012-04-05 14:27:12 -0700498 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700499 }
RoboErikfb290df2013-12-16 11:27:55 -0800500
Jeff Browna41ca772010-08-11 14:46:32 -0700501 /**
502 * Unregisters an input channel.
503 * @param inputChannel The input channel to unregister.
504 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700505 public void unregisterInputChannel(InputChannel inputChannel) {
506 if (inputChannel == null) {
507 throw new IllegalArgumentException("inputChannel must not be null.");
508 }
RoboErikfb290df2013-12-16 11:27:55 -0800509
Jeff Brown4532e612012-04-05 14:27:12 -0700510 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700511 }
Jeff Brown0029c662011-03-30 02:25:18 -0700512
513 /**
514 * Sets an input filter that will receive all input events before they are dispatched.
515 * The input filter may then reinterpret input events or inject new ones.
516 *
517 * To ensure consistency, the input dispatcher automatically drops all events
518 * in progress whenever an input filter is installed or uninstalled. After an input
519 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
520 * Any events it attempts to send after it has been uninstalled will be dropped.
521 *
522 * @param filter The input filter, or null to remove the current filter.
523 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700524 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700525 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700526 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700527 if (oldFilter == filter) {
528 return; // nothing to do
529 }
530
531 if (oldFilter != null) {
532 mInputFilter = null;
533 mInputFilterHost.disconnectLocked();
534 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700535 try {
536 oldFilter.uninstall();
537 } catch (RemoteException re) {
538 /* ignore */
539 }
Jeff Brown0029c662011-03-30 02:25:18 -0700540 }
541
542 if (filter != null) {
543 mInputFilter = filter;
544 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700545 try {
546 filter.install(mInputFilterHost);
547 } catch (RemoteException re) {
548 /* ignore */
549 }
Jeff Brown0029c662011-03-30 02:25:18 -0700550 }
551
Jeff Brown4532e612012-04-05 14:27:12 -0700552 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700553 }
554 }
555
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700556 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700557 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brownca9bc702014-02-11 14:32:56 -0800558 return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
559 }
560
561 private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700562 if (event == null) {
563 throw new IllegalArgumentException("event must not be null");
564 }
Jeff Brownac143512012-04-05 18:57:33 -0700565 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
566 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
567 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
568 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700569 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700570
Jeff Brownac143512012-04-05 18:57:33 -0700571 final int pid = Binder.getCallingPid();
572 final int uid = Binder.getCallingUid();
573 final long ident = Binder.clearCallingIdentity();
574 final int result;
575 try {
Jeff Brownca9bc702014-02-11 14:32:56 -0800576 result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
Jeff Brownac143512012-04-05 18:57:33 -0700577 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
578 } finally {
579 Binder.restoreCallingIdentity(ident);
580 }
581 switch (result) {
582 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
583 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
584 throw new SecurityException(
585 "Injecting to another application requires INJECT_EVENTS permission");
586 case INPUT_EVENT_INJECTION_SUCCEEDED:
587 return true;
588 case INPUT_EVENT_INJECTION_TIMED_OUT:
589 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
590 return false;
591 case INPUT_EVENT_INJECTION_FAILED:
592 default:
593 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
594 return false;
595 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700596 }
Jeff Brown0029c662011-03-30 02:25:18 -0700597
Jeff Brown8d608662010-08-30 03:02:23 -0700598 /**
599 * Gets information about the input device with the specified id.
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700600 * @param deviceId The device id.
Jeff Brown8d608662010-08-30 03:02:23 -0700601 * @return The input device or null if not found.
602 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700603 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700604 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700605 synchronized (mInputDevicesLock) {
606 final int count = mInputDevices.length;
607 for (int i = 0; i < count; i++) {
608 final InputDevice inputDevice = mInputDevices[i];
609 if (inputDevice.getId() == deviceId) {
610 return inputDevice;
611 }
612 }
613 }
614 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700615 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700616
Jeff Brown8d608662010-08-30 03:02:23 -0700617 /**
618 * Gets the ids of all input devices in the system.
619 * @return The input device ids.
620 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700621 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700622 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700623 synchronized (mInputDevicesLock) {
624 final int count = mInputDevices.length;
625 int[] ids = new int[count];
626 for (int i = 0; i < count; i++) {
627 ids[i] = mInputDevices[i].getId();
628 }
629 return ids;
630 }
631 }
632
Jeff Browndaa37532012-05-01 15:54:03 -0700633 /**
634 * Gets all input devices in the system.
635 * @return The array of input devices.
636 */
637 public InputDevice[] getInputDevices() {
638 synchronized (mInputDevicesLock) {
639 return mInputDevices;
640 }
641 }
642
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700643 @Override // Binder call
644 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
645 if (listener == null) {
646 throw new IllegalArgumentException("listener must not be null");
647 }
648
649 synchronized (mInputDevicesLock) {
650 int callingPid = Binder.getCallingPid();
651 if (mInputDevicesChangedListeners.get(callingPid) != null) {
652 throw new SecurityException("The calling process has already "
653 + "registered an InputDevicesChangedListener.");
654 }
655
656 InputDevicesChangedListenerRecord record =
657 new InputDevicesChangedListenerRecord(callingPid, listener);
658 try {
659 IBinder binder = listener.asBinder();
660 binder.linkToDeath(record, 0);
661 } catch (RemoteException ex) {
662 // give up
663 throw new RuntimeException(ex);
664 }
665
666 mInputDevicesChangedListeners.put(callingPid, record);
667 }
668 }
669
670 private void onInputDevicesChangedListenerDied(int pid) {
671 synchronized (mInputDevicesLock) {
672 mInputDevicesChangedListeners.remove(pid);
673 }
674 }
675
676 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700677 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
678 // Scan for changes.
679 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700680 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700681 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700682 final int numListeners;
683 final int[] deviceIdAndGeneration;
684 synchronized (mInputDevicesLock) {
685 if (!mInputDevicesChangedPending) {
686 return;
687 }
688 mInputDevicesChangedPending = false;
689
690 numListeners = mInputDevicesChangedListeners.size();
691 for (int i = 0; i < numListeners; i++) {
692 mTempInputDevicesChangedListenersToNotify.add(
693 mInputDevicesChangedListeners.valueAt(i));
694 }
695
696 final int numDevices = mInputDevices.length;
697 deviceIdAndGeneration = new int[numDevices * 2];
698 for (int i = 0; i < numDevices; i++) {
699 final InputDevice inputDevice = mInputDevices[i];
700 deviceIdAndGeneration[i * 2] = inputDevice.getId();
701 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700702
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700703 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700704 if (!containsInputDeviceWithDescriptor(oldInputDevices,
705 inputDevice.getDescriptor())) {
706 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
707 } else {
708 mTempFullKeyboards.add(inputDevice);
709 }
710 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700711 }
712 }
713
Jeff Browncf39bdf2012-05-18 14:41:19 -0700714 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700715 for (int i = 0; i < numListeners; i++) {
716 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
717 deviceIdAndGeneration);
718 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700719 mTempInputDevicesChangedListenersToNotify.clear();
720
721 // Check for missing keyboard layouts.
722 if (mNotificationManager != null) {
723 final int numFullKeyboards = mTempFullKeyboards.size();
724 boolean missingLayoutForExternalKeyboard = false;
725 boolean missingLayoutForExternalKeyboardAdded = false;
Michael Wrightc93fbd12014-09-22 20:07:59 -0700726 boolean multipleMissingLayoutsForExternalKeyboardsAdded = false;
727 InputDevice keyboardMissingLayout = null;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700728 synchronized (mDataStore) {
729 for (int i = 0; i < numFullKeyboards; i++) {
730 final InputDevice inputDevice = mTempFullKeyboards.get(i);
Michael Wright86aaca62014-09-08 18:54:45 -0700731 final String layout =
732 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
733 if (layout == null) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700734 missingLayoutForExternalKeyboard = true;
735 if (i < numFullKeyboardsAdded) {
736 missingLayoutForExternalKeyboardAdded = true;
Michael Wrightc93fbd12014-09-22 20:07:59 -0700737 if (keyboardMissingLayout == null) {
738 keyboardMissingLayout = inputDevice;
739 } else {
740 multipleMissingLayoutsForExternalKeyboardsAdded = true;
741 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700742 }
743 }
744 }
745 }
746 if (missingLayoutForExternalKeyboard) {
747 if (missingLayoutForExternalKeyboardAdded) {
Michael Wrightc93fbd12014-09-22 20:07:59 -0700748 if (multipleMissingLayoutsForExternalKeyboardsAdded) {
749 // We have more than one keyboard missing a layout, so drop the
750 // user at the generic input methods page so they can pick which
751 // one to set.
752 showMissingKeyboardLayoutNotification(null);
753 } else {
754 showMissingKeyboardLayoutNotification(keyboardMissingLayout);
755 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700756 }
757 } else if (mKeyboardLayoutNotificationShown) {
758 hideMissingKeyboardLayoutNotification();
759 }
760 }
761 mTempFullKeyboards.clear();
762 }
763
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800764 @Override // Binder call & native callback
Jason Gerecked5220742014-03-10 09:47:59 -0700765 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
766 int surfaceRotation) {
Jason Gerecked6396d62014-01-27 18:30:37 -0800767 if (inputDeviceDescriptor == null) {
768 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
769 }
770
771 synchronized (mDataStore) {
Jason Gerecked5220742014-03-10 09:47:59 -0700772 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
Jason Gerecked6396d62014-01-27 18:30:37 -0800773 }
774 }
775
776 @Override // Binder call
Jason Gerecked5220742014-03-10 09:47:59 -0700777 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
Jason Gerecked6396d62014-01-27 18:30:37 -0800778 TouchCalibration calibration) {
779 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
780 "setTouchCalibrationForInputDevice()")) {
781 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
782 }
783 if (inputDeviceDescriptor == null) {
784 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
785 }
786 if (calibration == null) {
787 throw new IllegalArgumentException("calibration must not be null");
788 }
Jason Gerecked5220742014-03-10 09:47:59 -0700789 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
790 throw new IllegalArgumentException("surfaceRotation value out of bounds");
791 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800792
793 synchronized (mDataStore) {
794 try {
Jason Gerecked5220742014-03-10 09:47:59 -0700795 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
796 calibration)) {
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800797 nativeReloadCalibration(mPtr);
798 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800799 } finally {
800 mDataStore.saveIfNeeded();
801 }
802 }
803 }
804
Michael Wright39e5e942015-08-19 22:52:47 +0100805 @Override // Binder call
Michael Wright9209c9c2015-09-03 17:57:01 +0100806 public int isInTabletMode() {
807 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
808 "isInTabletMode()")) {
809 throw new SecurityException("Requires TABLET_MODE permission");
810 }
811 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
812 }
813
814 @Override // Binder call
Michael Wright39e5e942015-08-19 22:52:47 +0100815 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
Michael Wright9209c9c2015-09-03 17:57:01 +0100816 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
Michael Wright39e5e942015-08-19 22:52:47 +0100817 "registerTabletModeChangedListener()")) {
818 throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
819 }
820 if (listener == null) {
821 throw new IllegalArgumentException("listener must not be null");
822 }
823
824 synchronized (mTabletModeLock) {
825 final int callingPid = Binder.getCallingPid();
826 if (mTabletModeChangedListeners.get(callingPid) != null) {
827 throw new IllegalStateException("The calling process has already registered "
828 + "a TabletModeChangedListener.");
829 }
830 TabletModeChangedListenerRecord record =
831 new TabletModeChangedListenerRecord(callingPid, listener);
832 try {
833 IBinder binder = listener.asBinder();
834 binder.linkToDeath(record, 0);
835 } catch (RemoteException ex) {
836 throw new RuntimeException(ex);
837 }
838 mTabletModeChangedListeners.put(callingPid, record);
839 }
840 }
841
842 private void onTabletModeChangedListenerDied(int pid) {
843 synchronized (mTabletModeLock) {
844 mTabletModeChangedListeners.remove(pid);
845 }
846 }
847
848 // Must be called on handler
849 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
850 mTempTabletModeChangedListenersToNotify.clear();
851 final int numListeners;
852 synchronized (mTabletModeLock) {
853 numListeners = mTabletModeChangedListeners.size();
854 for (int i = 0; i < numListeners; i++) {
855 mTempTabletModeChangedListenersToNotify.add(
856 mTabletModeChangedListeners.valueAt(i));
857 }
858 }
859 for (int i = 0; i < numListeners; i++) {
860 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
861 whenNanos, inTabletMode);
862 }
863 }
864
Jeff Browncf39bdf2012-05-18 14:41:19 -0700865 // Must be called on handler.
Michael Wrightc93fbd12014-09-22 20:07:59 -0700866 private void showMissingKeyboardLayoutNotification(InputDevice device) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700867 if (!mKeyboardLayoutNotificationShown) {
Michael Wrightc93fbd12014-09-22 20:07:59 -0700868 final Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
869 if (device != null) {
870 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -0700871 }
Michael Wrightc93fbd12014-09-22 20:07:59 -0700872 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
873 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
874 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
875 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
876 intent, 0, null, UserHandle.CURRENT);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700877
878 Resources r = mContext.getResources();
879 Notification notification = new Notification.Builder(mContext)
880 .setContentTitle(r.getString(
881 R.string.select_keyboard_layout_notification_title))
882 .setContentText(r.getString(
883 R.string.select_keyboard_layout_notification_message))
Michael Wrightc93fbd12014-09-22 20:07:59 -0700884 .setContentIntent(keyboardLayoutIntent)
Jeff Browncf39bdf2012-05-18 14:41:19 -0700885 .setSmallIcon(R.drawable.ic_settings_language)
886 .setPriority(Notification.PRIORITY_LOW)
Alan Viverette4a357cd2015-03-18 18:37:18 -0700887 .setColor(mContext.getColor(
Selim Cinek255dd042014-08-19 22:29:02 +0200888 com.android.internal.R.color.system_notification_accent_color))
Jeff Browncf39bdf2012-05-18 14:41:19 -0700889 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700890 mNotificationManager.notifyAsUser(null,
891 R.string.select_keyboard_layout_notification_title,
892 notification, UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700893 mKeyboardLayoutNotificationShown = true;
894 }
895 }
896
897 // Must be called on handler.
898 private void hideMissingKeyboardLayoutNotification() {
899 if (mKeyboardLayoutNotificationShown) {
900 mKeyboardLayoutNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700901 mNotificationManager.cancelAsUser(null,
902 R.string.select_keyboard_layout_notification_title,
903 UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700904 }
905 }
906
907 // Must be called on handler.
908 private void updateKeyboardLayouts() {
909 // Scan all input devices state for keyboard layouts that have been uninstalled.
910 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
911 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
912 @Override
Michael Wright8ebac232014-09-18 18:29:49 -0700913 public void visitKeyboardLayout(Resources resources, String descriptor, String label,
914 String collection, int keyboardLayoutResId, int priority) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700915 availableKeyboardLayouts.add(descriptor);
916 }
917 });
918 synchronized (mDataStore) {
919 try {
920 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
921 } finally {
922 mDataStore.saveIfNeeded();
923 }
924 }
925
926 // Reload keyboard layouts.
927 reloadKeyboardLayouts();
928 }
929
Jeff Browncf39bdf2012-05-18 14:41:19 -0700930 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
931 String descriptor) {
932 final int numDevices = inputDevices.length;
933 for (int i = 0; i < numDevices; i++) {
934 final InputDevice inputDevice = inputDevices[i];
935 if (inputDevice.getDescriptor().equals(descriptor)) {
936 return true;
937 }
938 }
939 return false;
Jeff Brown8d608662010-08-30 03:02:23 -0700940 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700941
942 @Override // Binder call
943 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700944 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
945 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
946 @Override
Michael Wright8ebac232014-09-18 18:29:49 -0700947 public void visitKeyboardLayout(Resources resources, String descriptor, String label,
948 String collection, int keyboardLayoutResId, int priority) {
949 list.add(new KeyboardLayout(descriptor, label, collection, priority));
Jeff Brown6ec6f792012-04-17 16:52:41 -0700950 }
951 });
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700952 return list.toArray(new KeyboardLayout[list.size()]);
953 }
954
955 @Override // Binder call
956 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
957 if (keyboardLayoutDescriptor == null) {
958 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
959 }
960
Jeff Brown6ec6f792012-04-17 16:52:41 -0700961 final KeyboardLayout[] result = new KeyboardLayout[1];
962 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
963 @Override
Michael Wright8ebac232014-09-18 18:29:49 -0700964 public void visitKeyboardLayout(Resources resources, String descriptor,
965 String label, String collection, int keyboardLayoutResId, int priority) {
966 result[0] = new KeyboardLayout(descriptor, label, collection, priority);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700967 }
968 });
969 if (result[0] == null) {
970 Log.w(TAG, "Could not get keyboard layout with descriptor '"
971 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700972 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700973 return result[0];
974 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700975
Jeff Brown6ec6f792012-04-17 16:52:41 -0700976 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700977 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700978 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
979 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
980 PackageManager.GET_META_DATA)) {
Michael Wright8ebac232014-09-18 18:29:49 -0700981 final ActivityInfo activityInfo = resolveInfo.activityInfo;
982 final int priority = resolveInfo.priority;
983 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700984 }
985 }
986
Jeff Brown6ec6f792012-04-17 16:52:41 -0700987 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
988 KeyboardLayoutVisitor visitor) {
989 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
990 if (d != null) {
991 final PackageManager pm = mContext.getPackageManager();
992 try {
993 ActivityInfo receiver = pm.getReceiverInfo(
994 new ComponentName(d.packageName, d.receiverName),
995 PackageManager.GET_META_DATA);
Michael Wright8ebac232014-09-18 18:29:49 -0700996 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700997 } catch (NameNotFoundException ex) {
998 }
999 }
1000 }
1001
1002 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
Michael Wright8ebac232014-09-18 18:29:49 -07001003 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001004 Bundle metaData = receiver.metaData;
1005 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001006 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001007 }
1008
1009 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1010 if (configResId == 0) {
1011 Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
1012 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001013 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001014 }
1015
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001016 CharSequence receiverLabel = receiver.loadLabel(pm);
1017 String collection = receiverLabel != null ? receiverLabel.toString() : "";
Michael Wright8ebac232014-09-18 18:29:49 -07001018 int priority;
1019 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1020 priority = requestedPriority;
1021 } else {
1022 priority = 0;
1023 }
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001024
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001025 try {
1026 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1027 XmlResourceParser parser = resources.getXml(configResId);
1028 try {
1029 XmlUtils.beginDocument(parser, "keyboard-layouts");
1030
1031 for (;;) {
1032 XmlUtils.nextElement(parser);
1033 String element = parser.getName();
1034 if (element == null) {
1035 break;
1036 }
1037 if (element.equals("keyboard-layout")) {
1038 TypedArray a = resources.obtainAttributes(
1039 parser, com.android.internal.R.styleable.KeyboardLayout);
1040 try {
1041 String name = a.getString(
1042 com.android.internal.R.styleable.KeyboardLayout_name);
1043 String label = a.getString(
1044 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -07001045 int keyboardLayoutResId = a.getResourceId(
1046 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1047 0);
1048 if (name == null || label == null || keyboardLayoutResId == 0) {
1049 Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001050 + "attributes in keyboard layout "
1051 + "resource from receiver "
1052 + receiver.packageName + "/" + receiver.name);
1053 } else {
1054 String descriptor = KeyboardLayoutDescriptor.format(
1055 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001056 if (keyboardName == null || name.equals(keyboardName)) {
1057 visitor.visitKeyboardLayout(resources, descriptor,
Michael Wright8ebac232014-09-18 18:29:49 -07001058 label, collection, keyboardLayoutResId, priority);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001059 }
1060 }
1061 } finally {
1062 a.recycle();
1063 }
1064 } else {
1065 Log.w(TAG, "Skipping unrecognized element '" + element
1066 + "' in keyboard layout resource from receiver "
1067 + receiver.packageName + "/" + receiver.name);
1068 }
1069 }
1070 } finally {
1071 parser.close();
1072 }
1073 } catch (Exception ex) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001074 Log.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001075 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001076 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001077 }
1078
RoboErikfb290df2013-12-16 11:27:55 -08001079 /**
1080 * Builds a layout descriptor for the vendor/product. This returns the
1081 * descriptor for ids that aren't useful (such as the default 0, 0).
1082 */
1083 private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1084 if (identifier == null || identifier.getDescriptor() == null) {
1085 throw new IllegalArgumentException("identifier and descriptor must not be null");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001086 }
1087
RoboErikfb290df2013-12-16 11:27:55 -08001088 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1089 return identifier.getDescriptor();
1090 }
1091 StringBuilder bob = new StringBuilder();
1092 bob.append("vendor:").append(identifier.getVendorId());
1093 bob.append(",product:").append(identifier.getProductId());
1094 return bob.toString();
1095 }
1096
1097 @Override // Binder call
1098 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1099
1100 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001101 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001102 String layout = null;
1103 // try loading it using the layout descriptor if we have it
1104 layout = mDataStore.getCurrentKeyboardLayout(key);
1105 if (layout == null && !key.equals(identifier.getDescriptor())) {
1106 // if it doesn't exist fall back to the device descriptor
1107 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1108 }
1109 if (DEBUG) {
1110 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1111 + layout);
1112 }
1113 return layout;
Jeff Browna3bc5652012-04-17 11:42:25 -07001114 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001115 }
1116
1117 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001118 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001119 String keyboardLayoutDescriptor) {
1120 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001121 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001122 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1123 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001124 if (keyboardLayoutDescriptor == null) {
1125 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1126 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001127
RoboErikfb290df2013-12-16 11:27:55 -08001128 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001129 synchronized (mDataStore) {
1130 try {
RoboErikfb290df2013-12-16 11:27:55 -08001131 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1132 if (DEBUG) {
1133 Slog.d(TAG, "Saved keyboard layout using " + key);
1134 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001135 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1136 }
Jeff Browna3bc5652012-04-17 11:42:25 -07001137 } finally {
1138 mDataStore.saveIfNeeded();
1139 }
1140 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001141 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001142
Jeff Browncf39bdf2012-05-18 14:41:19 -07001143 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001144 public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
1145 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001146 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001147 String[] layouts = mDataStore.getKeyboardLayouts(key);
1148 if ((layouts == null || layouts.length == 0)
1149 && !key.equals(identifier.getDescriptor())) {
1150 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1151 }
1152 return layouts;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001153 }
1154 }
1155
1156 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001157 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001158 String keyboardLayoutDescriptor) {
1159 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1160 "addKeyboardLayoutForInputDevice()")) {
1161 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1162 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001163 if (keyboardLayoutDescriptor == null) {
1164 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1165 }
1166
RoboErikfb290df2013-12-16 11:27:55 -08001167 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001168 synchronized (mDataStore) {
1169 try {
RoboErikfb290df2013-12-16 11:27:55 -08001170 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1171 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1172 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1173 }
1174 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
Jeff Browncf39bdf2012-05-18 14:41:19 -07001175 && !Objects.equal(oldLayout,
RoboErikfb290df2013-12-16 11:27:55 -08001176 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001177 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1178 }
1179 } finally {
1180 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001181 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001182 }
1183 }
1184
1185 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001186 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001187 String keyboardLayoutDescriptor) {
1188 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1189 "removeKeyboardLayoutForInputDevice()")) {
1190 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1191 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001192 if (keyboardLayoutDescriptor == null) {
1193 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1194 }
1195
RoboErikfb290df2013-12-16 11:27:55 -08001196 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001197 synchronized (mDataStore) {
1198 try {
RoboErikfb290df2013-12-16 11:27:55 -08001199 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1200 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1201 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1202 }
1203 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1204 if (!key.equals(identifier.getDescriptor())) {
1205 // We need to remove from both places to ensure it is gone
1206 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1207 keyboardLayoutDescriptor);
1208 }
1209 if (removed && !Objects.equal(oldLayout,
1210 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001211 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1212 }
1213 } finally {
1214 mDataStore.saveIfNeeded();
1215 }
1216 }
1217 }
1218
Yohei Yukawab097b822015-12-01 10:43:08 -08001219 // Must be called on handler.
1220 private void handleSwitchInputMethodSubtype(int userId,
1221 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
1222 if (DEBUG) {
1223 Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
1224 + " ime=" + inputMethodInfo + " subtype=" + subtype);
1225 }
1226 }
1227
Jeff Browncf39bdf2012-05-18 14:41:19 -07001228 public void switchKeyboardLayout(int deviceId, int direction) {
1229 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
1230 }
1231
1232 // Must be called on handler.
1233 private void handleSwitchKeyboardLayout(int deviceId, int direction) {
1234 final InputDevice device = getInputDevice(deviceId);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001235 if (device != null) {
1236 final boolean changed;
1237 final String keyboardLayoutDescriptor;
RoboErikfb290df2013-12-16 11:27:55 -08001238
1239 String key = getLayoutDescriptor(device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001240 synchronized (mDataStore) {
1241 try {
RoboErikfb290df2013-12-16 11:27:55 -08001242 changed = mDataStore.switchKeyboardLayout(key, direction);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001243 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
RoboErikfb290df2013-12-16 11:27:55 -08001244 key);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001245 } finally {
1246 mDataStore.saveIfNeeded();
1247 }
1248 }
1249
1250 if (changed) {
1251 if (mSwitchedKeyboardLayoutToast != null) {
1252 mSwitchedKeyboardLayoutToast.cancel();
1253 mSwitchedKeyboardLayoutToast = null;
1254 }
1255 if (keyboardLayoutDescriptor != null) {
1256 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
1257 if (keyboardLayout != null) {
1258 mSwitchedKeyboardLayoutToast = Toast.makeText(
1259 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
1260 mSwitchedKeyboardLayoutToast.show();
1261 }
1262 }
1263
1264 reloadKeyboardLayouts();
1265 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001266 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001267 }
1268
Jeff Brown9302c872011-07-13 22:51:29 -07001269 public void setInputWindows(InputWindowHandle[] windowHandles) {
Jeff Brown4532e612012-04-05 14:27:12 -07001270 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -07001271 }
RoboErikfb290df2013-12-16 11:27:55 -08001272
Jeff Brown9302c872011-07-13 22:51:29 -07001273 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -07001274 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -07001275 }
RoboErikfb290df2013-12-16 11:27:55 -08001276
Jeff Brown349703e2010-06-22 01:27:15 -07001277 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001278 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001279 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001280
1281 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001282 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001283 }
1284
Jeff Browne6504122010-09-27 14:52:15 -07001285 /**
1286 * Atomically transfers touch focus from one window to another as identified by
1287 * their input channels. It is possible for multiple windows to have
1288 * touch focus if they support split touch dispatch
1289 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1290 * method only transfers touch focus of the specified window without affecting
1291 * other windows that may also have touch focus at the same time.
1292 * @param fromChannel The channel of a window that currently has touch focus.
1293 * @param toChannel The channel of the window that should receive touch focus in
1294 * place of the first.
1295 * @return True if the transfer was successful. False if the window with the
1296 * specified channel did not actually have touch focus at the time of the request.
1297 */
1298 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1299 if (fromChannel == null) {
1300 throw new IllegalArgumentException("fromChannel must not be null.");
1301 }
1302 if (toChannel == null) {
1303 throw new IllegalArgumentException("toChannel must not be null.");
1304 }
Jeff Brown4532e612012-04-05 14:27:12 -07001305 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -07001306 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001307
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001308 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001309 public void tryPointerSpeed(int speed) {
1310 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1311 "tryPointerSpeed()")) {
1312 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1313 }
1314
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001315 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1316 throw new IllegalArgumentException("speed out of range");
1317 }
1318
Jeff Brownac143512012-04-05 18:57:33 -07001319 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001320 }
1321
1322 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001323 int speed = getPointerSpeedSetting();
1324 setPointerSpeedUnchecked(speed);
1325 }
1326
1327 private void setPointerSpeedUnchecked(int speed) {
1328 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1329 InputManager.MAX_POINTER_SPEED);
1330 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001331 }
1332
1333 private void registerPointerSpeedSettingObserver() {
1334 mContext.getContentResolver().registerContentObserver(
1335 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001336 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001337 @Override
1338 public void onChange(boolean selfChange) {
1339 updatePointerSpeedFromSettings();
1340 }
Jeff Brownd4935962012-09-25 13:27:20 -07001341 }, UserHandle.USER_ALL);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001342 }
1343
Jeff Brownac143512012-04-05 18:57:33 -07001344 private int getPointerSpeedSetting() {
1345 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001346 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001347 speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1348 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001349 } catch (SettingNotFoundException snfe) {
1350 }
1351 return speed;
1352 }
1353
Jeff Browndaf4a122011-08-26 17:14:14 -07001354 public void updateShowTouchesFromSettings() {
1355 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001356 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001357 }
1358
1359 private void registerShowTouchesSettingObserver() {
1360 mContext.getContentResolver().registerContentObserver(
1361 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001362 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001363 @Override
1364 public void onChange(boolean selfChange) {
1365 updateShowTouchesFromSettings();
1366 }
Jeff Brownd4935962012-09-25 13:27:20 -07001367 }, UserHandle.USER_ALL);
Jeff Browndaf4a122011-08-26 17:14:14 -07001368 }
1369
Jun Mukaie4e75da2015-12-15 16:19:20 -08001370 public void updateAccessibilityLargePointerFromSettings() {
1371 final int accessibilityConfig = Settings.Secure.getIntForUser(
1372 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1373 0, UserHandle.USER_CURRENT);
1374 PointerIcon.sUseLargeIcons = (accessibilityConfig == 1);
1375 nativeReloadPointerIcons(mPtr);
1376 }
1377
Jun Mukai19a56012015-11-24 11:25:52 -08001378 private void registerAccessibilityLargePointerSettingObserver() {
1379 mContext.getContentResolver().registerContentObserver(
1380 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1381 new ContentObserver(mHandler) {
1382 @Override
1383 public void onChange(boolean selfChange) {
Jun Mukaie4e75da2015-12-15 16:19:20 -08001384 updateAccessibilityLargePointerFromSettings();
Jun Mukai19a56012015-11-24 11:25:52 -08001385 }
1386 }, UserHandle.USER_ALL);
1387 }
1388
Jeff Browndaf4a122011-08-26 17:14:14 -07001389 private int getShowTouchesSetting(int defaultValue) {
1390 int result = defaultValue;
1391 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001392 result = Settings.System.getIntForUser(mContext.getContentResolver(),
1393 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
Jeff Browndaf4a122011-08-26 17:14:14 -07001394 } catch (SettingNotFoundException snfe) {
1395 }
1396 return result;
1397 }
1398
Jeff Browna47425a2012-04-13 04:09:27 -07001399 // Binder call
1400 @Override
1401 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1402 if (repeat >= pattern.length) {
1403 throw new ArrayIndexOutOfBoundsException();
1404 }
1405
1406 VibratorToken v;
1407 synchronized (mVibratorLock) {
1408 v = mVibratorTokens.get(token);
1409 if (v == null) {
1410 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1411 try {
1412 token.linkToDeath(v, 0);
1413 } catch (RemoteException ex) {
1414 // give up
1415 throw new RuntimeException(ex);
1416 }
1417 mVibratorTokens.put(token, v);
1418 }
1419 }
1420
1421 synchronized (v) {
1422 v.mVibrating = true;
1423 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1424 }
1425 }
1426
1427 // Binder call
1428 @Override
1429 public void cancelVibrate(int deviceId, IBinder token) {
1430 VibratorToken v;
1431 synchronized (mVibratorLock) {
1432 v = mVibratorTokens.get(token);
1433 if (v == null || v.mDeviceId != deviceId) {
1434 return; // nothing to cancel
1435 }
1436 }
1437
1438 cancelVibrateIfNeeded(v);
1439 }
1440
1441 void onVibratorTokenDied(VibratorToken v) {
1442 synchronized (mVibratorLock) {
1443 mVibratorTokens.remove(v.mToken);
1444 }
1445
1446 cancelVibrateIfNeeded(v);
1447 }
1448
1449 private void cancelVibrateIfNeeded(VibratorToken v) {
1450 synchronized (v) {
1451 if (v.mVibrating) {
1452 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1453 v.mVibrating = false;
1454 }
1455 }
1456 }
1457
Jun Mukai19a56012015-11-24 11:25:52 -08001458 // Binder call
1459 @Override
1460 public void setPointerIconShape(int iconId) {
1461 nativeSetPointerIconShape(mPtr, iconId);
1462 }
Jun Mukai1db53972015-09-11 18:08:31 -07001463
Jun Mukaid4eaef72015-10-30 15:54:33 -07001464 // Binder call
1465 @Override
1466 public void setCustomPointerIcon(PointerIcon icon) {
1467 nativeSetCustomPointerIcon(mPtr, icon);
1468 }
1469
Jeff Brown4532e612012-04-05 14:27:12 -07001470 @Override
1471 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna3bc5652012-04-17 11:42:25 -07001472 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
Jeff Brown4532e612012-04-05 14:27:12 -07001473 != PackageManager.PERMISSION_GRANTED) {
1474 pw.println("Permission Denial: can't dump InputManager from from pid="
1475 + Binder.getCallingPid()
1476 + ", uid=" + Binder.getCallingUid());
1477 return;
1478 }
1479
1480 pw.println("INPUT MANAGER (dumpsys input)\n");
1481 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001482 if (dumpStr != null) {
1483 pw.println(dumpStr);
1484 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001485 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001486
Jeff Brownac143512012-04-05 18:57:33 -07001487 private boolean checkCallingPermission(String permission, String func) {
1488 // Quick check: if the calling permission is me, it's all okay.
1489 if (Binder.getCallingPid() == Process.myPid()) {
1490 return true;
1491 }
1492
1493 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1494 return true;
1495 }
1496 String msg = "Permission Denial: " + func + " from pid="
1497 + Binder.getCallingPid()
1498 + ", uid=" + Binder.getCallingUid()
1499 + " requires " + permission;
1500 Slog.w(TAG, msg);
1501 return false;
1502 }
1503
Jeff Brown4532e612012-04-05 14:27:12 -07001504 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001505 @Override
Jeff Brown89ef0722011-08-10 16:25:21 -07001506 public void monitor() {
1507 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -07001508 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001509 }
1510
Jeff Brown4532e612012-04-05 14:27:12 -07001511 // Native callback.
1512 private void notifyConfigurationChanged(long whenNanos) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001513 mWindowManagerCallbacks.notifyConfigurationChanged();
Jeff Brown4532e612012-04-05 14:27:12 -07001514 }
1515
1516 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001517 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1518 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001519 if (!mInputDevicesChangedPending) {
1520 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001521 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1522 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001523 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001524
1525 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001526 }
1527 }
1528
1529 // Native callback.
Jeff Brownbcc046a2012-09-27 20:46:43 -07001530 private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1531 if (DEBUG) {
1532 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1533 + ", mask=" + Integer.toHexString(switchMask));
1534 }
1535
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001536 if ((switchMask & SW_LID_BIT) != 0) {
1537 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
Jeff Brownbcc046a2012-09-27 20:46:43 -07001538 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
Jeff Brown53384282012-08-20 20:16:01 -07001539 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001540
Michael Wright3818c922014-09-02 13:59:07 -07001541 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
Michael Wright9e10d252014-09-13 19:41:20 -07001542 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
Michael Wright3818c922014-09-02 13:59:07 -07001543 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1544 }
1545
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001546 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1547 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1548 switchMask);
1549 }
Michael Wright39e5e942015-08-19 22:52:47 +01001550
Michael Wright9209c9c2015-09-03 17:57:01 +01001551 if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
Michael Wright39e5e942015-08-19 22:52:47 +01001552 SomeArgs args = SomeArgs.obtain();
1553 args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
1554 args.argi2 = (int) (whenNanos >> 32);
1555 args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
1556 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
1557 args).sendToTarget();
1558 }
Jeff Brown4532e612012-04-05 14:27:12 -07001559 }
1560
1561 // Native callback.
1562 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001563 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
Jeff Brown4532e612012-04-05 14:27:12 -07001564 }
1565
1566 // Native callback.
1567 private long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001568 InputWindowHandle inputWindowHandle, String reason) {
1569 return mWindowManagerCallbacks.notifyANR(
1570 inputApplicationHandle, inputWindowHandle, reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001571 }
1572
1573 // Native callback.
1574 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1575 synchronized (mInputFilterLock) {
1576 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001577 try {
1578 mInputFilter.filterInputEvent(event, policyFlags);
1579 } catch (RemoteException e) {
1580 /* ignore */
1581 }
Jeff Brown4532e612012-04-05 14:27:12 -07001582 return false;
1583 }
1584 }
1585 event.recycle();
1586 return true;
1587 }
1588
1589 // Native callback.
Jeff Brown037c33e2014-04-09 00:31:55 -07001590 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1591 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001592 }
1593
1594 // Native callback.
Michael Wright70af00a2014-09-03 19:30:20 -07001595 private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
1596 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
Jeff Brown26875502014-01-30 21:47:47 -08001597 whenNanos, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001598 }
1599
1600 // Native callback.
1601 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1602 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001603 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001604 }
1605
1606 // Native callback.
1607 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1608 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001609 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001610 }
1611
1612 // Native callback.
1613 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1614 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1615 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1616 }
1617
1618 // Native callback.
1619 private int getVirtualKeyQuietTimeMillis() {
1620 return mContext.getResources().getInteger(
1621 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1622 }
1623
1624 // Native callback.
1625 private String[] getExcludedDeviceNames() {
1626 ArrayList<String> names = new ArrayList<String>();
1627
1628 // Read partner-provided list of excluded input devices
1629 XmlPullParser parser = null;
1630 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1631 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1632 FileReader confreader = null;
1633 try {
1634 confreader = new FileReader(confFile);
1635 parser = Xml.newPullParser();
1636 parser.setInput(confreader);
1637 XmlUtils.beginDocument(parser, "devices");
1638
1639 while (true) {
1640 XmlUtils.nextElement(parser);
1641 if (!"device".equals(parser.getName())) {
1642 break;
1643 }
1644 String name = parser.getAttributeValue(null, "name");
1645 if (name != null) {
1646 names.add(name);
1647 }
1648 }
1649 } catch (FileNotFoundException e) {
1650 // It's ok if the file does not exist.
1651 } catch (Exception e) {
1652 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1653 } finally {
1654 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1655 }
1656
1657 return names.toArray(new String[names.size()]);
1658 }
1659
1660 // Native callback.
1661 private int getKeyRepeatTimeout() {
1662 return ViewConfiguration.getKeyRepeatTimeout();
1663 }
1664
1665 // Native callback.
1666 private int getKeyRepeatDelay() {
1667 return ViewConfiguration.getKeyRepeatDelay();
1668 }
1669
1670 // Native callback.
1671 private int getHoverTapTimeout() {
1672 return ViewConfiguration.getHoverTapTimeout();
1673 }
1674
1675 // Native callback.
1676 private int getHoverTapSlop() {
1677 return ViewConfiguration.getHoverTapSlop();
1678 }
1679
1680 // Native callback.
1681 private int getDoubleTapTimeout() {
1682 return ViewConfiguration.getDoubleTapTimeout();
1683 }
1684
1685 // Native callback.
1686 private int getLongPressTimeout() {
1687 return ViewConfiguration.getLongPressTimeout();
1688 }
1689
1690 // Native callback.
1691 private int getPointerLayer() {
Jeff Browna9d131c2012-09-20 16:48:17 -07001692 return mWindowManagerCallbacks.getPointerLayer();
Jeff Brown4532e612012-04-05 14:27:12 -07001693 }
1694
1695 // Native callback.
1696 private PointerIcon getPointerIcon() {
1697 return PointerIcon.getDefaultIcon(mContext);
1698 }
1699
Jeff Brown6ec6f792012-04-17 16:52:41 -07001700 // Native callback.
RoboErikfb290df2013-12-16 11:27:55 -08001701 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001702 if (!mSystemReady) {
1703 return null;
1704 }
1705
RoboErikfb290df2013-12-16 11:27:55 -08001706 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001707 if (keyboardLayoutDescriptor == null) {
1708 return null;
1709 }
1710
1711 final String[] result = new String[2];
1712 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1713 @Override
Michael Wright8ebac232014-09-18 18:29:49 -07001714 public void visitKeyboardLayout(Resources resources, String descriptor, String label,
1715 String collection, int keyboardLayoutResId, int priority) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001716 try {
1717 result[0] = descriptor;
1718 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07001719 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07001720 } catch (IOException ex) {
1721 } catch (NotFoundException ex) {
1722 }
1723 }
1724 });
1725 if (result[0] == null) {
1726 Log.w(TAG, "Could not get keyboard layout with descriptor '"
1727 + keyboardLayoutDescriptor + "'.");
1728 return null;
1729 }
1730 return result;
1731 }
1732
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001733 // Native callback.
1734 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07001735 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
1736 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
1737 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001738 }
1739 return null;
1740 }
1741
Jeff Brown4532e612012-04-05 14:27:12 -07001742 /**
1743 * Callback interface implemented by the Window Manager.
1744 */
Jeff Browna9d131c2012-09-20 16:48:17 -07001745 public interface WindowManagerCallbacks {
Jeff Brown4532e612012-04-05 14:27:12 -07001746 public void notifyConfigurationChanged();
1747
1748 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
1749
Michael Wright3818c922014-09-02 13:59:07 -07001750 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
1751
Jeff Brown4532e612012-04-05 14:27:12 -07001752 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
1753
1754 public long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001755 InputWindowHandle inputWindowHandle, String reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001756
Jeff Brown037c33e2014-04-09 00:31:55 -07001757 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001758
Michael Wright70af00a2014-09-03 19:30:20 -07001759 public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001760
1761 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
1762 KeyEvent event, int policyFlags);
1763
1764 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1765 KeyEvent event, int policyFlags);
1766
1767 public int getPointerLayer();
1768 }
1769
1770 /**
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001771 * Callback interface implemented by WiredAccessoryObserver.
1772 */
1773 public interface WiredAccessoryCallbacks {
1774 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
Eric Laurent4a5eeb92014-05-06 10:49:04 -07001775 public void systemReady();
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001776 }
1777
1778 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001779 * Private handler for the input manager.
1780 */
1781 private final class InputManagerHandler extends Handler {
Jeff Browna9d131c2012-09-20 16:48:17 -07001782 public InputManagerHandler(Looper looper) {
1783 super(looper, null, true /*async*/);
Jeff Browna2910d02012-08-25 12:29:46 -07001784 }
1785
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001786 @Override
1787 public void handleMessage(Message msg) {
1788 switch (msg.what) {
1789 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07001790 deliverInputDevicesChanged((InputDevice[])msg.obj);
1791 break;
1792 case MSG_SWITCH_KEYBOARD_LAYOUT:
1793 handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
1794 break;
1795 case MSG_RELOAD_KEYBOARD_LAYOUTS:
1796 reloadKeyboardLayouts();
1797 break;
1798 case MSG_UPDATE_KEYBOARD_LAYOUTS:
1799 updateKeyboardLayouts();
1800 break;
1801 case MSG_RELOAD_DEVICE_ALIASES:
1802 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001803 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08001804 case MSG_DELIVER_TABLET_MODE_CHANGED: {
Michael Wright39e5e942015-08-19 22:52:47 +01001805 SomeArgs args = (SomeArgs) msg.obj;
1806 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
1807 boolean inTabletMode = (boolean) args.arg1;
1808 deliverTabletModeChanged(whenNanos, inTabletMode);
1809 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08001810 }
1811 case MSG_INPUT_METHOD_SUBTYPE_CHANGED: {
1812 final int userId = msg.arg1;
1813 final SomeArgs args = (SomeArgs) msg.obj;
1814 final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1;
1815 final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2;
1816 args.recycle();
1817 handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype);
1818 break;
1819 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001820 }
1821 }
1822 }
1823
1824 /**
Jeff Brown4532e612012-04-05 14:27:12 -07001825 * Hosting interface for input filters to call back into the input manager.
1826 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001827 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07001828 private boolean mDisconnected;
1829
1830 public void disconnectLocked() {
1831 mDisconnected = true;
1832 }
1833
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001834 @Override
Jeff Brown0029c662011-03-30 02:25:18 -07001835 public void sendInputEvent(InputEvent event, int policyFlags) {
1836 if (event == null) {
1837 throw new IllegalArgumentException("event must not be null");
1838 }
1839
1840 synchronized (mInputFilterLock) {
1841 if (!mDisconnected) {
Jeff Brownca9bc702014-02-11 14:32:56 -08001842 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
Jeff Brownac143512012-04-05 18:57:33 -07001843 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07001844 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
1845 }
1846 }
1847 }
1848 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001849
1850 private static final class KeyboardLayoutDescriptor {
1851 public String packageName;
1852 public String receiverName;
1853 public String keyboardLayoutName;
1854
1855 public static String format(String packageName,
1856 String receiverName, String keyboardName) {
1857 return packageName + "/" + receiverName + "/" + keyboardName;
1858 }
1859
1860 public static KeyboardLayoutDescriptor parse(String descriptor) {
1861 int pos = descriptor.indexOf('/');
1862 if (pos < 0 || pos + 1 == descriptor.length()) {
1863 return null;
1864 }
1865 int pos2 = descriptor.indexOf('/', pos + 1);
1866 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
1867 return null;
1868 }
1869
1870 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
1871 result.packageName = descriptor.substring(0, pos);
1872 result.receiverName = descriptor.substring(pos + 1, pos2);
1873 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
1874 return result;
1875 }
1876 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001877
Jeff Brown6ec6f792012-04-17 16:52:41 -07001878 private interface KeyboardLayoutVisitor {
Michael Wright8ebac232014-09-18 18:29:49 -07001879 void visitKeyboardLayout(Resources resources, String descriptor, String label,
1880 String collection, int keyboardLayoutResId, int priority);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001881 }
1882
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001883 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
1884 private final int mPid;
1885 private final IInputDevicesChangedListener mListener;
1886
1887 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
1888 mPid = pid;
1889 mListener = listener;
1890 }
1891
1892 @Override
1893 public void binderDied() {
1894 if (DEBUG) {
1895 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
1896 }
1897 onInputDevicesChangedListenerDied(mPid);
1898 }
1899
1900 public void notifyInputDevicesChanged(int[] info) {
1901 try {
1902 mListener.onInputDevicesChanged(info);
1903 } catch (RemoteException ex) {
1904 Slog.w(TAG, "Failed to notify process "
1905 + mPid + " that input devices changed, assuming it died.", ex);
1906 binderDied();
1907 }
1908 }
1909 }
Jeff Browna47425a2012-04-13 04:09:27 -07001910
Michael Wright39e5e942015-08-19 22:52:47 +01001911 private final class TabletModeChangedListenerRecord implements DeathRecipient {
1912 private final int mPid;
1913 private final ITabletModeChangedListener mListener;
1914
1915 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
1916 mPid = pid;
1917 mListener = listener;
1918 }
1919
1920 @Override
1921 public void binderDied() {
1922 if (DEBUG) {
1923 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
1924 }
1925 onTabletModeChangedListenerDied(mPid);
1926 }
1927
1928 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
1929 try {
1930 mListener.onTabletModeChanged(whenNanos, inTabletMode);
1931 } catch (RemoteException ex) {
1932 Slog.w(TAG, "Failed to notify process " + mPid +
1933 " that tablet mode changed, assuming it died.", ex);
1934 binderDied();
1935 }
1936 }
1937 }
1938
Jeff Browna47425a2012-04-13 04:09:27 -07001939 private final class VibratorToken implements DeathRecipient {
1940 public final int mDeviceId;
1941 public final IBinder mToken;
1942 public final int mTokenValue;
1943
1944 public boolean mVibrating;
1945
1946 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
1947 mDeviceId = deviceId;
1948 mToken = token;
1949 mTokenValue = tokenValue;
1950 }
1951
1952 @Override
1953 public void binderDied() {
1954 if (DEBUG) {
1955 Slog.d(TAG, "Vibrator token died.");
1956 }
1957 onVibratorTokenDied(this);
1958 }
1959 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08001960
1961 private final class LocalService extends InputManagerInternal {
1962 @Override
1963 public void setDisplayViewports(
1964 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
1965 setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
1966 }
Jeff Brownca9bc702014-02-11 14:32:56 -08001967
1968 @Override
1969 public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
1970 return injectInputEventInternal(event, displayId, mode);
1971 }
Jeff Brown037c33e2014-04-09 00:31:55 -07001972
1973 @Override
1974 public void setInteractive(boolean interactive) {
1975 nativeSetInteractive(mPtr, interactive);
1976 }
Yohei Yukawab097b822015-12-01 10:43:08 -08001977
1978 @Override
1979 public void onInputMethodSubtypeChanged(int userId,
1980 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
1981 final SomeArgs someArgs = SomeArgs.obtain();
1982 someArgs.arg1 = inputMethodInfo;
1983 someArgs.arg2 = subtype;
1984 mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs)
1985 .sendToTarget();
1986 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08001987 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001988}