blob: fbb393846c52127815052991b31e2ad650a56845 [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;
Michael Wright39e5e942015-08-19 22:52:47 +010026import com.android.internal.os.SomeArgs;
Jeff Browncf39bdf2012-05-18 14:41:19 -070027import com.android.internal.R;
Michael Wrightb004b512017-01-18 18:09:29 +000028import com.android.internal.util.Preconditions;
Jeff Brown46b9ac02010-04-22 18:58:52 -070029import com.android.internal.util.XmlUtils;
Jeff Brown4ccb8232014-01-16 22:16:42 -080030import com.android.server.DisplayThread;
31import com.android.server.LocalServices;
Jeff Brown89ef0722011-08-10 16:25:21 -070032import com.android.server.Watchdog;
Jeff Brown46b9ac02010-04-22 18:58:52 -070033
34import org.xmlpull.v1.XmlPullParser;
35
Jeff Browna3bc5652012-04-17 11:42:25 -070036import android.Manifest;
Jeff Browncf39bdf2012-05-18 14:41:19 -070037import android.app.Notification;
38import android.app.NotificationManager;
39import android.app.PendingIntent;
Jeff Brown5bbd4b42012-04-20 19:28:00 -070040import android.bluetooth.BluetoothAdapter;
41import android.bluetooth.BluetoothDevice;
Jeff Brown6ec6f792012-04-17 16:52:41 -070042import android.content.BroadcastReceiver;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070043import android.content.ComponentName;
Jeff Brown46b9ac02010-04-22 18:58:52 -070044import android.content.Context;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070045import android.content.Intent;
Jeff Brown6ec6f792012-04-17 16:52:41 -070046import android.content.IntentFilter;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070047import android.content.pm.ActivityInfo;
Michael Wright8ebac232014-09-18 18:29:49 -070048import android.content.pm.ApplicationInfo;
Jeff Brown349703e2010-06-22 01:27:15 -070049import android.content.pm.PackageManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070050import android.content.pm.ResolveInfo;
51import android.content.pm.PackageManager.NameNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070052import android.content.res.Resources;
Jeff Brown6ec6f792012-04-17 16:52:41 -070053import android.content.res.Resources.NotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070054import android.content.res.TypedArray;
55import android.content.res.XmlResourceParser;
Jeff Brown1a84fd12011-06-02 01:26:32 -070056import android.database.ContentObserver;
Jeff Brown4ccb8232014-01-16 22:16:42 -080057import android.hardware.display.DisplayViewport;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070058import android.hardware.input.IInputDevicesChangedListener;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070059import android.hardware.input.IInputManager;
RoboErikfb290df2013-12-16 11:27:55 -080060import android.hardware.input.InputDeviceIdentifier;
Jeff Brownac143512012-04-05 18:57:33 -070061import android.hardware.input.InputManager;
Jeff Brown4ccb8232014-01-16 22:16:42 -080062import android.hardware.input.InputManagerInternal;
Michael Wright39e5e942015-08-19 22:52:47 +010063import android.hardware.input.ITabletModeChangedListener;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070064import android.hardware.input.KeyboardLayout;
Jason Gerecked6396d62014-01-27 18:30:37 -080065import android.hardware.input.TouchCalibration;
Jeff Brown4532e612012-04-05 14:27:12 -070066import android.os.Binder;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070067import android.os.Bundle;
Jeff Brown46b9ac02010-04-22 18:58:52 -070068import android.os.Environment;
Jeff Brown4532e612012-04-05 14:27:12 -070069import android.os.Handler;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070070import android.os.IBinder;
Jeff Browna9d131c2012-09-20 16:48:17 -070071import android.os.Looper;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070072import android.os.Message;
Jeff Brown05dc66a2011-03-02 14:41:58 -080073import android.os.MessageQueue;
Jeff Brownac143512012-04-05 18:57:33 -070074import android.os.Process;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070075import android.os.RemoteException;
Michael Wrightd5f7ed92016-01-19 11:23:51 -080076import android.os.ResultReceiver;
77import android.os.ShellCommand;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070078import android.os.UserHandle;
Jeff Brown1a84fd12011-06-02 01:26:32 -070079import android.provider.Settings;
80import android.provider.Settings.SettingNotFoundException;
Michael Wright07483422015-10-30 16:20:13 +000081import android.text.TextUtils;
Jeff Brown46b9ac02010-04-22 18:58:52 -070082import android.util.Slog;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070083import android.util.SparseArray;
Jeff Brown46b9ac02010-04-22 18:58:52 -070084import android.util.Xml;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070085import android.view.IInputFilter;
86import android.view.IInputFilterHost;
Jeff Brown46b9ac02010-04-22 18:58:52 -070087import android.view.InputChannel;
Jeff Brown8d608662010-08-30 03:02:23 -070088import android.view.InputDevice;
Jeff Brown6ec402b2010-07-28 15:48:59 -070089import android.view.InputEvent;
Jeff Brown1f245102010-11-18 20:53:46 -080090import android.view.KeyEvent;
Jeff Brown2352b972011-04-12 22:39:53 -070091import android.view.PointerIcon;
Jason Gerecked5220742014-03-10 09:47:59 -070092import android.view.Surface;
Jeff Browna4547672011-03-02 21:38:11 -080093import android.view.ViewConfiguration;
Jeff Brown0029c662011-03-30 02:25:18 -070094import android.view.WindowManagerPolicy;
Yohei Yukawab097b822015-12-01 10:43:08 -080095import android.view.inputmethod.InputMethodInfo;
96import android.view.inputmethod.InputMethodSubtype;
Jeff Brown46b9ac02010-04-22 18:58:52 -070097
Jeff Brown46b9ac02010-04-22 18:58:52 -070098import java.io.File;
Jeff Brown4532e612012-04-05 14:27:12 -070099import java.io.FileDescriptor;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700100import java.io.FileNotFoundException;
101import java.io.FileReader;
Adrian Roos99182342016-06-15 15:30:46 -0700102import java.io.FileWriter;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700103import java.io.IOException;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700104import java.io.InputStreamReader;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700105import java.io.PrintWriter;
106import java.util.ArrayList;
Michael Wright07483422015-10-30 16:20:13 +0000107import java.util.Collections;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700108import java.util.HashMap;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700109import java.util.HashSet;
Michael Wright39e5e942015-08-19 22:52:47 +0100110import java.util.List;
Michael Wright07483422015-10-30 16:20:13 +0000111import java.util.Locale;
Jeff Browna3bc5652012-04-17 11:42:25 -0700112
Adrian Roos99182342016-06-15 15:30:46 -0700113import libcore.io.IoUtils;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700114import libcore.io.Streams;
Jeff Browna3bc5652012-04-17 11:42:25 -0700115import libcore.util.Objects;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700116
117/*
118 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -0700119 */
Jeff Brownd728bf52012-09-08 18:05:28 -0700120public class InputManagerService extends IInputManager.Stub
Jeff Brown4ccb8232014-01-16 22:16:42 -0800121 implements Watchdog.Monitor {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700122 static final String TAG = "InputManager";
Jeff Brown1b9ba572012-05-21 10:54:18 -0700123 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -0700124
Jeff Brown4532e612012-04-05 14:27:12 -0700125 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
126
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700127 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700128 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
129 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
130 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
131 private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
Michael Wright39e5e942015-08-19 22:52:47 +0100132 private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
Yohei Yukawab097b822015-12-01 10:43:08 -0800133 private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700134
Jeff Brown4532e612012-04-05 14:27:12 -0700135 // Pointer to native input manager service object.
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000136 private final long mPtr;
Jeff Brown4532e612012-04-05 14:27:12 -0700137
Jeff Brown46b9ac02010-04-22 18:58:52 -0700138 private final Context mContext;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700139 private final InputManagerHandler mHandler;
Jeff Browna9d131c2012-09-20 16:48:17 -0700140
Adrian Roos99182342016-06-15 15:30:46 -0700141 private final File mDoubleTouchGestureEnableFile;
142
Jeff Browna9d131c2012-09-20 16:48:17 -0700143 private WindowManagerCallbacks mWindowManagerCallbacks;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700144 private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700145 private boolean mSystemReady;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700146 private NotificationManager mNotificationManager;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700147
Michael Wright39e5e942015-08-19 22:52:47 +0100148 private final Object mTabletModeLock = new Object();
149 // List of currently registered tablet mode changed listeners by process id
150 private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
151 new SparseArray<>(); // guarded by mTabletModeLock
152 private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
153 new ArrayList<>();
154
Jeff Browna3bc5652012-04-17 11:42:25 -0700155 // Persistent data store. Must be locked each time during use.
156 private final PersistentDataStore mDataStore = new PersistentDataStore();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700157
158 // List of currently registered input devices changed listeners by process id.
159 private Object mInputDevicesLock = new Object();
160 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
161 private InputDevice[] mInputDevices = new InputDevice[0];
162 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
163 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
164 private final ArrayList<InputDevicesChangedListenerRecord>
165 mTempInputDevicesChangedListenersToNotify =
166 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
Jeff Browncf39bdf2012-05-18 14:41:19 -0700167 private final ArrayList<InputDevice>
168 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
169 private boolean mKeyboardLayoutNotificationShown;
Michael Wrightd5f7ed92016-01-19 11:23:51 -0800170 private InputMethodSubtypeHandle mCurrentImeHandle;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700171
Jeff Browna47425a2012-04-13 04:09:27 -0700172 // State for vibrator tokens.
173 private Object mVibratorLock = new Object();
174 private HashMap<IBinder, VibratorToken> mVibratorTokens =
175 new HashMap<IBinder, VibratorToken>();
176 private int mNextVibratorTokenValue;
177
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700178 // State for the currently installed input filter.
179 final Object mInputFilterLock = new Object();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700180 IInputFilter mInputFilter; // guarded by mInputFilterLock
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700181 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
Jeff Brown1a84fd12011-06-02 01:26:32 -0700182
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000183 private static native long nativeInit(InputManagerService service,
Jeff Brown4532e612012-04-05 14:27:12 -0700184 Context context, MessageQueue messageQueue);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000185 private static native void nativeStart(long ptr);
186 private static native void nativeSetDisplayViewport(long ptr, boolean external,
Jeff Brownd728bf52012-09-08 18:05:28 -0700187 int displayId, int rotation,
188 int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
Jeff Brown83d616a2012-09-09 20:33:43 -0700189 int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
190 int deviceWidth, int deviceHeight);
Jeff Brownd728bf52012-09-08 18:05:28 -0700191
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000192 private static native int nativeGetScanCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700193 int deviceId, int sourceMask, int scanCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000194 private static native int nativeGetKeyCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700195 int deviceId, int sourceMask, int keyCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000196 private static native int nativeGetSwitchState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700197 int deviceId, int sourceMask, int sw);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000198 private static native boolean nativeHasKeys(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700199 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000200 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
Jeff Brown928e0542011-01-10 11:17:36 -0800201 InputWindowHandle inputWindowHandle, boolean monitor);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000202 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
203 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
Jeff Brownca9bc702014-02-11 14:32:56 -0800204 private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId,
Jeff Brown0029c662011-03-30 02:25:18 -0700205 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
206 int policyFlags);
Andrii Kulian112d0562016-03-08 10:44:22 -0800207 private static native void nativeToggleCapsLock(long ptr, int deviceId);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000208 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
209 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
210 private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
211 private static native void nativeSetFocusedApplication(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700212 InputApplicationHandle application);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000213 private static native boolean nativeTransferTouchFocus(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700214 InputChannel fromChannel, InputChannel toChannel);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000215 private static native void nativeSetPointerSpeed(long ptr, int speed);
216 private static native void nativeSetShowTouches(long ptr, boolean enabled);
Jeff Brown037c33e2014-04-09 00:31:55 -0700217 private static native void nativeSetInteractive(long ptr, boolean interactive);
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800218 private static native void nativeReloadCalibration(long ptr);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000219 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
Jeff Browna47425a2012-04-13 04:09:27 -0700220 int repeat, int token);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000221 private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
222 private static native void nativeReloadKeyboardLayouts(long ptr);
223 private static native void nativeReloadDeviceAliases(long ptr);
224 private static native String nativeDump(long ptr);
225 private static native void nativeMonitor(long ptr);
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100226 private static native void nativeSetPointerIconType(long ptr, int iconId);
Jun Mukai19a56012015-11-24 11:25:52 -0800227 private static native void nativeReloadPointerIcons(long ptr);
Jun Mukaid4eaef72015-10-30 15:54:33 -0700228 private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
Jeff Brown4532e612012-04-05 14:27:12 -0700229
Jeff Brownac143512012-04-05 18:57:33 -0700230 // Input event injection constants defined in InputDispatcher.h.
231 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
232 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
233 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
234 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
235
236 // Maximum number of milliseconds to wait for input event injection.
237 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
238
Jeff Brown6d0fec22010-07-23 21:28:06 -0700239 // Key states (may be returned by queries about the current state of a
240 // particular key code, scan code or switch).
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700241
Jeff Brown6d0fec22010-07-23 21:28:06 -0700242 /** The key state is unknown or the requested key itself is not supported. */
243 public static final int KEY_STATE_UNKNOWN = -1;
244
245 /** The key is up. /*/
246 public static final int KEY_STATE_UP = 0;
247
248 /** The key is down. */
249 public static final int KEY_STATE_DOWN = 1;
250
251 /** The key is down but is a virtual key press that is being emulated by the system. */
252 public static final int KEY_STATE_VIRTUAL = 2;
253
Jeff Brownc458ce92012-04-30 14:58:40 -0700254 /** Scan code: Mouse / trackball button. */
255 public static final int BTN_MOUSE = 0x110;
256
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700257 // Switch code values must match bionic/libc/kernel/common/linux/input.h
Jeff Brownc458ce92012-04-30 14:58:40 -0700258 /** Switch code: Lid switch. When set, lid is shut. */
259 public static final int SW_LID = 0x00;
260
Michael Wright39e5e942015-08-19 22:52:47 +0100261 /** Switch code: Tablet mode switch.
262 * When set, the device is in tablet mode (i.e. no keyboard is connected).
263 */
264 public static final int SW_TABLET_MODE = 0x01;
265
Jeff Brownc458ce92012-04-30 14:58:40 -0700266 /** Switch code: Keypad slide. When set, keyboard is exposed. */
267 public static final int SW_KEYPAD_SLIDE = 0x0a;
268
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700269 /** Switch code: Headphone. When set, headphone is inserted. */
270 public static final int SW_HEADPHONE_INSERT = 0x02;
271
272 /** Switch code: Microphone. When set, microphone is inserted. */
273 public static final int SW_MICROPHONE_INSERT = 0x04;
274
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500275 /** Switch code: Line out. When set, Line out (hi-Z) is inserted. */
276 public static final int SW_LINEOUT_INSERT = 0x06;
277
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700278 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */
279 public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
280
Michael Wright3818c922014-09-02 13:59:07 -0700281 /** Switch code: Camera lens cover. When set the lens is covered. */
282 public static final int SW_CAMERA_LENS_COVER = 0x09;
283
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700284 public static final int SW_LID_BIT = 1 << SW_LID;
Michael Wright39e5e942015-08-19 22:52:47 +0100285 public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700286 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
287 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
288 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500289 public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700290 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
291 public static final int SW_JACK_BITS =
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500292 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
Michael Wright3818c922014-09-02 13:59:07 -0700293 public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700294
295 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
296 final boolean mUseDevInputEventForAudioJack;
297
Jeff Brown4ccb8232014-01-16 22:16:42 -0800298 public InputManagerService(Context context) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700299 this.mContext = context;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800300 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
Jeff Brown05dc66a2011-03-02 14:41:58 -0800301
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700302 mUseDevInputEventForAudioJack =
303 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
304 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
305 + mUseDevInputEventForAudioJack);
Jeff Brown4532e612012-04-05 14:27:12 -0700306 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown4ccb8232014-01-16 22:16:42 -0800307
Adrian Roos99182342016-06-15 15:30:46 -0700308 String doubleTouchGestureEnablePath = context.getResources().getString(
309 R.string.config_doubleTouchGestureEnableFile);
310 mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
311 new File(doubleTouchGestureEnablePath);
312
Jeff Brown4ccb8232014-01-16 22:16:42 -0800313 LocalServices.addService(InputManagerInternal.class, new LocalService());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700314 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700315
Jeff Browna9d131c2012-09-20 16:48:17 -0700316 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
317 mWindowManagerCallbacks = callbacks;
318 }
319
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700320 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
321 mWiredAccessoryCallbacks = callbacks;
322 }
323
Jeff Brown46b9ac02010-04-22 18:58:52 -0700324 public void start() {
325 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700326 nativeStart(mPtr);
327
328 // Add ourself to the Watchdog monitors.
329 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700330
331 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700332 registerShowTouchesSettingObserver();
Jun Mukai19a56012015-11-24 11:25:52 -0800333 registerAccessibilityLargePointerSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700334
Jeff Brownd4935962012-09-25 13:27:20 -0700335 mContext.registerReceiver(new BroadcastReceiver() {
336 @Override
337 public void onReceive(Context context, Intent intent) {
338 updatePointerSpeedFromSettings();
339 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800340 updateAccessibilityLargePointerFromSettings();
Jeff Brownd4935962012-09-25 13:27:20 -0700341 }
342 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
343
Jeff Brown1a84fd12011-06-02 01:26:32 -0700344 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700345 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800346 updateAccessibilityLargePointerFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700347 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700348
Matthew Xie96313142012-06-29 16:57:31 -0700349 // TODO(BT) Pass in paramter for bluetooth system
Svetoslav Ganova0027152013-06-25 14:59:53 -0700350 public void systemRunning() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700351 if (DEBUG) {
352 Slog.d(TAG, "System ready.");
353 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700354 mNotificationManager = (NotificationManager)mContext.getSystemService(
355 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700356 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700357
358 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
359 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
360 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Jeff Brown69b07162013-11-07 00:30:16 -0800361 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700362 filter.addDataScheme("package");
363 mContext.registerReceiver(new BroadcastReceiver() {
364 @Override
365 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700366 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700367 }
368 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700369
370 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
371 mContext.registerReceiver(new BroadcastReceiver() {
372 @Override
373 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700374 reloadDeviceAliases();
375 }
376 }, filter, null, mHandler);
377
Jeff Browncf39bdf2012-05-18 14:41:19 -0700378 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
379 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700380
381 if (mWiredAccessoryCallbacks != null) {
382 mWiredAccessoryCallbacks.systemReady();
383 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700384 }
385
386 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700387 if (DEBUG) {
388 Slog.d(TAG, "Reloading keyboard layouts.");
389 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700390 nativeReloadKeyboardLayouts(mPtr);
391 }
392
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700393 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700394 if (DEBUG) {
395 Slog.d(TAG, "Reloading device names.");
396 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700397 nativeReloadDeviceAliases(mPtr);
398 }
399
Jeff Brown4ccb8232014-01-16 22:16:42 -0800400 private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
Jeff Brownd728bf52012-09-08 18:05:28 -0700401 DisplayViewport externalTouchViewport) {
402 if (defaultViewport.valid) {
403 setDisplayViewport(false, defaultViewport);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700404 }
Jeff Brownd728bf52012-09-08 18:05:28 -0700405
406 if (externalTouchViewport.valid) {
407 setDisplayViewport(true, externalTouchViewport);
408 } else if (defaultViewport.valid) {
409 setDisplayViewport(true, defaultViewport);
Jeff Brownb6997262010-10-08 22:31:17 -0700410 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700411 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700412
Jeff Brownd728bf52012-09-08 18:05:28 -0700413 private void setDisplayViewport(boolean external, DisplayViewport viewport) {
414 nativeSetDisplayViewport(mPtr, external,
415 viewport.displayId, viewport.orientation,
416 viewport.logicalFrame.left, viewport.logicalFrame.top,
417 viewport.logicalFrame.right, viewport.logicalFrame.bottom,
418 viewport.physicalFrame.left, viewport.physicalFrame.top,
Jeff Brown83d616a2012-09-09 20:33:43 -0700419 viewport.physicalFrame.right, viewport.physicalFrame.bottom,
420 viewport.deviceWidth, viewport.deviceHeight);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700421 }
Jeff Brownac143512012-04-05 18:57:33 -0700422
Jeff Brown6d0fec22010-07-23 21:28:06 -0700423 /**
424 * Gets the current state of a key or button by key code.
425 * @param deviceId The input device id, or -1 to consult all devices.
426 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
427 * consider all input sources. An input device is consulted if at least one of its
428 * non-class input source bits matches the specified source mask.
429 * @param keyCode The key code to check.
430 * @return The key state.
431 */
432 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700433 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700434 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700435
Jeff Brown6d0fec22010-07-23 21:28:06 -0700436 /**
437 * Gets the current state of a key or button by scan code.
438 * @param deviceId The input device id, or -1 to consult all devices.
439 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
440 * consider all input sources. An input device is consulted if at least one of its
441 * non-class input source bits matches the specified source mask.
442 * @param scanCode The scan code to check.
443 * @return The key state.
444 */
445 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700446 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700447 }
RoboErikfb290df2013-12-16 11:27:55 -0800448
Jeff Brown6d0fec22010-07-23 21:28:06 -0700449 /**
450 * Gets the current state of a switch by switch code.
451 * @param deviceId The input device id, or -1 to consult all devices.
452 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
453 * consider all input sources. An input device is consulted if at least one of its
454 * non-class input source bits matches the specified source mask.
455 * @param switchCode The switch code to check.
456 * @return The switch state.
457 */
458 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700459 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700460 }
461
Jeff Brown6d0fec22010-07-23 21:28:06 -0700462 /**
463 * Determines whether the specified key codes are supported by a particular device.
464 * @param deviceId The input device id, or -1 to consult all devices.
465 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
466 * consider all input sources. An input device is consulted if at least one of its
467 * non-class input source bits matches the specified source mask.
468 * @param keyCodes The array of key codes to check.
469 * @param keyExists An array at least as large as keyCodes whose entries will be set
470 * to true or false based on the presence or absence of support for the corresponding
471 * key codes.
472 * @return True if the lookup was successful, false otherwise.
473 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700474 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700475 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700476 if (keyCodes == null) {
477 throw new IllegalArgumentException("keyCodes must not be null.");
478 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700479 if (keyExists == null || keyExists.length < keyCodes.length) {
480 throw new IllegalArgumentException("keyExists must not be null and must be at "
481 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700482 }
RoboErikfb290df2013-12-16 11:27:55 -0800483
Jeff Brown4532e612012-04-05 14:27:12 -0700484 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700485 }
RoboErikfb290df2013-12-16 11:27:55 -0800486
Jeff Browna41ca772010-08-11 14:46:32 -0700487 /**
488 * Creates an input channel that will receive all input from the input dispatcher.
489 * @param inputChannelName The input channel name.
490 * @return The input channel.
491 */
492 public InputChannel monitorInput(String inputChannelName) {
493 if (inputChannelName == null) {
494 throw new IllegalArgumentException("inputChannelName must not be null.");
495 }
RoboErikfb290df2013-12-16 11:27:55 -0800496
Jeff Browna41ca772010-08-11 14:46:32 -0700497 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700498 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700499 inputChannels[0].dispose(); // don't need to retain the Java object reference
500 return inputChannels[1];
501 }
502
503 /**
504 * Registers an input channel so that it can be used as an input event target.
505 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800506 * @param inputWindowHandle The handle of the input window associated with the
507 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700508 */
Jeff Brown928e0542011-01-10 11:17:36 -0800509 public void registerInputChannel(InputChannel inputChannel,
510 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700511 if (inputChannel == null) {
512 throw new IllegalArgumentException("inputChannel must not be null.");
513 }
RoboErikfb290df2013-12-16 11:27:55 -0800514
Jeff Brown4532e612012-04-05 14:27:12 -0700515 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700516 }
RoboErikfb290df2013-12-16 11:27:55 -0800517
Jeff Browna41ca772010-08-11 14:46:32 -0700518 /**
519 * Unregisters an input channel.
520 * @param inputChannel The input channel to unregister.
521 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700522 public void unregisterInputChannel(InputChannel inputChannel) {
523 if (inputChannel == null) {
524 throw new IllegalArgumentException("inputChannel must not be null.");
525 }
RoboErikfb290df2013-12-16 11:27:55 -0800526
Jeff Brown4532e612012-04-05 14:27:12 -0700527 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700528 }
Jeff Brown0029c662011-03-30 02:25:18 -0700529
530 /**
531 * Sets an input filter that will receive all input events before they are dispatched.
532 * The input filter may then reinterpret input events or inject new ones.
533 *
534 * To ensure consistency, the input dispatcher automatically drops all events
535 * in progress whenever an input filter is installed or uninstalled. After an input
536 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
537 * Any events it attempts to send after it has been uninstalled will be dropped.
538 *
539 * @param filter The input filter, or null to remove the current filter.
540 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700541 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700542 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700543 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700544 if (oldFilter == filter) {
545 return; // nothing to do
546 }
547
548 if (oldFilter != null) {
549 mInputFilter = null;
550 mInputFilterHost.disconnectLocked();
551 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700552 try {
553 oldFilter.uninstall();
554 } catch (RemoteException re) {
555 /* ignore */
556 }
Jeff Brown0029c662011-03-30 02:25:18 -0700557 }
558
559 if (filter != null) {
560 mInputFilter = filter;
561 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700562 try {
563 filter.install(mInputFilterHost);
564 } catch (RemoteException re) {
565 /* ignore */
566 }
Jeff Brown0029c662011-03-30 02:25:18 -0700567 }
568
Jeff Brown4532e612012-04-05 14:27:12 -0700569 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700570 }
571 }
572
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700573 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700574 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brownca9bc702014-02-11 14:32:56 -0800575 return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
576 }
577
578 private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700579 if (event == null) {
580 throw new IllegalArgumentException("event must not be null");
581 }
Jeff Brownac143512012-04-05 18:57:33 -0700582 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
583 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
584 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
585 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700586 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700587
Jeff Brownac143512012-04-05 18:57:33 -0700588 final int pid = Binder.getCallingPid();
589 final int uid = Binder.getCallingUid();
590 final long ident = Binder.clearCallingIdentity();
591 final int result;
592 try {
Jeff Brownca9bc702014-02-11 14:32:56 -0800593 result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
Jeff Brownac143512012-04-05 18:57:33 -0700594 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
595 } finally {
596 Binder.restoreCallingIdentity(ident);
597 }
598 switch (result) {
599 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
600 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
601 throw new SecurityException(
602 "Injecting to another application requires INJECT_EVENTS permission");
603 case INPUT_EVENT_INJECTION_SUCCEEDED:
604 return true;
605 case INPUT_EVENT_INJECTION_TIMED_OUT:
606 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
607 return false;
608 case INPUT_EVENT_INJECTION_FAILED:
609 default:
610 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
611 return false;
612 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700613 }
Jeff Brown0029c662011-03-30 02:25:18 -0700614
Jeff Brown8d608662010-08-30 03:02:23 -0700615 /**
616 * Gets information about the input device with the specified id.
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700617 * @param deviceId The device id.
Jeff Brown8d608662010-08-30 03:02:23 -0700618 * @return The input device or null if not found.
619 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700620 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700621 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700622 synchronized (mInputDevicesLock) {
623 final int count = mInputDevices.length;
624 for (int i = 0; i < count; i++) {
625 final InputDevice inputDevice = mInputDevices[i];
626 if (inputDevice.getId() == deviceId) {
627 return inputDevice;
628 }
629 }
630 }
631 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700632 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700633
Jeff Brown8d608662010-08-30 03:02:23 -0700634 /**
635 * Gets the ids of all input devices in the system.
636 * @return The input device ids.
637 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700638 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700639 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700640 synchronized (mInputDevicesLock) {
641 final int count = mInputDevices.length;
642 int[] ids = new int[count];
643 for (int i = 0; i < count; i++) {
644 ids[i] = mInputDevices[i].getId();
645 }
646 return ids;
647 }
648 }
649
Jeff Browndaa37532012-05-01 15:54:03 -0700650 /**
651 * Gets all input devices in the system.
652 * @return The array of input devices.
653 */
654 public InputDevice[] getInputDevices() {
655 synchronized (mInputDevicesLock) {
656 return mInputDevices;
657 }
658 }
659
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700660 @Override // Binder call
661 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
662 if (listener == null) {
663 throw new IllegalArgumentException("listener must not be null");
664 }
665
666 synchronized (mInputDevicesLock) {
667 int callingPid = Binder.getCallingPid();
668 if (mInputDevicesChangedListeners.get(callingPid) != null) {
669 throw new SecurityException("The calling process has already "
670 + "registered an InputDevicesChangedListener.");
671 }
672
673 InputDevicesChangedListenerRecord record =
674 new InputDevicesChangedListenerRecord(callingPid, listener);
675 try {
676 IBinder binder = listener.asBinder();
677 binder.linkToDeath(record, 0);
678 } catch (RemoteException ex) {
679 // give up
680 throw new RuntimeException(ex);
681 }
682
683 mInputDevicesChangedListeners.put(callingPid, record);
684 }
685 }
686
687 private void onInputDevicesChangedListenerDied(int pid) {
688 synchronized (mInputDevicesLock) {
689 mInputDevicesChangedListeners.remove(pid);
690 }
691 }
692
693 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700694 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
695 // Scan for changes.
696 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700697 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700698 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700699 final int numListeners;
700 final int[] deviceIdAndGeneration;
701 synchronized (mInputDevicesLock) {
702 if (!mInputDevicesChangedPending) {
703 return;
704 }
705 mInputDevicesChangedPending = false;
706
707 numListeners = mInputDevicesChangedListeners.size();
708 for (int i = 0; i < numListeners; i++) {
709 mTempInputDevicesChangedListenersToNotify.add(
710 mInputDevicesChangedListeners.valueAt(i));
711 }
712
713 final int numDevices = mInputDevices.length;
714 deviceIdAndGeneration = new int[numDevices * 2];
715 for (int i = 0; i < numDevices; i++) {
716 final InputDevice inputDevice = mInputDevices[i];
717 deviceIdAndGeneration[i * 2] = inputDevice.getId();
718 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700719
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700720 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700721 if (!containsInputDeviceWithDescriptor(oldInputDevices,
722 inputDevice.getDescriptor())) {
723 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
724 } else {
725 mTempFullKeyboards.add(inputDevice);
726 }
727 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700728 }
729 }
730
Jeff Browncf39bdf2012-05-18 14:41:19 -0700731 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700732 for (int i = 0; i < numListeners; i++) {
733 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
734 deviceIdAndGeneration);
735 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700736 mTempInputDevicesChangedListenersToNotify.clear();
737
738 // Check for missing keyboard layouts.
Michael Wright07483422015-10-30 16:20:13 +0000739 List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
740 final int numFullKeyboards = mTempFullKeyboards.size();
741 synchronized (mDataStore) {
742 for (int i = 0; i < numFullKeyboards; i++) {
743 final InputDevice inputDevice = mTempFullKeyboards.get(i);
744 String layout =
745 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
746 if (layout == null) {
747 layout = getDefaultKeyboardLayout(inputDevice);
748 if (layout != null) {
749 setCurrentKeyboardLayoutForInputDevice(
750 inputDevice.getIdentifier(), layout);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700751 }
752 }
Michael Wright07483422015-10-30 16:20:13 +0000753 if (layout == null) {
754 keyboardsMissingLayout.add(inputDevice);
755 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700756 }
Michael Wright07483422015-10-30 16:20:13 +0000757 }
758
759 if (mNotificationManager != null) {
760 if (!keyboardsMissingLayout.isEmpty()) {
761 if (keyboardsMissingLayout.size() > 1) {
762 // We have more than one keyboard missing a layout, so drop the
763 // user at the generic input methods page so they can pick which
764 // one to set.
765 showMissingKeyboardLayoutNotification(null);
766 } else {
767 showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
Jeff Browncf39bdf2012-05-18 14:41:19 -0700768 }
769 } else if (mKeyboardLayoutNotificationShown) {
770 hideMissingKeyboardLayoutNotification();
771 }
772 }
773 mTempFullKeyboards.clear();
774 }
775
Michael Wright07483422015-10-30 16:20:13 +0000776 private String getDefaultKeyboardLayout(final InputDevice d) {
777 final Locale systemLocale = mContext.getResources().getConfiguration().locale;
778 // If our locale doesn't have a language for some reason, then we don't really have a
779 // reasonable default.
780 if (TextUtils.isEmpty(systemLocale.getLanguage())) {
781 return null;
782 }
783 final List<KeyboardLayout> layouts = new ArrayList<>();
784 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
785 @Override
786 public void visitKeyboardLayout(Resources resources,
787 int keyboardLayoutResId, KeyboardLayout layout) {
788 // Only select a default when we know the layout is appropriate. For now, this
789 // means its a custom layout for a specific keyboard.
790 if (layout.getVendorId() != d.getVendorId()
791 || layout.getProductId() != d.getProductId()) {
792 return;
793 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800794 final LocaleList locales = layout.getLocales();
795 final int numLocales = locales.size();
796 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
797 if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
Michael Wright07483422015-10-30 16:20:13 +0000798 layouts.add(layout);
799 break;
800 }
801 }
802 }
803 });
804
805 if (layouts.isEmpty()) {
806 return null;
807 }
808
809 // First sort so that ones with higher priority are listed at the top
810 Collections.sort(layouts);
811 // Next we want to try to find an exact match of language, country and variant.
812 final int N = layouts.size();
813 for (int i = 0; i < N; i++) {
814 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800815 final LocaleList locales = layout.getLocales();
816 final int numLocales = locales.size();
817 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
818 final Locale locale = locales.get(localeIndex);
819 if (locale.getCountry().equals(systemLocale.getCountry())
820 && locale.getVariant().equals(systemLocale.getVariant())) {
Michael Wright07483422015-10-30 16:20:13 +0000821 return layout.getDescriptor();
822 }
823 }
824 }
825 // Then try an exact match of language and country
826 for (int i = 0; i < N; i++) {
827 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800828 final LocaleList locales = layout.getLocales();
829 final int numLocales = locales.size();
830 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
831 final Locale locale = locales.get(localeIndex);
832 if (locale.getCountry().equals(systemLocale.getCountry())) {
Michael Wright07483422015-10-30 16:20:13 +0000833 return layout.getDescriptor();
834 }
835 }
836 }
837
838 // Give up and just use the highest priority layout with matching language
839 return layouts.get(0).getDescriptor();
840 }
841
842 private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
843 // Different languages are never compatible
844 if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
845 return false;
846 }
847 // If both the system and the keyboard layout have a country specifier, they must be equal.
848 if (!TextUtils.isEmpty(systemLocale.getCountry())
849 && !TextUtils.isEmpty(keyboardLocale.getCountry())
850 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
851 return false;
852 }
853 return true;
854 }
855
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800856 @Override // Binder call & native callback
Jason Gerecked5220742014-03-10 09:47:59 -0700857 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
858 int surfaceRotation) {
Jason Gerecked6396d62014-01-27 18:30:37 -0800859 if (inputDeviceDescriptor == null) {
860 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
861 }
862
863 synchronized (mDataStore) {
Jason Gerecked5220742014-03-10 09:47:59 -0700864 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
Jason Gerecked6396d62014-01-27 18:30:37 -0800865 }
866 }
867
868 @Override // Binder call
Jason Gerecked5220742014-03-10 09:47:59 -0700869 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
Jason Gerecked6396d62014-01-27 18:30:37 -0800870 TouchCalibration calibration) {
871 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
872 "setTouchCalibrationForInputDevice()")) {
873 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
874 }
875 if (inputDeviceDescriptor == null) {
876 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
877 }
878 if (calibration == null) {
879 throw new IllegalArgumentException("calibration must not be null");
880 }
Jason Gerecked5220742014-03-10 09:47:59 -0700881 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
882 throw new IllegalArgumentException("surfaceRotation value out of bounds");
883 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800884
885 synchronized (mDataStore) {
886 try {
Jason Gerecked5220742014-03-10 09:47:59 -0700887 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
888 calibration)) {
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800889 nativeReloadCalibration(mPtr);
890 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800891 } finally {
892 mDataStore.saveIfNeeded();
893 }
894 }
895 }
896
Michael Wright39e5e942015-08-19 22:52:47 +0100897 @Override // Binder call
Michael Wright9209c9c2015-09-03 17:57:01 +0100898 public int isInTabletMode() {
899 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
900 "isInTabletMode()")) {
901 throw new SecurityException("Requires TABLET_MODE permission");
902 }
903 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
904 }
905
906 @Override // Binder call
Michael Wright39e5e942015-08-19 22:52:47 +0100907 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
Michael Wright9209c9c2015-09-03 17:57:01 +0100908 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
Michael Wright39e5e942015-08-19 22:52:47 +0100909 "registerTabletModeChangedListener()")) {
910 throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
911 }
912 if (listener == null) {
913 throw new IllegalArgumentException("listener must not be null");
914 }
915
916 synchronized (mTabletModeLock) {
917 final int callingPid = Binder.getCallingPid();
918 if (mTabletModeChangedListeners.get(callingPid) != null) {
919 throw new IllegalStateException("The calling process has already registered "
920 + "a TabletModeChangedListener.");
921 }
922 TabletModeChangedListenerRecord record =
923 new TabletModeChangedListenerRecord(callingPid, listener);
924 try {
925 IBinder binder = listener.asBinder();
926 binder.linkToDeath(record, 0);
927 } catch (RemoteException ex) {
928 throw new RuntimeException(ex);
929 }
930 mTabletModeChangedListeners.put(callingPid, record);
931 }
932 }
933
934 private void onTabletModeChangedListenerDied(int pid) {
935 synchronized (mTabletModeLock) {
936 mTabletModeChangedListeners.remove(pid);
937 }
938 }
939
940 // Must be called on handler
941 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
942 mTempTabletModeChangedListenersToNotify.clear();
943 final int numListeners;
944 synchronized (mTabletModeLock) {
945 numListeners = mTabletModeChangedListeners.size();
946 for (int i = 0; i < numListeners; i++) {
947 mTempTabletModeChangedListenersToNotify.add(
948 mTabletModeChangedListeners.valueAt(i));
949 }
950 }
951 for (int i = 0; i < numListeners; i++) {
952 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
953 whenNanos, inTabletMode);
954 }
955 }
956
Jeff Browncf39bdf2012-05-18 14:41:19 -0700957 // Must be called on handler.
Michael Wrightc93fbd12014-09-22 20:07:59 -0700958 private void showMissingKeyboardLayoutNotification(InputDevice device) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700959 if (!mKeyboardLayoutNotificationShown) {
Yohei Yukawa2bff4902016-03-30 01:06:37 -0700960 final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
Michael Wrightc93fbd12014-09-22 20:07:59 -0700961 if (device != null) {
962 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -0700963 }
Michael Wrightc93fbd12014-09-22 20:07:59 -0700964 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
965 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
966 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
967 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
968 intent, 0, null, UserHandle.CURRENT);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700969
970 Resources r = mContext.getResources();
971 Notification notification = new Notification.Builder(mContext)
972 .setContentTitle(r.getString(
973 R.string.select_keyboard_layout_notification_title))
974 .setContentText(r.getString(
975 R.string.select_keyboard_layout_notification_message))
Michael Wrightc93fbd12014-09-22 20:07:59 -0700976 .setContentIntent(keyboardLayoutIntent)
Jeff Browncf39bdf2012-05-18 14:41:19 -0700977 .setSmallIcon(R.drawable.ic_settings_language)
978 .setPriority(Notification.PRIORITY_LOW)
Alan Viverette4a357cd2015-03-18 18:37:18 -0700979 .setColor(mContext.getColor(
Selim Cinek255dd042014-08-19 22:29:02 +0200980 com.android.internal.R.color.system_notification_accent_color))
Jeff Browncf39bdf2012-05-18 14:41:19 -0700981 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700982 mNotificationManager.notifyAsUser(null,
983 R.string.select_keyboard_layout_notification_title,
984 notification, UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700985 mKeyboardLayoutNotificationShown = true;
986 }
987 }
988
989 // Must be called on handler.
990 private void hideMissingKeyboardLayoutNotification() {
991 if (mKeyboardLayoutNotificationShown) {
992 mKeyboardLayoutNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700993 mNotificationManager.cancelAsUser(null,
994 R.string.select_keyboard_layout_notification_title,
995 UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700996 }
997 }
998
999 // Must be called on handler.
1000 private void updateKeyboardLayouts() {
1001 // Scan all input devices state for keyboard layouts that have been uninstalled.
1002 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
1003 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1004 @Override
Michael Wright07483422015-10-30 16:20:13 +00001005 public void visitKeyboardLayout(Resources resources,
1006 int keyboardLayoutResId, KeyboardLayout layout) {
1007 availableKeyboardLayouts.add(layout.getDescriptor());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001008 }
1009 });
1010 synchronized (mDataStore) {
1011 try {
1012 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
1013 } finally {
1014 mDataStore.saveIfNeeded();
1015 }
1016 }
1017
1018 // Reload keyboard layouts.
1019 reloadKeyboardLayouts();
1020 }
1021
Jeff Browncf39bdf2012-05-18 14:41:19 -07001022 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
1023 String descriptor) {
1024 final int numDevices = inputDevices.length;
1025 for (int i = 0; i < numDevices; i++) {
1026 final InputDevice inputDevice = inputDevices[i];
1027 if (inputDevice.getDescriptor().equals(descriptor)) {
1028 return true;
1029 }
1030 }
1031 return false;
Jeff Brown8d608662010-08-30 03:02:23 -07001032 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001033
1034 @Override // Binder call
1035 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001036 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
1037 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1038 @Override
Michael Wright07483422015-10-30 16:20:13 +00001039 public void visitKeyboardLayout(Resources resources,
1040 int keyboardLayoutResId, KeyboardLayout layout) {
1041 list.add(layout);
1042 }
1043 });
1044 return list.toArray(new KeyboardLayout[list.size()]);
1045 }
1046
Michael Wrightb0e804a2016-01-04 16:48:53 -05001047 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001048 public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1049 final InputDeviceIdentifier identifier) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001050 final String[] enabledLayoutDescriptors =
1051 getEnabledKeyboardLayoutsForInputDevice(identifier);
1052 final ArrayList<KeyboardLayout> enabledLayouts =
1053 new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length);
1054 final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>();
Michael Wright07483422015-10-30 16:20:13 +00001055 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1056 boolean mHasSeenDeviceSpecificLayout;
1057
1058 @Override
1059 public void visitKeyboardLayout(Resources resources,
1060 int keyboardLayoutResId, KeyboardLayout layout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001061 // First check if it's enabled. If the keyboard layout is enabled then we always
1062 // want to return it as a possible layout for the device.
1063 for (String s : enabledLayoutDescriptors) {
1064 if (s != null && s.equals(layout.getDescriptor())) {
1065 enabledLayouts.add(layout);
1066 return;
1067 }
1068 }
1069 // Next find any potential layouts that aren't yet enabled for the device. For
1070 // devices that have special layouts we assume there's a reason that the generic
1071 // layouts don't work for them so we don't want to return them since it's likely
1072 // to result in a poor user experience.
Michael Wright07483422015-10-30 16:20:13 +00001073 if (layout.getVendorId() == identifier.getVendorId()
1074 && layout.getProductId() == identifier.getProductId()) {
1075 if (!mHasSeenDeviceSpecificLayout) {
1076 mHasSeenDeviceSpecificLayout = true;
Michael Wrightb0e804a2016-01-04 16:48:53 -05001077 potentialLayouts.clear();
Michael Wright07483422015-10-30 16:20:13 +00001078 }
Michael Wrightb0e804a2016-01-04 16:48:53 -05001079 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001080 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
1081 && !mHasSeenDeviceSpecificLayout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001082 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001083 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001084 }
1085 });
Michael Wrightb0e804a2016-01-04 16:48:53 -05001086 final int enabledLayoutSize = enabledLayouts.size();
1087 final int potentialLayoutSize = potentialLayouts.size();
1088 KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
1089 enabledLayouts.toArray(layouts);
1090 for (int i = 0; i < potentialLayoutSize; i++) {
1091 layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
1092 }
1093 return layouts;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001094 }
1095
1096 @Override // Binder call
1097 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
1098 if (keyboardLayoutDescriptor == null) {
1099 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1100 }
1101
Jeff Brown6ec6f792012-04-17 16:52:41 -07001102 final KeyboardLayout[] result = new KeyboardLayout[1];
1103 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1104 @Override
Michael Wright07483422015-10-30 16:20:13 +00001105 public void visitKeyboardLayout(Resources resources,
1106 int keyboardLayoutResId, KeyboardLayout layout) {
1107 result[0] = layout;
Jeff Brown6ec6f792012-04-17 16:52:41 -07001108 }
1109 });
1110 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00001111 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07001112 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001113 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001114 return result[0];
1115 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001116
Jeff Brown6ec6f792012-04-17 16:52:41 -07001117 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001118 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001119 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
1120 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001121 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
1122 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
Michael Wright8ebac232014-09-18 18:29:49 -07001123 final ActivityInfo activityInfo = resolveInfo.activityInfo;
1124 final int priority = resolveInfo.priority;
1125 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001126 }
1127 }
1128
Jeff Brown6ec6f792012-04-17 16:52:41 -07001129 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
1130 KeyboardLayoutVisitor visitor) {
1131 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
1132 if (d != null) {
1133 final PackageManager pm = mContext.getPackageManager();
1134 try {
1135 ActivityInfo receiver = pm.getReceiverInfo(
1136 new ComponentName(d.packageName, d.receiverName),
Jeff Sharkey5217cac2015-12-20 15:34:01 -07001137 PackageManager.GET_META_DATA
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001138 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1139 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Michael Wright8ebac232014-09-18 18:29:49 -07001140 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001141 } catch (NameNotFoundException ex) {
1142 }
1143 }
1144 }
1145
1146 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
Michael Wright8ebac232014-09-18 18:29:49 -07001147 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001148 Bundle metaData = receiver.metaData;
1149 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001150 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001151 }
1152
1153 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1154 if (configResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001155 Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001156 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001157 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001158 }
1159
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001160 CharSequence receiverLabel = receiver.loadLabel(pm);
1161 String collection = receiverLabel != null ? receiverLabel.toString() : "";
Michael Wright8ebac232014-09-18 18:29:49 -07001162 int priority;
1163 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1164 priority = requestedPriority;
1165 } else {
1166 priority = 0;
1167 }
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001168
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001169 try {
1170 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1171 XmlResourceParser parser = resources.getXml(configResId);
1172 try {
1173 XmlUtils.beginDocument(parser, "keyboard-layouts");
1174
1175 for (;;) {
1176 XmlUtils.nextElement(parser);
1177 String element = parser.getName();
1178 if (element == null) {
1179 break;
1180 }
1181 if (element.equals("keyboard-layout")) {
1182 TypedArray a = resources.obtainAttributes(
1183 parser, com.android.internal.R.styleable.KeyboardLayout);
1184 try {
1185 String name = a.getString(
1186 com.android.internal.R.styleable.KeyboardLayout_name);
1187 String label = a.getString(
1188 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -07001189 int keyboardLayoutResId = a.getResourceId(
1190 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1191 0);
Michael Wright07483422015-10-30 16:20:13 +00001192 String languageTags = a.getString(
1193 com.android.internal.R.styleable.KeyboardLayout_locale);
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001194 LocaleList locales = getLocalesFromLanguageTags(languageTags);
Michael Wright07483422015-10-30 16:20:13 +00001195 int vid = a.getInt(
1196 com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
1197 int pid = a.getInt(
1198 com.android.internal.R.styleable.KeyboardLayout_productId, -1);
1199
Jeff Brown2f095762012-05-10 21:29:33 -07001200 if (name == null || label == null || keyboardLayoutResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001201 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001202 + "attributes in keyboard layout "
1203 + "resource from receiver "
1204 + receiver.packageName + "/" + receiver.name);
1205 } else {
1206 String descriptor = KeyboardLayoutDescriptor.format(
1207 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001208 if (keyboardName == null || name.equals(keyboardName)) {
Michael Wright07483422015-10-30 16:20:13 +00001209 KeyboardLayout layout = new KeyboardLayout(
1210 descriptor, label, collection, priority,
1211 locales, vid, pid);
1212 visitor.visitKeyboardLayout(
1213 resources, keyboardLayoutResId, layout);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001214 }
1215 }
1216 } finally {
1217 a.recycle();
1218 }
1219 } else {
Michael Wright07483422015-10-30 16:20:13 +00001220 Slog.w(TAG, "Skipping unrecognized element '" + element
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001221 + "' in keyboard layout resource from receiver "
1222 + receiver.packageName + "/" + receiver.name);
1223 }
1224 }
1225 } finally {
1226 parser.close();
1227 }
1228 } catch (Exception ex) {
Michael Wright07483422015-10-30 16:20:13 +00001229 Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001230 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001231 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001232 }
1233
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001234 @NonNull
1235 private static LocaleList getLocalesFromLanguageTags(String languageTags) {
Michael Wright07483422015-10-30 16:20:13 +00001236 if (TextUtils.isEmpty(languageTags)) {
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001237 return LocaleList.getEmptyLocaleList();
Michael Wright07483422015-10-30 16:20:13 +00001238 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001239 return LocaleList.forLanguageTags(languageTags.replace('|', ','));
Michael Wright07483422015-10-30 16:20:13 +00001240 }
1241
RoboErikfb290df2013-12-16 11:27:55 -08001242 /**
1243 * Builds a layout descriptor for the vendor/product. This returns the
1244 * descriptor for ids that aren't useful (such as the default 0, 0).
1245 */
1246 private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1247 if (identifier == null || identifier.getDescriptor() == null) {
1248 throw new IllegalArgumentException("identifier and descriptor must not be null");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001249 }
1250
RoboErikfb290df2013-12-16 11:27:55 -08001251 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1252 return identifier.getDescriptor();
1253 }
1254 StringBuilder bob = new StringBuilder();
1255 bob.append("vendor:").append(identifier.getVendorId());
1256 bob.append(",product:").append(identifier.getProductId());
1257 return bob.toString();
1258 }
1259
1260 @Override // Binder call
1261 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1262
1263 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001264 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001265 String layout = null;
1266 // try loading it using the layout descriptor if we have it
1267 layout = mDataStore.getCurrentKeyboardLayout(key);
1268 if (layout == null && !key.equals(identifier.getDescriptor())) {
1269 // if it doesn't exist fall back to the device descriptor
1270 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1271 }
1272 if (DEBUG) {
1273 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1274 + layout);
1275 }
1276 return layout;
Jeff Browna3bc5652012-04-17 11:42:25 -07001277 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001278 }
1279
1280 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001281 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001282 String keyboardLayoutDescriptor) {
1283 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001284 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001285 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1286 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001287 if (keyboardLayoutDescriptor == null) {
1288 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1289 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001290
RoboErikfb290df2013-12-16 11:27:55 -08001291 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001292 synchronized (mDataStore) {
1293 try {
RoboErikfb290df2013-12-16 11:27:55 -08001294 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1295 if (DEBUG) {
1296 Slog.d(TAG, "Saved keyboard layout using " + key);
1297 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001298 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1299 }
Jeff Browna3bc5652012-04-17 11:42:25 -07001300 } finally {
1301 mDataStore.saveIfNeeded();
1302 }
1303 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001304 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001305
Jeff Browncf39bdf2012-05-18 14:41:19 -07001306 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001307 public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
RoboErikfb290df2013-12-16 11:27:55 -08001308 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001309 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001310 String[] layouts = mDataStore.getKeyboardLayouts(key);
1311 if ((layouts == null || layouts.length == 0)
1312 && !key.equals(identifier.getDescriptor())) {
1313 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1314 }
1315 return layouts;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001316 }
1317 }
1318
1319 @Override // Binder call
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001320 @Nullable
1321 public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1322 InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) {
1323 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
1324 String key = getLayoutDescriptor(identifier);
1325 final String keyboardLayoutDescriptor;
1326 synchronized (mDataStore) {
1327 keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle);
1328 }
1329
1330 if (keyboardLayoutDescriptor == null) {
1331 return null;
1332 }
1333
1334 final KeyboardLayout[] result = new KeyboardLayout[1];
1335 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1336 @Override
1337 public void visitKeyboardLayout(Resources resources,
1338 int keyboardLayoutResId, KeyboardLayout layout) {
1339 result[0] = layout;
1340 }
1341 });
1342 if (result[0] == null) {
1343 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
1344 + keyboardLayoutDescriptor + "'.");
1345 }
1346 return result[0];
1347 }
1348
1349 @Override
1350 public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1351 InputMethodInfo imeInfo, InputMethodSubtype imeSubtype,
1352 String keyboardLayoutDescriptor) {
1353 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1354 "setKeyboardLayoutForInputDevice()")) {
1355 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1356 }
1357 if (keyboardLayoutDescriptor == null) {
1358 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1359 }
Yohei Yukawa46ac35d2016-04-20 16:59:45 -07001360 if (imeInfo == null) {
1361 throw new IllegalArgumentException("imeInfo must not be null");
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001362 }
1363 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
1364 setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
1365 }
1366
1367 private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier,
1368 InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
1369 String key = getLayoutDescriptor(identifier);
1370 synchronized (mDataStore) {
1371 try {
1372 if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) {
1373 if (DEBUG) {
1374 Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor +
1375 " for subtype " + imeHandle + " and device " + identifier +
1376 " using key " + key);
1377 }
1378 if (imeHandle.equals(mCurrentImeHandle)) {
1379 if (DEBUG) {
1380 Slog.d(TAG, "Layout for current subtype changed, switching layout");
1381 }
1382 SomeArgs args = SomeArgs.obtain();
1383 args.arg1 = identifier;
1384 args.arg2 = imeHandle;
1385 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget();
1386 }
1387 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1388 }
1389 } finally {
1390 mDataStore.saveIfNeeded();
1391 }
1392 }
1393 }
1394
1395 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001396 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001397 String keyboardLayoutDescriptor) {
1398 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1399 "addKeyboardLayoutForInputDevice()")) {
1400 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1401 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001402 if (keyboardLayoutDescriptor == null) {
1403 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1404 }
1405
RoboErikfb290df2013-12-16 11:27:55 -08001406 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001407 synchronized (mDataStore) {
1408 try {
RoboErikfb290df2013-12-16 11:27:55 -08001409 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1410 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1411 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1412 }
1413 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001414 && !Objects.equal(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001415 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1416 }
1417 } finally {
1418 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001419 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001420 }
1421 }
1422
1423 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001424 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001425 String keyboardLayoutDescriptor) {
1426 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1427 "removeKeyboardLayoutForInputDevice()")) {
1428 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1429 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001430 if (keyboardLayoutDescriptor == null) {
1431 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1432 }
1433
RoboErikfb290df2013-12-16 11:27:55 -08001434 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001435 synchronized (mDataStore) {
1436 try {
RoboErikfb290df2013-12-16 11:27:55 -08001437 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1438 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1439 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1440 }
1441 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1442 if (!key.equals(identifier.getDescriptor())) {
1443 // We need to remove from both places to ensure it is gone
1444 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1445 keyboardLayoutDescriptor);
1446 }
1447 if (removed && !Objects.equal(oldLayout,
1448 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001449 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1450 }
1451 } finally {
1452 mDataStore.saveIfNeeded();
1453 }
1454 }
1455 }
1456
Yohei Yukawab097b822015-12-01 10:43:08 -08001457 // Must be called on handler.
1458 private void handleSwitchInputMethodSubtype(int userId,
1459 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
1460 if (DEBUG) {
1461 Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
1462 + " ime=" + inputMethodInfo + " subtype=" + subtype);
1463 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001464 if (inputMethodInfo == null) {
1465 Slog.d(TAG, "No InputMethod is running, ignoring change");
1466 return;
1467 }
1468 if (subtype != null && !"keyboard".equals(subtype.getMode())) {
1469 Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change");
1470 return;
1471 }
1472 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype);
1473 if (!handle.equals(mCurrentImeHandle)) {
1474 mCurrentImeHandle = handle;
1475 handleSwitchKeyboardLayout(null, handle);
1476 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001477 }
1478
1479 // Must be called on handler.
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001480 private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier,
1481 InputMethodSubtypeHandle handle) {
1482 synchronized (mInputDevicesLock) {
1483 for (InputDevice device : mInputDevices) {
1484 if (identifier != null && !device.getIdentifier().equals(identifier) ||
1485 !device.isFullKeyboard()) {
1486 continue;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001487 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001488 String key = getLayoutDescriptor(device.getIdentifier());
1489 boolean changed = false;
1490 synchronized (mDataStore) {
1491 try {
1492 if (mDataStore.switchKeyboardLayout(key, handle)) {
1493 changed = true;
1494 }
1495 } finally {
1496 mDataStore.saveIfNeeded();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001497 }
1498 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001499 if (changed) {
1500 reloadKeyboardLayouts();
1501 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001502 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001503 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001504 }
1505
Jeff Brown9302c872011-07-13 22:51:29 -07001506 public void setInputWindows(InputWindowHandle[] windowHandles) {
Jeff Brown4532e612012-04-05 14:27:12 -07001507 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -07001508 }
RoboErikfb290df2013-12-16 11:27:55 -08001509
Jeff Brown9302c872011-07-13 22:51:29 -07001510 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -07001511 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -07001512 }
RoboErikfb290df2013-12-16 11:27:55 -08001513
Jeff Brown349703e2010-06-22 01:27:15 -07001514 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001515 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001516 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001517
1518 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001519 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001520 }
1521
Jeff Browne6504122010-09-27 14:52:15 -07001522 /**
1523 * Atomically transfers touch focus from one window to another as identified by
1524 * their input channels. It is possible for multiple windows to have
1525 * touch focus if they support split touch dispatch
1526 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1527 * method only transfers touch focus of the specified window without affecting
1528 * other windows that may also have touch focus at the same time.
1529 * @param fromChannel The channel of a window that currently has touch focus.
1530 * @param toChannel The channel of the window that should receive touch focus in
1531 * place of the first.
1532 * @return True if the transfer was successful. False if the window with the
1533 * specified channel did not actually have touch focus at the time of the request.
1534 */
1535 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1536 if (fromChannel == null) {
1537 throw new IllegalArgumentException("fromChannel must not be null.");
1538 }
1539 if (toChannel == null) {
1540 throw new IllegalArgumentException("toChannel must not be null.");
1541 }
Jeff Brown4532e612012-04-05 14:27:12 -07001542 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -07001543 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001544
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001545 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001546 public void tryPointerSpeed(int speed) {
1547 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1548 "tryPointerSpeed()")) {
1549 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1550 }
1551
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001552 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1553 throw new IllegalArgumentException("speed out of range");
1554 }
1555
Jeff Brownac143512012-04-05 18:57:33 -07001556 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001557 }
1558
1559 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001560 int speed = getPointerSpeedSetting();
1561 setPointerSpeedUnchecked(speed);
1562 }
1563
1564 private void setPointerSpeedUnchecked(int speed) {
1565 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1566 InputManager.MAX_POINTER_SPEED);
1567 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001568 }
1569
1570 private void registerPointerSpeedSettingObserver() {
1571 mContext.getContentResolver().registerContentObserver(
1572 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001573 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001574 @Override
1575 public void onChange(boolean selfChange) {
1576 updatePointerSpeedFromSettings();
1577 }
Jeff Brownd4935962012-09-25 13:27:20 -07001578 }, UserHandle.USER_ALL);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001579 }
1580
Jeff Brownac143512012-04-05 18:57:33 -07001581 private int getPointerSpeedSetting() {
1582 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001583 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001584 speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1585 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001586 } catch (SettingNotFoundException snfe) {
1587 }
1588 return speed;
1589 }
1590
Jeff Browndaf4a122011-08-26 17:14:14 -07001591 public void updateShowTouchesFromSettings() {
1592 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001593 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001594 }
1595
1596 private void registerShowTouchesSettingObserver() {
1597 mContext.getContentResolver().registerContentObserver(
1598 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001599 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001600 @Override
1601 public void onChange(boolean selfChange) {
1602 updateShowTouchesFromSettings();
1603 }
Jeff Brownd4935962012-09-25 13:27:20 -07001604 }, UserHandle.USER_ALL);
Jeff Browndaf4a122011-08-26 17:14:14 -07001605 }
1606
Jun Mukaie4e75da2015-12-15 16:19:20 -08001607 public void updateAccessibilityLargePointerFromSettings() {
1608 final int accessibilityConfig = Settings.Secure.getIntForUser(
1609 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1610 0, UserHandle.USER_CURRENT);
Jun Mukai1f3dbff2015-12-16 14:41:25 -08001611 PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
Jun Mukaie4e75da2015-12-15 16:19:20 -08001612 nativeReloadPointerIcons(mPtr);
1613 }
1614
Jun Mukai19a56012015-11-24 11:25:52 -08001615 private void registerAccessibilityLargePointerSettingObserver() {
1616 mContext.getContentResolver().registerContentObserver(
1617 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1618 new ContentObserver(mHandler) {
1619 @Override
1620 public void onChange(boolean selfChange) {
Jun Mukaie4e75da2015-12-15 16:19:20 -08001621 updateAccessibilityLargePointerFromSettings();
Jun Mukai19a56012015-11-24 11:25:52 -08001622 }
1623 }, UserHandle.USER_ALL);
1624 }
1625
Jeff Browndaf4a122011-08-26 17:14:14 -07001626 private int getShowTouchesSetting(int defaultValue) {
1627 int result = defaultValue;
1628 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001629 result = Settings.System.getIntForUser(mContext.getContentResolver(),
1630 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
Jeff Browndaf4a122011-08-26 17:14:14 -07001631 } catch (SettingNotFoundException snfe) {
1632 }
1633 return result;
1634 }
1635
Jeff Browna47425a2012-04-13 04:09:27 -07001636 // Binder call
1637 @Override
1638 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1639 if (repeat >= pattern.length) {
1640 throw new ArrayIndexOutOfBoundsException();
1641 }
1642
1643 VibratorToken v;
1644 synchronized (mVibratorLock) {
1645 v = mVibratorTokens.get(token);
1646 if (v == null) {
1647 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1648 try {
1649 token.linkToDeath(v, 0);
1650 } catch (RemoteException ex) {
1651 // give up
1652 throw new RuntimeException(ex);
1653 }
1654 mVibratorTokens.put(token, v);
1655 }
1656 }
1657
1658 synchronized (v) {
1659 v.mVibrating = true;
1660 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1661 }
1662 }
1663
1664 // Binder call
1665 @Override
1666 public void cancelVibrate(int deviceId, IBinder token) {
1667 VibratorToken v;
1668 synchronized (mVibratorLock) {
1669 v = mVibratorTokens.get(token);
1670 if (v == null || v.mDeviceId != deviceId) {
1671 return; // nothing to cancel
1672 }
1673 }
1674
1675 cancelVibrateIfNeeded(v);
1676 }
1677
1678 void onVibratorTokenDied(VibratorToken v) {
1679 synchronized (mVibratorLock) {
1680 mVibratorTokens.remove(v.mToken);
1681 }
1682
1683 cancelVibrateIfNeeded(v);
1684 }
1685
1686 private void cancelVibrateIfNeeded(VibratorToken v) {
1687 synchronized (v) {
1688 if (v.mVibrating) {
1689 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1690 v.mVibrating = false;
1691 }
1692 }
1693 }
1694
Jun Mukai19a56012015-11-24 11:25:52 -08001695 // Binder call
1696 @Override
Michael Wrightf9d9ce772016-05-13 17:44:16 +01001697 public void setPointerIconType(int iconId) {
1698 nativeSetPointerIconType(mPtr, iconId);
Jun Mukai19a56012015-11-24 11:25:52 -08001699 }
Jun Mukai1db53972015-09-11 18:08:31 -07001700
Jun Mukaid4eaef72015-10-30 15:54:33 -07001701 // Binder call
1702 @Override
1703 public void setCustomPointerIcon(PointerIcon icon) {
Michael Wrightb004b512017-01-18 18:09:29 +00001704 Preconditions.checkNotNull(icon);
Jun Mukaid4eaef72015-10-30 15:54:33 -07001705 nativeSetCustomPointerIcon(mPtr, icon);
1706 }
1707
Jeff Brown4532e612012-04-05 14:27:12 -07001708 @Override
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001709 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
Jeff Browna3bc5652012-04-17 11:42:25 -07001710 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
Jeff Brown4532e612012-04-05 14:27:12 -07001711 != PackageManager.PERMISSION_GRANTED) {
1712 pw.println("Permission Denial: can't dump InputManager from from pid="
1713 + Binder.getCallingPid()
1714 + ", uid=" + Binder.getCallingUid());
1715 return;
1716 }
1717
1718 pw.println("INPUT MANAGER (dumpsys input)\n");
1719 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001720 if (dumpStr != null) {
1721 pw.println(dumpStr);
1722 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001723 pw.println(" Keyboard Layouts:");
1724 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1725 @Override
1726 public void visitKeyboardLayout(Resources resources,
1727 int keyboardLayoutResId, KeyboardLayout layout) {
1728 pw.println(" \"" + layout + "\": " + layout.getDescriptor());
1729 }
1730 });
1731 pw.println();
1732 synchronized(mDataStore) {
1733 mDataStore.dump(pw, " ");
1734 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001735 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001736
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001737 @Override
1738 public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07001739 FileDescriptor err, String[] args, ShellCallback callback,
1740 ResultReceiver resultReceiver) {
1741 (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001742 }
1743
1744 public int onShellCommand(Shell shell, String cmd) {
1745 if (TextUtils.isEmpty(cmd)) {
1746 shell.onHelp();
1747 return 1;
1748 }
1749 if (cmd.equals("setlayout")) {
1750 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1751 "onShellCommand()")) {
1752 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1753 }
1754 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
1755 shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired()));
1756 String descriptor = shell.getNextArgRequired();
1757 int vid = Integer.decode(shell.getNextArgRequired());
1758 int pid = Integer.decode(shell.getNextArgRequired());
1759 InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid);
1760 setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired());
1761 }
1762 return 0;
1763 }
1764
1765
Jeff Brownac143512012-04-05 18:57:33 -07001766 private boolean checkCallingPermission(String permission, String func) {
1767 // Quick check: if the calling permission is me, it's all okay.
1768 if (Binder.getCallingPid() == Process.myPid()) {
1769 return true;
1770 }
1771
1772 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1773 return true;
1774 }
1775 String msg = "Permission Denial: " + func + " from pid="
1776 + Binder.getCallingPid()
1777 + ", uid=" + Binder.getCallingUid()
1778 + " requires " + permission;
1779 Slog.w(TAG, msg);
1780 return false;
1781 }
1782
Jeff Brown4532e612012-04-05 14:27:12 -07001783 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001784 @Override
Jeff Brown89ef0722011-08-10 16:25:21 -07001785 public void monitor() {
1786 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -07001787 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001788 }
1789
Jeff Brown4532e612012-04-05 14:27:12 -07001790 // Native callback.
1791 private void notifyConfigurationChanged(long whenNanos) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001792 mWindowManagerCallbacks.notifyConfigurationChanged();
Jeff Brown4532e612012-04-05 14:27:12 -07001793 }
1794
1795 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001796 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1797 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001798 if (!mInputDevicesChangedPending) {
1799 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001800 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1801 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001802 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001803
1804 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001805 }
1806 }
1807
1808 // Native callback.
Jeff Brownbcc046a2012-09-27 20:46:43 -07001809 private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1810 if (DEBUG) {
1811 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1812 + ", mask=" + Integer.toHexString(switchMask));
1813 }
1814
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001815 if ((switchMask & SW_LID_BIT) != 0) {
1816 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
Jeff Brownbcc046a2012-09-27 20:46:43 -07001817 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
Jeff Brown53384282012-08-20 20:16:01 -07001818 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001819
Michael Wright3818c922014-09-02 13:59:07 -07001820 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
Michael Wright9e10d252014-09-13 19:41:20 -07001821 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
Michael Wright3818c922014-09-02 13:59:07 -07001822 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1823 }
1824
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001825 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1826 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1827 switchMask);
1828 }
Michael Wright39e5e942015-08-19 22:52:47 +01001829
Michael Wright9209c9c2015-09-03 17:57:01 +01001830 if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
Michael Wright39e5e942015-08-19 22:52:47 +01001831 SomeArgs args = SomeArgs.obtain();
1832 args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
1833 args.argi2 = (int) (whenNanos >> 32);
1834 args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
1835 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
1836 args).sendToTarget();
1837 }
Jeff Brown4532e612012-04-05 14:27:12 -07001838 }
1839
1840 // Native callback.
1841 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001842 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
Jeff Brown4532e612012-04-05 14:27:12 -07001843 }
1844
1845 // Native callback.
1846 private long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001847 InputWindowHandle inputWindowHandle, String reason) {
1848 return mWindowManagerCallbacks.notifyANR(
1849 inputApplicationHandle, inputWindowHandle, reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001850 }
1851
1852 // Native callback.
1853 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1854 synchronized (mInputFilterLock) {
1855 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001856 try {
1857 mInputFilter.filterInputEvent(event, policyFlags);
1858 } catch (RemoteException e) {
1859 /* ignore */
1860 }
Jeff Brown4532e612012-04-05 14:27:12 -07001861 return false;
1862 }
1863 }
1864 event.recycle();
1865 return true;
1866 }
1867
1868 // Native callback.
Jeff Brown037c33e2014-04-09 00:31:55 -07001869 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1870 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001871 }
1872
1873 // Native callback.
Michael Wright70af00a2014-09-03 19:30:20 -07001874 private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
1875 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
Jeff Brown26875502014-01-30 21:47:47 -08001876 whenNanos, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001877 }
1878
1879 // Native callback.
1880 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1881 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001882 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001883 }
1884
1885 // Native callback.
1886 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1887 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001888 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001889 }
1890
1891 // Native callback.
1892 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1893 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1894 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1895 }
1896
1897 // Native callback.
1898 private int getVirtualKeyQuietTimeMillis() {
1899 return mContext.getResources().getInteger(
1900 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1901 }
1902
1903 // Native callback.
1904 private String[] getExcludedDeviceNames() {
1905 ArrayList<String> names = new ArrayList<String>();
1906
1907 // Read partner-provided list of excluded input devices
1908 XmlPullParser parser = null;
1909 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1910 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1911 FileReader confreader = null;
1912 try {
1913 confreader = new FileReader(confFile);
1914 parser = Xml.newPullParser();
1915 parser.setInput(confreader);
1916 XmlUtils.beginDocument(parser, "devices");
1917
1918 while (true) {
1919 XmlUtils.nextElement(parser);
1920 if (!"device".equals(parser.getName())) {
1921 break;
1922 }
1923 String name = parser.getAttributeValue(null, "name");
1924 if (name != null) {
1925 names.add(name);
1926 }
1927 }
1928 } catch (FileNotFoundException e) {
1929 // It's ok if the file does not exist.
1930 } catch (Exception e) {
1931 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1932 } finally {
1933 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1934 }
1935
1936 return names.toArray(new String[names.size()]);
1937 }
1938
1939 // Native callback.
1940 private int getKeyRepeatTimeout() {
1941 return ViewConfiguration.getKeyRepeatTimeout();
1942 }
1943
1944 // Native callback.
1945 private int getKeyRepeatDelay() {
1946 return ViewConfiguration.getKeyRepeatDelay();
1947 }
1948
1949 // Native callback.
1950 private int getHoverTapTimeout() {
1951 return ViewConfiguration.getHoverTapTimeout();
1952 }
1953
1954 // Native callback.
1955 private int getHoverTapSlop() {
1956 return ViewConfiguration.getHoverTapSlop();
1957 }
1958
1959 // Native callback.
1960 private int getDoubleTapTimeout() {
1961 return ViewConfiguration.getDoubleTapTimeout();
1962 }
1963
1964 // Native callback.
1965 private int getLongPressTimeout() {
1966 return ViewConfiguration.getLongPressTimeout();
1967 }
1968
1969 // Native callback.
1970 private int getPointerLayer() {
Jeff Browna9d131c2012-09-20 16:48:17 -07001971 return mWindowManagerCallbacks.getPointerLayer();
Jeff Brown4532e612012-04-05 14:27:12 -07001972 }
1973
1974 // Native callback.
1975 private PointerIcon getPointerIcon() {
1976 return PointerIcon.getDefaultIcon(mContext);
1977 }
1978
Jeff Brown6ec6f792012-04-17 16:52:41 -07001979 // Native callback.
RoboErikfb290df2013-12-16 11:27:55 -08001980 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001981 if (!mSystemReady) {
1982 return null;
1983 }
1984
RoboErikfb290df2013-12-16 11:27:55 -08001985 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001986 if (keyboardLayoutDescriptor == null) {
1987 return null;
1988 }
1989
1990 final String[] result = new String[2];
1991 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1992 @Override
Michael Wright07483422015-10-30 16:20:13 +00001993 public void visitKeyboardLayout(Resources resources,
1994 int keyboardLayoutResId, KeyboardLayout layout) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001995 try {
Michael Wright07483422015-10-30 16:20:13 +00001996 result[0] = layout.getDescriptor();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001997 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07001998 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07001999 } catch (IOException ex) {
2000 } catch (NotFoundException ex) {
2001 }
2002 }
2003 });
2004 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00002005 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07002006 + keyboardLayoutDescriptor + "'.");
2007 return null;
2008 }
2009 return result;
2010 }
2011
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002012 // Native callback.
2013 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07002014 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
2015 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
2016 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002017 }
2018 return null;
2019 }
2020
Jeff Brown4532e612012-04-05 14:27:12 -07002021 /**
2022 * Callback interface implemented by the Window Manager.
2023 */
Jeff Browna9d131c2012-09-20 16:48:17 -07002024 public interface WindowManagerCallbacks {
Jeff Brown4532e612012-04-05 14:27:12 -07002025 public void notifyConfigurationChanged();
2026
2027 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
2028
Michael Wright3818c922014-09-02 13:59:07 -07002029 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
2030
Jeff Brown4532e612012-04-05 14:27:12 -07002031 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
2032
2033 public long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07002034 InputWindowHandle inputWindowHandle, String reason);
Jeff Brown4532e612012-04-05 14:27:12 -07002035
Jeff Brown037c33e2014-04-09 00:31:55 -07002036 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002037
Michael Wright70af00a2014-09-03 19:30:20 -07002038 public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002039
2040 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
2041 KeyEvent event, int policyFlags);
2042
2043 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
2044 KeyEvent event, int policyFlags);
2045
2046 public int getPointerLayer();
2047 }
2048
2049 /**
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002050 * Callback interface implemented by WiredAccessoryObserver.
2051 */
2052 public interface WiredAccessoryCallbacks {
2053 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002054 public void systemReady();
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002055 }
2056
2057 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002058 * Private handler for the input manager.
2059 */
2060 private final class InputManagerHandler extends Handler {
Jeff Browna9d131c2012-09-20 16:48:17 -07002061 public InputManagerHandler(Looper looper) {
2062 super(looper, null, true /*async*/);
Jeff Browna2910d02012-08-25 12:29:46 -07002063 }
2064
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002065 @Override
2066 public void handleMessage(Message msg) {
2067 switch (msg.what) {
2068 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07002069 deliverInputDevicesChanged((InputDevice[])msg.obj);
2070 break;
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002071 case MSG_SWITCH_KEYBOARD_LAYOUT: {
2072 SomeArgs args = (SomeArgs)msg.obj;
2073 handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1,
2074 (InputMethodSubtypeHandle)args.arg2);
Jeff Browncf39bdf2012-05-18 14:41:19 -07002075 break;
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002076 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07002077 case MSG_RELOAD_KEYBOARD_LAYOUTS:
2078 reloadKeyboardLayouts();
2079 break;
2080 case MSG_UPDATE_KEYBOARD_LAYOUTS:
2081 updateKeyboardLayouts();
2082 break;
2083 case MSG_RELOAD_DEVICE_ALIASES:
2084 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002085 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08002086 case MSG_DELIVER_TABLET_MODE_CHANGED: {
Michael Wright39e5e942015-08-19 22:52:47 +01002087 SomeArgs args = (SomeArgs) msg.obj;
2088 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
2089 boolean inTabletMode = (boolean) args.arg1;
2090 deliverTabletModeChanged(whenNanos, inTabletMode);
2091 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08002092 }
2093 case MSG_INPUT_METHOD_SUBTYPE_CHANGED: {
2094 final int userId = msg.arg1;
2095 final SomeArgs args = (SomeArgs) msg.obj;
2096 final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1;
2097 final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2;
2098 args.recycle();
2099 handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype);
2100 break;
2101 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002102 }
2103 }
2104 }
2105
2106 /**
Jeff Brown4532e612012-04-05 14:27:12 -07002107 * Hosting interface for input filters to call back into the input manager.
2108 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07002109 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07002110 private boolean mDisconnected;
2111
2112 public void disconnectLocked() {
2113 mDisconnected = true;
2114 }
2115
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002116 @Override
Jeff Brown0029c662011-03-30 02:25:18 -07002117 public void sendInputEvent(InputEvent event, int policyFlags) {
2118 if (event == null) {
2119 throw new IllegalArgumentException("event must not be null");
2120 }
2121
2122 synchronized (mInputFilterLock) {
2123 if (!mDisconnected) {
Jeff Brownca9bc702014-02-11 14:32:56 -08002124 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
Jeff Brownac143512012-04-05 18:57:33 -07002125 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07002126 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
2127 }
2128 }
2129 }
2130 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07002131
2132 private static final class KeyboardLayoutDescriptor {
2133 public String packageName;
2134 public String receiverName;
2135 public String keyboardLayoutName;
2136
2137 public static String format(String packageName,
2138 String receiverName, String keyboardName) {
2139 return packageName + "/" + receiverName + "/" + keyboardName;
2140 }
2141
2142 public static KeyboardLayoutDescriptor parse(String descriptor) {
2143 int pos = descriptor.indexOf('/');
2144 if (pos < 0 || pos + 1 == descriptor.length()) {
2145 return null;
2146 }
2147 int pos2 = descriptor.indexOf('/', pos + 1);
2148 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
2149 return null;
2150 }
2151
2152 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
2153 result.packageName = descriptor.substring(0, pos);
2154 result.receiverName = descriptor.substring(pos + 1, pos2);
2155 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
2156 return result;
2157 }
2158 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002159
Jeff Brown6ec6f792012-04-17 16:52:41 -07002160 private interface KeyboardLayoutVisitor {
Michael Wright07483422015-10-30 16:20:13 +00002161 void visitKeyboardLayout(Resources resources,
2162 int keyboardLayoutResId, KeyboardLayout layout);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002163 }
2164
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002165 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
2166 private final int mPid;
2167 private final IInputDevicesChangedListener mListener;
2168
2169 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
2170 mPid = pid;
2171 mListener = listener;
2172 }
2173
2174 @Override
2175 public void binderDied() {
2176 if (DEBUG) {
2177 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
2178 }
2179 onInputDevicesChangedListenerDied(mPid);
2180 }
2181
2182 public void notifyInputDevicesChanged(int[] info) {
2183 try {
2184 mListener.onInputDevicesChanged(info);
2185 } catch (RemoteException ex) {
2186 Slog.w(TAG, "Failed to notify process "
2187 + mPid + " that input devices changed, assuming it died.", ex);
2188 binderDied();
2189 }
2190 }
2191 }
Jeff Browna47425a2012-04-13 04:09:27 -07002192
Michael Wright39e5e942015-08-19 22:52:47 +01002193 private final class TabletModeChangedListenerRecord implements DeathRecipient {
2194 private final int mPid;
2195 private final ITabletModeChangedListener mListener;
2196
2197 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
2198 mPid = pid;
2199 mListener = listener;
2200 }
2201
2202 @Override
2203 public void binderDied() {
2204 if (DEBUG) {
2205 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
2206 }
2207 onTabletModeChangedListenerDied(mPid);
2208 }
2209
2210 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
2211 try {
2212 mListener.onTabletModeChanged(whenNanos, inTabletMode);
2213 } catch (RemoteException ex) {
2214 Slog.w(TAG, "Failed to notify process " + mPid +
2215 " that tablet mode changed, assuming it died.", ex);
2216 binderDied();
2217 }
2218 }
2219 }
2220
Jeff Browna47425a2012-04-13 04:09:27 -07002221 private final class VibratorToken implements DeathRecipient {
2222 public final int mDeviceId;
2223 public final IBinder mToken;
2224 public final int mTokenValue;
2225
2226 public boolean mVibrating;
2227
2228 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
2229 mDeviceId = deviceId;
2230 mToken = token;
2231 mTokenValue = tokenValue;
2232 }
2233
2234 @Override
2235 public void binderDied() {
2236 if (DEBUG) {
2237 Slog.d(TAG, "Vibrator token died.");
2238 }
2239 onVibratorTokenDied(this);
2240 }
2241 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002242
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002243 private class Shell extends ShellCommand {
2244 @Override
2245 public int onCommand(String cmd) {
2246 return onShellCommand(this, cmd);
2247 }
2248
2249 @Override
2250 public void onHelp() {
2251 final PrintWriter pw = getOutPrintWriter();
2252 pw.println("Input manager commands:");
2253 pw.println(" help");
2254 pw.println(" Print this help text.");
2255 pw.println("");
2256 pw.println(" setlayout IME_ID IME_SUPTYPE_HASH_CODE"
2257 + " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR");
2258 pw.println(" Sets a keyboard layout for a given IME subtype and input device pair");
2259 }
2260 }
2261
Jeff Brown4ccb8232014-01-16 22:16:42 -08002262 private final class LocalService extends InputManagerInternal {
2263 @Override
2264 public void setDisplayViewports(
2265 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
2266 setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
2267 }
Jeff Brownca9bc702014-02-11 14:32:56 -08002268
2269 @Override
2270 public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
2271 return injectInputEventInternal(event, displayId, mode);
2272 }
Jeff Brown037c33e2014-04-09 00:31:55 -07002273
2274 @Override
2275 public void setInteractive(boolean interactive) {
2276 nativeSetInteractive(mPtr, interactive);
2277 }
Yohei Yukawab097b822015-12-01 10:43:08 -08002278
2279 @Override
2280 public void onInputMethodSubtypeChanged(int userId,
2281 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
2282 final SomeArgs someArgs = SomeArgs.obtain();
2283 someArgs.arg1 = inputMethodInfo;
2284 someArgs.arg2 = subtype;
2285 mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs)
2286 .sendToTarget();
2287 }
Andrii Kulian112d0562016-03-08 10:44:22 -08002288
2289 @Override
2290 public void toggleCapsLock(int deviceId) {
2291 nativeToggleCapsLock(mPtr, deviceId);
2292 }
Adrian Roos99182342016-06-15 15:30:46 -07002293
2294 @Override
2295 public void setPulseGestureEnabled(boolean enabled) {
2296 if (mDoubleTouchGestureEnableFile != null) {
2297 FileWriter writer = null;
2298 try {
2299 writer = new FileWriter(mDoubleTouchGestureEnableFile);
2300 writer.write(enabled ? "1" : "0");
2301 } catch (IOException e) {
2302 Log.wtf(TAG, "Unable to setPulseGestureEnabled", e);
2303 } finally {
2304 IoUtils.closeQuietly(writer);
2305 }
2306 }
2307 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002308 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07002309}