blob: 0e52871d3d8903787d655de2f1d4e735db7476a1 [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 Yukawa5660fad2016-01-27 22:04:09 -080019import android.annotation.NonNull;
Yohei Yukawab097b822015-12-01 10:43:08 -080020import android.annotation.Nullable;
Yohei Yukawa23cbe852016-05-17 16:42:58 -070021import android.os.LocaleList;
Dianne Hackborn354736e2016-08-22 17:00:05 -070022import android.os.ShellCallback;
Adrian Roos99182342016-06-15 15:30:46 -070023import android.util.Log;
Jeff Brownca9bc702014-02-11 14:32:56 -080024import android.view.Display;
Michael Wrightd5f7ed92016-01-19 11:23:51 -080025import com.android.internal.inputmethod.InputMethodSubtypeHandle;
Chris Wren282cfef2017-03-27 15:01:44 -040026import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050027import com.android.internal.notification.SystemNotificationChannels;
Michael Wright39e5e942015-08-19 22:52:47 +010028import com.android.internal.os.SomeArgs;
Jeff Browncf39bdf2012-05-18 14:41:19 -070029import com.android.internal.R;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060030import com.android.internal.util.DumpUtils;
Michael Wrightb004b512017-01-18 18:09:29 +000031import com.android.internal.util.Preconditions;
Jeff Brown46b9ac02010-04-22 18:58:52 -070032import com.android.internal.util.XmlUtils;
Jeff Brown4ccb8232014-01-16 22:16:42 -080033import com.android.server.DisplayThread;
34import com.android.server.LocalServices;
Jeff Brown89ef0722011-08-10 16:25:21 -070035import com.android.server.Watchdog;
Jeff Brown46b9ac02010-04-22 18:58:52 -070036
37import org.xmlpull.v1.XmlPullParser;
38
Jeff Browna3bc5652012-04-17 11:42:25 -070039import android.Manifest;
Jeff Browncf39bdf2012-05-18 14:41:19 -070040import android.app.Notification;
41import android.app.NotificationManager;
42import android.app.PendingIntent;
Jeff Brown5bbd4b42012-04-20 19:28:00 -070043import android.bluetooth.BluetoothAdapter;
44import android.bluetooth.BluetoothDevice;
Jeff Brown6ec6f792012-04-17 16:52:41 -070045import android.content.BroadcastReceiver;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070046import android.content.ComponentName;
Jeff Brown46b9ac02010-04-22 18:58:52 -070047import android.content.Context;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070048import android.content.Intent;
Jeff Brown6ec6f792012-04-17 16:52:41 -070049import android.content.IntentFilter;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070050import android.content.pm.ActivityInfo;
Michael Wright8ebac232014-09-18 18:29:49 -070051import android.content.pm.ApplicationInfo;
Jeff Brown349703e2010-06-22 01:27:15 -070052import android.content.pm.PackageManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070053import android.content.pm.ResolveInfo;
54import android.content.pm.PackageManager.NameNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070055import android.content.res.Resources;
Jeff Brown6ec6f792012-04-17 16:52:41 -070056import android.content.res.Resources.NotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070057import android.content.res.TypedArray;
58import android.content.res.XmlResourceParser;
Jeff Brown1a84fd12011-06-02 01:26:32 -070059import android.database.ContentObserver;
Jeff Brown4ccb8232014-01-16 22:16:42 -080060import android.hardware.display.DisplayViewport;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070061import android.hardware.input.IInputDevicesChangedListener;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070062import android.hardware.input.IInputManager;
RoboErikfb290df2013-12-16 11:27:55 -080063import android.hardware.input.InputDeviceIdentifier;
Jeff Brownac143512012-04-05 18:57:33 -070064import android.hardware.input.InputManager;
Jeff Brown4ccb8232014-01-16 22:16:42 -080065import android.hardware.input.InputManagerInternal;
Michael Wright39e5e942015-08-19 22:52:47 +010066import android.hardware.input.ITabletModeChangedListener;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070067import android.hardware.input.KeyboardLayout;
Jason Gerecked6396d62014-01-27 18:30:37 -080068import android.hardware.input.TouchCalibration;
Jeff Brown4532e612012-04-05 14:27:12 -070069import android.os.Binder;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070070import android.os.Bundle;
Jeff Brown46b9ac02010-04-22 18:58:52 -070071import android.os.Environment;
Jeff Brown4532e612012-04-05 14:27:12 -070072import android.os.Handler;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070073import android.os.IBinder;
Jeff Browna9d131c2012-09-20 16:48:17 -070074import android.os.Looper;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070075import android.os.Message;
Jeff Brown05dc66a2011-03-02 14:41:58 -080076import android.os.MessageQueue;
Jeff Brownac143512012-04-05 18:57:33 -070077import android.os.Process;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070078import android.os.RemoteException;
Michael Wrightd5f7ed92016-01-19 11:23:51 -080079import android.os.ResultReceiver;
80import android.os.ShellCommand;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070081import android.os.UserHandle;
Jeff Brown1a84fd12011-06-02 01:26:32 -070082import android.provider.Settings;
83import android.provider.Settings.SettingNotFoundException;
Michael Wright07483422015-10-30 16:20:13 +000084import android.text.TextUtils;
Jeff Brown46b9ac02010-04-22 18:58:52 -070085import android.util.Slog;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070086import android.util.SparseArray;
Jeff Brown46b9ac02010-04-22 18:58:52 -070087import android.util.Xml;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070088import android.view.IInputFilter;
89import android.view.IInputFilterHost;
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -080090import android.view.IWindow;
Jeff Brown46b9ac02010-04-22 18:58:52 -070091import android.view.InputChannel;
Jeff Brown8d608662010-08-30 03:02:23 -070092import android.view.InputDevice;
Jeff Brown6ec402b2010-07-28 15:48:59 -070093import android.view.InputEvent;
Jeff Brown1f245102010-11-18 20:53:46 -080094import android.view.KeyEvent;
Jeff Brown2352b972011-04-12 22:39:53 -070095import android.view.PointerIcon;
Jason Gerecked5220742014-03-10 09:47:59 -070096import android.view.Surface;
Jeff Browna4547672011-03-02 21:38:11 -080097import android.view.ViewConfiguration;
Jeff Brown0029c662011-03-30 02:25:18 -070098import android.view.WindowManagerPolicy;
Yohei Yukawab097b822015-12-01 10:43:08 -080099import android.view.inputmethod.InputMethodInfo;
100import android.view.inputmethod.InputMethodSubtype;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700101
Jeff Brown46b9ac02010-04-22 18:58:52 -0700102import java.io.File;
Jeff Brown4532e612012-04-05 14:27:12 -0700103import java.io.FileDescriptor;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700104import java.io.FileNotFoundException;
105import java.io.FileReader;
Adrian Roos99182342016-06-15 15:30:46 -0700106import java.io.FileWriter;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700107import java.io.IOException;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700108import java.io.InputStreamReader;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700109import java.io.PrintWriter;
110import java.util.ArrayList;
Michael Wright07483422015-10-30 16:20:13 +0000111import java.util.Collections;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700112import java.util.HashMap;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700113import java.util.HashSet;
Michael Wright39e5e942015-08-19 22:52:47 +0100114import java.util.List;
Michael Wright07483422015-10-30 16:20:13 +0000115import java.util.Locale;
Jeff Browna3bc5652012-04-17 11:42:25 -0700116
Adrian Roos99182342016-06-15 15:30:46 -0700117import libcore.io.IoUtils;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700118import libcore.io.Streams;
Jeff Browna3bc5652012-04-17 11:42:25 -0700119import libcore.util.Objects;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700120
121/*
122 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -0700123 */
Jeff Brownd728bf52012-09-08 18:05:28 -0700124public class InputManagerService extends IInputManager.Stub
Jeff Brown4ccb8232014-01-16 22:16:42 -0800125 implements Watchdog.Monitor {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700126 static final String TAG = "InputManager";
Jeff Brown1b9ba572012-05-21 10:54:18 -0700127 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -0700128
Jeff Brown4532e612012-04-05 14:27:12 -0700129 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
130
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700131 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700132 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
133 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
134 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
135 private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
Michael Wright39e5e942015-08-19 22:52:47 +0100136 private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
Yohei Yukawab097b822015-12-01 10:43:08 -0800137 private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700138
Jeff Brown4532e612012-04-05 14:27:12 -0700139 // Pointer to native input manager service object.
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000140 private final long mPtr;
Jeff Brown4532e612012-04-05 14:27:12 -0700141
Jeff Brown46b9ac02010-04-22 18:58:52 -0700142 private final Context mContext;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700143 private final InputManagerHandler mHandler;
Jeff Browna9d131c2012-09-20 16:48:17 -0700144
Adrian Roos99182342016-06-15 15:30:46 -0700145 private final File mDoubleTouchGestureEnableFile;
146
Jeff Browna9d131c2012-09-20 16:48:17 -0700147 private WindowManagerCallbacks mWindowManagerCallbacks;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700148 private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700149 private boolean mSystemReady;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700150 private NotificationManager mNotificationManager;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700151
Michael Wright39e5e942015-08-19 22:52:47 +0100152 private final Object mTabletModeLock = new Object();
153 // List of currently registered tablet mode changed listeners by process id
154 private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
155 new SparseArray<>(); // guarded by mTabletModeLock
156 private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
157 new ArrayList<>();
158
Jeff Browna3bc5652012-04-17 11:42:25 -0700159 // Persistent data store. Must be locked each time during use.
160 private final PersistentDataStore mDataStore = new PersistentDataStore();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700161
162 // List of currently registered input devices changed listeners by process id.
163 private Object mInputDevicesLock = new Object();
164 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
165 private InputDevice[] mInputDevices = new InputDevice[0];
166 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
167 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
168 private final ArrayList<InputDevicesChangedListenerRecord>
169 mTempInputDevicesChangedListenersToNotify =
170 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
Jeff Browncf39bdf2012-05-18 14:41:19 -0700171 private final ArrayList<InputDevice>
172 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
173 private boolean mKeyboardLayoutNotificationShown;
Michael Wrightd5f7ed92016-01-19 11:23:51 -0800174 private InputMethodSubtypeHandle mCurrentImeHandle;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700175
Jeff Browna47425a2012-04-13 04:09:27 -0700176 // State for vibrator tokens.
177 private Object mVibratorLock = new Object();
178 private HashMap<IBinder, VibratorToken> mVibratorTokens =
179 new HashMap<IBinder, VibratorToken>();
180 private int mNextVibratorTokenValue;
181
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700182 // State for the currently installed input filter.
183 final Object mInputFilterLock = new Object();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700184 IInputFilter mInputFilter; // guarded by mInputFilterLock
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700185 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
Jeff Brown1a84fd12011-06-02 01:26:32 -0700186
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -0800187 private IWindow mFocusedWindow;
188 private boolean mFocusedWindowHasCapture;
189
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000190 private static native long nativeInit(InputManagerService service,
Jeff Brown4532e612012-04-05 14:27:12 -0700191 Context context, MessageQueue messageQueue);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000192 private static native void nativeStart(long ptr);
193 private static native void nativeSetDisplayViewport(long ptr, boolean external,
Jeff Brownd728bf52012-09-08 18:05:28 -0700194 int displayId, int rotation,
195 int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
Jeff Brown83d616a2012-09-09 20:33:43 -0700196 int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
197 int deviceWidth, int deviceHeight);
Jeff Brownd728bf52012-09-08 18:05:28 -0700198
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000199 private static native int nativeGetScanCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700200 int deviceId, int sourceMask, int scanCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000201 private static native int nativeGetKeyCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700202 int deviceId, int sourceMask, int keyCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000203 private static native int nativeGetSwitchState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700204 int deviceId, int sourceMask, int sw);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000205 private static native boolean nativeHasKeys(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700206 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000207 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
Jeff Brown928e0542011-01-10 11:17:36 -0800208 InputWindowHandle inputWindowHandle, boolean monitor);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000209 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
210 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
Jeff Brownca9bc702014-02-11 14:32:56 -0800211 private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId,
Jeff Brown0029c662011-03-30 02:25:18 -0700212 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
213 int policyFlags);
Andrii Kulian112d0562016-03-08 10:44:22 -0800214 private static native void nativeToggleCapsLock(long ptr, int deviceId);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000215 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
216 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
217 private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
218 private static native void nativeSetFocusedApplication(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700219 InputApplicationHandle application);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000220 private static native boolean nativeTransferTouchFocus(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700221 InputChannel fromChannel, InputChannel toChannel);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000222 private static native void nativeSetPointerSpeed(long ptr, int speed);
223 private static native void nativeSetShowTouches(long ptr, boolean enabled);
Jeff Brown037c33e2014-04-09 00:31:55 -0700224 private static native void nativeSetInteractive(long ptr, boolean interactive);
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800225 private static native void nativeReloadCalibration(long ptr);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000226 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
Jeff Browna47425a2012-04-13 04:09:27 -0700227 int repeat, int token);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000228 private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
229 private static native void nativeReloadKeyboardLayouts(long ptr);
230 private static native void nativeReloadDeviceAliases(long ptr);
231 private static native String nativeDump(long ptr);
232 private static native void nativeMonitor(long ptr);
Siarhei Vishniakoua7f99b52017-03-21 17:39:40 -0700233 private static native boolean nativeIsInputDeviceEnabled(long ptr, int deviceId);
234 private static native void nativeEnableInputDevice(long ptr, int deviceId);
235 private static native void nativeDisableInputDevice(long ptr, int deviceId);
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100236 private static native void nativeSetPointerIconType(long ptr, int iconId);
Jun Mukai19a56012015-11-24 11:25:52 -0800237 private static native void nativeReloadPointerIcons(long ptr);
Jun Mukaid4eaef72015-10-30 15:54:33 -0700238 private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -0800239 private static native void nativeSetPointerCapture(long ptr, boolean detached);
Jeff Brown4532e612012-04-05 14:27:12 -0700240
Jeff Brownac143512012-04-05 18:57:33 -0700241 // Input event injection constants defined in InputDispatcher.h.
242 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
243 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
244 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
245 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
246
247 // Maximum number of milliseconds to wait for input event injection.
248 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
249
Jeff Brown6d0fec22010-07-23 21:28:06 -0700250 // Key states (may be returned by queries about the current state of a
251 // particular key code, scan code or switch).
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700252
Jeff Brown6d0fec22010-07-23 21:28:06 -0700253 /** The key state is unknown or the requested key itself is not supported. */
254 public static final int KEY_STATE_UNKNOWN = -1;
255
256 /** The key is up. /*/
257 public static final int KEY_STATE_UP = 0;
258
259 /** The key is down. */
260 public static final int KEY_STATE_DOWN = 1;
261
262 /** The key is down but is a virtual key press that is being emulated by the system. */
263 public static final int KEY_STATE_VIRTUAL = 2;
264
Jeff Brownc458ce92012-04-30 14:58:40 -0700265 /** Scan code: Mouse / trackball button. */
266 public static final int BTN_MOUSE = 0x110;
267
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700268 // Switch code values must match bionic/libc/kernel/common/linux/input.h
Jeff Brownc458ce92012-04-30 14:58:40 -0700269 /** Switch code: Lid switch. When set, lid is shut. */
270 public static final int SW_LID = 0x00;
271
Michael Wright39e5e942015-08-19 22:52:47 +0100272 /** Switch code: Tablet mode switch.
273 * When set, the device is in tablet mode (i.e. no keyboard is connected).
274 */
275 public static final int SW_TABLET_MODE = 0x01;
276
Jeff Brownc458ce92012-04-30 14:58:40 -0700277 /** Switch code: Keypad slide. When set, keyboard is exposed. */
278 public static final int SW_KEYPAD_SLIDE = 0x0a;
279
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700280 /** Switch code: Headphone. When set, headphone is inserted. */
281 public static final int SW_HEADPHONE_INSERT = 0x02;
282
283 /** Switch code: Microphone. When set, microphone is inserted. */
284 public static final int SW_MICROPHONE_INSERT = 0x04;
285
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500286 /** Switch code: Line out. When set, Line out (hi-Z) is inserted. */
287 public static final int SW_LINEOUT_INSERT = 0x06;
288
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700289 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */
290 public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
291
Michael Wright3818c922014-09-02 13:59:07 -0700292 /** Switch code: Camera lens cover. When set the lens is covered. */
293 public static final int SW_CAMERA_LENS_COVER = 0x09;
294
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700295 public static final int SW_LID_BIT = 1 << SW_LID;
Michael Wright39e5e942015-08-19 22:52:47 +0100296 public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700297 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
298 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
299 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500300 public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700301 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
302 public static final int SW_JACK_BITS =
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500303 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
Michael Wright3818c922014-09-02 13:59:07 -0700304 public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700305
306 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
307 final boolean mUseDevInputEventForAudioJack;
308
Jeff Brown4ccb8232014-01-16 22:16:42 -0800309 public InputManagerService(Context context) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700310 this.mContext = context;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800311 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
Jeff Brown05dc66a2011-03-02 14:41:58 -0800312
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700313 mUseDevInputEventForAudioJack =
314 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
315 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
316 + mUseDevInputEventForAudioJack);
Jeff Brown4532e612012-04-05 14:27:12 -0700317 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown4ccb8232014-01-16 22:16:42 -0800318
Adrian Roos99182342016-06-15 15:30:46 -0700319 String doubleTouchGestureEnablePath = context.getResources().getString(
320 R.string.config_doubleTouchGestureEnableFile);
321 mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
322 new File(doubleTouchGestureEnablePath);
323
Jeff Brown4ccb8232014-01-16 22:16:42 -0800324 LocalServices.addService(InputManagerInternal.class, new LocalService());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700325 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700326
Jeff Browna9d131c2012-09-20 16:48:17 -0700327 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
328 mWindowManagerCallbacks = callbacks;
329 }
330
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700331 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
332 mWiredAccessoryCallbacks = callbacks;
333 }
334
Jeff Brown46b9ac02010-04-22 18:58:52 -0700335 public void start() {
336 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700337 nativeStart(mPtr);
338
339 // Add ourself to the Watchdog monitors.
340 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700341
342 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700343 registerShowTouchesSettingObserver();
Jun Mukai19a56012015-11-24 11:25:52 -0800344 registerAccessibilityLargePointerSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700345
Jeff Brownd4935962012-09-25 13:27:20 -0700346 mContext.registerReceiver(new BroadcastReceiver() {
347 @Override
348 public void onReceive(Context context, Intent intent) {
349 updatePointerSpeedFromSettings();
350 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800351 updateAccessibilityLargePointerFromSettings();
Jeff Brownd4935962012-09-25 13:27:20 -0700352 }
353 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
354
Jeff Brown1a84fd12011-06-02 01:26:32 -0700355 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700356 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800357 updateAccessibilityLargePointerFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700358 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700359
Matthew Xie96313142012-06-29 16:57:31 -0700360 // TODO(BT) Pass in paramter for bluetooth system
Svetoslav Ganova0027152013-06-25 14:59:53 -0700361 public void systemRunning() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700362 if (DEBUG) {
363 Slog.d(TAG, "System ready.");
364 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700365 mNotificationManager = (NotificationManager)mContext.getSystemService(
366 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700367 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700368
369 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
370 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
371 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Jeff Brown69b07162013-11-07 00:30:16 -0800372 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700373 filter.addDataScheme("package");
374 mContext.registerReceiver(new BroadcastReceiver() {
375 @Override
376 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700377 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700378 }
379 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700380
381 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
382 mContext.registerReceiver(new BroadcastReceiver() {
383 @Override
384 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700385 reloadDeviceAliases();
386 }
387 }, filter, null, mHandler);
388
Jeff Browncf39bdf2012-05-18 14:41:19 -0700389 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
390 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700391
392 if (mWiredAccessoryCallbacks != null) {
393 mWiredAccessoryCallbacks.systemReady();
394 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700395 }
396
397 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700398 if (DEBUG) {
399 Slog.d(TAG, "Reloading keyboard layouts.");
400 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700401 nativeReloadKeyboardLayouts(mPtr);
402 }
403
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700404 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700405 if (DEBUG) {
406 Slog.d(TAG, "Reloading device names.");
407 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700408 nativeReloadDeviceAliases(mPtr);
409 }
410
Jeff Brown4ccb8232014-01-16 22:16:42 -0800411 private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
Jeff Brownd728bf52012-09-08 18:05:28 -0700412 DisplayViewport externalTouchViewport) {
413 if (defaultViewport.valid) {
414 setDisplayViewport(false, defaultViewport);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700415 }
Jeff Brownd728bf52012-09-08 18:05:28 -0700416
417 if (externalTouchViewport.valid) {
418 setDisplayViewport(true, externalTouchViewport);
419 } else if (defaultViewport.valid) {
420 setDisplayViewport(true, defaultViewport);
Jeff Brownb6997262010-10-08 22:31:17 -0700421 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700422 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700423
Jeff Brownd728bf52012-09-08 18:05:28 -0700424 private void setDisplayViewport(boolean external, DisplayViewport viewport) {
425 nativeSetDisplayViewport(mPtr, external,
426 viewport.displayId, viewport.orientation,
427 viewport.logicalFrame.left, viewport.logicalFrame.top,
428 viewport.logicalFrame.right, viewport.logicalFrame.bottom,
429 viewport.physicalFrame.left, viewport.physicalFrame.top,
Jeff Brown83d616a2012-09-09 20:33:43 -0700430 viewport.physicalFrame.right, viewport.physicalFrame.bottom,
431 viewport.deviceWidth, viewport.deviceHeight);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700432 }
Jeff Brownac143512012-04-05 18:57:33 -0700433
Jeff Brown6d0fec22010-07-23 21:28:06 -0700434 /**
435 * Gets the current state of a key or button by key code.
436 * @param deviceId The input device id, or -1 to consult all devices.
437 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
438 * consider all input sources. An input device is consulted if at least one of its
439 * non-class input source bits matches the specified source mask.
440 * @param keyCode The key code to check.
441 * @return The key state.
442 */
443 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700444 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700445 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700446
Jeff Brown6d0fec22010-07-23 21:28:06 -0700447 /**
448 * Gets the current state of a key or button by scan code.
449 * @param deviceId The input device id, or -1 to consult all devices.
450 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
451 * consider all input sources. An input device is consulted if at least one of its
452 * non-class input source bits matches the specified source mask.
453 * @param scanCode The scan code to check.
454 * @return The key state.
455 */
456 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700457 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700458 }
RoboErikfb290df2013-12-16 11:27:55 -0800459
Jeff Brown6d0fec22010-07-23 21:28:06 -0700460 /**
461 * Gets the current state of a switch by switch code.
462 * @param deviceId The input device id, or -1 to consult all devices.
463 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
464 * consider all input sources. An input device is consulted if at least one of its
465 * non-class input source bits matches the specified source mask.
466 * @param switchCode The switch code to check.
467 * @return The switch state.
468 */
469 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700470 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700471 }
472
Jeff Brown6d0fec22010-07-23 21:28:06 -0700473 /**
474 * Determines whether the specified key codes are supported by a particular device.
475 * @param deviceId The input device id, or -1 to consult all devices.
476 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
477 * consider all input sources. An input device is consulted if at least one of its
478 * non-class input source bits matches the specified source mask.
479 * @param keyCodes The array of key codes to check.
480 * @param keyExists An array at least as large as keyCodes whose entries will be set
481 * to true or false based on the presence or absence of support for the corresponding
482 * key codes.
483 * @return True if the lookup was successful, false otherwise.
484 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700485 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700486 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700487 if (keyCodes == null) {
488 throw new IllegalArgumentException("keyCodes must not be null.");
489 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700490 if (keyExists == null || keyExists.length < keyCodes.length) {
491 throw new IllegalArgumentException("keyExists must not be null and must be at "
492 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700493 }
RoboErikfb290df2013-12-16 11:27:55 -0800494
Jeff Brown4532e612012-04-05 14:27:12 -0700495 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700496 }
RoboErikfb290df2013-12-16 11:27:55 -0800497
Jeff Browna41ca772010-08-11 14:46:32 -0700498 /**
499 * Creates an input channel that will receive all input from the input dispatcher.
500 * @param inputChannelName The input channel name.
501 * @return The input channel.
502 */
503 public InputChannel monitorInput(String inputChannelName) {
504 if (inputChannelName == null) {
505 throw new IllegalArgumentException("inputChannelName must not be null.");
506 }
RoboErikfb290df2013-12-16 11:27:55 -0800507
Jeff Browna41ca772010-08-11 14:46:32 -0700508 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700509 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700510 inputChannels[0].dispose(); // don't need to retain the Java object reference
511 return inputChannels[1];
512 }
513
514 /**
515 * Registers an input channel so that it can be used as an input event target.
516 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800517 * @param inputWindowHandle The handle of the input window associated with the
518 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700519 */
Jeff Brown928e0542011-01-10 11:17:36 -0800520 public void registerInputChannel(InputChannel inputChannel,
521 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700522 if (inputChannel == null) {
523 throw new IllegalArgumentException("inputChannel must not be null.");
524 }
RoboErikfb290df2013-12-16 11:27:55 -0800525
Jeff Brown4532e612012-04-05 14:27:12 -0700526 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700527 }
RoboErikfb290df2013-12-16 11:27:55 -0800528
Jeff Browna41ca772010-08-11 14:46:32 -0700529 /**
530 * Unregisters an input channel.
531 * @param inputChannel The input channel to unregister.
532 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700533 public void unregisterInputChannel(InputChannel inputChannel) {
534 if (inputChannel == null) {
535 throw new IllegalArgumentException("inputChannel must not be null.");
536 }
RoboErikfb290df2013-12-16 11:27:55 -0800537
Jeff Brown4532e612012-04-05 14:27:12 -0700538 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700539 }
Jeff Brown0029c662011-03-30 02:25:18 -0700540
541 /**
542 * Sets an input filter that will receive all input events before they are dispatched.
543 * The input filter may then reinterpret input events or inject new ones.
544 *
545 * To ensure consistency, the input dispatcher automatically drops all events
546 * in progress whenever an input filter is installed or uninstalled. After an input
547 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
548 * Any events it attempts to send after it has been uninstalled will be dropped.
549 *
550 * @param filter The input filter, or null to remove the current filter.
551 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700552 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700553 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700554 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700555 if (oldFilter == filter) {
556 return; // nothing to do
557 }
558
559 if (oldFilter != null) {
560 mInputFilter = null;
561 mInputFilterHost.disconnectLocked();
562 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700563 try {
564 oldFilter.uninstall();
565 } catch (RemoteException re) {
566 /* ignore */
567 }
Jeff Brown0029c662011-03-30 02:25:18 -0700568 }
569
570 if (filter != null) {
571 mInputFilter = filter;
572 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700573 try {
574 filter.install(mInputFilterHost);
575 } catch (RemoteException re) {
576 /* ignore */
577 }
Jeff Brown0029c662011-03-30 02:25:18 -0700578 }
579
Jeff Brown4532e612012-04-05 14:27:12 -0700580 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700581 }
582 }
583
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700584 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700585 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brownca9bc702014-02-11 14:32:56 -0800586 return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
587 }
588
589 private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700590 if (event == null) {
591 throw new IllegalArgumentException("event must not be null");
592 }
Jeff Brownac143512012-04-05 18:57:33 -0700593 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
594 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
595 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
596 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700597 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700598
Jeff Brownac143512012-04-05 18:57:33 -0700599 final int pid = Binder.getCallingPid();
600 final int uid = Binder.getCallingUid();
601 final long ident = Binder.clearCallingIdentity();
602 final int result;
603 try {
Jeff Brownca9bc702014-02-11 14:32:56 -0800604 result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
Jeff Brownac143512012-04-05 18:57:33 -0700605 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
606 } finally {
607 Binder.restoreCallingIdentity(ident);
608 }
609 switch (result) {
610 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
611 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
612 throw new SecurityException(
613 "Injecting to another application requires INJECT_EVENTS permission");
614 case INPUT_EVENT_INJECTION_SUCCEEDED:
615 return true;
616 case INPUT_EVENT_INJECTION_TIMED_OUT:
617 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
618 return false;
619 case INPUT_EVENT_INJECTION_FAILED:
620 default:
621 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
622 return false;
623 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700624 }
Jeff Brown0029c662011-03-30 02:25:18 -0700625
Jeff Brown8d608662010-08-30 03:02:23 -0700626 /**
627 * Gets information about the input device with the specified id.
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700628 * @param deviceId The device id.
Jeff Brown8d608662010-08-30 03:02:23 -0700629 * @return The input device or null if not found.
630 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700631 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700632 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700633 synchronized (mInputDevicesLock) {
634 final int count = mInputDevices.length;
635 for (int i = 0; i < count; i++) {
636 final InputDevice inputDevice = mInputDevices[i];
637 if (inputDevice.getId() == deviceId) {
638 return inputDevice;
639 }
640 }
641 }
642 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700643 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700644
Siarhei Vishniakoua7f99b52017-03-21 17:39:40 -0700645 // Binder call
646 @Override
647 public boolean isInputDeviceEnabled(int deviceId) {
648 return nativeIsInputDeviceEnabled(mPtr, deviceId);
649 }
650
651 // Binder call
652 @Override
653 public void enableInputDevice(int deviceId) {
654 if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
655 "enableInputDevice()")) {
656 throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
657 }
658 nativeEnableInputDevice(mPtr, deviceId);
659 }
660
661 // Binder call
662 @Override
663 public void disableInputDevice(int deviceId) {
664 if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
665 "disableInputDevice()")) {
666 throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
667 }
668 nativeDisableInputDevice(mPtr, deviceId);
669 }
670
Jeff Brown8d608662010-08-30 03:02:23 -0700671 /**
672 * Gets the ids of all input devices in the system.
673 * @return The input device ids.
674 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700675 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700676 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700677 synchronized (mInputDevicesLock) {
678 final int count = mInputDevices.length;
679 int[] ids = new int[count];
680 for (int i = 0; i < count; i++) {
681 ids[i] = mInputDevices[i].getId();
682 }
683 return ids;
684 }
685 }
686
Jeff Browndaa37532012-05-01 15:54:03 -0700687 /**
688 * Gets all input devices in the system.
689 * @return The array of input devices.
690 */
691 public InputDevice[] getInputDevices() {
692 synchronized (mInputDevicesLock) {
693 return mInputDevices;
694 }
695 }
696
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700697 @Override // Binder call
698 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
699 if (listener == null) {
700 throw new IllegalArgumentException("listener must not be null");
701 }
702
703 synchronized (mInputDevicesLock) {
704 int callingPid = Binder.getCallingPid();
705 if (mInputDevicesChangedListeners.get(callingPid) != null) {
706 throw new SecurityException("The calling process has already "
707 + "registered an InputDevicesChangedListener.");
708 }
709
710 InputDevicesChangedListenerRecord record =
711 new InputDevicesChangedListenerRecord(callingPid, listener);
712 try {
713 IBinder binder = listener.asBinder();
714 binder.linkToDeath(record, 0);
715 } catch (RemoteException ex) {
716 // give up
717 throw new RuntimeException(ex);
718 }
719
720 mInputDevicesChangedListeners.put(callingPid, record);
721 }
722 }
723
724 private void onInputDevicesChangedListenerDied(int pid) {
725 synchronized (mInputDevicesLock) {
726 mInputDevicesChangedListeners.remove(pid);
727 }
728 }
729
730 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700731 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
732 // Scan for changes.
733 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700734 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700735 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700736 final int numListeners;
737 final int[] deviceIdAndGeneration;
738 synchronized (mInputDevicesLock) {
739 if (!mInputDevicesChangedPending) {
740 return;
741 }
742 mInputDevicesChangedPending = false;
743
744 numListeners = mInputDevicesChangedListeners.size();
745 for (int i = 0; i < numListeners; i++) {
746 mTempInputDevicesChangedListenersToNotify.add(
747 mInputDevicesChangedListeners.valueAt(i));
748 }
749
750 final int numDevices = mInputDevices.length;
751 deviceIdAndGeneration = new int[numDevices * 2];
752 for (int i = 0; i < numDevices; i++) {
753 final InputDevice inputDevice = mInputDevices[i];
754 deviceIdAndGeneration[i * 2] = inputDevice.getId();
755 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700756
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700757 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700758 if (!containsInputDeviceWithDescriptor(oldInputDevices,
759 inputDevice.getDescriptor())) {
760 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
761 } else {
762 mTempFullKeyboards.add(inputDevice);
763 }
764 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700765 }
766 }
767
Jeff Browncf39bdf2012-05-18 14:41:19 -0700768 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700769 for (int i = 0; i < numListeners; i++) {
770 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
771 deviceIdAndGeneration);
772 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700773 mTempInputDevicesChangedListenersToNotify.clear();
774
775 // Check for missing keyboard layouts.
Michael Wright07483422015-10-30 16:20:13 +0000776 List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
777 final int numFullKeyboards = mTempFullKeyboards.size();
778 synchronized (mDataStore) {
779 for (int i = 0; i < numFullKeyboards; i++) {
780 final InputDevice inputDevice = mTempFullKeyboards.get(i);
781 String layout =
782 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
783 if (layout == null) {
784 layout = getDefaultKeyboardLayout(inputDevice);
785 if (layout != null) {
786 setCurrentKeyboardLayoutForInputDevice(
787 inputDevice.getIdentifier(), layout);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700788 }
789 }
Michael Wright07483422015-10-30 16:20:13 +0000790 if (layout == null) {
791 keyboardsMissingLayout.add(inputDevice);
792 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700793 }
Michael Wright07483422015-10-30 16:20:13 +0000794 }
795
796 if (mNotificationManager != null) {
797 if (!keyboardsMissingLayout.isEmpty()) {
798 if (keyboardsMissingLayout.size() > 1) {
799 // We have more than one keyboard missing a layout, so drop the
800 // user at the generic input methods page so they can pick which
801 // one to set.
802 showMissingKeyboardLayoutNotification(null);
803 } else {
804 showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
Jeff Browncf39bdf2012-05-18 14:41:19 -0700805 }
806 } else if (mKeyboardLayoutNotificationShown) {
807 hideMissingKeyboardLayoutNotification();
808 }
809 }
810 mTempFullKeyboards.clear();
811 }
812
Michael Wright07483422015-10-30 16:20:13 +0000813 private String getDefaultKeyboardLayout(final InputDevice d) {
814 final Locale systemLocale = mContext.getResources().getConfiguration().locale;
815 // If our locale doesn't have a language for some reason, then we don't really have a
816 // reasonable default.
817 if (TextUtils.isEmpty(systemLocale.getLanguage())) {
818 return null;
819 }
820 final List<KeyboardLayout> layouts = new ArrayList<>();
821 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
822 @Override
823 public void visitKeyboardLayout(Resources resources,
824 int keyboardLayoutResId, KeyboardLayout layout) {
825 // Only select a default when we know the layout is appropriate. For now, this
826 // means its a custom layout for a specific keyboard.
827 if (layout.getVendorId() != d.getVendorId()
828 || layout.getProductId() != d.getProductId()) {
829 return;
830 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800831 final LocaleList locales = layout.getLocales();
832 final int numLocales = locales.size();
833 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
834 if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
Michael Wright07483422015-10-30 16:20:13 +0000835 layouts.add(layout);
836 break;
837 }
838 }
839 }
840 });
841
842 if (layouts.isEmpty()) {
843 return null;
844 }
845
846 // First sort so that ones with higher priority are listed at the top
847 Collections.sort(layouts);
848 // Next we want to try to find an exact match of language, country and variant.
849 final int N = layouts.size();
850 for (int i = 0; i < N; i++) {
851 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800852 final LocaleList locales = layout.getLocales();
853 final int numLocales = locales.size();
854 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
855 final Locale locale = locales.get(localeIndex);
856 if (locale.getCountry().equals(systemLocale.getCountry())
857 && locale.getVariant().equals(systemLocale.getVariant())) {
Michael Wright07483422015-10-30 16:20:13 +0000858 return layout.getDescriptor();
859 }
860 }
861 }
862 // Then try an exact match of language and country
863 for (int i = 0; i < N; i++) {
864 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800865 final LocaleList locales = layout.getLocales();
866 final int numLocales = locales.size();
867 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
868 final Locale locale = locales.get(localeIndex);
869 if (locale.getCountry().equals(systemLocale.getCountry())) {
Michael Wright07483422015-10-30 16:20:13 +0000870 return layout.getDescriptor();
871 }
872 }
873 }
874
875 // Give up and just use the highest priority layout with matching language
876 return layouts.get(0).getDescriptor();
877 }
878
879 private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
880 // Different languages are never compatible
881 if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
882 return false;
883 }
884 // If both the system and the keyboard layout have a country specifier, they must be equal.
885 if (!TextUtils.isEmpty(systemLocale.getCountry())
886 && !TextUtils.isEmpty(keyboardLocale.getCountry())
887 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
888 return false;
889 }
890 return true;
891 }
892
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800893 @Override // Binder call & native callback
Jason Gerecked5220742014-03-10 09:47:59 -0700894 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
895 int surfaceRotation) {
Jason Gerecked6396d62014-01-27 18:30:37 -0800896 if (inputDeviceDescriptor == null) {
897 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
898 }
899
900 synchronized (mDataStore) {
Jason Gerecked5220742014-03-10 09:47:59 -0700901 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
Jason Gerecked6396d62014-01-27 18:30:37 -0800902 }
903 }
904
905 @Override // Binder call
Jason Gerecked5220742014-03-10 09:47:59 -0700906 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
Jason Gerecked6396d62014-01-27 18:30:37 -0800907 TouchCalibration calibration) {
908 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
909 "setTouchCalibrationForInputDevice()")) {
910 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
911 }
912 if (inputDeviceDescriptor == null) {
913 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
914 }
915 if (calibration == null) {
916 throw new IllegalArgumentException("calibration must not be null");
917 }
Jason Gerecked5220742014-03-10 09:47:59 -0700918 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
919 throw new IllegalArgumentException("surfaceRotation value out of bounds");
920 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800921
922 synchronized (mDataStore) {
923 try {
Jason Gerecked5220742014-03-10 09:47:59 -0700924 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
925 calibration)) {
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800926 nativeReloadCalibration(mPtr);
927 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800928 } finally {
929 mDataStore.saveIfNeeded();
930 }
931 }
932 }
933
Michael Wright39e5e942015-08-19 22:52:47 +0100934 @Override // Binder call
Michael Wright9209c9c2015-09-03 17:57:01 +0100935 public int isInTabletMode() {
936 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
937 "isInTabletMode()")) {
938 throw new SecurityException("Requires TABLET_MODE permission");
939 }
940 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
941 }
942
943 @Override // Binder call
Michael Wright39e5e942015-08-19 22:52:47 +0100944 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
Michael Wright9209c9c2015-09-03 17:57:01 +0100945 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
Michael Wright39e5e942015-08-19 22:52:47 +0100946 "registerTabletModeChangedListener()")) {
947 throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
948 }
949 if (listener == null) {
950 throw new IllegalArgumentException("listener must not be null");
951 }
952
953 synchronized (mTabletModeLock) {
954 final int callingPid = Binder.getCallingPid();
955 if (mTabletModeChangedListeners.get(callingPid) != null) {
956 throw new IllegalStateException("The calling process has already registered "
957 + "a TabletModeChangedListener.");
958 }
959 TabletModeChangedListenerRecord record =
960 new TabletModeChangedListenerRecord(callingPid, listener);
961 try {
962 IBinder binder = listener.asBinder();
963 binder.linkToDeath(record, 0);
964 } catch (RemoteException ex) {
965 throw new RuntimeException(ex);
966 }
967 mTabletModeChangedListeners.put(callingPid, record);
968 }
969 }
970
971 private void onTabletModeChangedListenerDied(int pid) {
972 synchronized (mTabletModeLock) {
973 mTabletModeChangedListeners.remove(pid);
974 }
975 }
976
977 // Must be called on handler
978 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
979 mTempTabletModeChangedListenersToNotify.clear();
980 final int numListeners;
981 synchronized (mTabletModeLock) {
982 numListeners = mTabletModeChangedListeners.size();
983 for (int i = 0; i < numListeners; i++) {
984 mTempTabletModeChangedListenersToNotify.add(
985 mTabletModeChangedListeners.valueAt(i));
986 }
987 }
988 for (int i = 0; i < numListeners; i++) {
989 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
990 whenNanos, inTabletMode);
991 }
992 }
993
Jeff Browncf39bdf2012-05-18 14:41:19 -0700994 // Must be called on handler.
Michael Wrightc93fbd12014-09-22 20:07:59 -0700995 private void showMissingKeyboardLayoutNotification(InputDevice device) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700996 if (!mKeyboardLayoutNotificationShown) {
Yohei Yukawa2bff4902016-03-30 01:06:37 -0700997 final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
Michael Wrightc93fbd12014-09-22 20:07:59 -0700998 if (device != null) {
999 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001000 }
Michael Wrightc93fbd12014-09-22 20:07:59 -07001001 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1002 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
1003 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
1004 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
1005 intent, 0, null, UserHandle.CURRENT);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001006
1007 Resources r = mContext.getResources();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001008 Notification notification =
1009 new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
1010 .setContentTitle(r.getString(
1011 R.string.select_keyboard_layout_notification_title))
1012 .setContentText(r.getString(
1013 R.string.select_keyboard_layout_notification_message))
1014 .setContentIntent(keyboardLayoutIntent)
1015 .setSmallIcon(R.drawable.ic_settings_language)
1016 .setColor(mContext.getColor(
1017 com.android.internal.R.color.system_notification_accent_color))
1018 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001019 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04001020 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001021 notification, UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001022 mKeyboardLayoutNotificationShown = true;
1023 }
1024 }
1025
1026 // Must be called on handler.
1027 private void hideMissingKeyboardLayoutNotification() {
1028 if (mKeyboardLayoutNotificationShown) {
1029 mKeyboardLayoutNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001030 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04001031 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001032 UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001033 }
1034 }
1035
1036 // Must be called on handler.
1037 private void updateKeyboardLayouts() {
1038 // Scan all input devices state for keyboard layouts that have been uninstalled.
1039 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
1040 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1041 @Override
Michael Wright07483422015-10-30 16:20:13 +00001042 public void visitKeyboardLayout(Resources resources,
1043 int keyboardLayoutResId, KeyboardLayout layout) {
1044 availableKeyboardLayouts.add(layout.getDescriptor());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001045 }
1046 });
1047 synchronized (mDataStore) {
1048 try {
1049 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
1050 } finally {
1051 mDataStore.saveIfNeeded();
1052 }
1053 }
1054
1055 // Reload keyboard layouts.
1056 reloadKeyboardLayouts();
1057 }
1058
Jeff Browncf39bdf2012-05-18 14:41:19 -07001059 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
1060 String descriptor) {
1061 final int numDevices = inputDevices.length;
1062 for (int i = 0; i < numDevices; i++) {
1063 final InputDevice inputDevice = inputDevices[i];
1064 if (inputDevice.getDescriptor().equals(descriptor)) {
1065 return true;
1066 }
1067 }
1068 return false;
Jeff Brown8d608662010-08-30 03:02:23 -07001069 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001070
1071 @Override // Binder call
1072 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001073 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
1074 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1075 @Override
Michael Wright07483422015-10-30 16:20:13 +00001076 public void visitKeyboardLayout(Resources resources,
1077 int keyboardLayoutResId, KeyboardLayout layout) {
1078 list.add(layout);
1079 }
1080 });
1081 return list.toArray(new KeyboardLayout[list.size()]);
1082 }
1083
Michael Wrightb0e804a2016-01-04 16:48:53 -05001084 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001085 public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1086 final InputDeviceIdentifier identifier) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001087 final String[] enabledLayoutDescriptors =
1088 getEnabledKeyboardLayoutsForInputDevice(identifier);
1089 final ArrayList<KeyboardLayout> enabledLayouts =
1090 new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length);
1091 final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>();
Michael Wright07483422015-10-30 16:20:13 +00001092 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1093 boolean mHasSeenDeviceSpecificLayout;
1094
1095 @Override
1096 public void visitKeyboardLayout(Resources resources,
1097 int keyboardLayoutResId, KeyboardLayout layout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001098 // First check if it's enabled. If the keyboard layout is enabled then we always
1099 // want to return it as a possible layout for the device.
1100 for (String s : enabledLayoutDescriptors) {
1101 if (s != null && s.equals(layout.getDescriptor())) {
1102 enabledLayouts.add(layout);
1103 return;
1104 }
1105 }
1106 // Next find any potential layouts that aren't yet enabled for the device. For
1107 // devices that have special layouts we assume there's a reason that the generic
1108 // layouts don't work for them so we don't want to return them since it's likely
1109 // to result in a poor user experience.
Michael Wright07483422015-10-30 16:20:13 +00001110 if (layout.getVendorId() == identifier.getVendorId()
1111 && layout.getProductId() == identifier.getProductId()) {
1112 if (!mHasSeenDeviceSpecificLayout) {
1113 mHasSeenDeviceSpecificLayout = true;
Michael Wrightb0e804a2016-01-04 16:48:53 -05001114 potentialLayouts.clear();
Michael Wright07483422015-10-30 16:20:13 +00001115 }
Michael Wrightb0e804a2016-01-04 16:48:53 -05001116 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001117 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
1118 && !mHasSeenDeviceSpecificLayout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001119 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001120 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001121 }
1122 });
Michael Wrightb0e804a2016-01-04 16:48:53 -05001123 final int enabledLayoutSize = enabledLayouts.size();
1124 final int potentialLayoutSize = potentialLayouts.size();
1125 KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
1126 enabledLayouts.toArray(layouts);
1127 for (int i = 0; i < potentialLayoutSize; i++) {
1128 layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
1129 }
1130 return layouts;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001131 }
1132
1133 @Override // Binder call
1134 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
1135 if (keyboardLayoutDescriptor == null) {
1136 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1137 }
1138
Jeff Brown6ec6f792012-04-17 16:52:41 -07001139 final KeyboardLayout[] result = new KeyboardLayout[1];
1140 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1141 @Override
Michael Wright07483422015-10-30 16:20:13 +00001142 public void visitKeyboardLayout(Resources resources,
1143 int keyboardLayoutResId, KeyboardLayout layout) {
1144 result[0] = layout;
Jeff Brown6ec6f792012-04-17 16:52:41 -07001145 }
1146 });
1147 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00001148 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07001149 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001150 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001151 return result[0];
1152 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001153
Jeff Brown6ec6f792012-04-17 16:52:41 -07001154 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001155 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001156 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
1157 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001158 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
1159 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
Michael Wright8ebac232014-09-18 18:29:49 -07001160 final ActivityInfo activityInfo = resolveInfo.activityInfo;
1161 final int priority = resolveInfo.priority;
1162 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001163 }
1164 }
1165
Jeff Brown6ec6f792012-04-17 16:52:41 -07001166 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
1167 KeyboardLayoutVisitor visitor) {
1168 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
1169 if (d != null) {
1170 final PackageManager pm = mContext.getPackageManager();
1171 try {
1172 ActivityInfo receiver = pm.getReceiverInfo(
1173 new ComponentName(d.packageName, d.receiverName),
Jeff Sharkey5217cac2015-12-20 15:34:01 -07001174 PackageManager.GET_META_DATA
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001175 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1176 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Michael Wright8ebac232014-09-18 18:29:49 -07001177 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001178 } catch (NameNotFoundException ex) {
1179 }
1180 }
1181 }
1182
1183 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
Michael Wright8ebac232014-09-18 18:29:49 -07001184 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001185 Bundle metaData = receiver.metaData;
1186 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001187 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001188 }
1189
1190 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1191 if (configResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001192 Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001193 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001194 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001195 }
1196
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001197 CharSequence receiverLabel = receiver.loadLabel(pm);
1198 String collection = receiverLabel != null ? receiverLabel.toString() : "";
Michael Wright8ebac232014-09-18 18:29:49 -07001199 int priority;
1200 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1201 priority = requestedPriority;
1202 } else {
1203 priority = 0;
1204 }
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001205
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001206 try {
1207 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1208 XmlResourceParser parser = resources.getXml(configResId);
1209 try {
1210 XmlUtils.beginDocument(parser, "keyboard-layouts");
1211
1212 for (;;) {
1213 XmlUtils.nextElement(parser);
1214 String element = parser.getName();
1215 if (element == null) {
1216 break;
1217 }
1218 if (element.equals("keyboard-layout")) {
1219 TypedArray a = resources.obtainAttributes(
1220 parser, com.android.internal.R.styleable.KeyboardLayout);
1221 try {
1222 String name = a.getString(
1223 com.android.internal.R.styleable.KeyboardLayout_name);
1224 String label = a.getString(
1225 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -07001226 int keyboardLayoutResId = a.getResourceId(
1227 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1228 0);
Michael Wright07483422015-10-30 16:20:13 +00001229 String languageTags = a.getString(
1230 com.android.internal.R.styleable.KeyboardLayout_locale);
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001231 LocaleList locales = getLocalesFromLanguageTags(languageTags);
Michael Wright07483422015-10-30 16:20:13 +00001232 int vid = a.getInt(
1233 com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
1234 int pid = a.getInt(
1235 com.android.internal.R.styleable.KeyboardLayout_productId, -1);
1236
Jeff Brown2f095762012-05-10 21:29:33 -07001237 if (name == null || label == null || keyboardLayoutResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001238 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001239 + "attributes in keyboard layout "
1240 + "resource from receiver "
1241 + receiver.packageName + "/" + receiver.name);
1242 } else {
1243 String descriptor = KeyboardLayoutDescriptor.format(
1244 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001245 if (keyboardName == null || name.equals(keyboardName)) {
Michael Wright07483422015-10-30 16:20:13 +00001246 KeyboardLayout layout = new KeyboardLayout(
1247 descriptor, label, collection, priority,
1248 locales, vid, pid);
1249 visitor.visitKeyboardLayout(
1250 resources, keyboardLayoutResId, layout);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001251 }
1252 }
1253 } finally {
1254 a.recycle();
1255 }
1256 } else {
Michael Wright07483422015-10-30 16:20:13 +00001257 Slog.w(TAG, "Skipping unrecognized element '" + element
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001258 + "' in keyboard layout resource from receiver "
1259 + receiver.packageName + "/" + receiver.name);
1260 }
1261 }
1262 } finally {
1263 parser.close();
1264 }
1265 } catch (Exception ex) {
Michael Wright07483422015-10-30 16:20:13 +00001266 Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001267 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001268 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001269 }
1270
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001271 @NonNull
1272 private static LocaleList getLocalesFromLanguageTags(String languageTags) {
Michael Wright07483422015-10-30 16:20:13 +00001273 if (TextUtils.isEmpty(languageTags)) {
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001274 return LocaleList.getEmptyLocaleList();
Michael Wright07483422015-10-30 16:20:13 +00001275 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001276 return LocaleList.forLanguageTags(languageTags.replace('|', ','));
Michael Wright07483422015-10-30 16:20:13 +00001277 }
1278
RoboErikfb290df2013-12-16 11:27:55 -08001279 /**
1280 * Builds a layout descriptor for the vendor/product. This returns the
1281 * descriptor for ids that aren't useful (such as the default 0, 0).
1282 */
1283 private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1284 if (identifier == null || identifier.getDescriptor() == null) {
1285 throw new IllegalArgumentException("identifier and descriptor must not be null");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001286 }
1287
RoboErikfb290df2013-12-16 11:27:55 -08001288 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1289 return identifier.getDescriptor();
1290 }
1291 StringBuilder bob = new StringBuilder();
1292 bob.append("vendor:").append(identifier.getVendorId());
1293 bob.append(",product:").append(identifier.getProductId());
1294 return bob.toString();
1295 }
1296
1297 @Override // Binder call
1298 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1299
1300 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001301 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001302 String layout = null;
1303 // try loading it using the layout descriptor if we have it
1304 layout = mDataStore.getCurrentKeyboardLayout(key);
1305 if (layout == null && !key.equals(identifier.getDescriptor())) {
1306 // if it doesn't exist fall back to the device descriptor
1307 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1308 }
1309 if (DEBUG) {
1310 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1311 + layout);
1312 }
1313 return layout;
Jeff Browna3bc5652012-04-17 11:42:25 -07001314 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001315 }
1316
1317 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001318 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001319 String keyboardLayoutDescriptor) {
1320 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001321 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001322 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1323 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001324 if (keyboardLayoutDescriptor == null) {
1325 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1326 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001327
RoboErikfb290df2013-12-16 11:27:55 -08001328 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001329 synchronized (mDataStore) {
1330 try {
RoboErikfb290df2013-12-16 11:27:55 -08001331 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1332 if (DEBUG) {
1333 Slog.d(TAG, "Saved keyboard layout using " + key);
1334 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001335 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1336 }
Jeff Browna3bc5652012-04-17 11:42:25 -07001337 } finally {
1338 mDataStore.saveIfNeeded();
1339 }
1340 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001341 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001342
Jeff Browncf39bdf2012-05-18 14:41:19 -07001343 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001344 public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
RoboErikfb290df2013-12-16 11:27:55 -08001345 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001346 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001347 String[] layouts = mDataStore.getKeyboardLayouts(key);
1348 if ((layouts == null || layouts.length == 0)
1349 && !key.equals(identifier.getDescriptor())) {
1350 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1351 }
1352 return layouts;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001353 }
1354 }
1355
1356 @Override // Binder call
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001357 @Nullable
1358 public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1359 InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) {
1360 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
1361 String key = getLayoutDescriptor(identifier);
1362 final String keyboardLayoutDescriptor;
1363 synchronized (mDataStore) {
1364 keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle);
1365 }
1366
1367 if (keyboardLayoutDescriptor == null) {
1368 return null;
1369 }
1370
1371 final KeyboardLayout[] result = new KeyboardLayout[1];
1372 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1373 @Override
1374 public void visitKeyboardLayout(Resources resources,
1375 int keyboardLayoutResId, KeyboardLayout layout) {
1376 result[0] = layout;
1377 }
1378 });
1379 if (result[0] == null) {
1380 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
1381 + keyboardLayoutDescriptor + "'.");
1382 }
1383 return result[0];
1384 }
1385
1386 @Override
1387 public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1388 InputMethodInfo imeInfo, InputMethodSubtype imeSubtype,
1389 String keyboardLayoutDescriptor) {
1390 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1391 "setKeyboardLayoutForInputDevice()")) {
1392 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1393 }
1394 if (keyboardLayoutDescriptor == null) {
1395 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1396 }
Yohei Yukawa46ac35d2016-04-20 16:59:45 -07001397 if (imeInfo == null) {
1398 throw new IllegalArgumentException("imeInfo must not be null");
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001399 }
1400 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
1401 setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
1402 }
1403
1404 private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier,
1405 InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
1406 String key = getLayoutDescriptor(identifier);
1407 synchronized (mDataStore) {
1408 try {
1409 if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) {
1410 if (DEBUG) {
1411 Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor +
1412 " for subtype " + imeHandle + " and device " + identifier +
1413 " using key " + key);
1414 }
1415 if (imeHandle.equals(mCurrentImeHandle)) {
1416 if (DEBUG) {
1417 Slog.d(TAG, "Layout for current subtype changed, switching layout");
1418 }
1419 SomeArgs args = SomeArgs.obtain();
1420 args.arg1 = identifier;
1421 args.arg2 = imeHandle;
1422 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget();
1423 }
1424 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1425 }
1426 } finally {
1427 mDataStore.saveIfNeeded();
1428 }
1429 }
1430 }
1431
1432 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001433 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001434 String keyboardLayoutDescriptor) {
1435 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1436 "addKeyboardLayoutForInputDevice()")) {
1437 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1438 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001439 if (keyboardLayoutDescriptor == null) {
1440 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1441 }
1442
RoboErikfb290df2013-12-16 11:27:55 -08001443 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001444 synchronized (mDataStore) {
1445 try {
RoboErikfb290df2013-12-16 11:27:55 -08001446 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1447 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1448 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1449 }
1450 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001451 && !Objects.equal(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001452 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1453 }
1454 } finally {
1455 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001456 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001457 }
1458 }
1459
1460 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001461 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001462 String keyboardLayoutDescriptor) {
1463 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1464 "removeKeyboardLayoutForInputDevice()")) {
1465 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1466 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001467 if (keyboardLayoutDescriptor == null) {
1468 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1469 }
1470
RoboErikfb290df2013-12-16 11:27:55 -08001471 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001472 synchronized (mDataStore) {
1473 try {
RoboErikfb290df2013-12-16 11:27:55 -08001474 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1475 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1476 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1477 }
1478 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1479 if (!key.equals(identifier.getDescriptor())) {
1480 // We need to remove from both places to ensure it is gone
1481 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1482 keyboardLayoutDescriptor);
1483 }
1484 if (removed && !Objects.equal(oldLayout,
1485 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001486 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1487 }
1488 } finally {
1489 mDataStore.saveIfNeeded();
1490 }
1491 }
1492 }
1493
Yohei Yukawab097b822015-12-01 10:43:08 -08001494 // Must be called on handler.
1495 private void handleSwitchInputMethodSubtype(int userId,
1496 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
1497 if (DEBUG) {
1498 Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
1499 + " ime=" + inputMethodInfo + " subtype=" + subtype);
1500 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001501 if (inputMethodInfo == null) {
1502 Slog.d(TAG, "No InputMethod is running, ignoring change");
1503 return;
1504 }
1505 if (subtype != null && !"keyboard".equals(subtype.getMode())) {
1506 Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change");
1507 return;
1508 }
1509 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype);
1510 if (!handle.equals(mCurrentImeHandle)) {
1511 mCurrentImeHandle = handle;
1512 handleSwitchKeyboardLayout(null, handle);
1513 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001514 }
1515
1516 // Must be called on handler.
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001517 private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier,
1518 InputMethodSubtypeHandle handle) {
1519 synchronized (mInputDevicesLock) {
1520 for (InputDevice device : mInputDevices) {
1521 if (identifier != null && !device.getIdentifier().equals(identifier) ||
1522 !device.isFullKeyboard()) {
1523 continue;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001524 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001525 String key = getLayoutDescriptor(device.getIdentifier());
1526 boolean changed = false;
1527 synchronized (mDataStore) {
1528 try {
1529 if (mDataStore.switchKeyboardLayout(key, handle)) {
1530 changed = true;
1531 }
1532 } finally {
1533 mDataStore.saveIfNeeded();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001534 }
1535 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001536 if (changed) {
1537 reloadKeyboardLayouts();
1538 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001539 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001540 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001541 }
1542
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001543 public void setInputWindows(InputWindowHandle[] windowHandles,
1544 InputWindowHandle focusedWindowHandle) {
1545 final IWindow newFocusedWindow =
1546 focusedWindowHandle != null ? focusedWindowHandle.clientWindow : null;
1547 if (mFocusedWindow != newFocusedWindow) {
1548 mFocusedWindow = newFocusedWindow;
1549 if (mFocusedWindowHasCapture) {
1550 setPointerCapture(false);
1551 }
1552 }
Jeff Brown4532e612012-04-05 14:27:12 -07001553 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -07001554 }
RoboErikfb290df2013-12-16 11:27:55 -08001555
Jeff Brown9302c872011-07-13 22:51:29 -07001556 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -07001557 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -07001558 }
RoboErikfb290df2013-12-16 11:27:55 -08001559
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001560 @Override
1561 public void requestPointerCapture(IBinder windowToken, boolean enabled) {
1562 if (mFocusedWindow == null || mFocusedWindow.asBinder() != windowToken) {
1563 Slog.e(TAG, "requestPointerCapture called for a window that has no focus: "
1564 + windowToken);
1565 return;
1566 }
1567 if (mFocusedWindowHasCapture == enabled) {
1568 Slog.i(TAG, "requestPointerCapture: already " + (enabled ? "enabled" : "disabled"));
1569 return;
1570 }
1571 setPointerCapture(enabled);
1572 try {
1573 mFocusedWindow.dispatchPointerCaptureChanged(enabled);
1574 } catch (RemoteException ex) {
1575 /* ignore */
1576 }
1577 }
1578
1579 private void setPointerCapture(boolean enabled) {
1580 mFocusedWindowHasCapture = enabled;
1581 nativeSetPointerCapture(mPtr, enabled);
1582 }
1583
Jeff Brown349703e2010-06-22 01:27:15 -07001584 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001585 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001586 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001587
1588 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001589 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001590 }
1591
Jeff Browne6504122010-09-27 14:52:15 -07001592 /**
1593 * Atomically transfers touch focus from one window to another as identified by
1594 * their input channels. It is possible for multiple windows to have
1595 * touch focus if they support split touch dispatch
1596 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1597 * method only transfers touch focus of the specified window without affecting
1598 * other windows that may also have touch focus at the same time.
1599 * @param fromChannel The channel of a window that currently has touch focus.
1600 * @param toChannel The channel of the window that should receive touch focus in
1601 * place of the first.
1602 * @return True if the transfer was successful. False if the window with the
1603 * specified channel did not actually have touch focus at the time of the request.
1604 */
1605 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1606 if (fromChannel == null) {
1607 throw new IllegalArgumentException("fromChannel must not be null.");
1608 }
1609 if (toChannel == null) {
1610 throw new IllegalArgumentException("toChannel must not be null.");
1611 }
Jeff Brown4532e612012-04-05 14:27:12 -07001612 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -07001613 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001614
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001615 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001616 public void tryPointerSpeed(int speed) {
1617 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1618 "tryPointerSpeed()")) {
1619 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1620 }
1621
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001622 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1623 throw new IllegalArgumentException("speed out of range");
1624 }
1625
Jeff Brownac143512012-04-05 18:57:33 -07001626 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001627 }
1628
1629 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001630 int speed = getPointerSpeedSetting();
1631 setPointerSpeedUnchecked(speed);
1632 }
1633
1634 private void setPointerSpeedUnchecked(int speed) {
1635 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1636 InputManager.MAX_POINTER_SPEED);
1637 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001638 }
1639
1640 private void registerPointerSpeedSettingObserver() {
1641 mContext.getContentResolver().registerContentObserver(
1642 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001643 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001644 @Override
1645 public void onChange(boolean selfChange) {
1646 updatePointerSpeedFromSettings();
1647 }
Jeff Brownd4935962012-09-25 13:27:20 -07001648 }, UserHandle.USER_ALL);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001649 }
1650
Jeff Brownac143512012-04-05 18:57:33 -07001651 private int getPointerSpeedSetting() {
1652 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001653 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001654 speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1655 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001656 } catch (SettingNotFoundException snfe) {
1657 }
1658 return speed;
1659 }
1660
Jeff Browndaf4a122011-08-26 17:14:14 -07001661 public void updateShowTouchesFromSettings() {
1662 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001663 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001664 }
1665
1666 private void registerShowTouchesSettingObserver() {
1667 mContext.getContentResolver().registerContentObserver(
1668 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001669 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001670 @Override
1671 public void onChange(boolean selfChange) {
1672 updateShowTouchesFromSettings();
1673 }
Jeff Brownd4935962012-09-25 13:27:20 -07001674 }, UserHandle.USER_ALL);
Jeff Browndaf4a122011-08-26 17:14:14 -07001675 }
1676
Jun Mukaie4e75da2015-12-15 16:19:20 -08001677 public void updateAccessibilityLargePointerFromSettings() {
1678 final int accessibilityConfig = Settings.Secure.getIntForUser(
1679 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1680 0, UserHandle.USER_CURRENT);
Jun Mukai1f3dbff2015-12-16 14:41:25 -08001681 PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
Jun Mukaie4e75da2015-12-15 16:19:20 -08001682 nativeReloadPointerIcons(mPtr);
1683 }
1684
Jun Mukai19a56012015-11-24 11:25:52 -08001685 private void registerAccessibilityLargePointerSettingObserver() {
1686 mContext.getContentResolver().registerContentObserver(
1687 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1688 new ContentObserver(mHandler) {
1689 @Override
1690 public void onChange(boolean selfChange) {
Jun Mukaie4e75da2015-12-15 16:19:20 -08001691 updateAccessibilityLargePointerFromSettings();
Jun Mukai19a56012015-11-24 11:25:52 -08001692 }
1693 }, UserHandle.USER_ALL);
1694 }
1695
Jeff Browndaf4a122011-08-26 17:14:14 -07001696 private int getShowTouchesSetting(int defaultValue) {
1697 int result = defaultValue;
1698 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001699 result = Settings.System.getIntForUser(mContext.getContentResolver(),
1700 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
Jeff Browndaf4a122011-08-26 17:14:14 -07001701 } catch (SettingNotFoundException snfe) {
1702 }
1703 return result;
1704 }
1705
Jeff Browna47425a2012-04-13 04:09:27 -07001706 // Binder call
1707 @Override
1708 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1709 if (repeat >= pattern.length) {
1710 throw new ArrayIndexOutOfBoundsException();
1711 }
1712
1713 VibratorToken v;
1714 synchronized (mVibratorLock) {
1715 v = mVibratorTokens.get(token);
1716 if (v == null) {
1717 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1718 try {
1719 token.linkToDeath(v, 0);
1720 } catch (RemoteException ex) {
1721 // give up
1722 throw new RuntimeException(ex);
1723 }
1724 mVibratorTokens.put(token, v);
1725 }
1726 }
1727
1728 synchronized (v) {
1729 v.mVibrating = true;
1730 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1731 }
1732 }
1733
1734 // Binder call
1735 @Override
1736 public void cancelVibrate(int deviceId, IBinder token) {
1737 VibratorToken v;
1738 synchronized (mVibratorLock) {
1739 v = mVibratorTokens.get(token);
1740 if (v == null || v.mDeviceId != deviceId) {
1741 return; // nothing to cancel
1742 }
1743 }
1744
1745 cancelVibrateIfNeeded(v);
1746 }
1747
1748 void onVibratorTokenDied(VibratorToken v) {
1749 synchronized (mVibratorLock) {
1750 mVibratorTokens.remove(v.mToken);
1751 }
1752
1753 cancelVibrateIfNeeded(v);
1754 }
1755
1756 private void cancelVibrateIfNeeded(VibratorToken v) {
1757 synchronized (v) {
1758 if (v.mVibrating) {
1759 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1760 v.mVibrating = false;
1761 }
1762 }
1763 }
1764
Jun Mukai19a56012015-11-24 11:25:52 -08001765 // Binder call
1766 @Override
Michael Wrightf9d9ce772016-05-13 17:44:16 +01001767 public void setPointerIconType(int iconId) {
1768 nativeSetPointerIconType(mPtr, iconId);
Jun Mukai19a56012015-11-24 11:25:52 -08001769 }
Jun Mukai1db53972015-09-11 18:08:31 -07001770
Jun Mukaid4eaef72015-10-30 15:54:33 -07001771 // Binder call
1772 @Override
1773 public void setCustomPointerIcon(PointerIcon icon) {
Michael Wrightb004b512017-01-18 18:09:29 +00001774 Preconditions.checkNotNull(icon);
Jun Mukaid4eaef72015-10-30 15:54:33 -07001775 nativeSetCustomPointerIcon(mPtr, icon);
1776 }
1777
Jeff Brown4532e612012-04-05 14:27:12 -07001778 @Override
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001779 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001780 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Jeff Brown4532e612012-04-05 14:27:12 -07001781
1782 pw.println("INPUT MANAGER (dumpsys input)\n");
1783 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001784 if (dumpStr != null) {
1785 pw.println(dumpStr);
1786 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001787 pw.println(" Keyboard Layouts:");
1788 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1789 @Override
1790 public void visitKeyboardLayout(Resources resources,
1791 int keyboardLayoutResId, KeyboardLayout layout) {
1792 pw.println(" \"" + layout + "\": " + layout.getDescriptor());
1793 }
1794 });
1795 pw.println();
1796 synchronized(mDataStore) {
1797 mDataStore.dump(pw, " ");
1798 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001799 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001800
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001801 @Override
1802 public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07001803 FileDescriptor err, String[] args, ShellCallback callback,
1804 ResultReceiver resultReceiver) {
1805 (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001806 }
1807
1808 public int onShellCommand(Shell shell, String cmd) {
1809 if (TextUtils.isEmpty(cmd)) {
1810 shell.onHelp();
1811 return 1;
1812 }
1813 if (cmd.equals("setlayout")) {
1814 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1815 "onShellCommand()")) {
1816 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1817 }
1818 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
1819 shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired()));
1820 String descriptor = shell.getNextArgRequired();
1821 int vid = Integer.decode(shell.getNextArgRequired());
1822 int pid = Integer.decode(shell.getNextArgRequired());
1823 InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid);
1824 setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired());
1825 }
1826 return 0;
1827 }
1828
1829
Jeff Brownac143512012-04-05 18:57:33 -07001830 private boolean checkCallingPermission(String permission, String func) {
1831 // Quick check: if the calling permission is me, it's all okay.
1832 if (Binder.getCallingPid() == Process.myPid()) {
1833 return true;
1834 }
1835
1836 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1837 return true;
1838 }
1839 String msg = "Permission Denial: " + func + " from pid="
1840 + Binder.getCallingPid()
1841 + ", uid=" + Binder.getCallingUid()
1842 + " requires " + permission;
1843 Slog.w(TAG, msg);
1844 return false;
1845 }
1846
Jeff Brown4532e612012-04-05 14:27:12 -07001847 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001848 @Override
Jeff Brown89ef0722011-08-10 16:25:21 -07001849 public void monitor() {
1850 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -07001851 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001852 }
1853
Jeff Brown4532e612012-04-05 14:27:12 -07001854 // Native callback.
1855 private void notifyConfigurationChanged(long whenNanos) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001856 mWindowManagerCallbacks.notifyConfigurationChanged();
Jeff Brown4532e612012-04-05 14:27:12 -07001857 }
1858
1859 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001860 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1861 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001862 if (!mInputDevicesChangedPending) {
1863 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001864 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1865 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001866 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001867
1868 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001869 }
1870 }
1871
1872 // Native callback.
Jeff Brownbcc046a2012-09-27 20:46:43 -07001873 private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1874 if (DEBUG) {
1875 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1876 + ", mask=" + Integer.toHexString(switchMask));
1877 }
1878
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001879 if ((switchMask & SW_LID_BIT) != 0) {
1880 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
Jeff Brownbcc046a2012-09-27 20:46:43 -07001881 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
Jeff Brown53384282012-08-20 20:16:01 -07001882 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001883
Michael Wright3818c922014-09-02 13:59:07 -07001884 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
Michael Wright9e10d252014-09-13 19:41:20 -07001885 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
Michael Wright3818c922014-09-02 13:59:07 -07001886 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1887 }
1888
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001889 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1890 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1891 switchMask);
1892 }
Michael Wright39e5e942015-08-19 22:52:47 +01001893
Michael Wright9209c9c2015-09-03 17:57:01 +01001894 if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
Michael Wright39e5e942015-08-19 22:52:47 +01001895 SomeArgs args = SomeArgs.obtain();
1896 args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
1897 args.argi2 = (int) (whenNanos >> 32);
1898 args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
1899 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
1900 args).sendToTarget();
1901 }
Jeff Brown4532e612012-04-05 14:27:12 -07001902 }
1903
1904 // Native callback.
1905 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001906 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
Jeff Brown4532e612012-04-05 14:27:12 -07001907 }
1908
1909 // Native callback.
1910 private long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001911 InputWindowHandle inputWindowHandle, String reason) {
1912 return mWindowManagerCallbacks.notifyANR(
1913 inputApplicationHandle, inputWindowHandle, reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001914 }
1915
1916 // Native callback.
1917 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1918 synchronized (mInputFilterLock) {
1919 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001920 try {
1921 mInputFilter.filterInputEvent(event, policyFlags);
1922 } catch (RemoteException e) {
1923 /* ignore */
1924 }
Jeff Brown4532e612012-04-05 14:27:12 -07001925 return false;
1926 }
1927 }
1928 event.recycle();
1929 return true;
1930 }
1931
1932 // Native callback.
Jeff Brown037c33e2014-04-09 00:31:55 -07001933 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1934 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001935 }
1936
1937 // Native callback.
Michael Wright70af00a2014-09-03 19:30:20 -07001938 private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
1939 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
Jeff Brown26875502014-01-30 21:47:47 -08001940 whenNanos, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001941 }
1942
1943 // Native callback.
1944 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1945 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001946 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001947 }
1948
1949 // Native callback.
1950 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1951 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001952 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001953 }
1954
1955 // Native callback.
1956 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1957 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1958 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1959 }
1960
1961 // Native callback.
1962 private int getVirtualKeyQuietTimeMillis() {
1963 return mContext.getResources().getInteger(
1964 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1965 }
1966
1967 // Native callback.
1968 private String[] getExcludedDeviceNames() {
1969 ArrayList<String> names = new ArrayList<String>();
1970
1971 // Read partner-provided list of excluded input devices
1972 XmlPullParser parser = null;
1973 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1974 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1975 FileReader confreader = null;
1976 try {
1977 confreader = new FileReader(confFile);
1978 parser = Xml.newPullParser();
1979 parser.setInput(confreader);
1980 XmlUtils.beginDocument(parser, "devices");
1981
1982 while (true) {
1983 XmlUtils.nextElement(parser);
1984 if (!"device".equals(parser.getName())) {
1985 break;
1986 }
1987 String name = parser.getAttributeValue(null, "name");
1988 if (name != null) {
1989 names.add(name);
1990 }
1991 }
1992 } catch (FileNotFoundException e) {
1993 // It's ok if the file does not exist.
1994 } catch (Exception e) {
1995 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1996 } finally {
1997 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1998 }
1999
2000 return names.toArray(new String[names.size()]);
2001 }
2002
2003 // Native callback.
2004 private int getKeyRepeatTimeout() {
2005 return ViewConfiguration.getKeyRepeatTimeout();
2006 }
2007
2008 // Native callback.
2009 private int getKeyRepeatDelay() {
2010 return ViewConfiguration.getKeyRepeatDelay();
2011 }
2012
2013 // Native callback.
2014 private int getHoverTapTimeout() {
2015 return ViewConfiguration.getHoverTapTimeout();
2016 }
2017
2018 // Native callback.
2019 private int getHoverTapSlop() {
2020 return ViewConfiguration.getHoverTapSlop();
2021 }
2022
2023 // Native callback.
2024 private int getDoubleTapTimeout() {
2025 return ViewConfiguration.getDoubleTapTimeout();
2026 }
2027
2028 // Native callback.
2029 private int getLongPressTimeout() {
2030 return ViewConfiguration.getLongPressTimeout();
2031 }
2032
2033 // Native callback.
2034 private int getPointerLayer() {
Jeff Browna9d131c2012-09-20 16:48:17 -07002035 return mWindowManagerCallbacks.getPointerLayer();
Jeff Brown4532e612012-04-05 14:27:12 -07002036 }
2037
2038 // Native callback.
2039 private PointerIcon getPointerIcon() {
2040 return PointerIcon.getDefaultIcon(mContext);
2041 }
2042
Jeff Brown6ec6f792012-04-17 16:52:41 -07002043 // Native callback.
RoboErikfb290df2013-12-16 11:27:55 -08002044 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07002045 if (!mSystemReady) {
2046 return null;
2047 }
2048
RoboErikfb290df2013-12-16 11:27:55 -08002049 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002050 if (keyboardLayoutDescriptor == null) {
2051 return null;
2052 }
2053
2054 final String[] result = new String[2];
2055 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
2056 @Override
Michael Wright07483422015-10-30 16:20:13 +00002057 public void visitKeyboardLayout(Resources resources,
2058 int keyboardLayoutResId, KeyboardLayout layout) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07002059 try {
Michael Wright07483422015-10-30 16:20:13 +00002060 result[0] = layout.getDescriptor();
Jeff Brown6ec6f792012-04-17 16:52:41 -07002061 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07002062 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07002063 } catch (IOException ex) {
2064 } catch (NotFoundException ex) {
2065 }
2066 }
2067 });
2068 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00002069 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07002070 + keyboardLayoutDescriptor + "'.");
2071 return null;
2072 }
2073 return result;
2074 }
2075
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002076 // Native callback.
2077 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07002078 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
2079 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
2080 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002081 }
2082 return null;
2083 }
2084
Jeff Brown4532e612012-04-05 14:27:12 -07002085 /**
2086 * Callback interface implemented by the Window Manager.
2087 */
Jeff Browna9d131c2012-09-20 16:48:17 -07002088 public interface WindowManagerCallbacks {
Jeff Brown4532e612012-04-05 14:27:12 -07002089 public void notifyConfigurationChanged();
2090
2091 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
2092
Michael Wright3818c922014-09-02 13:59:07 -07002093 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
2094
Jeff Brown4532e612012-04-05 14:27:12 -07002095 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
2096
2097 public long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07002098 InputWindowHandle inputWindowHandle, String reason);
Jeff Brown4532e612012-04-05 14:27:12 -07002099
Jeff Brown037c33e2014-04-09 00:31:55 -07002100 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002101
Michael Wright70af00a2014-09-03 19:30:20 -07002102 public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002103
2104 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
2105 KeyEvent event, int policyFlags);
2106
2107 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
2108 KeyEvent event, int policyFlags);
2109
2110 public int getPointerLayer();
2111 }
2112
2113 /**
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002114 * Callback interface implemented by WiredAccessoryObserver.
2115 */
2116 public interface WiredAccessoryCallbacks {
2117 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002118 public void systemReady();
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002119 }
2120
2121 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002122 * Private handler for the input manager.
2123 */
2124 private final class InputManagerHandler extends Handler {
Jeff Browna9d131c2012-09-20 16:48:17 -07002125 public InputManagerHandler(Looper looper) {
2126 super(looper, null, true /*async*/);
Jeff Browna2910d02012-08-25 12:29:46 -07002127 }
2128
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002129 @Override
2130 public void handleMessage(Message msg) {
2131 switch (msg.what) {
2132 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07002133 deliverInputDevicesChanged((InputDevice[])msg.obj);
2134 break;
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002135 case MSG_SWITCH_KEYBOARD_LAYOUT: {
2136 SomeArgs args = (SomeArgs)msg.obj;
2137 handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1,
2138 (InputMethodSubtypeHandle)args.arg2);
Jeff Browncf39bdf2012-05-18 14:41:19 -07002139 break;
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002140 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07002141 case MSG_RELOAD_KEYBOARD_LAYOUTS:
2142 reloadKeyboardLayouts();
2143 break;
2144 case MSG_UPDATE_KEYBOARD_LAYOUTS:
2145 updateKeyboardLayouts();
2146 break;
2147 case MSG_RELOAD_DEVICE_ALIASES:
2148 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002149 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08002150 case MSG_DELIVER_TABLET_MODE_CHANGED: {
Michael Wright39e5e942015-08-19 22:52:47 +01002151 SomeArgs args = (SomeArgs) msg.obj;
2152 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
2153 boolean inTabletMode = (boolean) args.arg1;
2154 deliverTabletModeChanged(whenNanos, inTabletMode);
2155 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08002156 }
2157 case MSG_INPUT_METHOD_SUBTYPE_CHANGED: {
2158 final int userId = msg.arg1;
2159 final SomeArgs args = (SomeArgs) msg.obj;
2160 final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1;
2161 final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2;
2162 args.recycle();
2163 handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype);
2164 break;
2165 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002166 }
2167 }
2168 }
2169
2170 /**
Jeff Brown4532e612012-04-05 14:27:12 -07002171 * Hosting interface for input filters to call back into the input manager.
2172 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07002173 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07002174 private boolean mDisconnected;
2175
2176 public void disconnectLocked() {
2177 mDisconnected = true;
2178 }
2179
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002180 @Override
Jeff Brown0029c662011-03-30 02:25:18 -07002181 public void sendInputEvent(InputEvent event, int policyFlags) {
2182 if (event == null) {
2183 throw new IllegalArgumentException("event must not be null");
2184 }
2185
2186 synchronized (mInputFilterLock) {
2187 if (!mDisconnected) {
Jeff Brownca9bc702014-02-11 14:32:56 -08002188 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
Jeff Brownac143512012-04-05 18:57:33 -07002189 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07002190 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
2191 }
2192 }
2193 }
2194 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07002195
2196 private static final class KeyboardLayoutDescriptor {
2197 public String packageName;
2198 public String receiverName;
2199 public String keyboardLayoutName;
2200
2201 public static String format(String packageName,
2202 String receiverName, String keyboardName) {
2203 return packageName + "/" + receiverName + "/" + keyboardName;
2204 }
2205
2206 public static KeyboardLayoutDescriptor parse(String descriptor) {
2207 int pos = descriptor.indexOf('/');
2208 if (pos < 0 || pos + 1 == descriptor.length()) {
2209 return null;
2210 }
2211 int pos2 = descriptor.indexOf('/', pos + 1);
2212 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
2213 return null;
2214 }
2215
2216 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
2217 result.packageName = descriptor.substring(0, pos);
2218 result.receiverName = descriptor.substring(pos + 1, pos2);
2219 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
2220 return result;
2221 }
2222 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002223
Jeff Brown6ec6f792012-04-17 16:52:41 -07002224 private interface KeyboardLayoutVisitor {
Michael Wright07483422015-10-30 16:20:13 +00002225 void visitKeyboardLayout(Resources resources,
2226 int keyboardLayoutResId, KeyboardLayout layout);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002227 }
2228
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002229 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
2230 private final int mPid;
2231 private final IInputDevicesChangedListener mListener;
2232
2233 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
2234 mPid = pid;
2235 mListener = listener;
2236 }
2237
2238 @Override
2239 public void binderDied() {
2240 if (DEBUG) {
2241 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
2242 }
2243 onInputDevicesChangedListenerDied(mPid);
2244 }
2245
2246 public void notifyInputDevicesChanged(int[] info) {
2247 try {
2248 mListener.onInputDevicesChanged(info);
2249 } catch (RemoteException ex) {
2250 Slog.w(TAG, "Failed to notify process "
2251 + mPid + " that input devices changed, assuming it died.", ex);
2252 binderDied();
2253 }
2254 }
2255 }
Jeff Browna47425a2012-04-13 04:09:27 -07002256
Michael Wright39e5e942015-08-19 22:52:47 +01002257 private final class TabletModeChangedListenerRecord implements DeathRecipient {
2258 private final int mPid;
2259 private final ITabletModeChangedListener mListener;
2260
2261 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
2262 mPid = pid;
2263 mListener = listener;
2264 }
2265
2266 @Override
2267 public void binderDied() {
2268 if (DEBUG) {
2269 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
2270 }
2271 onTabletModeChangedListenerDied(mPid);
2272 }
2273
2274 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
2275 try {
2276 mListener.onTabletModeChanged(whenNanos, inTabletMode);
2277 } catch (RemoteException ex) {
2278 Slog.w(TAG, "Failed to notify process " + mPid +
2279 " that tablet mode changed, assuming it died.", ex);
2280 binderDied();
2281 }
2282 }
2283 }
2284
Jeff Browna47425a2012-04-13 04:09:27 -07002285 private final class VibratorToken implements DeathRecipient {
2286 public final int mDeviceId;
2287 public final IBinder mToken;
2288 public final int mTokenValue;
2289
2290 public boolean mVibrating;
2291
2292 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
2293 mDeviceId = deviceId;
2294 mToken = token;
2295 mTokenValue = tokenValue;
2296 }
2297
2298 @Override
2299 public void binderDied() {
2300 if (DEBUG) {
2301 Slog.d(TAG, "Vibrator token died.");
2302 }
2303 onVibratorTokenDied(this);
2304 }
2305 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002306
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002307 private class Shell extends ShellCommand {
2308 @Override
2309 public int onCommand(String cmd) {
2310 return onShellCommand(this, cmd);
2311 }
2312
2313 @Override
2314 public void onHelp() {
2315 final PrintWriter pw = getOutPrintWriter();
2316 pw.println("Input manager commands:");
2317 pw.println(" help");
2318 pw.println(" Print this help text.");
2319 pw.println("");
2320 pw.println(" setlayout IME_ID IME_SUPTYPE_HASH_CODE"
2321 + " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR");
2322 pw.println(" Sets a keyboard layout for a given IME subtype and input device pair");
2323 }
2324 }
2325
Jeff Brown4ccb8232014-01-16 22:16:42 -08002326 private final class LocalService extends InputManagerInternal {
2327 @Override
2328 public void setDisplayViewports(
2329 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
2330 setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
2331 }
Jeff Brownca9bc702014-02-11 14:32:56 -08002332
2333 @Override
2334 public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
2335 return injectInputEventInternal(event, displayId, mode);
2336 }
Jeff Brown037c33e2014-04-09 00:31:55 -07002337
2338 @Override
2339 public void setInteractive(boolean interactive) {
2340 nativeSetInteractive(mPtr, interactive);
2341 }
Yohei Yukawab097b822015-12-01 10:43:08 -08002342
2343 @Override
2344 public void onInputMethodSubtypeChanged(int userId,
2345 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
2346 final SomeArgs someArgs = SomeArgs.obtain();
2347 someArgs.arg1 = inputMethodInfo;
2348 someArgs.arg2 = subtype;
2349 mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs)
2350 .sendToTarget();
2351 }
Andrii Kulian112d0562016-03-08 10:44:22 -08002352
2353 @Override
2354 public void toggleCapsLock(int deviceId) {
2355 nativeToggleCapsLock(mPtr, deviceId);
2356 }
Adrian Roos99182342016-06-15 15:30:46 -07002357
2358 @Override
2359 public void setPulseGestureEnabled(boolean enabled) {
2360 if (mDoubleTouchGestureEnableFile != null) {
2361 FileWriter writer = null;
2362 try {
2363 writer = new FileWriter(mDoubleTouchGestureEnableFile);
2364 writer.write(enabled ? "1" : "0");
2365 } catch (IOException e) {
2366 Log.wtf(TAG, "Unable to setPulseGestureEnabled", e);
2367 } finally {
2368 IoUtils.closeQuietly(writer);
2369 }
2370 }
2371 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002372 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07002373}