blob: aafc9a8f50d7ac5e887832b6469431a31dd0b598 [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);
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100233 private static native void nativeSetPointerIconType(long ptr, int iconId);
Jun Mukai19a56012015-11-24 11:25:52 -0800234 private static native void nativeReloadPointerIcons(long ptr);
Jun Mukaid4eaef72015-10-30 15:54:33 -0700235 private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -0800236 private static native void nativeSetPointerCapture(long ptr, boolean detached);
Jeff Brown4532e612012-04-05 14:27:12 -0700237
Jeff Brownac143512012-04-05 18:57:33 -0700238 // Input event injection constants defined in InputDispatcher.h.
239 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
240 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
241 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
242 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
243
244 // Maximum number of milliseconds to wait for input event injection.
245 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
246
Jeff Brown6d0fec22010-07-23 21:28:06 -0700247 // Key states (may be returned by queries about the current state of a
248 // particular key code, scan code or switch).
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700249
Jeff Brown6d0fec22010-07-23 21:28:06 -0700250 /** The key state is unknown or the requested key itself is not supported. */
251 public static final int KEY_STATE_UNKNOWN = -1;
252
253 /** The key is up. /*/
254 public static final int KEY_STATE_UP = 0;
255
256 /** The key is down. */
257 public static final int KEY_STATE_DOWN = 1;
258
259 /** The key is down but is a virtual key press that is being emulated by the system. */
260 public static final int KEY_STATE_VIRTUAL = 2;
261
Jeff Brownc458ce92012-04-30 14:58:40 -0700262 /** Scan code: Mouse / trackball button. */
263 public static final int BTN_MOUSE = 0x110;
264
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700265 // Switch code values must match bionic/libc/kernel/common/linux/input.h
Jeff Brownc458ce92012-04-30 14:58:40 -0700266 /** Switch code: Lid switch. When set, lid is shut. */
267 public static final int SW_LID = 0x00;
268
Michael Wright39e5e942015-08-19 22:52:47 +0100269 /** Switch code: Tablet mode switch.
270 * When set, the device is in tablet mode (i.e. no keyboard is connected).
271 */
272 public static final int SW_TABLET_MODE = 0x01;
273
Jeff Brownc458ce92012-04-30 14:58:40 -0700274 /** Switch code: Keypad slide. When set, keyboard is exposed. */
275 public static final int SW_KEYPAD_SLIDE = 0x0a;
276
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700277 /** Switch code: Headphone. When set, headphone is inserted. */
278 public static final int SW_HEADPHONE_INSERT = 0x02;
279
280 /** Switch code: Microphone. When set, microphone is inserted. */
281 public static final int SW_MICROPHONE_INSERT = 0x04;
282
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500283 /** Switch code: Line out. When set, Line out (hi-Z) is inserted. */
284 public static final int SW_LINEOUT_INSERT = 0x06;
285
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700286 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */
287 public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
288
Michael Wright3818c922014-09-02 13:59:07 -0700289 /** Switch code: Camera lens cover. When set the lens is covered. */
290 public static final int SW_CAMERA_LENS_COVER = 0x09;
291
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700292 public static final int SW_LID_BIT = 1 << SW_LID;
Michael Wright39e5e942015-08-19 22:52:47 +0100293 public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700294 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
295 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
296 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500297 public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700298 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
299 public static final int SW_JACK_BITS =
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500300 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
Michael Wright3818c922014-09-02 13:59:07 -0700301 public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700302
303 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
304 final boolean mUseDevInputEventForAudioJack;
305
Jeff Brown4ccb8232014-01-16 22:16:42 -0800306 public InputManagerService(Context context) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700307 this.mContext = context;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800308 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
Jeff Brown05dc66a2011-03-02 14:41:58 -0800309
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700310 mUseDevInputEventForAudioJack =
311 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
312 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
313 + mUseDevInputEventForAudioJack);
Jeff Brown4532e612012-04-05 14:27:12 -0700314 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown4ccb8232014-01-16 22:16:42 -0800315
Adrian Roos99182342016-06-15 15:30:46 -0700316 String doubleTouchGestureEnablePath = context.getResources().getString(
317 R.string.config_doubleTouchGestureEnableFile);
318 mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
319 new File(doubleTouchGestureEnablePath);
320
Jeff Brown4ccb8232014-01-16 22:16:42 -0800321 LocalServices.addService(InputManagerInternal.class, new LocalService());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700322 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700323
Jeff Browna9d131c2012-09-20 16:48:17 -0700324 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
325 mWindowManagerCallbacks = callbacks;
326 }
327
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700328 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
329 mWiredAccessoryCallbacks = callbacks;
330 }
331
Jeff Brown46b9ac02010-04-22 18:58:52 -0700332 public void start() {
333 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700334 nativeStart(mPtr);
335
336 // Add ourself to the Watchdog monitors.
337 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700338
339 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700340 registerShowTouchesSettingObserver();
Jun Mukai19a56012015-11-24 11:25:52 -0800341 registerAccessibilityLargePointerSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700342
Jeff Brownd4935962012-09-25 13:27:20 -0700343 mContext.registerReceiver(new BroadcastReceiver() {
344 @Override
345 public void onReceive(Context context, Intent intent) {
346 updatePointerSpeedFromSettings();
347 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800348 updateAccessibilityLargePointerFromSettings();
Jeff Brownd4935962012-09-25 13:27:20 -0700349 }
350 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
351
Jeff Brown1a84fd12011-06-02 01:26:32 -0700352 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700353 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800354 updateAccessibilityLargePointerFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700355 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700356
Matthew Xie96313142012-06-29 16:57:31 -0700357 // TODO(BT) Pass in paramter for bluetooth system
Svetoslav Ganova0027152013-06-25 14:59:53 -0700358 public void systemRunning() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700359 if (DEBUG) {
360 Slog.d(TAG, "System ready.");
361 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700362 mNotificationManager = (NotificationManager)mContext.getSystemService(
363 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700364 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700365
366 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
367 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
368 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Jeff Brown69b07162013-11-07 00:30:16 -0800369 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700370 filter.addDataScheme("package");
371 mContext.registerReceiver(new BroadcastReceiver() {
372 @Override
373 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700374 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700375 }
376 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700377
378 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
379 mContext.registerReceiver(new BroadcastReceiver() {
380 @Override
381 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700382 reloadDeviceAliases();
383 }
384 }, filter, null, mHandler);
385
Jeff Browncf39bdf2012-05-18 14:41:19 -0700386 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
387 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700388
389 if (mWiredAccessoryCallbacks != null) {
390 mWiredAccessoryCallbacks.systemReady();
391 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700392 }
393
394 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700395 if (DEBUG) {
396 Slog.d(TAG, "Reloading keyboard layouts.");
397 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700398 nativeReloadKeyboardLayouts(mPtr);
399 }
400
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700401 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700402 if (DEBUG) {
403 Slog.d(TAG, "Reloading device names.");
404 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700405 nativeReloadDeviceAliases(mPtr);
406 }
407
Jeff Brown4ccb8232014-01-16 22:16:42 -0800408 private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
Jeff Brownd728bf52012-09-08 18:05:28 -0700409 DisplayViewport externalTouchViewport) {
410 if (defaultViewport.valid) {
411 setDisplayViewport(false, defaultViewport);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700412 }
Jeff Brownd728bf52012-09-08 18:05:28 -0700413
414 if (externalTouchViewport.valid) {
415 setDisplayViewport(true, externalTouchViewport);
416 } else if (defaultViewport.valid) {
417 setDisplayViewport(true, defaultViewport);
Jeff Brownb6997262010-10-08 22:31:17 -0700418 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700419 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700420
Jeff Brownd728bf52012-09-08 18:05:28 -0700421 private void setDisplayViewport(boolean external, DisplayViewport viewport) {
422 nativeSetDisplayViewport(mPtr, external,
423 viewport.displayId, viewport.orientation,
424 viewport.logicalFrame.left, viewport.logicalFrame.top,
425 viewport.logicalFrame.right, viewport.logicalFrame.bottom,
426 viewport.physicalFrame.left, viewport.physicalFrame.top,
Jeff Brown83d616a2012-09-09 20:33:43 -0700427 viewport.physicalFrame.right, viewport.physicalFrame.bottom,
428 viewport.deviceWidth, viewport.deviceHeight);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700429 }
Jeff Brownac143512012-04-05 18:57:33 -0700430
Jeff Brown6d0fec22010-07-23 21:28:06 -0700431 /**
432 * Gets the current state of a key or button by key code.
433 * @param deviceId The input device id, or -1 to consult all devices.
434 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
435 * consider all input sources. An input device is consulted if at least one of its
436 * non-class input source bits matches the specified source mask.
437 * @param keyCode The key code to check.
438 * @return The key state.
439 */
440 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700441 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700442 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700443
Jeff Brown6d0fec22010-07-23 21:28:06 -0700444 /**
445 * Gets the current state of a key or button by scan code.
446 * @param deviceId The input device id, or -1 to consult all devices.
447 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
448 * consider all input sources. An input device is consulted if at least one of its
449 * non-class input source bits matches the specified source mask.
450 * @param scanCode The scan code to check.
451 * @return The key state.
452 */
453 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700454 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700455 }
RoboErikfb290df2013-12-16 11:27:55 -0800456
Jeff Brown6d0fec22010-07-23 21:28:06 -0700457 /**
458 * Gets the current state of a switch by switch code.
459 * @param deviceId The input device id, or -1 to consult all devices.
460 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
461 * consider all input sources. An input device is consulted if at least one of its
462 * non-class input source bits matches the specified source mask.
463 * @param switchCode The switch code to check.
464 * @return The switch state.
465 */
466 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700467 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700468 }
469
Jeff Brown6d0fec22010-07-23 21:28:06 -0700470 /**
471 * Determines whether the specified key codes are supported by a particular device.
472 * @param deviceId The input device id, or -1 to consult all devices.
473 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
474 * consider all input sources. An input device is consulted if at least one of its
475 * non-class input source bits matches the specified source mask.
476 * @param keyCodes The array of key codes to check.
477 * @param keyExists An array at least as large as keyCodes whose entries will be set
478 * to true or false based on the presence or absence of support for the corresponding
479 * key codes.
480 * @return True if the lookup was successful, false otherwise.
481 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700482 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700483 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700484 if (keyCodes == null) {
485 throw new IllegalArgumentException("keyCodes must not be null.");
486 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700487 if (keyExists == null || keyExists.length < keyCodes.length) {
488 throw new IllegalArgumentException("keyExists must not be null and must be at "
489 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700490 }
RoboErikfb290df2013-12-16 11:27:55 -0800491
Jeff Brown4532e612012-04-05 14:27:12 -0700492 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700493 }
RoboErikfb290df2013-12-16 11:27:55 -0800494
Jeff Browna41ca772010-08-11 14:46:32 -0700495 /**
496 * Creates an input channel that will receive all input from the input dispatcher.
497 * @param inputChannelName The input channel name.
498 * @return The input channel.
499 */
500 public InputChannel monitorInput(String inputChannelName) {
501 if (inputChannelName == null) {
502 throw new IllegalArgumentException("inputChannelName must not be null.");
503 }
RoboErikfb290df2013-12-16 11:27:55 -0800504
Jeff Browna41ca772010-08-11 14:46:32 -0700505 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700506 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700507 inputChannels[0].dispose(); // don't need to retain the Java object reference
508 return inputChannels[1];
509 }
510
511 /**
512 * Registers an input channel so that it can be used as an input event target.
513 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800514 * @param inputWindowHandle The handle of the input window associated with the
515 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700516 */
Jeff Brown928e0542011-01-10 11:17:36 -0800517 public void registerInputChannel(InputChannel inputChannel,
518 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700519 if (inputChannel == null) {
520 throw new IllegalArgumentException("inputChannel must not be null.");
521 }
RoboErikfb290df2013-12-16 11:27:55 -0800522
Jeff Brown4532e612012-04-05 14:27:12 -0700523 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700524 }
RoboErikfb290df2013-12-16 11:27:55 -0800525
Jeff Browna41ca772010-08-11 14:46:32 -0700526 /**
527 * Unregisters an input channel.
528 * @param inputChannel The input channel to unregister.
529 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700530 public void unregisterInputChannel(InputChannel inputChannel) {
531 if (inputChannel == null) {
532 throw new IllegalArgumentException("inputChannel must not be null.");
533 }
RoboErikfb290df2013-12-16 11:27:55 -0800534
Jeff Brown4532e612012-04-05 14:27:12 -0700535 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700536 }
Jeff Brown0029c662011-03-30 02:25:18 -0700537
538 /**
539 * Sets an input filter that will receive all input events before they are dispatched.
540 * The input filter may then reinterpret input events or inject new ones.
541 *
542 * To ensure consistency, the input dispatcher automatically drops all events
543 * in progress whenever an input filter is installed or uninstalled. After an input
544 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
545 * Any events it attempts to send after it has been uninstalled will be dropped.
546 *
547 * @param filter The input filter, or null to remove the current filter.
548 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700549 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700550 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700551 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700552 if (oldFilter == filter) {
553 return; // nothing to do
554 }
555
556 if (oldFilter != null) {
557 mInputFilter = null;
558 mInputFilterHost.disconnectLocked();
559 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700560 try {
561 oldFilter.uninstall();
562 } catch (RemoteException re) {
563 /* ignore */
564 }
Jeff Brown0029c662011-03-30 02:25:18 -0700565 }
566
567 if (filter != null) {
568 mInputFilter = filter;
569 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700570 try {
571 filter.install(mInputFilterHost);
572 } catch (RemoteException re) {
573 /* ignore */
574 }
Jeff Brown0029c662011-03-30 02:25:18 -0700575 }
576
Jeff Brown4532e612012-04-05 14:27:12 -0700577 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700578 }
579 }
580
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700581 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700582 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brownca9bc702014-02-11 14:32:56 -0800583 return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
584 }
585
586 private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700587 if (event == null) {
588 throw new IllegalArgumentException("event must not be null");
589 }
Jeff Brownac143512012-04-05 18:57:33 -0700590 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
591 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
592 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
593 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700594 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700595
Jeff Brownac143512012-04-05 18:57:33 -0700596 final int pid = Binder.getCallingPid();
597 final int uid = Binder.getCallingUid();
598 final long ident = Binder.clearCallingIdentity();
599 final int result;
600 try {
Jeff Brownca9bc702014-02-11 14:32:56 -0800601 result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
Jeff Brownac143512012-04-05 18:57:33 -0700602 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
603 } finally {
604 Binder.restoreCallingIdentity(ident);
605 }
606 switch (result) {
607 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
608 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
609 throw new SecurityException(
610 "Injecting to another application requires INJECT_EVENTS permission");
611 case INPUT_EVENT_INJECTION_SUCCEEDED:
612 return true;
613 case INPUT_EVENT_INJECTION_TIMED_OUT:
614 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
615 return false;
616 case INPUT_EVENT_INJECTION_FAILED:
617 default:
618 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
619 return false;
620 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700621 }
Jeff Brown0029c662011-03-30 02:25:18 -0700622
Jeff Brown8d608662010-08-30 03:02:23 -0700623 /**
624 * Gets information about the input device with the specified id.
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700625 * @param deviceId The device id.
Jeff Brown8d608662010-08-30 03:02:23 -0700626 * @return The input device or null if not found.
627 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700628 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700629 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700630 synchronized (mInputDevicesLock) {
631 final int count = mInputDevices.length;
632 for (int i = 0; i < count; i++) {
633 final InputDevice inputDevice = mInputDevices[i];
634 if (inputDevice.getId() == deviceId) {
635 return inputDevice;
636 }
637 }
638 }
639 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700640 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700641
Jeff Brown8d608662010-08-30 03:02:23 -0700642 /**
643 * Gets the ids of all input devices in the system.
644 * @return The input device ids.
645 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700646 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700647 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700648 synchronized (mInputDevicesLock) {
649 final int count = mInputDevices.length;
650 int[] ids = new int[count];
651 for (int i = 0; i < count; i++) {
652 ids[i] = mInputDevices[i].getId();
653 }
654 return ids;
655 }
656 }
657
Jeff Browndaa37532012-05-01 15:54:03 -0700658 /**
659 * Gets all input devices in the system.
660 * @return The array of input devices.
661 */
662 public InputDevice[] getInputDevices() {
663 synchronized (mInputDevicesLock) {
664 return mInputDevices;
665 }
666 }
667
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700668 @Override // Binder call
669 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
670 if (listener == null) {
671 throw new IllegalArgumentException("listener must not be null");
672 }
673
674 synchronized (mInputDevicesLock) {
675 int callingPid = Binder.getCallingPid();
676 if (mInputDevicesChangedListeners.get(callingPid) != null) {
677 throw new SecurityException("The calling process has already "
678 + "registered an InputDevicesChangedListener.");
679 }
680
681 InputDevicesChangedListenerRecord record =
682 new InputDevicesChangedListenerRecord(callingPid, listener);
683 try {
684 IBinder binder = listener.asBinder();
685 binder.linkToDeath(record, 0);
686 } catch (RemoteException ex) {
687 // give up
688 throw new RuntimeException(ex);
689 }
690
691 mInputDevicesChangedListeners.put(callingPid, record);
692 }
693 }
694
695 private void onInputDevicesChangedListenerDied(int pid) {
696 synchronized (mInputDevicesLock) {
697 mInputDevicesChangedListeners.remove(pid);
698 }
699 }
700
701 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700702 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
703 // Scan for changes.
704 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700705 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700706 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700707 final int numListeners;
708 final int[] deviceIdAndGeneration;
709 synchronized (mInputDevicesLock) {
710 if (!mInputDevicesChangedPending) {
711 return;
712 }
713 mInputDevicesChangedPending = false;
714
715 numListeners = mInputDevicesChangedListeners.size();
716 for (int i = 0; i < numListeners; i++) {
717 mTempInputDevicesChangedListenersToNotify.add(
718 mInputDevicesChangedListeners.valueAt(i));
719 }
720
721 final int numDevices = mInputDevices.length;
722 deviceIdAndGeneration = new int[numDevices * 2];
723 for (int i = 0; i < numDevices; i++) {
724 final InputDevice inputDevice = mInputDevices[i];
725 deviceIdAndGeneration[i * 2] = inputDevice.getId();
726 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700727
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700728 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700729 if (!containsInputDeviceWithDescriptor(oldInputDevices,
730 inputDevice.getDescriptor())) {
731 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
732 } else {
733 mTempFullKeyboards.add(inputDevice);
734 }
735 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700736 }
737 }
738
Jeff Browncf39bdf2012-05-18 14:41:19 -0700739 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700740 for (int i = 0; i < numListeners; i++) {
741 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
742 deviceIdAndGeneration);
743 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700744 mTempInputDevicesChangedListenersToNotify.clear();
745
746 // Check for missing keyboard layouts.
Michael Wright07483422015-10-30 16:20:13 +0000747 List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
748 final int numFullKeyboards = mTempFullKeyboards.size();
749 synchronized (mDataStore) {
750 for (int i = 0; i < numFullKeyboards; i++) {
751 final InputDevice inputDevice = mTempFullKeyboards.get(i);
752 String layout =
753 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
754 if (layout == null) {
755 layout = getDefaultKeyboardLayout(inputDevice);
756 if (layout != null) {
757 setCurrentKeyboardLayoutForInputDevice(
758 inputDevice.getIdentifier(), layout);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700759 }
760 }
Michael Wright07483422015-10-30 16:20:13 +0000761 if (layout == null) {
762 keyboardsMissingLayout.add(inputDevice);
763 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700764 }
Michael Wright07483422015-10-30 16:20:13 +0000765 }
766
767 if (mNotificationManager != null) {
768 if (!keyboardsMissingLayout.isEmpty()) {
769 if (keyboardsMissingLayout.size() > 1) {
770 // We have more than one keyboard missing a layout, so drop the
771 // user at the generic input methods page so they can pick which
772 // one to set.
773 showMissingKeyboardLayoutNotification(null);
774 } else {
775 showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
Jeff Browncf39bdf2012-05-18 14:41:19 -0700776 }
777 } else if (mKeyboardLayoutNotificationShown) {
778 hideMissingKeyboardLayoutNotification();
779 }
780 }
781 mTempFullKeyboards.clear();
782 }
783
Michael Wright07483422015-10-30 16:20:13 +0000784 private String getDefaultKeyboardLayout(final InputDevice d) {
785 final Locale systemLocale = mContext.getResources().getConfiguration().locale;
786 // If our locale doesn't have a language for some reason, then we don't really have a
787 // reasonable default.
788 if (TextUtils.isEmpty(systemLocale.getLanguage())) {
789 return null;
790 }
791 final List<KeyboardLayout> layouts = new ArrayList<>();
792 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
793 @Override
794 public void visitKeyboardLayout(Resources resources,
795 int keyboardLayoutResId, KeyboardLayout layout) {
796 // Only select a default when we know the layout is appropriate. For now, this
797 // means its a custom layout for a specific keyboard.
798 if (layout.getVendorId() != d.getVendorId()
799 || layout.getProductId() != d.getProductId()) {
800 return;
801 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800802 final LocaleList locales = layout.getLocales();
803 final int numLocales = locales.size();
804 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
805 if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
Michael Wright07483422015-10-30 16:20:13 +0000806 layouts.add(layout);
807 break;
808 }
809 }
810 }
811 });
812
813 if (layouts.isEmpty()) {
814 return null;
815 }
816
817 // First sort so that ones with higher priority are listed at the top
818 Collections.sort(layouts);
819 // Next we want to try to find an exact match of language, country and variant.
820 final int N = layouts.size();
821 for (int i = 0; i < N; i++) {
822 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800823 final LocaleList locales = layout.getLocales();
824 final int numLocales = locales.size();
825 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
826 final Locale locale = locales.get(localeIndex);
827 if (locale.getCountry().equals(systemLocale.getCountry())
828 && locale.getVariant().equals(systemLocale.getVariant())) {
Michael Wright07483422015-10-30 16:20:13 +0000829 return layout.getDescriptor();
830 }
831 }
832 }
833 // Then try an exact match of language and country
834 for (int i = 0; i < N; i++) {
835 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800836 final LocaleList locales = layout.getLocales();
837 final int numLocales = locales.size();
838 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
839 final Locale locale = locales.get(localeIndex);
840 if (locale.getCountry().equals(systemLocale.getCountry())) {
Michael Wright07483422015-10-30 16:20:13 +0000841 return layout.getDescriptor();
842 }
843 }
844 }
845
846 // Give up and just use the highest priority layout with matching language
847 return layouts.get(0).getDescriptor();
848 }
849
850 private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
851 // Different languages are never compatible
852 if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
853 return false;
854 }
855 // If both the system and the keyboard layout have a country specifier, they must be equal.
856 if (!TextUtils.isEmpty(systemLocale.getCountry())
857 && !TextUtils.isEmpty(keyboardLocale.getCountry())
858 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
859 return false;
860 }
861 return true;
862 }
863
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800864 @Override // Binder call & native callback
Jason Gerecked5220742014-03-10 09:47:59 -0700865 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
866 int surfaceRotation) {
Jason Gerecked6396d62014-01-27 18:30:37 -0800867 if (inputDeviceDescriptor == null) {
868 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
869 }
870
871 synchronized (mDataStore) {
Jason Gerecked5220742014-03-10 09:47:59 -0700872 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
Jason Gerecked6396d62014-01-27 18:30:37 -0800873 }
874 }
875
876 @Override // Binder call
Jason Gerecked5220742014-03-10 09:47:59 -0700877 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
Jason Gerecked6396d62014-01-27 18:30:37 -0800878 TouchCalibration calibration) {
879 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
880 "setTouchCalibrationForInputDevice()")) {
881 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
882 }
883 if (inputDeviceDescriptor == null) {
884 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
885 }
886 if (calibration == null) {
887 throw new IllegalArgumentException("calibration must not be null");
888 }
Jason Gerecked5220742014-03-10 09:47:59 -0700889 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
890 throw new IllegalArgumentException("surfaceRotation value out of bounds");
891 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800892
893 synchronized (mDataStore) {
894 try {
Jason Gerecked5220742014-03-10 09:47:59 -0700895 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
896 calibration)) {
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800897 nativeReloadCalibration(mPtr);
898 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800899 } finally {
900 mDataStore.saveIfNeeded();
901 }
902 }
903 }
904
Michael Wright39e5e942015-08-19 22:52:47 +0100905 @Override // Binder call
Michael Wright9209c9c2015-09-03 17:57:01 +0100906 public int isInTabletMode() {
907 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
908 "isInTabletMode()")) {
909 throw new SecurityException("Requires TABLET_MODE permission");
910 }
911 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
912 }
913
914 @Override // Binder call
Michael Wright39e5e942015-08-19 22:52:47 +0100915 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
Michael Wright9209c9c2015-09-03 17:57:01 +0100916 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
Michael Wright39e5e942015-08-19 22:52:47 +0100917 "registerTabletModeChangedListener()")) {
918 throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
919 }
920 if (listener == null) {
921 throw new IllegalArgumentException("listener must not be null");
922 }
923
924 synchronized (mTabletModeLock) {
925 final int callingPid = Binder.getCallingPid();
926 if (mTabletModeChangedListeners.get(callingPid) != null) {
927 throw new IllegalStateException("The calling process has already registered "
928 + "a TabletModeChangedListener.");
929 }
930 TabletModeChangedListenerRecord record =
931 new TabletModeChangedListenerRecord(callingPid, listener);
932 try {
933 IBinder binder = listener.asBinder();
934 binder.linkToDeath(record, 0);
935 } catch (RemoteException ex) {
936 throw new RuntimeException(ex);
937 }
938 mTabletModeChangedListeners.put(callingPid, record);
939 }
940 }
941
942 private void onTabletModeChangedListenerDied(int pid) {
943 synchronized (mTabletModeLock) {
944 mTabletModeChangedListeners.remove(pid);
945 }
946 }
947
948 // Must be called on handler
949 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
950 mTempTabletModeChangedListenersToNotify.clear();
951 final int numListeners;
952 synchronized (mTabletModeLock) {
953 numListeners = mTabletModeChangedListeners.size();
954 for (int i = 0; i < numListeners; i++) {
955 mTempTabletModeChangedListenersToNotify.add(
956 mTabletModeChangedListeners.valueAt(i));
957 }
958 }
959 for (int i = 0; i < numListeners; i++) {
960 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
961 whenNanos, inTabletMode);
962 }
963 }
964
Jeff Browncf39bdf2012-05-18 14:41:19 -0700965 // Must be called on handler.
Michael Wrightc93fbd12014-09-22 20:07:59 -0700966 private void showMissingKeyboardLayoutNotification(InputDevice device) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700967 if (!mKeyboardLayoutNotificationShown) {
Yohei Yukawa2bff4902016-03-30 01:06:37 -0700968 final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
Michael Wrightc93fbd12014-09-22 20:07:59 -0700969 if (device != null) {
970 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -0700971 }
Michael Wrightc93fbd12014-09-22 20:07:59 -0700972 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
973 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
974 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
975 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
976 intent, 0, null, UserHandle.CURRENT);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700977
978 Resources r = mContext.getResources();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -0500979 Notification notification =
980 new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
981 .setContentTitle(r.getString(
982 R.string.select_keyboard_layout_notification_title))
983 .setContentText(r.getString(
984 R.string.select_keyboard_layout_notification_message))
985 .setContentIntent(keyboardLayoutIntent)
986 .setSmallIcon(R.drawable.ic_settings_language)
987 .setColor(mContext.getColor(
988 com.android.internal.R.color.system_notification_accent_color))
989 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700990 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -0400991 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700992 notification, UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700993 mKeyboardLayoutNotificationShown = true;
994 }
995 }
996
997 // Must be called on handler.
998 private void hideMissingKeyboardLayoutNotification() {
999 if (mKeyboardLayoutNotificationShown) {
1000 mKeyboardLayoutNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001001 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04001002 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001003 UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001004 }
1005 }
1006
1007 // Must be called on handler.
1008 private void updateKeyboardLayouts() {
1009 // Scan all input devices state for keyboard layouts that have been uninstalled.
1010 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
1011 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1012 @Override
Michael Wright07483422015-10-30 16:20:13 +00001013 public void visitKeyboardLayout(Resources resources,
1014 int keyboardLayoutResId, KeyboardLayout layout) {
1015 availableKeyboardLayouts.add(layout.getDescriptor());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001016 }
1017 });
1018 synchronized (mDataStore) {
1019 try {
1020 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
1021 } finally {
1022 mDataStore.saveIfNeeded();
1023 }
1024 }
1025
1026 // Reload keyboard layouts.
1027 reloadKeyboardLayouts();
1028 }
1029
Jeff Browncf39bdf2012-05-18 14:41:19 -07001030 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
1031 String descriptor) {
1032 final int numDevices = inputDevices.length;
1033 for (int i = 0; i < numDevices; i++) {
1034 final InputDevice inputDevice = inputDevices[i];
1035 if (inputDevice.getDescriptor().equals(descriptor)) {
1036 return true;
1037 }
1038 }
1039 return false;
Jeff Brown8d608662010-08-30 03:02:23 -07001040 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001041
1042 @Override // Binder call
1043 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001044 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
1045 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1046 @Override
Michael Wright07483422015-10-30 16:20:13 +00001047 public void visitKeyboardLayout(Resources resources,
1048 int keyboardLayoutResId, KeyboardLayout layout) {
1049 list.add(layout);
1050 }
1051 });
1052 return list.toArray(new KeyboardLayout[list.size()]);
1053 }
1054
Michael Wrightb0e804a2016-01-04 16:48:53 -05001055 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001056 public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1057 final InputDeviceIdentifier identifier) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001058 final String[] enabledLayoutDescriptors =
1059 getEnabledKeyboardLayoutsForInputDevice(identifier);
1060 final ArrayList<KeyboardLayout> enabledLayouts =
1061 new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length);
1062 final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>();
Michael Wright07483422015-10-30 16:20:13 +00001063 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1064 boolean mHasSeenDeviceSpecificLayout;
1065
1066 @Override
1067 public void visitKeyboardLayout(Resources resources,
1068 int keyboardLayoutResId, KeyboardLayout layout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001069 // First check if it's enabled. If the keyboard layout is enabled then we always
1070 // want to return it as a possible layout for the device.
1071 for (String s : enabledLayoutDescriptors) {
1072 if (s != null && s.equals(layout.getDescriptor())) {
1073 enabledLayouts.add(layout);
1074 return;
1075 }
1076 }
1077 // Next find any potential layouts that aren't yet enabled for the device. For
1078 // devices that have special layouts we assume there's a reason that the generic
1079 // layouts don't work for them so we don't want to return them since it's likely
1080 // to result in a poor user experience.
Michael Wright07483422015-10-30 16:20:13 +00001081 if (layout.getVendorId() == identifier.getVendorId()
1082 && layout.getProductId() == identifier.getProductId()) {
1083 if (!mHasSeenDeviceSpecificLayout) {
1084 mHasSeenDeviceSpecificLayout = true;
Michael Wrightb0e804a2016-01-04 16:48:53 -05001085 potentialLayouts.clear();
Michael Wright07483422015-10-30 16:20:13 +00001086 }
Michael Wrightb0e804a2016-01-04 16:48:53 -05001087 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001088 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
1089 && !mHasSeenDeviceSpecificLayout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001090 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001091 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001092 }
1093 });
Michael Wrightb0e804a2016-01-04 16:48:53 -05001094 final int enabledLayoutSize = enabledLayouts.size();
1095 final int potentialLayoutSize = potentialLayouts.size();
1096 KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
1097 enabledLayouts.toArray(layouts);
1098 for (int i = 0; i < potentialLayoutSize; i++) {
1099 layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
1100 }
1101 return layouts;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001102 }
1103
1104 @Override // Binder call
1105 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
1106 if (keyboardLayoutDescriptor == null) {
1107 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1108 }
1109
Jeff Brown6ec6f792012-04-17 16:52:41 -07001110 final KeyboardLayout[] result = new KeyboardLayout[1];
1111 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1112 @Override
Michael Wright07483422015-10-30 16:20:13 +00001113 public void visitKeyboardLayout(Resources resources,
1114 int keyboardLayoutResId, KeyboardLayout layout) {
1115 result[0] = layout;
Jeff Brown6ec6f792012-04-17 16:52:41 -07001116 }
1117 });
1118 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00001119 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07001120 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001121 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001122 return result[0];
1123 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001124
Jeff Brown6ec6f792012-04-17 16:52:41 -07001125 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001126 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001127 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
1128 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001129 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
1130 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
Michael Wright8ebac232014-09-18 18:29:49 -07001131 final ActivityInfo activityInfo = resolveInfo.activityInfo;
1132 final int priority = resolveInfo.priority;
1133 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001134 }
1135 }
1136
Jeff Brown6ec6f792012-04-17 16:52:41 -07001137 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
1138 KeyboardLayoutVisitor visitor) {
1139 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
1140 if (d != null) {
1141 final PackageManager pm = mContext.getPackageManager();
1142 try {
1143 ActivityInfo receiver = pm.getReceiverInfo(
1144 new ComponentName(d.packageName, d.receiverName),
Jeff Sharkey5217cac2015-12-20 15:34:01 -07001145 PackageManager.GET_META_DATA
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001146 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1147 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Michael Wright8ebac232014-09-18 18:29:49 -07001148 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001149 } catch (NameNotFoundException ex) {
1150 }
1151 }
1152 }
1153
1154 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
Michael Wright8ebac232014-09-18 18:29:49 -07001155 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001156 Bundle metaData = receiver.metaData;
1157 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001158 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001159 }
1160
1161 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1162 if (configResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001163 Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001164 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001165 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001166 }
1167
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001168 CharSequence receiverLabel = receiver.loadLabel(pm);
1169 String collection = receiverLabel != null ? receiverLabel.toString() : "";
Michael Wright8ebac232014-09-18 18:29:49 -07001170 int priority;
1171 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1172 priority = requestedPriority;
1173 } else {
1174 priority = 0;
1175 }
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001176
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001177 try {
1178 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1179 XmlResourceParser parser = resources.getXml(configResId);
1180 try {
1181 XmlUtils.beginDocument(parser, "keyboard-layouts");
1182
1183 for (;;) {
1184 XmlUtils.nextElement(parser);
1185 String element = parser.getName();
1186 if (element == null) {
1187 break;
1188 }
1189 if (element.equals("keyboard-layout")) {
1190 TypedArray a = resources.obtainAttributes(
1191 parser, com.android.internal.R.styleable.KeyboardLayout);
1192 try {
1193 String name = a.getString(
1194 com.android.internal.R.styleable.KeyboardLayout_name);
1195 String label = a.getString(
1196 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -07001197 int keyboardLayoutResId = a.getResourceId(
1198 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1199 0);
Michael Wright07483422015-10-30 16:20:13 +00001200 String languageTags = a.getString(
1201 com.android.internal.R.styleable.KeyboardLayout_locale);
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001202 LocaleList locales = getLocalesFromLanguageTags(languageTags);
Michael Wright07483422015-10-30 16:20:13 +00001203 int vid = a.getInt(
1204 com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
1205 int pid = a.getInt(
1206 com.android.internal.R.styleable.KeyboardLayout_productId, -1);
1207
Jeff Brown2f095762012-05-10 21:29:33 -07001208 if (name == null || label == null || keyboardLayoutResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001209 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001210 + "attributes in keyboard layout "
1211 + "resource from receiver "
1212 + receiver.packageName + "/" + receiver.name);
1213 } else {
1214 String descriptor = KeyboardLayoutDescriptor.format(
1215 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001216 if (keyboardName == null || name.equals(keyboardName)) {
Michael Wright07483422015-10-30 16:20:13 +00001217 KeyboardLayout layout = new KeyboardLayout(
1218 descriptor, label, collection, priority,
1219 locales, vid, pid);
1220 visitor.visitKeyboardLayout(
1221 resources, keyboardLayoutResId, layout);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001222 }
1223 }
1224 } finally {
1225 a.recycle();
1226 }
1227 } else {
Michael Wright07483422015-10-30 16:20:13 +00001228 Slog.w(TAG, "Skipping unrecognized element '" + element
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001229 + "' in keyboard layout resource from receiver "
1230 + receiver.packageName + "/" + receiver.name);
1231 }
1232 }
1233 } finally {
1234 parser.close();
1235 }
1236 } catch (Exception ex) {
Michael Wright07483422015-10-30 16:20:13 +00001237 Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001238 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001239 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001240 }
1241
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001242 @NonNull
1243 private static LocaleList getLocalesFromLanguageTags(String languageTags) {
Michael Wright07483422015-10-30 16:20:13 +00001244 if (TextUtils.isEmpty(languageTags)) {
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001245 return LocaleList.getEmptyLocaleList();
Michael Wright07483422015-10-30 16:20:13 +00001246 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001247 return LocaleList.forLanguageTags(languageTags.replace('|', ','));
Michael Wright07483422015-10-30 16:20:13 +00001248 }
1249
RoboErikfb290df2013-12-16 11:27:55 -08001250 /**
1251 * Builds a layout descriptor for the vendor/product. This returns the
1252 * descriptor for ids that aren't useful (such as the default 0, 0).
1253 */
1254 private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1255 if (identifier == null || identifier.getDescriptor() == null) {
1256 throw new IllegalArgumentException("identifier and descriptor must not be null");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001257 }
1258
RoboErikfb290df2013-12-16 11:27:55 -08001259 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1260 return identifier.getDescriptor();
1261 }
1262 StringBuilder bob = new StringBuilder();
1263 bob.append("vendor:").append(identifier.getVendorId());
1264 bob.append(",product:").append(identifier.getProductId());
1265 return bob.toString();
1266 }
1267
1268 @Override // Binder call
1269 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1270
1271 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001272 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001273 String layout = null;
1274 // try loading it using the layout descriptor if we have it
1275 layout = mDataStore.getCurrentKeyboardLayout(key);
1276 if (layout == null && !key.equals(identifier.getDescriptor())) {
1277 // if it doesn't exist fall back to the device descriptor
1278 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1279 }
1280 if (DEBUG) {
1281 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1282 + layout);
1283 }
1284 return layout;
Jeff Browna3bc5652012-04-17 11:42:25 -07001285 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001286 }
1287
1288 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001289 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001290 String keyboardLayoutDescriptor) {
1291 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001292 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001293 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1294 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001295 if (keyboardLayoutDescriptor == null) {
1296 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1297 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001298
RoboErikfb290df2013-12-16 11:27:55 -08001299 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001300 synchronized (mDataStore) {
1301 try {
RoboErikfb290df2013-12-16 11:27:55 -08001302 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1303 if (DEBUG) {
1304 Slog.d(TAG, "Saved keyboard layout using " + key);
1305 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001306 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1307 }
Jeff Browna3bc5652012-04-17 11:42:25 -07001308 } finally {
1309 mDataStore.saveIfNeeded();
1310 }
1311 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001312 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001313
Jeff Browncf39bdf2012-05-18 14:41:19 -07001314 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001315 public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
RoboErikfb290df2013-12-16 11:27:55 -08001316 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001317 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001318 String[] layouts = mDataStore.getKeyboardLayouts(key);
1319 if ((layouts == null || layouts.length == 0)
1320 && !key.equals(identifier.getDescriptor())) {
1321 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1322 }
1323 return layouts;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001324 }
1325 }
1326
1327 @Override // Binder call
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001328 @Nullable
1329 public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1330 InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) {
1331 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
1332 String key = getLayoutDescriptor(identifier);
1333 final String keyboardLayoutDescriptor;
1334 synchronized (mDataStore) {
1335 keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle);
1336 }
1337
1338 if (keyboardLayoutDescriptor == null) {
1339 return null;
1340 }
1341
1342 final KeyboardLayout[] result = new KeyboardLayout[1];
1343 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1344 @Override
1345 public void visitKeyboardLayout(Resources resources,
1346 int keyboardLayoutResId, KeyboardLayout layout) {
1347 result[0] = layout;
1348 }
1349 });
1350 if (result[0] == null) {
1351 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
1352 + keyboardLayoutDescriptor + "'.");
1353 }
1354 return result[0];
1355 }
1356
1357 @Override
1358 public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1359 InputMethodInfo imeInfo, InputMethodSubtype imeSubtype,
1360 String keyboardLayoutDescriptor) {
1361 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1362 "setKeyboardLayoutForInputDevice()")) {
1363 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1364 }
1365 if (keyboardLayoutDescriptor == null) {
1366 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1367 }
Yohei Yukawa46ac35d2016-04-20 16:59:45 -07001368 if (imeInfo == null) {
1369 throw new IllegalArgumentException("imeInfo must not be null");
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001370 }
1371 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
1372 setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
1373 }
1374
1375 private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier,
1376 InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
1377 String key = getLayoutDescriptor(identifier);
1378 synchronized (mDataStore) {
1379 try {
1380 if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) {
1381 if (DEBUG) {
1382 Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor +
1383 " for subtype " + imeHandle + " and device " + identifier +
1384 " using key " + key);
1385 }
1386 if (imeHandle.equals(mCurrentImeHandle)) {
1387 if (DEBUG) {
1388 Slog.d(TAG, "Layout for current subtype changed, switching layout");
1389 }
1390 SomeArgs args = SomeArgs.obtain();
1391 args.arg1 = identifier;
1392 args.arg2 = imeHandle;
1393 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget();
1394 }
1395 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1396 }
1397 } finally {
1398 mDataStore.saveIfNeeded();
1399 }
1400 }
1401 }
1402
1403 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001404 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001405 String keyboardLayoutDescriptor) {
1406 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1407 "addKeyboardLayoutForInputDevice()")) {
1408 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1409 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001410 if (keyboardLayoutDescriptor == null) {
1411 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1412 }
1413
RoboErikfb290df2013-12-16 11:27:55 -08001414 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001415 synchronized (mDataStore) {
1416 try {
RoboErikfb290df2013-12-16 11:27:55 -08001417 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1418 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1419 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1420 }
1421 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001422 && !Objects.equal(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001423 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1424 }
1425 } finally {
1426 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001427 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001428 }
1429 }
1430
1431 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001432 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001433 String keyboardLayoutDescriptor) {
1434 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1435 "removeKeyboardLayoutForInputDevice()")) {
1436 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1437 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001438 if (keyboardLayoutDescriptor == null) {
1439 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1440 }
1441
RoboErikfb290df2013-12-16 11:27:55 -08001442 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001443 synchronized (mDataStore) {
1444 try {
RoboErikfb290df2013-12-16 11:27:55 -08001445 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1446 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1447 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1448 }
1449 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1450 if (!key.equals(identifier.getDescriptor())) {
1451 // We need to remove from both places to ensure it is gone
1452 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1453 keyboardLayoutDescriptor);
1454 }
1455 if (removed && !Objects.equal(oldLayout,
1456 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001457 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1458 }
1459 } finally {
1460 mDataStore.saveIfNeeded();
1461 }
1462 }
1463 }
1464
Yohei Yukawab097b822015-12-01 10:43:08 -08001465 // Must be called on handler.
1466 private void handleSwitchInputMethodSubtype(int userId,
1467 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
1468 if (DEBUG) {
1469 Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
1470 + " ime=" + inputMethodInfo + " subtype=" + subtype);
1471 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001472 if (inputMethodInfo == null) {
1473 Slog.d(TAG, "No InputMethod is running, ignoring change");
1474 return;
1475 }
1476 if (subtype != null && !"keyboard".equals(subtype.getMode())) {
1477 Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change");
1478 return;
1479 }
1480 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype);
1481 if (!handle.equals(mCurrentImeHandle)) {
1482 mCurrentImeHandle = handle;
1483 handleSwitchKeyboardLayout(null, handle);
1484 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001485 }
1486
1487 // Must be called on handler.
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001488 private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier,
1489 InputMethodSubtypeHandle handle) {
1490 synchronized (mInputDevicesLock) {
1491 for (InputDevice device : mInputDevices) {
1492 if (identifier != null && !device.getIdentifier().equals(identifier) ||
1493 !device.isFullKeyboard()) {
1494 continue;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001495 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001496 String key = getLayoutDescriptor(device.getIdentifier());
1497 boolean changed = false;
1498 synchronized (mDataStore) {
1499 try {
1500 if (mDataStore.switchKeyboardLayout(key, handle)) {
1501 changed = true;
1502 }
1503 } finally {
1504 mDataStore.saveIfNeeded();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001505 }
1506 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001507 if (changed) {
1508 reloadKeyboardLayouts();
1509 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001510 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001511 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001512 }
1513
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001514 public void setInputWindows(InputWindowHandle[] windowHandles,
1515 InputWindowHandle focusedWindowHandle) {
1516 final IWindow newFocusedWindow =
1517 focusedWindowHandle != null ? focusedWindowHandle.clientWindow : null;
1518 if (mFocusedWindow != newFocusedWindow) {
1519 mFocusedWindow = newFocusedWindow;
1520 if (mFocusedWindowHasCapture) {
1521 setPointerCapture(false);
1522 }
1523 }
Jeff Brown4532e612012-04-05 14:27:12 -07001524 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -07001525 }
RoboErikfb290df2013-12-16 11:27:55 -08001526
Jeff Brown9302c872011-07-13 22:51:29 -07001527 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -07001528 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -07001529 }
RoboErikfb290df2013-12-16 11:27:55 -08001530
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001531 @Override
1532 public void requestPointerCapture(IBinder windowToken, boolean enabled) {
1533 if (mFocusedWindow == null || mFocusedWindow.asBinder() != windowToken) {
1534 Slog.e(TAG, "requestPointerCapture called for a window that has no focus: "
1535 + windowToken);
1536 return;
1537 }
1538 if (mFocusedWindowHasCapture == enabled) {
1539 Slog.i(TAG, "requestPointerCapture: already " + (enabled ? "enabled" : "disabled"));
1540 return;
1541 }
1542 setPointerCapture(enabled);
1543 try {
1544 mFocusedWindow.dispatchPointerCaptureChanged(enabled);
1545 } catch (RemoteException ex) {
1546 /* ignore */
1547 }
1548 }
1549
1550 private void setPointerCapture(boolean enabled) {
1551 mFocusedWindowHasCapture = enabled;
1552 nativeSetPointerCapture(mPtr, enabled);
1553 }
1554
Jeff Brown349703e2010-06-22 01:27:15 -07001555 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001556 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001557 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001558
1559 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001560 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001561 }
1562
Jeff Browne6504122010-09-27 14:52:15 -07001563 /**
1564 * Atomically transfers touch focus from one window to another as identified by
1565 * their input channels. It is possible for multiple windows to have
1566 * touch focus if they support split touch dispatch
1567 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1568 * method only transfers touch focus of the specified window without affecting
1569 * other windows that may also have touch focus at the same time.
1570 * @param fromChannel The channel of a window that currently has touch focus.
1571 * @param toChannel The channel of the window that should receive touch focus in
1572 * place of the first.
1573 * @return True if the transfer was successful. False if the window with the
1574 * specified channel did not actually have touch focus at the time of the request.
1575 */
1576 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1577 if (fromChannel == null) {
1578 throw new IllegalArgumentException("fromChannel must not be null.");
1579 }
1580 if (toChannel == null) {
1581 throw new IllegalArgumentException("toChannel must not be null.");
1582 }
Jeff Brown4532e612012-04-05 14:27:12 -07001583 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -07001584 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001585
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001586 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001587 public void tryPointerSpeed(int speed) {
1588 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1589 "tryPointerSpeed()")) {
1590 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1591 }
1592
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001593 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1594 throw new IllegalArgumentException("speed out of range");
1595 }
1596
Jeff Brownac143512012-04-05 18:57:33 -07001597 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001598 }
1599
1600 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001601 int speed = getPointerSpeedSetting();
1602 setPointerSpeedUnchecked(speed);
1603 }
1604
1605 private void setPointerSpeedUnchecked(int speed) {
1606 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1607 InputManager.MAX_POINTER_SPEED);
1608 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001609 }
1610
1611 private void registerPointerSpeedSettingObserver() {
1612 mContext.getContentResolver().registerContentObserver(
1613 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001614 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001615 @Override
1616 public void onChange(boolean selfChange) {
1617 updatePointerSpeedFromSettings();
1618 }
Jeff Brownd4935962012-09-25 13:27:20 -07001619 }, UserHandle.USER_ALL);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001620 }
1621
Jeff Brownac143512012-04-05 18:57:33 -07001622 private int getPointerSpeedSetting() {
1623 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001624 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001625 speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1626 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001627 } catch (SettingNotFoundException snfe) {
1628 }
1629 return speed;
1630 }
1631
Jeff Browndaf4a122011-08-26 17:14:14 -07001632 public void updateShowTouchesFromSettings() {
1633 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001634 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001635 }
1636
1637 private void registerShowTouchesSettingObserver() {
1638 mContext.getContentResolver().registerContentObserver(
1639 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001640 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001641 @Override
1642 public void onChange(boolean selfChange) {
1643 updateShowTouchesFromSettings();
1644 }
Jeff Brownd4935962012-09-25 13:27:20 -07001645 }, UserHandle.USER_ALL);
Jeff Browndaf4a122011-08-26 17:14:14 -07001646 }
1647
Jun Mukaie4e75da2015-12-15 16:19:20 -08001648 public void updateAccessibilityLargePointerFromSettings() {
1649 final int accessibilityConfig = Settings.Secure.getIntForUser(
1650 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1651 0, UserHandle.USER_CURRENT);
Jun Mukai1f3dbff2015-12-16 14:41:25 -08001652 PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
Jun Mukaie4e75da2015-12-15 16:19:20 -08001653 nativeReloadPointerIcons(mPtr);
1654 }
1655
Jun Mukai19a56012015-11-24 11:25:52 -08001656 private void registerAccessibilityLargePointerSettingObserver() {
1657 mContext.getContentResolver().registerContentObserver(
1658 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1659 new ContentObserver(mHandler) {
1660 @Override
1661 public void onChange(boolean selfChange) {
Jun Mukaie4e75da2015-12-15 16:19:20 -08001662 updateAccessibilityLargePointerFromSettings();
Jun Mukai19a56012015-11-24 11:25:52 -08001663 }
1664 }, UserHandle.USER_ALL);
1665 }
1666
Jeff Browndaf4a122011-08-26 17:14:14 -07001667 private int getShowTouchesSetting(int defaultValue) {
1668 int result = defaultValue;
1669 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001670 result = Settings.System.getIntForUser(mContext.getContentResolver(),
1671 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
Jeff Browndaf4a122011-08-26 17:14:14 -07001672 } catch (SettingNotFoundException snfe) {
1673 }
1674 return result;
1675 }
1676
Jeff Browna47425a2012-04-13 04:09:27 -07001677 // Binder call
1678 @Override
1679 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1680 if (repeat >= pattern.length) {
1681 throw new ArrayIndexOutOfBoundsException();
1682 }
1683
1684 VibratorToken v;
1685 synchronized (mVibratorLock) {
1686 v = mVibratorTokens.get(token);
1687 if (v == null) {
1688 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1689 try {
1690 token.linkToDeath(v, 0);
1691 } catch (RemoteException ex) {
1692 // give up
1693 throw new RuntimeException(ex);
1694 }
1695 mVibratorTokens.put(token, v);
1696 }
1697 }
1698
1699 synchronized (v) {
1700 v.mVibrating = true;
1701 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1702 }
1703 }
1704
1705 // Binder call
1706 @Override
1707 public void cancelVibrate(int deviceId, IBinder token) {
1708 VibratorToken v;
1709 synchronized (mVibratorLock) {
1710 v = mVibratorTokens.get(token);
1711 if (v == null || v.mDeviceId != deviceId) {
1712 return; // nothing to cancel
1713 }
1714 }
1715
1716 cancelVibrateIfNeeded(v);
1717 }
1718
1719 void onVibratorTokenDied(VibratorToken v) {
1720 synchronized (mVibratorLock) {
1721 mVibratorTokens.remove(v.mToken);
1722 }
1723
1724 cancelVibrateIfNeeded(v);
1725 }
1726
1727 private void cancelVibrateIfNeeded(VibratorToken v) {
1728 synchronized (v) {
1729 if (v.mVibrating) {
1730 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1731 v.mVibrating = false;
1732 }
1733 }
1734 }
1735
Jun Mukai19a56012015-11-24 11:25:52 -08001736 // Binder call
1737 @Override
Michael Wrightf9d9ce772016-05-13 17:44:16 +01001738 public void setPointerIconType(int iconId) {
1739 nativeSetPointerIconType(mPtr, iconId);
Jun Mukai19a56012015-11-24 11:25:52 -08001740 }
Jun Mukai1db53972015-09-11 18:08:31 -07001741
Jun Mukaid4eaef72015-10-30 15:54:33 -07001742 // Binder call
1743 @Override
1744 public void setCustomPointerIcon(PointerIcon icon) {
Michael Wrightb004b512017-01-18 18:09:29 +00001745 Preconditions.checkNotNull(icon);
Jun Mukaid4eaef72015-10-30 15:54:33 -07001746 nativeSetCustomPointerIcon(mPtr, icon);
1747 }
1748
Jeff Brown4532e612012-04-05 14:27:12 -07001749 @Override
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001750 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001751 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Jeff Brown4532e612012-04-05 14:27:12 -07001752
1753 pw.println("INPUT MANAGER (dumpsys input)\n");
1754 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001755 if (dumpStr != null) {
1756 pw.println(dumpStr);
1757 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001758 pw.println(" Keyboard Layouts:");
1759 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1760 @Override
1761 public void visitKeyboardLayout(Resources resources,
1762 int keyboardLayoutResId, KeyboardLayout layout) {
1763 pw.println(" \"" + layout + "\": " + layout.getDescriptor());
1764 }
1765 });
1766 pw.println();
1767 synchronized(mDataStore) {
1768 mDataStore.dump(pw, " ");
1769 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001770 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001771
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001772 @Override
1773 public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07001774 FileDescriptor err, String[] args, ShellCallback callback,
1775 ResultReceiver resultReceiver) {
1776 (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001777 }
1778
1779 public int onShellCommand(Shell shell, String cmd) {
1780 if (TextUtils.isEmpty(cmd)) {
1781 shell.onHelp();
1782 return 1;
1783 }
1784 if (cmd.equals("setlayout")) {
1785 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1786 "onShellCommand()")) {
1787 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1788 }
1789 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
1790 shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired()));
1791 String descriptor = shell.getNextArgRequired();
1792 int vid = Integer.decode(shell.getNextArgRequired());
1793 int pid = Integer.decode(shell.getNextArgRequired());
1794 InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid);
1795 setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired());
1796 }
1797 return 0;
1798 }
1799
1800
Jeff Brownac143512012-04-05 18:57:33 -07001801 private boolean checkCallingPermission(String permission, String func) {
1802 // Quick check: if the calling permission is me, it's all okay.
1803 if (Binder.getCallingPid() == Process.myPid()) {
1804 return true;
1805 }
1806
1807 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1808 return true;
1809 }
1810 String msg = "Permission Denial: " + func + " from pid="
1811 + Binder.getCallingPid()
1812 + ", uid=" + Binder.getCallingUid()
1813 + " requires " + permission;
1814 Slog.w(TAG, msg);
1815 return false;
1816 }
1817
Jeff Brown4532e612012-04-05 14:27:12 -07001818 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001819 @Override
Jeff Brown89ef0722011-08-10 16:25:21 -07001820 public void monitor() {
1821 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -07001822 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001823 }
1824
Jeff Brown4532e612012-04-05 14:27:12 -07001825 // Native callback.
1826 private void notifyConfigurationChanged(long whenNanos) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001827 mWindowManagerCallbacks.notifyConfigurationChanged();
Jeff Brown4532e612012-04-05 14:27:12 -07001828 }
1829
1830 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001831 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1832 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001833 if (!mInputDevicesChangedPending) {
1834 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001835 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1836 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001837 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001838
1839 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001840 }
1841 }
1842
1843 // Native callback.
Jeff Brownbcc046a2012-09-27 20:46:43 -07001844 private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1845 if (DEBUG) {
1846 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1847 + ", mask=" + Integer.toHexString(switchMask));
1848 }
1849
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001850 if ((switchMask & SW_LID_BIT) != 0) {
1851 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
Jeff Brownbcc046a2012-09-27 20:46:43 -07001852 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
Jeff Brown53384282012-08-20 20:16:01 -07001853 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001854
Michael Wright3818c922014-09-02 13:59:07 -07001855 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
Michael Wright9e10d252014-09-13 19:41:20 -07001856 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
Michael Wright3818c922014-09-02 13:59:07 -07001857 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1858 }
1859
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001860 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1861 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1862 switchMask);
1863 }
Michael Wright39e5e942015-08-19 22:52:47 +01001864
Michael Wright9209c9c2015-09-03 17:57:01 +01001865 if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
Michael Wright39e5e942015-08-19 22:52:47 +01001866 SomeArgs args = SomeArgs.obtain();
1867 args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
1868 args.argi2 = (int) (whenNanos >> 32);
1869 args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
1870 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
1871 args).sendToTarget();
1872 }
Jeff Brown4532e612012-04-05 14:27:12 -07001873 }
1874
1875 // Native callback.
1876 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001877 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
Jeff Brown4532e612012-04-05 14:27:12 -07001878 }
1879
1880 // Native callback.
1881 private long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001882 InputWindowHandle inputWindowHandle, String reason) {
1883 return mWindowManagerCallbacks.notifyANR(
1884 inputApplicationHandle, inputWindowHandle, reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001885 }
1886
1887 // Native callback.
1888 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1889 synchronized (mInputFilterLock) {
1890 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001891 try {
1892 mInputFilter.filterInputEvent(event, policyFlags);
1893 } catch (RemoteException e) {
1894 /* ignore */
1895 }
Jeff Brown4532e612012-04-05 14:27:12 -07001896 return false;
1897 }
1898 }
1899 event.recycle();
1900 return true;
1901 }
1902
1903 // Native callback.
Jeff Brown037c33e2014-04-09 00:31:55 -07001904 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1905 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001906 }
1907
1908 // Native callback.
Michael Wright70af00a2014-09-03 19:30:20 -07001909 private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
1910 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
Jeff Brown26875502014-01-30 21:47:47 -08001911 whenNanos, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001912 }
1913
1914 // Native callback.
1915 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1916 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001917 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001918 }
1919
1920 // Native callback.
1921 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1922 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001923 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001924 }
1925
1926 // Native callback.
1927 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1928 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1929 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1930 }
1931
1932 // Native callback.
1933 private int getVirtualKeyQuietTimeMillis() {
1934 return mContext.getResources().getInteger(
1935 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1936 }
1937
1938 // Native callback.
1939 private String[] getExcludedDeviceNames() {
1940 ArrayList<String> names = new ArrayList<String>();
1941
1942 // Read partner-provided list of excluded input devices
1943 XmlPullParser parser = null;
1944 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1945 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1946 FileReader confreader = null;
1947 try {
1948 confreader = new FileReader(confFile);
1949 parser = Xml.newPullParser();
1950 parser.setInput(confreader);
1951 XmlUtils.beginDocument(parser, "devices");
1952
1953 while (true) {
1954 XmlUtils.nextElement(parser);
1955 if (!"device".equals(parser.getName())) {
1956 break;
1957 }
1958 String name = parser.getAttributeValue(null, "name");
1959 if (name != null) {
1960 names.add(name);
1961 }
1962 }
1963 } catch (FileNotFoundException e) {
1964 // It's ok if the file does not exist.
1965 } catch (Exception e) {
1966 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1967 } finally {
1968 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1969 }
1970
1971 return names.toArray(new String[names.size()]);
1972 }
1973
1974 // Native callback.
1975 private int getKeyRepeatTimeout() {
1976 return ViewConfiguration.getKeyRepeatTimeout();
1977 }
1978
1979 // Native callback.
1980 private int getKeyRepeatDelay() {
1981 return ViewConfiguration.getKeyRepeatDelay();
1982 }
1983
1984 // Native callback.
1985 private int getHoverTapTimeout() {
1986 return ViewConfiguration.getHoverTapTimeout();
1987 }
1988
1989 // Native callback.
1990 private int getHoverTapSlop() {
1991 return ViewConfiguration.getHoverTapSlop();
1992 }
1993
1994 // Native callback.
1995 private int getDoubleTapTimeout() {
1996 return ViewConfiguration.getDoubleTapTimeout();
1997 }
1998
1999 // Native callback.
2000 private int getLongPressTimeout() {
2001 return ViewConfiguration.getLongPressTimeout();
2002 }
2003
2004 // Native callback.
2005 private int getPointerLayer() {
Jeff Browna9d131c2012-09-20 16:48:17 -07002006 return mWindowManagerCallbacks.getPointerLayer();
Jeff Brown4532e612012-04-05 14:27:12 -07002007 }
2008
2009 // Native callback.
2010 private PointerIcon getPointerIcon() {
2011 return PointerIcon.getDefaultIcon(mContext);
2012 }
2013
Jeff Brown6ec6f792012-04-17 16:52:41 -07002014 // Native callback.
RoboErikfb290df2013-12-16 11:27:55 -08002015 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07002016 if (!mSystemReady) {
2017 return null;
2018 }
2019
RoboErikfb290df2013-12-16 11:27:55 -08002020 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002021 if (keyboardLayoutDescriptor == null) {
2022 return null;
2023 }
2024
2025 final String[] result = new String[2];
2026 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
2027 @Override
Michael Wright07483422015-10-30 16:20:13 +00002028 public void visitKeyboardLayout(Resources resources,
2029 int keyboardLayoutResId, KeyboardLayout layout) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07002030 try {
Michael Wright07483422015-10-30 16:20:13 +00002031 result[0] = layout.getDescriptor();
Jeff Brown6ec6f792012-04-17 16:52:41 -07002032 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07002033 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07002034 } catch (IOException ex) {
2035 } catch (NotFoundException ex) {
2036 }
2037 }
2038 });
2039 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00002040 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07002041 + keyboardLayoutDescriptor + "'.");
2042 return null;
2043 }
2044 return result;
2045 }
2046
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002047 // Native callback.
2048 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07002049 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
2050 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
2051 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002052 }
2053 return null;
2054 }
2055
Jeff Brown4532e612012-04-05 14:27:12 -07002056 /**
2057 * Callback interface implemented by the Window Manager.
2058 */
Jeff Browna9d131c2012-09-20 16:48:17 -07002059 public interface WindowManagerCallbacks {
Jeff Brown4532e612012-04-05 14:27:12 -07002060 public void notifyConfigurationChanged();
2061
2062 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
2063
Michael Wright3818c922014-09-02 13:59:07 -07002064 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
2065
Jeff Brown4532e612012-04-05 14:27:12 -07002066 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
2067
2068 public long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07002069 InputWindowHandle inputWindowHandle, String reason);
Jeff Brown4532e612012-04-05 14:27:12 -07002070
Jeff Brown037c33e2014-04-09 00:31:55 -07002071 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002072
Michael Wright70af00a2014-09-03 19:30:20 -07002073 public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002074
2075 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
2076 KeyEvent event, int policyFlags);
2077
2078 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
2079 KeyEvent event, int policyFlags);
2080
2081 public int getPointerLayer();
2082 }
2083
2084 /**
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002085 * Callback interface implemented by WiredAccessoryObserver.
2086 */
2087 public interface WiredAccessoryCallbacks {
2088 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002089 public void systemReady();
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002090 }
2091
2092 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002093 * Private handler for the input manager.
2094 */
2095 private final class InputManagerHandler extends Handler {
Jeff Browna9d131c2012-09-20 16:48:17 -07002096 public InputManagerHandler(Looper looper) {
2097 super(looper, null, true /*async*/);
Jeff Browna2910d02012-08-25 12:29:46 -07002098 }
2099
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002100 @Override
2101 public void handleMessage(Message msg) {
2102 switch (msg.what) {
2103 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07002104 deliverInputDevicesChanged((InputDevice[])msg.obj);
2105 break;
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002106 case MSG_SWITCH_KEYBOARD_LAYOUT: {
2107 SomeArgs args = (SomeArgs)msg.obj;
2108 handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1,
2109 (InputMethodSubtypeHandle)args.arg2);
Jeff Browncf39bdf2012-05-18 14:41:19 -07002110 break;
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002111 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07002112 case MSG_RELOAD_KEYBOARD_LAYOUTS:
2113 reloadKeyboardLayouts();
2114 break;
2115 case MSG_UPDATE_KEYBOARD_LAYOUTS:
2116 updateKeyboardLayouts();
2117 break;
2118 case MSG_RELOAD_DEVICE_ALIASES:
2119 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002120 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08002121 case MSG_DELIVER_TABLET_MODE_CHANGED: {
Michael Wright39e5e942015-08-19 22:52:47 +01002122 SomeArgs args = (SomeArgs) msg.obj;
2123 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
2124 boolean inTabletMode = (boolean) args.arg1;
2125 deliverTabletModeChanged(whenNanos, inTabletMode);
2126 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08002127 }
2128 case MSG_INPUT_METHOD_SUBTYPE_CHANGED: {
2129 final int userId = msg.arg1;
2130 final SomeArgs args = (SomeArgs) msg.obj;
2131 final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1;
2132 final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2;
2133 args.recycle();
2134 handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype);
2135 break;
2136 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002137 }
2138 }
2139 }
2140
2141 /**
Jeff Brown4532e612012-04-05 14:27:12 -07002142 * Hosting interface for input filters to call back into the input manager.
2143 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07002144 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07002145 private boolean mDisconnected;
2146
2147 public void disconnectLocked() {
2148 mDisconnected = true;
2149 }
2150
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002151 @Override
Jeff Brown0029c662011-03-30 02:25:18 -07002152 public void sendInputEvent(InputEvent event, int policyFlags) {
2153 if (event == null) {
2154 throw new IllegalArgumentException("event must not be null");
2155 }
2156
2157 synchronized (mInputFilterLock) {
2158 if (!mDisconnected) {
Jeff Brownca9bc702014-02-11 14:32:56 -08002159 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
Jeff Brownac143512012-04-05 18:57:33 -07002160 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07002161 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
2162 }
2163 }
2164 }
2165 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07002166
2167 private static final class KeyboardLayoutDescriptor {
2168 public String packageName;
2169 public String receiverName;
2170 public String keyboardLayoutName;
2171
2172 public static String format(String packageName,
2173 String receiverName, String keyboardName) {
2174 return packageName + "/" + receiverName + "/" + keyboardName;
2175 }
2176
2177 public static KeyboardLayoutDescriptor parse(String descriptor) {
2178 int pos = descriptor.indexOf('/');
2179 if (pos < 0 || pos + 1 == descriptor.length()) {
2180 return null;
2181 }
2182 int pos2 = descriptor.indexOf('/', pos + 1);
2183 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
2184 return null;
2185 }
2186
2187 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
2188 result.packageName = descriptor.substring(0, pos);
2189 result.receiverName = descriptor.substring(pos + 1, pos2);
2190 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
2191 return result;
2192 }
2193 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002194
Jeff Brown6ec6f792012-04-17 16:52:41 -07002195 private interface KeyboardLayoutVisitor {
Michael Wright07483422015-10-30 16:20:13 +00002196 void visitKeyboardLayout(Resources resources,
2197 int keyboardLayoutResId, KeyboardLayout layout);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002198 }
2199
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002200 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
2201 private final int mPid;
2202 private final IInputDevicesChangedListener mListener;
2203
2204 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
2205 mPid = pid;
2206 mListener = listener;
2207 }
2208
2209 @Override
2210 public void binderDied() {
2211 if (DEBUG) {
2212 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
2213 }
2214 onInputDevicesChangedListenerDied(mPid);
2215 }
2216
2217 public void notifyInputDevicesChanged(int[] info) {
2218 try {
2219 mListener.onInputDevicesChanged(info);
2220 } catch (RemoteException ex) {
2221 Slog.w(TAG, "Failed to notify process "
2222 + mPid + " that input devices changed, assuming it died.", ex);
2223 binderDied();
2224 }
2225 }
2226 }
Jeff Browna47425a2012-04-13 04:09:27 -07002227
Michael Wright39e5e942015-08-19 22:52:47 +01002228 private final class TabletModeChangedListenerRecord implements DeathRecipient {
2229 private final int mPid;
2230 private final ITabletModeChangedListener mListener;
2231
2232 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
2233 mPid = pid;
2234 mListener = listener;
2235 }
2236
2237 @Override
2238 public void binderDied() {
2239 if (DEBUG) {
2240 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
2241 }
2242 onTabletModeChangedListenerDied(mPid);
2243 }
2244
2245 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
2246 try {
2247 mListener.onTabletModeChanged(whenNanos, inTabletMode);
2248 } catch (RemoteException ex) {
2249 Slog.w(TAG, "Failed to notify process " + mPid +
2250 " that tablet mode changed, assuming it died.", ex);
2251 binderDied();
2252 }
2253 }
2254 }
2255
Jeff Browna47425a2012-04-13 04:09:27 -07002256 private final class VibratorToken implements DeathRecipient {
2257 public final int mDeviceId;
2258 public final IBinder mToken;
2259 public final int mTokenValue;
2260
2261 public boolean mVibrating;
2262
2263 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
2264 mDeviceId = deviceId;
2265 mToken = token;
2266 mTokenValue = tokenValue;
2267 }
2268
2269 @Override
2270 public void binderDied() {
2271 if (DEBUG) {
2272 Slog.d(TAG, "Vibrator token died.");
2273 }
2274 onVibratorTokenDied(this);
2275 }
2276 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002277
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002278 private class Shell extends ShellCommand {
2279 @Override
2280 public int onCommand(String cmd) {
2281 return onShellCommand(this, cmd);
2282 }
2283
2284 @Override
2285 public void onHelp() {
2286 final PrintWriter pw = getOutPrintWriter();
2287 pw.println("Input manager commands:");
2288 pw.println(" help");
2289 pw.println(" Print this help text.");
2290 pw.println("");
2291 pw.println(" setlayout IME_ID IME_SUPTYPE_HASH_CODE"
2292 + " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR");
2293 pw.println(" Sets a keyboard layout for a given IME subtype and input device pair");
2294 }
2295 }
2296
Jeff Brown4ccb8232014-01-16 22:16:42 -08002297 private final class LocalService extends InputManagerInternal {
2298 @Override
2299 public void setDisplayViewports(
2300 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
2301 setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
2302 }
Jeff Brownca9bc702014-02-11 14:32:56 -08002303
2304 @Override
2305 public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
2306 return injectInputEventInternal(event, displayId, mode);
2307 }
Jeff Brown037c33e2014-04-09 00:31:55 -07002308
2309 @Override
2310 public void setInteractive(boolean interactive) {
2311 nativeSetInteractive(mPtr, interactive);
2312 }
Yohei Yukawab097b822015-12-01 10:43:08 -08002313
2314 @Override
2315 public void onInputMethodSubtypeChanged(int userId,
2316 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
2317 final SomeArgs someArgs = SomeArgs.obtain();
2318 someArgs.arg1 = inputMethodInfo;
2319 someArgs.arg2 = subtype;
2320 mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs)
2321 .sendToTarget();
2322 }
Andrii Kulian112d0562016-03-08 10:44:22 -08002323
2324 @Override
2325 public void toggleCapsLock(int deviceId) {
2326 nativeToggleCapsLock(mPtr, deviceId);
2327 }
Adrian Roos99182342016-06-15 15:30:46 -07002328
2329 @Override
2330 public void setPulseGestureEnabled(boolean enabled) {
2331 if (mDoubleTouchGestureEnableFile != null) {
2332 FileWriter writer = null;
2333 try {
2334 writer = new FileWriter(mDoubleTouchGestureEnableFile);
2335 writer.write(enabled ? "1" : "0");
2336 } catch (IOException e) {
2337 Log.wtf(TAG, "Unable to setPulseGestureEnabled", e);
2338 } finally {
2339 IoUtils.closeQuietly(writer);
2340 }
2341 }
2342 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002343 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07002344}