blob: 297d5bd1afc92f25d2af6d7c237b55b8f4c2c295 [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;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050026import com.android.internal.notification.SystemNotificationChannels;
Michael Wright39e5e942015-08-19 22:52:47 +010027import com.android.internal.os.SomeArgs;
Jeff Browncf39bdf2012-05-18 14:41:19 -070028import com.android.internal.R;
Michael Wrightb004b512017-01-18 18:09:29 +000029import com.android.internal.util.Preconditions;
Jeff Brown46b9ac02010-04-22 18:58:52 -070030import com.android.internal.util.XmlUtils;
Jeff Brown4ccb8232014-01-16 22:16:42 -080031import com.android.server.DisplayThread;
32import com.android.server.LocalServices;
Jeff Brown89ef0722011-08-10 16:25:21 -070033import com.android.server.Watchdog;
Jeff Brown46b9ac02010-04-22 18:58:52 -070034
35import org.xmlpull.v1.XmlPullParser;
36
Jeff Browna3bc5652012-04-17 11:42:25 -070037import android.Manifest;
Jeff Browncf39bdf2012-05-18 14:41:19 -070038import android.app.Notification;
39import android.app.NotificationManager;
40import android.app.PendingIntent;
Jeff Brown5bbd4b42012-04-20 19:28:00 -070041import android.bluetooth.BluetoothAdapter;
42import android.bluetooth.BluetoothDevice;
Jeff Brown6ec6f792012-04-17 16:52:41 -070043import android.content.BroadcastReceiver;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070044import android.content.ComponentName;
Jeff Brown46b9ac02010-04-22 18:58:52 -070045import android.content.Context;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070046import android.content.Intent;
Jeff Brown6ec6f792012-04-17 16:52:41 -070047import android.content.IntentFilter;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070048import android.content.pm.ActivityInfo;
Michael Wright8ebac232014-09-18 18:29:49 -070049import android.content.pm.ApplicationInfo;
Jeff Brown349703e2010-06-22 01:27:15 -070050import android.content.pm.PackageManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070051import android.content.pm.ResolveInfo;
52import android.content.pm.PackageManager.NameNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070053import android.content.res.Resources;
Jeff Brown6ec6f792012-04-17 16:52:41 -070054import android.content.res.Resources.NotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070055import android.content.res.TypedArray;
56import android.content.res.XmlResourceParser;
Jeff Brown1a84fd12011-06-02 01:26:32 -070057import android.database.ContentObserver;
Jeff Brown4ccb8232014-01-16 22:16:42 -080058import android.hardware.display.DisplayViewport;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070059import android.hardware.input.IInputDevicesChangedListener;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070060import android.hardware.input.IInputManager;
RoboErikfb290df2013-12-16 11:27:55 -080061import android.hardware.input.InputDeviceIdentifier;
Jeff Brownac143512012-04-05 18:57:33 -070062import android.hardware.input.InputManager;
Jeff Brown4ccb8232014-01-16 22:16:42 -080063import android.hardware.input.InputManagerInternal;
Michael Wright39e5e942015-08-19 22:52:47 +010064import android.hardware.input.ITabletModeChangedListener;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070065import android.hardware.input.KeyboardLayout;
Jason Gerecked6396d62014-01-27 18:30:37 -080066import android.hardware.input.TouchCalibration;
Jeff Brown4532e612012-04-05 14:27:12 -070067import android.os.Binder;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070068import android.os.Bundle;
Jeff Brown46b9ac02010-04-22 18:58:52 -070069import android.os.Environment;
Jeff Brown4532e612012-04-05 14:27:12 -070070import android.os.Handler;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070071import android.os.IBinder;
Jeff Browna9d131c2012-09-20 16:48:17 -070072import android.os.Looper;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070073import android.os.Message;
Jeff Brown05dc66a2011-03-02 14:41:58 -080074import android.os.MessageQueue;
Jeff Brownac143512012-04-05 18:57:33 -070075import android.os.Process;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070076import android.os.RemoteException;
Michael Wrightd5f7ed92016-01-19 11:23:51 -080077import android.os.ResultReceiver;
78import android.os.ShellCommand;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070079import android.os.UserHandle;
Jeff Brown1a84fd12011-06-02 01:26:32 -070080import android.provider.Settings;
81import android.provider.Settings.SettingNotFoundException;
Michael Wright07483422015-10-30 16:20:13 +000082import android.text.TextUtils;
Jeff Brown46b9ac02010-04-22 18:58:52 -070083import android.util.Slog;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070084import android.util.SparseArray;
Jeff Brown46b9ac02010-04-22 18:58:52 -070085import android.util.Xml;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070086import android.view.IInputFilter;
87import android.view.IInputFilterHost;
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -080088import android.view.IWindow;
Jeff Brown46b9ac02010-04-22 18:58:52 -070089import android.view.InputChannel;
Jeff Brown8d608662010-08-30 03:02:23 -070090import android.view.InputDevice;
Jeff Brown6ec402b2010-07-28 15:48:59 -070091import android.view.InputEvent;
Jeff Brown1f245102010-11-18 20:53:46 -080092import android.view.KeyEvent;
Jeff Brown2352b972011-04-12 22:39:53 -070093import android.view.PointerIcon;
Jason Gerecked5220742014-03-10 09:47:59 -070094import android.view.Surface;
Jeff Browna4547672011-03-02 21:38:11 -080095import android.view.ViewConfiguration;
Jeff Brown0029c662011-03-30 02:25:18 -070096import android.view.WindowManagerPolicy;
Yohei Yukawab097b822015-12-01 10:43:08 -080097import android.view.inputmethod.InputMethodInfo;
98import android.view.inputmethod.InputMethodSubtype;
Jeff Brown46b9ac02010-04-22 18:58:52 -070099
Jeff Brown46b9ac02010-04-22 18:58:52 -0700100import java.io.File;
Jeff Brown4532e612012-04-05 14:27:12 -0700101import java.io.FileDescriptor;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700102import java.io.FileNotFoundException;
103import java.io.FileReader;
Adrian Roos99182342016-06-15 15:30:46 -0700104import java.io.FileWriter;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700105import java.io.IOException;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700106import java.io.InputStreamReader;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700107import java.io.PrintWriter;
108import java.util.ArrayList;
Michael Wright07483422015-10-30 16:20:13 +0000109import java.util.Collections;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700110import java.util.HashMap;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700111import java.util.HashSet;
Michael Wright39e5e942015-08-19 22:52:47 +0100112import java.util.List;
Michael Wright07483422015-10-30 16:20:13 +0000113import java.util.Locale;
Jeff Browna3bc5652012-04-17 11:42:25 -0700114
Adrian Roos99182342016-06-15 15:30:46 -0700115import libcore.io.IoUtils;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700116import libcore.io.Streams;
Jeff Browna3bc5652012-04-17 11:42:25 -0700117import libcore.util.Objects;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700118
119/*
120 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -0700121 */
Jeff Brownd728bf52012-09-08 18:05:28 -0700122public class InputManagerService extends IInputManager.Stub
Jeff Brown4ccb8232014-01-16 22:16:42 -0800123 implements Watchdog.Monitor {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700124 static final String TAG = "InputManager";
Jeff Brown1b9ba572012-05-21 10:54:18 -0700125 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -0700126
Jeff Brown4532e612012-04-05 14:27:12 -0700127 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
128
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700129 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700130 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
131 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
132 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
133 private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
Michael Wright39e5e942015-08-19 22:52:47 +0100134 private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
Yohei Yukawab097b822015-12-01 10:43:08 -0800135 private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700136
Jeff Brown4532e612012-04-05 14:27:12 -0700137 // Pointer to native input manager service object.
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000138 private final long mPtr;
Jeff Brown4532e612012-04-05 14:27:12 -0700139
Jeff Brown46b9ac02010-04-22 18:58:52 -0700140 private final Context mContext;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700141 private final InputManagerHandler mHandler;
Jeff Browna9d131c2012-09-20 16:48:17 -0700142
Adrian Roos99182342016-06-15 15:30:46 -0700143 private final File mDoubleTouchGestureEnableFile;
144
Jeff Browna9d131c2012-09-20 16:48:17 -0700145 private WindowManagerCallbacks mWindowManagerCallbacks;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700146 private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700147 private boolean mSystemReady;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700148 private NotificationManager mNotificationManager;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700149
Michael Wright39e5e942015-08-19 22:52:47 +0100150 private final Object mTabletModeLock = new Object();
151 // List of currently registered tablet mode changed listeners by process id
152 private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
153 new SparseArray<>(); // guarded by mTabletModeLock
154 private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
155 new ArrayList<>();
156
Jeff Browna3bc5652012-04-17 11:42:25 -0700157 // Persistent data store. Must be locked each time during use.
158 private final PersistentDataStore mDataStore = new PersistentDataStore();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700159
160 // List of currently registered input devices changed listeners by process id.
161 private Object mInputDevicesLock = new Object();
162 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
163 private InputDevice[] mInputDevices = new InputDevice[0];
164 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
165 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
166 private final ArrayList<InputDevicesChangedListenerRecord>
167 mTempInputDevicesChangedListenersToNotify =
168 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
Jeff Browncf39bdf2012-05-18 14:41:19 -0700169 private final ArrayList<InputDevice>
170 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
171 private boolean mKeyboardLayoutNotificationShown;
Michael Wrightd5f7ed92016-01-19 11:23:51 -0800172 private InputMethodSubtypeHandle mCurrentImeHandle;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700173
Jeff Browna47425a2012-04-13 04:09:27 -0700174 // State for vibrator tokens.
175 private Object mVibratorLock = new Object();
176 private HashMap<IBinder, VibratorToken> mVibratorTokens =
177 new HashMap<IBinder, VibratorToken>();
178 private int mNextVibratorTokenValue;
179
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700180 // State for the currently installed input filter.
181 final Object mInputFilterLock = new Object();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700182 IInputFilter mInputFilter; // guarded by mInputFilterLock
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700183 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
Jeff Brown1a84fd12011-06-02 01:26:32 -0700184
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -0800185 private IWindow mFocusedWindow;
186 private boolean mFocusedWindowHasCapture;
187
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000188 private static native long nativeInit(InputManagerService service,
Jeff Brown4532e612012-04-05 14:27:12 -0700189 Context context, MessageQueue messageQueue);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000190 private static native void nativeStart(long ptr);
191 private static native void nativeSetDisplayViewport(long ptr, boolean external,
Jeff Brownd728bf52012-09-08 18:05:28 -0700192 int displayId, int rotation,
193 int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
Jeff Brown83d616a2012-09-09 20:33:43 -0700194 int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
195 int deviceWidth, int deviceHeight);
Jeff Brownd728bf52012-09-08 18:05:28 -0700196
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000197 private static native int nativeGetScanCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700198 int deviceId, int sourceMask, int scanCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000199 private static native int nativeGetKeyCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700200 int deviceId, int sourceMask, int keyCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000201 private static native int nativeGetSwitchState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700202 int deviceId, int sourceMask, int sw);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000203 private static native boolean nativeHasKeys(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700204 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000205 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
Jeff Brown928e0542011-01-10 11:17:36 -0800206 InputWindowHandle inputWindowHandle, boolean monitor);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000207 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
208 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
Jeff Brownca9bc702014-02-11 14:32:56 -0800209 private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId,
Jeff Brown0029c662011-03-30 02:25:18 -0700210 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
211 int policyFlags);
Andrii Kulian112d0562016-03-08 10:44:22 -0800212 private static native void nativeToggleCapsLock(long ptr, int deviceId);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000213 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
214 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
215 private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
216 private static native void nativeSetFocusedApplication(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700217 InputApplicationHandle application);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000218 private static native boolean nativeTransferTouchFocus(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700219 InputChannel fromChannel, InputChannel toChannel);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000220 private static native void nativeSetPointerSpeed(long ptr, int speed);
221 private static native void nativeSetShowTouches(long ptr, boolean enabled);
Jeff Brown037c33e2014-04-09 00:31:55 -0700222 private static native void nativeSetInteractive(long ptr, boolean interactive);
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800223 private static native void nativeReloadCalibration(long ptr);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000224 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
Jeff Browna47425a2012-04-13 04:09:27 -0700225 int repeat, int token);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000226 private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
227 private static native void nativeReloadKeyboardLayouts(long ptr);
228 private static native void nativeReloadDeviceAliases(long ptr);
229 private static native String nativeDump(long ptr);
230 private static native void nativeMonitor(long ptr);
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100231 private static native void nativeSetPointerIconType(long ptr, int iconId);
Jun Mukai19a56012015-11-24 11:25:52 -0800232 private static native void nativeReloadPointerIcons(long ptr);
Jun Mukaid4eaef72015-10-30 15:54:33 -0700233 private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -0800234 private static native void nativeSetPointerCapture(long ptr, boolean detached);
Jeff Brown4532e612012-04-05 14:27:12 -0700235
Jeff Brownac143512012-04-05 18:57:33 -0700236 // Input event injection constants defined in InputDispatcher.h.
237 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
238 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
239 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
240 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
241
242 // Maximum number of milliseconds to wait for input event injection.
243 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
244
Jeff Brown6d0fec22010-07-23 21:28:06 -0700245 // Key states (may be returned by queries about the current state of a
246 // particular key code, scan code or switch).
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700247
Jeff Brown6d0fec22010-07-23 21:28:06 -0700248 /** The key state is unknown or the requested key itself is not supported. */
249 public static final int KEY_STATE_UNKNOWN = -1;
250
251 /** The key is up. /*/
252 public static final int KEY_STATE_UP = 0;
253
254 /** The key is down. */
255 public static final int KEY_STATE_DOWN = 1;
256
257 /** The key is down but is a virtual key press that is being emulated by the system. */
258 public static final int KEY_STATE_VIRTUAL = 2;
259
Jeff Brownc458ce92012-04-30 14:58:40 -0700260 /** Scan code: Mouse / trackball button. */
261 public static final int BTN_MOUSE = 0x110;
262
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700263 // Switch code values must match bionic/libc/kernel/common/linux/input.h
Jeff Brownc458ce92012-04-30 14:58:40 -0700264 /** Switch code: Lid switch. When set, lid is shut. */
265 public static final int SW_LID = 0x00;
266
Michael Wright39e5e942015-08-19 22:52:47 +0100267 /** Switch code: Tablet mode switch.
268 * When set, the device is in tablet mode (i.e. no keyboard is connected).
269 */
270 public static final int SW_TABLET_MODE = 0x01;
271
Jeff Brownc458ce92012-04-30 14:58:40 -0700272 /** Switch code: Keypad slide. When set, keyboard is exposed. */
273 public static final int SW_KEYPAD_SLIDE = 0x0a;
274
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700275 /** Switch code: Headphone. When set, headphone is inserted. */
276 public static final int SW_HEADPHONE_INSERT = 0x02;
277
278 /** Switch code: Microphone. When set, microphone is inserted. */
279 public static final int SW_MICROPHONE_INSERT = 0x04;
280
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500281 /** Switch code: Line out. When set, Line out (hi-Z) is inserted. */
282 public static final int SW_LINEOUT_INSERT = 0x06;
283
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700284 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */
285 public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
286
Michael Wright3818c922014-09-02 13:59:07 -0700287 /** Switch code: Camera lens cover. When set the lens is covered. */
288 public static final int SW_CAMERA_LENS_COVER = 0x09;
289
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700290 public static final int SW_LID_BIT = 1 << SW_LID;
Michael Wright39e5e942015-08-19 22:52:47 +0100291 public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700292 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
293 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
294 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500295 public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700296 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
297 public static final int SW_JACK_BITS =
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500298 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
Michael Wright3818c922014-09-02 13:59:07 -0700299 public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700300
301 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
302 final boolean mUseDevInputEventForAudioJack;
303
Jeff Brown4ccb8232014-01-16 22:16:42 -0800304 public InputManagerService(Context context) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700305 this.mContext = context;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800306 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
Jeff Brown05dc66a2011-03-02 14:41:58 -0800307
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700308 mUseDevInputEventForAudioJack =
309 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
310 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
311 + mUseDevInputEventForAudioJack);
Jeff Brown4532e612012-04-05 14:27:12 -0700312 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown4ccb8232014-01-16 22:16:42 -0800313
Adrian Roos99182342016-06-15 15:30:46 -0700314 String doubleTouchGestureEnablePath = context.getResources().getString(
315 R.string.config_doubleTouchGestureEnableFile);
316 mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
317 new File(doubleTouchGestureEnablePath);
318
Jeff Brown4ccb8232014-01-16 22:16:42 -0800319 LocalServices.addService(InputManagerInternal.class, new LocalService());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700320 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700321
Jeff Browna9d131c2012-09-20 16:48:17 -0700322 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
323 mWindowManagerCallbacks = callbacks;
324 }
325
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700326 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
327 mWiredAccessoryCallbacks = callbacks;
328 }
329
Jeff Brown46b9ac02010-04-22 18:58:52 -0700330 public void start() {
331 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700332 nativeStart(mPtr);
333
334 // Add ourself to the Watchdog monitors.
335 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700336
337 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700338 registerShowTouchesSettingObserver();
Jun Mukai19a56012015-11-24 11:25:52 -0800339 registerAccessibilityLargePointerSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700340
Jeff Brownd4935962012-09-25 13:27:20 -0700341 mContext.registerReceiver(new BroadcastReceiver() {
342 @Override
343 public void onReceive(Context context, Intent intent) {
344 updatePointerSpeedFromSettings();
345 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800346 updateAccessibilityLargePointerFromSettings();
Jeff Brownd4935962012-09-25 13:27:20 -0700347 }
348 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
349
Jeff Brown1a84fd12011-06-02 01:26:32 -0700350 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700351 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800352 updateAccessibilityLargePointerFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700353 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700354
Matthew Xie96313142012-06-29 16:57:31 -0700355 // TODO(BT) Pass in paramter for bluetooth system
Svetoslav Ganova0027152013-06-25 14:59:53 -0700356 public void systemRunning() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700357 if (DEBUG) {
358 Slog.d(TAG, "System ready.");
359 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700360 mNotificationManager = (NotificationManager)mContext.getSystemService(
361 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700362 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700363
364 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
365 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
366 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Jeff Brown69b07162013-11-07 00:30:16 -0800367 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700368 filter.addDataScheme("package");
369 mContext.registerReceiver(new BroadcastReceiver() {
370 @Override
371 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700372 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700373 }
374 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700375
376 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
377 mContext.registerReceiver(new BroadcastReceiver() {
378 @Override
379 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700380 reloadDeviceAliases();
381 }
382 }, filter, null, mHandler);
383
Jeff Browncf39bdf2012-05-18 14:41:19 -0700384 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
385 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700386
387 if (mWiredAccessoryCallbacks != null) {
388 mWiredAccessoryCallbacks.systemReady();
389 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700390 }
391
392 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700393 if (DEBUG) {
394 Slog.d(TAG, "Reloading keyboard layouts.");
395 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700396 nativeReloadKeyboardLayouts(mPtr);
397 }
398
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700399 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700400 if (DEBUG) {
401 Slog.d(TAG, "Reloading device names.");
402 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700403 nativeReloadDeviceAliases(mPtr);
404 }
405
Jeff Brown4ccb8232014-01-16 22:16:42 -0800406 private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
Jeff Brownd728bf52012-09-08 18:05:28 -0700407 DisplayViewport externalTouchViewport) {
408 if (defaultViewport.valid) {
409 setDisplayViewport(false, defaultViewport);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700410 }
Jeff Brownd728bf52012-09-08 18:05:28 -0700411
412 if (externalTouchViewport.valid) {
413 setDisplayViewport(true, externalTouchViewport);
414 } else if (defaultViewport.valid) {
415 setDisplayViewport(true, defaultViewport);
Jeff Brownb6997262010-10-08 22:31:17 -0700416 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700417 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700418
Jeff Brownd728bf52012-09-08 18:05:28 -0700419 private void setDisplayViewport(boolean external, DisplayViewport viewport) {
420 nativeSetDisplayViewport(mPtr, external,
421 viewport.displayId, viewport.orientation,
422 viewport.logicalFrame.left, viewport.logicalFrame.top,
423 viewport.logicalFrame.right, viewport.logicalFrame.bottom,
424 viewport.physicalFrame.left, viewport.physicalFrame.top,
Jeff Brown83d616a2012-09-09 20:33:43 -0700425 viewport.physicalFrame.right, viewport.physicalFrame.bottom,
426 viewport.deviceWidth, viewport.deviceHeight);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700427 }
Jeff Brownac143512012-04-05 18:57:33 -0700428
Jeff Brown6d0fec22010-07-23 21:28:06 -0700429 /**
430 * Gets the current state of a key or button by key code.
431 * @param deviceId The input device id, or -1 to consult all devices.
432 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
433 * consider all input sources. An input device is consulted if at least one of its
434 * non-class input source bits matches the specified source mask.
435 * @param keyCode The key code to check.
436 * @return The key state.
437 */
438 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700439 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700440 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700441
Jeff Brown6d0fec22010-07-23 21:28:06 -0700442 /**
443 * Gets the current state of a key or button by scan code.
444 * @param deviceId The input device id, or -1 to consult all devices.
445 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
446 * consider all input sources. An input device is consulted if at least one of its
447 * non-class input source bits matches the specified source mask.
448 * @param scanCode The scan code to check.
449 * @return The key state.
450 */
451 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700452 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700453 }
RoboErikfb290df2013-12-16 11:27:55 -0800454
Jeff Brown6d0fec22010-07-23 21:28:06 -0700455 /**
456 * Gets the current state of a switch by switch code.
457 * @param deviceId The input device id, or -1 to consult all devices.
458 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
459 * consider all input sources. An input device is consulted if at least one of its
460 * non-class input source bits matches the specified source mask.
461 * @param switchCode The switch code to check.
462 * @return The switch state.
463 */
464 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700465 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700466 }
467
Jeff Brown6d0fec22010-07-23 21:28:06 -0700468 /**
469 * Determines whether the specified key codes are supported by a particular device.
470 * @param deviceId The input device id, or -1 to consult all devices.
471 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
472 * consider all input sources. An input device is consulted if at least one of its
473 * non-class input source bits matches the specified source mask.
474 * @param keyCodes The array of key codes to check.
475 * @param keyExists An array at least as large as keyCodes whose entries will be set
476 * to true or false based on the presence or absence of support for the corresponding
477 * key codes.
478 * @return True if the lookup was successful, false otherwise.
479 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700480 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700481 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700482 if (keyCodes == null) {
483 throw new IllegalArgumentException("keyCodes must not be null.");
484 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700485 if (keyExists == null || keyExists.length < keyCodes.length) {
486 throw new IllegalArgumentException("keyExists must not be null and must be at "
487 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700488 }
RoboErikfb290df2013-12-16 11:27:55 -0800489
Jeff Brown4532e612012-04-05 14:27:12 -0700490 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700491 }
RoboErikfb290df2013-12-16 11:27:55 -0800492
Jeff Browna41ca772010-08-11 14:46:32 -0700493 /**
494 * Creates an input channel that will receive all input from the input dispatcher.
495 * @param inputChannelName The input channel name.
496 * @return The input channel.
497 */
498 public InputChannel monitorInput(String inputChannelName) {
499 if (inputChannelName == null) {
500 throw new IllegalArgumentException("inputChannelName must not be null.");
501 }
RoboErikfb290df2013-12-16 11:27:55 -0800502
Jeff Browna41ca772010-08-11 14:46:32 -0700503 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700504 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700505 inputChannels[0].dispose(); // don't need to retain the Java object reference
506 return inputChannels[1];
507 }
508
509 /**
510 * Registers an input channel so that it can be used as an input event target.
511 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800512 * @param inputWindowHandle The handle of the input window associated with the
513 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700514 */
Jeff Brown928e0542011-01-10 11:17:36 -0800515 public void registerInputChannel(InputChannel inputChannel,
516 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700517 if (inputChannel == null) {
518 throw new IllegalArgumentException("inputChannel must not be null.");
519 }
RoboErikfb290df2013-12-16 11:27:55 -0800520
Jeff Brown4532e612012-04-05 14:27:12 -0700521 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700522 }
RoboErikfb290df2013-12-16 11:27:55 -0800523
Jeff Browna41ca772010-08-11 14:46:32 -0700524 /**
525 * Unregisters an input channel.
526 * @param inputChannel The input channel to unregister.
527 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700528 public void unregisterInputChannel(InputChannel inputChannel) {
529 if (inputChannel == null) {
530 throw new IllegalArgumentException("inputChannel must not be null.");
531 }
RoboErikfb290df2013-12-16 11:27:55 -0800532
Jeff Brown4532e612012-04-05 14:27:12 -0700533 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700534 }
Jeff Brown0029c662011-03-30 02:25:18 -0700535
536 /**
537 * Sets an input filter that will receive all input events before they are dispatched.
538 * The input filter may then reinterpret input events or inject new ones.
539 *
540 * To ensure consistency, the input dispatcher automatically drops all events
541 * in progress whenever an input filter is installed or uninstalled. After an input
542 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
543 * Any events it attempts to send after it has been uninstalled will be dropped.
544 *
545 * @param filter The input filter, or null to remove the current filter.
546 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700547 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700548 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700549 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700550 if (oldFilter == filter) {
551 return; // nothing to do
552 }
553
554 if (oldFilter != null) {
555 mInputFilter = null;
556 mInputFilterHost.disconnectLocked();
557 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700558 try {
559 oldFilter.uninstall();
560 } catch (RemoteException re) {
561 /* ignore */
562 }
Jeff Brown0029c662011-03-30 02:25:18 -0700563 }
564
565 if (filter != null) {
566 mInputFilter = filter;
567 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700568 try {
569 filter.install(mInputFilterHost);
570 } catch (RemoteException re) {
571 /* ignore */
572 }
Jeff Brown0029c662011-03-30 02:25:18 -0700573 }
574
Jeff Brown4532e612012-04-05 14:27:12 -0700575 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700576 }
577 }
578
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700579 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700580 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brownca9bc702014-02-11 14:32:56 -0800581 return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
582 }
583
584 private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700585 if (event == null) {
586 throw new IllegalArgumentException("event must not be null");
587 }
Jeff Brownac143512012-04-05 18:57:33 -0700588 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
589 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
590 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
591 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700592 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700593
Jeff Brownac143512012-04-05 18:57:33 -0700594 final int pid = Binder.getCallingPid();
595 final int uid = Binder.getCallingUid();
596 final long ident = Binder.clearCallingIdentity();
597 final int result;
598 try {
Jeff Brownca9bc702014-02-11 14:32:56 -0800599 result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
Jeff Brownac143512012-04-05 18:57:33 -0700600 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
601 } finally {
602 Binder.restoreCallingIdentity(ident);
603 }
604 switch (result) {
605 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
606 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
607 throw new SecurityException(
608 "Injecting to another application requires INJECT_EVENTS permission");
609 case INPUT_EVENT_INJECTION_SUCCEEDED:
610 return true;
611 case INPUT_EVENT_INJECTION_TIMED_OUT:
612 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
613 return false;
614 case INPUT_EVENT_INJECTION_FAILED:
615 default:
616 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
617 return false;
618 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700619 }
Jeff Brown0029c662011-03-30 02:25:18 -0700620
Jeff Brown8d608662010-08-30 03:02:23 -0700621 /**
622 * Gets information about the input device with the specified id.
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700623 * @param deviceId The device id.
Jeff Brown8d608662010-08-30 03:02:23 -0700624 * @return The input device or null if not found.
625 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700626 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700627 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700628 synchronized (mInputDevicesLock) {
629 final int count = mInputDevices.length;
630 for (int i = 0; i < count; i++) {
631 final InputDevice inputDevice = mInputDevices[i];
632 if (inputDevice.getId() == deviceId) {
633 return inputDevice;
634 }
635 }
636 }
637 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700638 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700639
Jeff Brown8d608662010-08-30 03:02:23 -0700640 /**
641 * Gets the ids of all input devices in the system.
642 * @return The input device ids.
643 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700644 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700645 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700646 synchronized (mInputDevicesLock) {
647 final int count = mInputDevices.length;
648 int[] ids = new int[count];
649 for (int i = 0; i < count; i++) {
650 ids[i] = mInputDevices[i].getId();
651 }
652 return ids;
653 }
654 }
655
Jeff Browndaa37532012-05-01 15:54:03 -0700656 /**
657 * Gets all input devices in the system.
658 * @return The array of input devices.
659 */
660 public InputDevice[] getInputDevices() {
661 synchronized (mInputDevicesLock) {
662 return mInputDevices;
663 }
664 }
665
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700666 @Override // Binder call
667 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
668 if (listener == null) {
669 throw new IllegalArgumentException("listener must not be null");
670 }
671
672 synchronized (mInputDevicesLock) {
673 int callingPid = Binder.getCallingPid();
674 if (mInputDevicesChangedListeners.get(callingPid) != null) {
675 throw new SecurityException("The calling process has already "
676 + "registered an InputDevicesChangedListener.");
677 }
678
679 InputDevicesChangedListenerRecord record =
680 new InputDevicesChangedListenerRecord(callingPid, listener);
681 try {
682 IBinder binder = listener.asBinder();
683 binder.linkToDeath(record, 0);
684 } catch (RemoteException ex) {
685 // give up
686 throw new RuntimeException(ex);
687 }
688
689 mInputDevicesChangedListeners.put(callingPid, record);
690 }
691 }
692
693 private void onInputDevicesChangedListenerDied(int pid) {
694 synchronized (mInputDevicesLock) {
695 mInputDevicesChangedListeners.remove(pid);
696 }
697 }
698
699 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700700 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
701 // Scan for changes.
702 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700703 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700704 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700705 final int numListeners;
706 final int[] deviceIdAndGeneration;
707 synchronized (mInputDevicesLock) {
708 if (!mInputDevicesChangedPending) {
709 return;
710 }
711 mInputDevicesChangedPending = false;
712
713 numListeners = mInputDevicesChangedListeners.size();
714 for (int i = 0; i < numListeners; i++) {
715 mTempInputDevicesChangedListenersToNotify.add(
716 mInputDevicesChangedListeners.valueAt(i));
717 }
718
719 final int numDevices = mInputDevices.length;
720 deviceIdAndGeneration = new int[numDevices * 2];
721 for (int i = 0; i < numDevices; i++) {
722 final InputDevice inputDevice = mInputDevices[i];
723 deviceIdAndGeneration[i * 2] = inputDevice.getId();
724 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700725
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700726 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700727 if (!containsInputDeviceWithDescriptor(oldInputDevices,
728 inputDevice.getDescriptor())) {
729 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
730 } else {
731 mTempFullKeyboards.add(inputDevice);
732 }
733 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700734 }
735 }
736
Jeff Browncf39bdf2012-05-18 14:41:19 -0700737 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700738 for (int i = 0; i < numListeners; i++) {
739 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
740 deviceIdAndGeneration);
741 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700742 mTempInputDevicesChangedListenersToNotify.clear();
743
744 // Check for missing keyboard layouts.
Michael Wright07483422015-10-30 16:20:13 +0000745 List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
746 final int numFullKeyboards = mTempFullKeyboards.size();
747 synchronized (mDataStore) {
748 for (int i = 0; i < numFullKeyboards; i++) {
749 final InputDevice inputDevice = mTempFullKeyboards.get(i);
750 String layout =
751 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
752 if (layout == null) {
753 layout = getDefaultKeyboardLayout(inputDevice);
754 if (layout != null) {
755 setCurrentKeyboardLayoutForInputDevice(
756 inputDevice.getIdentifier(), layout);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700757 }
758 }
Michael Wright07483422015-10-30 16:20:13 +0000759 if (layout == null) {
760 keyboardsMissingLayout.add(inputDevice);
761 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700762 }
Michael Wright07483422015-10-30 16:20:13 +0000763 }
764
765 if (mNotificationManager != null) {
766 if (!keyboardsMissingLayout.isEmpty()) {
767 if (keyboardsMissingLayout.size() > 1) {
768 // We have more than one keyboard missing a layout, so drop the
769 // user at the generic input methods page so they can pick which
770 // one to set.
771 showMissingKeyboardLayoutNotification(null);
772 } else {
773 showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
Jeff Browncf39bdf2012-05-18 14:41:19 -0700774 }
775 } else if (mKeyboardLayoutNotificationShown) {
776 hideMissingKeyboardLayoutNotification();
777 }
778 }
779 mTempFullKeyboards.clear();
780 }
781
Michael Wright07483422015-10-30 16:20:13 +0000782 private String getDefaultKeyboardLayout(final InputDevice d) {
783 final Locale systemLocale = mContext.getResources().getConfiguration().locale;
784 // If our locale doesn't have a language for some reason, then we don't really have a
785 // reasonable default.
786 if (TextUtils.isEmpty(systemLocale.getLanguage())) {
787 return null;
788 }
789 final List<KeyboardLayout> layouts = new ArrayList<>();
790 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
791 @Override
792 public void visitKeyboardLayout(Resources resources,
793 int keyboardLayoutResId, KeyboardLayout layout) {
794 // Only select a default when we know the layout is appropriate. For now, this
795 // means its a custom layout for a specific keyboard.
796 if (layout.getVendorId() != d.getVendorId()
797 || layout.getProductId() != d.getProductId()) {
798 return;
799 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800800 final LocaleList locales = layout.getLocales();
801 final int numLocales = locales.size();
802 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
803 if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
Michael Wright07483422015-10-30 16:20:13 +0000804 layouts.add(layout);
805 break;
806 }
807 }
808 }
809 });
810
811 if (layouts.isEmpty()) {
812 return null;
813 }
814
815 // First sort so that ones with higher priority are listed at the top
816 Collections.sort(layouts);
817 // Next we want to try to find an exact match of language, country and variant.
818 final int N = layouts.size();
819 for (int i = 0; i < N; i++) {
820 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800821 final LocaleList locales = layout.getLocales();
822 final int numLocales = locales.size();
823 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
824 final Locale locale = locales.get(localeIndex);
825 if (locale.getCountry().equals(systemLocale.getCountry())
826 && locale.getVariant().equals(systemLocale.getVariant())) {
Michael Wright07483422015-10-30 16:20:13 +0000827 return layout.getDescriptor();
828 }
829 }
830 }
831 // Then try an exact match of language and country
832 for (int i = 0; i < N; i++) {
833 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800834 final LocaleList locales = layout.getLocales();
835 final int numLocales = locales.size();
836 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
837 final Locale locale = locales.get(localeIndex);
838 if (locale.getCountry().equals(systemLocale.getCountry())) {
Michael Wright07483422015-10-30 16:20:13 +0000839 return layout.getDescriptor();
840 }
841 }
842 }
843
844 // Give up and just use the highest priority layout with matching language
845 return layouts.get(0).getDescriptor();
846 }
847
848 private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
849 // Different languages are never compatible
850 if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
851 return false;
852 }
853 // If both the system and the keyboard layout have a country specifier, they must be equal.
854 if (!TextUtils.isEmpty(systemLocale.getCountry())
855 && !TextUtils.isEmpty(keyboardLocale.getCountry())
856 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
857 return false;
858 }
859 return true;
860 }
861
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800862 @Override // Binder call & native callback
Jason Gerecked5220742014-03-10 09:47:59 -0700863 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
864 int surfaceRotation) {
Jason Gerecked6396d62014-01-27 18:30:37 -0800865 if (inputDeviceDescriptor == null) {
866 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
867 }
868
869 synchronized (mDataStore) {
Jason Gerecked5220742014-03-10 09:47:59 -0700870 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
Jason Gerecked6396d62014-01-27 18:30:37 -0800871 }
872 }
873
874 @Override // Binder call
Jason Gerecked5220742014-03-10 09:47:59 -0700875 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
Jason Gerecked6396d62014-01-27 18:30:37 -0800876 TouchCalibration calibration) {
877 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
878 "setTouchCalibrationForInputDevice()")) {
879 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
880 }
881 if (inputDeviceDescriptor == null) {
882 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
883 }
884 if (calibration == null) {
885 throw new IllegalArgumentException("calibration must not be null");
886 }
Jason Gerecked5220742014-03-10 09:47:59 -0700887 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
888 throw new IllegalArgumentException("surfaceRotation value out of bounds");
889 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800890
891 synchronized (mDataStore) {
892 try {
Jason Gerecked5220742014-03-10 09:47:59 -0700893 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
894 calibration)) {
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800895 nativeReloadCalibration(mPtr);
896 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800897 } finally {
898 mDataStore.saveIfNeeded();
899 }
900 }
901 }
902
Michael Wright39e5e942015-08-19 22:52:47 +0100903 @Override // Binder call
Michael Wright9209c9c2015-09-03 17:57:01 +0100904 public int isInTabletMode() {
905 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
906 "isInTabletMode()")) {
907 throw new SecurityException("Requires TABLET_MODE permission");
908 }
909 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
910 }
911
912 @Override // Binder call
Michael Wright39e5e942015-08-19 22:52:47 +0100913 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
Michael Wright9209c9c2015-09-03 17:57:01 +0100914 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
Michael Wright39e5e942015-08-19 22:52:47 +0100915 "registerTabletModeChangedListener()")) {
916 throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
917 }
918 if (listener == null) {
919 throw new IllegalArgumentException("listener must not be null");
920 }
921
922 synchronized (mTabletModeLock) {
923 final int callingPid = Binder.getCallingPid();
924 if (mTabletModeChangedListeners.get(callingPid) != null) {
925 throw new IllegalStateException("The calling process has already registered "
926 + "a TabletModeChangedListener.");
927 }
928 TabletModeChangedListenerRecord record =
929 new TabletModeChangedListenerRecord(callingPid, listener);
930 try {
931 IBinder binder = listener.asBinder();
932 binder.linkToDeath(record, 0);
933 } catch (RemoteException ex) {
934 throw new RuntimeException(ex);
935 }
936 mTabletModeChangedListeners.put(callingPid, record);
937 }
938 }
939
940 private void onTabletModeChangedListenerDied(int pid) {
941 synchronized (mTabletModeLock) {
942 mTabletModeChangedListeners.remove(pid);
943 }
944 }
945
946 // Must be called on handler
947 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
948 mTempTabletModeChangedListenersToNotify.clear();
949 final int numListeners;
950 synchronized (mTabletModeLock) {
951 numListeners = mTabletModeChangedListeners.size();
952 for (int i = 0; i < numListeners; i++) {
953 mTempTabletModeChangedListenersToNotify.add(
954 mTabletModeChangedListeners.valueAt(i));
955 }
956 }
957 for (int i = 0; i < numListeners; i++) {
958 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
959 whenNanos, inTabletMode);
960 }
961 }
962
Jeff Browncf39bdf2012-05-18 14:41:19 -0700963 // Must be called on handler.
Michael Wrightc93fbd12014-09-22 20:07:59 -0700964 private void showMissingKeyboardLayoutNotification(InputDevice device) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700965 if (!mKeyboardLayoutNotificationShown) {
Yohei Yukawa2bff4902016-03-30 01:06:37 -0700966 final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
Michael Wrightc93fbd12014-09-22 20:07:59 -0700967 if (device != null) {
968 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -0700969 }
Michael Wrightc93fbd12014-09-22 20:07:59 -0700970 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
971 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
972 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
973 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
974 intent, 0, null, UserHandle.CURRENT);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700975
976 Resources r = mContext.getResources();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -0500977 Notification notification =
978 new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
979 .setContentTitle(r.getString(
980 R.string.select_keyboard_layout_notification_title))
981 .setContentText(r.getString(
982 R.string.select_keyboard_layout_notification_message))
983 .setContentIntent(keyboardLayoutIntent)
984 .setSmallIcon(R.drawable.ic_settings_language)
985 .setColor(mContext.getColor(
986 com.android.internal.R.color.system_notification_accent_color))
987 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700988 mNotificationManager.notifyAsUser(null,
989 R.string.select_keyboard_layout_notification_title,
990 notification, UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700991 mKeyboardLayoutNotificationShown = true;
992 }
993 }
994
995 // Must be called on handler.
996 private void hideMissingKeyboardLayoutNotification() {
997 if (mKeyboardLayoutNotificationShown) {
998 mKeyboardLayoutNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700999 mNotificationManager.cancelAsUser(null,
1000 R.string.select_keyboard_layout_notification_title,
1001 UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001002 }
1003 }
1004
1005 // Must be called on handler.
1006 private void updateKeyboardLayouts() {
1007 // Scan all input devices state for keyboard layouts that have been uninstalled.
1008 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
1009 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1010 @Override
Michael Wright07483422015-10-30 16:20:13 +00001011 public void visitKeyboardLayout(Resources resources,
1012 int keyboardLayoutResId, KeyboardLayout layout) {
1013 availableKeyboardLayouts.add(layout.getDescriptor());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001014 }
1015 });
1016 synchronized (mDataStore) {
1017 try {
1018 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
1019 } finally {
1020 mDataStore.saveIfNeeded();
1021 }
1022 }
1023
1024 // Reload keyboard layouts.
1025 reloadKeyboardLayouts();
1026 }
1027
Jeff Browncf39bdf2012-05-18 14:41:19 -07001028 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
1029 String descriptor) {
1030 final int numDevices = inputDevices.length;
1031 for (int i = 0; i < numDevices; i++) {
1032 final InputDevice inputDevice = inputDevices[i];
1033 if (inputDevice.getDescriptor().equals(descriptor)) {
1034 return true;
1035 }
1036 }
1037 return false;
Jeff Brown8d608662010-08-30 03:02:23 -07001038 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001039
1040 @Override // Binder call
1041 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001042 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
1043 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1044 @Override
Michael Wright07483422015-10-30 16:20:13 +00001045 public void visitKeyboardLayout(Resources resources,
1046 int keyboardLayoutResId, KeyboardLayout layout) {
1047 list.add(layout);
1048 }
1049 });
1050 return list.toArray(new KeyboardLayout[list.size()]);
1051 }
1052
Michael Wrightb0e804a2016-01-04 16:48:53 -05001053 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001054 public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1055 final InputDeviceIdentifier identifier) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001056 final String[] enabledLayoutDescriptors =
1057 getEnabledKeyboardLayoutsForInputDevice(identifier);
1058 final ArrayList<KeyboardLayout> enabledLayouts =
1059 new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length);
1060 final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>();
Michael Wright07483422015-10-30 16:20:13 +00001061 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1062 boolean mHasSeenDeviceSpecificLayout;
1063
1064 @Override
1065 public void visitKeyboardLayout(Resources resources,
1066 int keyboardLayoutResId, KeyboardLayout layout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001067 // First check if it's enabled. If the keyboard layout is enabled then we always
1068 // want to return it as a possible layout for the device.
1069 for (String s : enabledLayoutDescriptors) {
1070 if (s != null && s.equals(layout.getDescriptor())) {
1071 enabledLayouts.add(layout);
1072 return;
1073 }
1074 }
1075 // Next find any potential layouts that aren't yet enabled for the device. For
1076 // devices that have special layouts we assume there's a reason that the generic
1077 // layouts don't work for them so we don't want to return them since it's likely
1078 // to result in a poor user experience.
Michael Wright07483422015-10-30 16:20:13 +00001079 if (layout.getVendorId() == identifier.getVendorId()
1080 && layout.getProductId() == identifier.getProductId()) {
1081 if (!mHasSeenDeviceSpecificLayout) {
1082 mHasSeenDeviceSpecificLayout = true;
Michael Wrightb0e804a2016-01-04 16:48:53 -05001083 potentialLayouts.clear();
Michael Wright07483422015-10-30 16:20:13 +00001084 }
Michael Wrightb0e804a2016-01-04 16:48:53 -05001085 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001086 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
1087 && !mHasSeenDeviceSpecificLayout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001088 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001089 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001090 }
1091 });
Michael Wrightb0e804a2016-01-04 16:48:53 -05001092 final int enabledLayoutSize = enabledLayouts.size();
1093 final int potentialLayoutSize = potentialLayouts.size();
1094 KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
1095 enabledLayouts.toArray(layouts);
1096 for (int i = 0; i < potentialLayoutSize; i++) {
1097 layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
1098 }
1099 return layouts;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001100 }
1101
1102 @Override // Binder call
1103 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
1104 if (keyboardLayoutDescriptor == null) {
1105 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1106 }
1107
Jeff Brown6ec6f792012-04-17 16:52:41 -07001108 final KeyboardLayout[] result = new KeyboardLayout[1];
1109 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1110 @Override
Michael Wright07483422015-10-30 16:20:13 +00001111 public void visitKeyboardLayout(Resources resources,
1112 int keyboardLayoutResId, KeyboardLayout layout) {
1113 result[0] = layout;
Jeff Brown6ec6f792012-04-17 16:52:41 -07001114 }
1115 });
1116 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00001117 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07001118 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001119 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001120 return result[0];
1121 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001122
Jeff Brown6ec6f792012-04-17 16:52:41 -07001123 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001124 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001125 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
1126 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001127 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
1128 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
Michael Wright8ebac232014-09-18 18:29:49 -07001129 final ActivityInfo activityInfo = resolveInfo.activityInfo;
1130 final int priority = resolveInfo.priority;
1131 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001132 }
1133 }
1134
Jeff Brown6ec6f792012-04-17 16:52:41 -07001135 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
1136 KeyboardLayoutVisitor visitor) {
1137 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
1138 if (d != null) {
1139 final PackageManager pm = mContext.getPackageManager();
1140 try {
1141 ActivityInfo receiver = pm.getReceiverInfo(
1142 new ComponentName(d.packageName, d.receiverName),
Jeff Sharkey5217cac2015-12-20 15:34:01 -07001143 PackageManager.GET_META_DATA
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001144 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1145 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Michael Wright8ebac232014-09-18 18:29:49 -07001146 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001147 } catch (NameNotFoundException ex) {
1148 }
1149 }
1150 }
1151
1152 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
Michael Wright8ebac232014-09-18 18:29:49 -07001153 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001154 Bundle metaData = receiver.metaData;
1155 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001156 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001157 }
1158
1159 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1160 if (configResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001161 Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001162 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001163 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001164 }
1165
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001166 CharSequence receiverLabel = receiver.loadLabel(pm);
1167 String collection = receiverLabel != null ? receiverLabel.toString() : "";
Michael Wright8ebac232014-09-18 18:29:49 -07001168 int priority;
1169 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1170 priority = requestedPriority;
1171 } else {
1172 priority = 0;
1173 }
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001174
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001175 try {
1176 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1177 XmlResourceParser parser = resources.getXml(configResId);
1178 try {
1179 XmlUtils.beginDocument(parser, "keyboard-layouts");
1180
1181 for (;;) {
1182 XmlUtils.nextElement(parser);
1183 String element = parser.getName();
1184 if (element == null) {
1185 break;
1186 }
1187 if (element.equals("keyboard-layout")) {
1188 TypedArray a = resources.obtainAttributes(
1189 parser, com.android.internal.R.styleable.KeyboardLayout);
1190 try {
1191 String name = a.getString(
1192 com.android.internal.R.styleable.KeyboardLayout_name);
1193 String label = a.getString(
1194 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -07001195 int keyboardLayoutResId = a.getResourceId(
1196 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1197 0);
Michael Wright07483422015-10-30 16:20:13 +00001198 String languageTags = a.getString(
1199 com.android.internal.R.styleable.KeyboardLayout_locale);
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001200 LocaleList locales = getLocalesFromLanguageTags(languageTags);
Michael Wright07483422015-10-30 16:20:13 +00001201 int vid = a.getInt(
1202 com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
1203 int pid = a.getInt(
1204 com.android.internal.R.styleable.KeyboardLayout_productId, -1);
1205
Jeff Brown2f095762012-05-10 21:29:33 -07001206 if (name == null || label == null || keyboardLayoutResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001207 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001208 + "attributes in keyboard layout "
1209 + "resource from receiver "
1210 + receiver.packageName + "/" + receiver.name);
1211 } else {
1212 String descriptor = KeyboardLayoutDescriptor.format(
1213 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001214 if (keyboardName == null || name.equals(keyboardName)) {
Michael Wright07483422015-10-30 16:20:13 +00001215 KeyboardLayout layout = new KeyboardLayout(
1216 descriptor, label, collection, priority,
1217 locales, vid, pid);
1218 visitor.visitKeyboardLayout(
1219 resources, keyboardLayoutResId, layout);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001220 }
1221 }
1222 } finally {
1223 a.recycle();
1224 }
1225 } else {
Michael Wright07483422015-10-30 16:20:13 +00001226 Slog.w(TAG, "Skipping unrecognized element '" + element
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001227 + "' in keyboard layout resource from receiver "
1228 + receiver.packageName + "/" + receiver.name);
1229 }
1230 }
1231 } finally {
1232 parser.close();
1233 }
1234 } catch (Exception ex) {
Michael Wright07483422015-10-30 16:20:13 +00001235 Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001236 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001237 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001238 }
1239
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001240 @NonNull
1241 private static LocaleList getLocalesFromLanguageTags(String languageTags) {
Michael Wright07483422015-10-30 16:20:13 +00001242 if (TextUtils.isEmpty(languageTags)) {
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001243 return LocaleList.getEmptyLocaleList();
Michael Wright07483422015-10-30 16:20:13 +00001244 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001245 return LocaleList.forLanguageTags(languageTags.replace('|', ','));
Michael Wright07483422015-10-30 16:20:13 +00001246 }
1247
RoboErikfb290df2013-12-16 11:27:55 -08001248 /**
1249 * Builds a layout descriptor for the vendor/product. This returns the
1250 * descriptor for ids that aren't useful (such as the default 0, 0).
1251 */
1252 private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1253 if (identifier == null || identifier.getDescriptor() == null) {
1254 throw new IllegalArgumentException("identifier and descriptor must not be null");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001255 }
1256
RoboErikfb290df2013-12-16 11:27:55 -08001257 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1258 return identifier.getDescriptor();
1259 }
1260 StringBuilder bob = new StringBuilder();
1261 bob.append("vendor:").append(identifier.getVendorId());
1262 bob.append(",product:").append(identifier.getProductId());
1263 return bob.toString();
1264 }
1265
1266 @Override // Binder call
1267 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1268
1269 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001270 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001271 String layout = null;
1272 // try loading it using the layout descriptor if we have it
1273 layout = mDataStore.getCurrentKeyboardLayout(key);
1274 if (layout == null && !key.equals(identifier.getDescriptor())) {
1275 // if it doesn't exist fall back to the device descriptor
1276 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1277 }
1278 if (DEBUG) {
1279 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1280 + layout);
1281 }
1282 return layout;
Jeff Browna3bc5652012-04-17 11:42:25 -07001283 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001284 }
1285
1286 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001287 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001288 String keyboardLayoutDescriptor) {
1289 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001290 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001291 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1292 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001293 if (keyboardLayoutDescriptor == null) {
1294 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1295 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001296
RoboErikfb290df2013-12-16 11:27:55 -08001297 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001298 synchronized (mDataStore) {
1299 try {
RoboErikfb290df2013-12-16 11:27:55 -08001300 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1301 if (DEBUG) {
1302 Slog.d(TAG, "Saved keyboard layout using " + key);
1303 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001304 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1305 }
Jeff Browna3bc5652012-04-17 11:42:25 -07001306 } finally {
1307 mDataStore.saveIfNeeded();
1308 }
1309 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001310 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001311
Jeff Browncf39bdf2012-05-18 14:41:19 -07001312 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001313 public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
RoboErikfb290df2013-12-16 11:27:55 -08001314 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001315 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001316 String[] layouts = mDataStore.getKeyboardLayouts(key);
1317 if ((layouts == null || layouts.length == 0)
1318 && !key.equals(identifier.getDescriptor())) {
1319 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1320 }
1321 return layouts;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001322 }
1323 }
1324
1325 @Override // Binder call
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001326 @Nullable
1327 public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1328 InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) {
1329 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
1330 String key = getLayoutDescriptor(identifier);
1331 final String keyboardLayoutDescriptor;
1332 synchronized (mDataStore) {
1333 keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle);
1334 }
1335
1336 if (keyboardLayoutDescriptor == null) {
1337 return null;
1338 }
1339
1340 final KeyboardLayout[] result = new KeyboardLayout[1];
1341 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1342 @Override
1343 public void visitKeyboardLayout(Resources resources,
1344 int keyboardLayoutResId, KeyboardLayout layout) {
1345 result[0] = layout;
1346 }
1347 });
1348 if (result[0] == null) {
1349 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
1350 + keyboardLayoutDescriptor + "'.");
1351 }
1352 return result[0];
1353 }
1354
1355 @Override
1356 public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
1357 InputMethodInfo imeInfo, InputMethodSubtype imeSubtype,
1358 String keyboardLayoutDescriptor) {
1359 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1360 "setKeyboardLayoutForInputDevice()")) {
1361 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1362 }
1363 if (keyboardLayoutDescriptor == null) {
1364 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1365 }
Yohei Yukawa46ac35d2016-04-20 16:59:45 -07001366 if (imeInfo == null) {
1367 throw new IllegalArgumentException("imeInfo must not be null");
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001368 }
1369 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
1370 setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
1371 }
1372
1373 private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier,
1374 InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
1375 String key = getLayoutDescriptor(identifier);
1376 synchronized (mDataStore) {
1377 try {
1378 if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) {
1379 if (DEBUG) {
1380 Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor +
1381 " for subtype " + imeHandle + " and device " + identifier +
1382 " using key " + key);
1383 }
1384 if (imeHandle.equals(mCurrentImeHandle)) {
1385 if (DEBUG) {
1386 Slog.d(TAG, "Layout for current subtype changed, switching layout");
1387 }
1388 SomeArgs args = SomeArgs.obtain();
1389 args.arg1 = identifier;
1390 args.arg2 = imeHandle;
1391 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget();
1392 }
1393 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1394 }
1395 } finally {
1396 mDataStore.saveIfNeeded();
1397 }
1398 }
1399 }
1400
1401 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001402 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001403 String keyboardLayoutDescriptor) {
1404 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1405 "addKeyboardLayoutForInputDevice()")) {
1406 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1407 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001408 if (keyboardLayoutDescriptor == null) {
1409 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1410 }
1411
RoboErikfb290df2013-12-16 11:27:55 -08001412 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001413 synchronized (mDataStore) {
1414 try {
RoboErikfb290df2013-12-16 11:27:55 -08001415 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1416 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1417 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1418 }
1419 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001420 && !Objects.equal(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001421 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1422 }
1423 } finally {
1424 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001425 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001426 }
1427 }
1428
1429 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001430 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001431 String keyboardLayoutDescriptor) {
1432 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1433 "removeKeyboardLayoutForInputDevice()")) {
1434 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1435 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001436 if (keyboardLayoutDescriptor == null) {
1437 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1438 }
1439
RoboErikfb290df2013-12-16 11:27:55 -08001440 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001441 synchronized (mDataStore) {
1442 try {
RoboErikfb290df2013-12-16 11:27:55 -08001443 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1444 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1445 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1446 }
1447 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1448 if (!key.equals(identifier.getDescriptor())) {
1449 // We need to remove from both places to ensure it is gone
1450 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1451 keyboardLayoutDescriptor);
1452 }
1453 if (removed && !Objects.equal(oldLayout,
1454 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001455 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1456 }
1457 } finally {
1458 mDataStore.saveIfNeeded();
1459 }
1460 }
1461 }
1462
Yohei Yukawab097b822015-12-01 10:43:08 -08001463 // Must be called on handler.
1464 private void handleSwitchInputMethodSubtype(int userId,
1465 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
1466 if (DEBUG) {
1467 Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
1468 + " ime=" + inputMethodInfo + " subtype=" + subtype);
1469 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001470 if (inputMethodInfo == null) {
1471 Slog.d(TAG, "No InputMethod is running, ignoring change");
1472 return;
1473 }
1474 if (subtype != null && !"keyboard".equals(subtype.getMode())) {
1475 Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change");
1476 return;
1477 }
1478 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype);
1479 if (!handle.equals(mCurrentImeHandle)) {
1480 mCurrentImeHandle = handle;
1481 handleSwitchKeyboardLayout(null, handle);
1482 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001483 }
1484
1485 // Must be called on handler.
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001486 private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier,
1487 InputMethodSubtypeHandle handle) {
1488 synchronized (mInputDevicesLock) {
1489 for (InputDevice device : mInputDevices) {
1490 if (identifier != null && !device.getIdentifier().equals(identifier) ||
1491 !device.isFullKeyboard()) {
1492 continue;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001493 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001494 String key = getLayoutDescriptor(device.getIdentifier());
1495 boolean changed = false;
1496 synchronized (mDataStore) {
1497 try {
1498 if (mDataStore.switchKeyboardLayout(key, handle)) {
1499 changed = true;
1500 }
1501 } finally {
1502 mDataStore.saveIfNeeded();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001503 }
1504 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001505 if (changed) {
1506 reloadKeyboardLayouts();
1507 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001508 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001509 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001510 }
1511
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001512 public void setInputWindows(InputWindowHandle[] windowHandles,
1513 InputWindowHandle focusedWindowHandle) {
1514 final IWindow newFocusedWindow =
1515 focusedWindowHandle != null ? focusedWindowHandle.clientWindow : null;
1516 if (mFocusedWindow != newFocusedWindow) {
1517 mFocusedWindow = newFocusedWindow;
1518 if (mFocusedWindowHasCapture) {
1519 setPointerCapture(false);
1520 }
1521 }
Jeff Brown4532e612012-04-05 14:27:12 -07001522 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -07001523 }
RoboErikfb290df2013-12-16 11:27:55 -08001524
Jeff Brown9302c872011-07-13 22:51:29 -07001525 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -07001526 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -07001527 }
RoboErikfb290df2013-12-16 11:27:55 -08001528
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001529 @Override
1530 public void requestPointerCapture(IBinder windowToken, boolean enabled) {
1531 if (mFocusedWindow == null || mFocusedWindow.asBinder() != windowToken) {
1532 Slog.e(TAG, "requestPointerCapture called for a window that has no focus: "
1533 + windowToken);
1534 return;
1535 }
1536 if (mFocusedWindowHasCapture == enabled) {
1537 Slog.i(TAG, "requestPointerCapture: already " + (enabled ? "enabled" : "disabled"));
1538 return;
1539 }
1540 setPointerCapture(enabled);
1541 try {
1542 mFocusedWindow.dispatchPointerCaptureChanged(enabled);
1543 } catch (RemoteException ex) {
1544 /* ignore */
1545 }
1546 }
1547
1548 private void setPointerCapture(boolean enabled) {
1549 mFocusedWindowHasCapture = enabled;
1550 nativeSetPointerCapture(mPtr, enabled);
1551 }
1552
Jeff Brown349703e2010-06-22 01:27:15 -07001553 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001554 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001555 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001556
1557 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001558 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001559 }
1560
Jeff Browne6504122010-09-27 14:52:15 -07001561 /**
1562 * Atomically transfers touch focus from one window to another as identified by
1563 * their input channels. It is possible for multiple windows to have
1564 * touch focus if they support split touch dispatch
1565 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1566 * method only transfers touch focus of the specified window without affecting
1567 * other windows that may also have touch focus at the same time.
1568 * @param fromChannel The channel of a window that currently has touch focus.
1569 * @param toChannel The channel of the window that should receive touch focus in
1570 * place of the first.
1571 * @return True if the transfer was successful. False if the window with the
1572 * specified channel did not actually have touch focus at the time of the request.
1573 */
1574 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1575 if (fromChannel == null) {
1576 throw new IllegalArgumentException("fromChannel must not be null.");
1577 }
1578 if (toChannel == null) {
1579 throw new IllegalArgumentException("toChannel must not be null.");
1580 }
Jeff Brown4532e612012-04-05 14:27:12 -07001581 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -07001582 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001583
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001584 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001585 public void tryPointerSpeed(int speed) {
1586 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1587 "tryPointerSpeed()")) {
1588 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1589 }
1590
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001591 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1592 throw new IllegalArgumentException("speed out of range");
1593 }
1594
Jeff Brownac143512012-04-05 18:57:33 -07001595 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001596 }
1597
1598 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001599 int speed = getPointerSpeedSetting();
1600 setPointerSpeedUnchecked(speed);
1601 }
1602
1603 private void setPointerSpeedUnchecked(int speed) {
1604 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1605 InputManager.MAX_POINTER_SPEED);
1606 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001607 }
1608
1609 private void registerPointerSpeedSettingObserver() {
1610 mContext.getContentResolver().registerContentObserver(
1611 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001612 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001613 @Override
1614 public void onChange(boolean selfChange) {
1615 updatePointerSpeedFromSettings();
1616 }
Jeff Brownd4935962012-09-25 13:27:20 -07001617 }, UserHandle.USER_ALL);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001618 }
1619
Jeff Brownac143512012-04-05 18:57:33 -07001620 private int getPointerSpeedSetting() {
1621 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001622 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001623 speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1624 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001625 } catch (SettingNotFoundException snfe) {
1626 }
1627 return speed;
1628 }
1629
Jeff Browndaf4a122011-08-26 17:14:14 -07001630 public void updateShowTouchesFromSettings() {
1631 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001632 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001633 }
1634
1635 private void registerShowTouchesSettingObserver() {
1636 mContext.getContentResolver().registerContentObserver(
1637 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001638 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001639 @Override
1640 public void onChange(boolean selfChange) {
1641 updateShowTouchesFromSettings();
1642 }
Jeff Brownd4935962012-09-25 13:27:20 -07001643 }, UserHandle.USER_ALL);
Jeff Browndaf4a122011-08-26 17:14:14 -07001644 }
1645
Jun Mukaie4e75da2015-12-15 16:19:20 -08001646 public void updateAccessibilityLargePointerFromSettings() {
1647 final int accessibilityConfig = Settings.Secure.getIntForUser(
1648 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1649 0, UserHandle.USER_CURRENT);
Jun Mukai1f3dbff2015-12-16 14:41:25 -08001650 PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
Jun Mukaie4e75da2015-12-15 16:19:20 -08001651 nativeReloadPointerIcons(mPtr);
1652 }
1653
Jun Mukai19a56012015-11-24 11:25:52 -08001654 private void registerAccessibilityLargePointerSettingObserver() {
1655 mContext.getContentResolver().registerContentObserver(
1656 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1657 new ContentObserver(mHandler) {
1658 @Override
1659 public void onChange(boolean selfChange) {
Jun Mukaie4e75da2015-12-15 16:19:20 -08001660 updateAccessibilityLargePointerFromSettings();
Jun Mukai19a56012015-11-24 11:25:52 -08001661 }
1662 }, UserHandle.USER_ALL);
1663 }
1664
Jeff Browndaf4a122011-08-26 17:14:14 -07001665 private int getShowTouchesSetting(int defaultValue) {
1666 int result = defaultValue;
1667 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001668 result = Settings.System.getIntForUser(mContext.getContentResolver(),
1669 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
Jeff Browndaf4a122011-08-26 17:14:14 -07001670 } catch (SettingNotFoundException snfe) {
1671 }
1672 return result;
1673 }
1674
Jeff Browna47425a2012-04-13 04:09:27 -07001675 // Binder call
1676 @Override
1677 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1678 if (repeat >= pattern.length) {
1679 throw new ArrayIndexOutOfBoundsException();
1680 }
1681
1682 VibratorToken v;
1683 synchronized (mVibratorLock) {
1684 v = mVibratorTokens.get(token);
1685 if (v == null) {
1686 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1687 try {
1688 token.linkToDeath(v, 0);
1689 } catch (RemoteException ex) {
1690 // give up
1691 throw new RuntimeException(ex);
1692 }
1693 mVibratorTokens.put(token, v);
1694 }
1695 }
1696
1697 synchronized (v) {
1698 v.mVibrating = true;
1699 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1700 }
1701 }
1702
1703 // Binder call
1704 @Override
1705 public void cancelVibrate(int deviceId, IBinder token) {
1706 VibratorToken v;
1707 synchronized (mVibratorLock) {
1708 v = mVibratorTokens.get(token);
1709 if (v == null || v.mDeviceId != deviceId) {
1710 return; // nothing to cancel
1711 }
1712 }
1713
1714 cancelVibrateIfNeeded(v);
1715 }
1716
1717 void onVibratorTokenDied(VibratorToken v) {
1718 synchronized (mVibratorLock) {
1719 mVibratorTokens.remove(v.mToken);
1720 }
1721
1722 cancelVibrateIfNeeded(v);
1723 }
1724
1725 private void cancelVibrateIfNeeded(VibratorToken v) {
1726 synchronized (v) {
1727 if (v.mVibrating) {
1728 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1729 v.mVibrating = false;
1730 }
1731 }
1732 }
1733
Jun Mukai19a56012015-11-24 11:25:52 -08001734 // Binder call
1735 @Override
Michael Wrightf9d9ce772016-05-13 17:44:16 +01001736 public void setPointerIconType(int iconId) {
1737 nativeSetPointerIconType(mPtr, iconId);
Jun Mukai19a56012015-11-24 11:25:52 -08001738 }
Jun Mukai1db53972015-09-11 18:08:31 -07001739
Jun Mukaid4eaef72015-10-30 15:54:33 -07001740 // Binder call
1741 @Override
1742 public void setCustomPointerIcon(PointerIcon icon) {
Michael Wrightb004b512017-01-18 18:09:29 +00001743 Preconditions.checkNotNull(icon);
Jun Mukaid4eaef72015-10-30 15:54:33 -07001744 nativeSetCustomPointerIcon(mPtr, icon);
1745 }
1746
Jeff Brown4532e612012-04-05 14:27:12 -07001747 @Override
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001748 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
Jeff Browna3bc5652012-04-17 11:42:25 -07001749 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
Jeff Brown4532e612012-04-05 14:27:12 -07001750 != PackageManager.PERMISSION_GRANTED) {
1751 pw.println("Permission Denial: can't dump InputManager from from pid="
1752 + Binder.getCallingPid()
1753 + ", uid=" + Binder.getCallingUid());
1754 return;
1755 }
1756
1757 pw.println("INPUT MANAGER (dumpsys input)\n");
1758 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001759 if (dumpStr != null) {
1760 pw.println(dumpStr);
1761 }
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001762 pw.println(" Keyboard Layouts:");
1763 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1764 @Override
1765 public void visitKeyboardLayout(Resources resources,
1766 int keyboardLayoutResId, KeyboardLayout layout) {
1767 pw.println(" \"" + layout + "\": " + layout.getDescriptor());
1768 }
1769 });
1770 pw.println();
1771 synchronized(mDataStore) {
1772 mDataStore.dump(pw, " ");
1773 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001774 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001775
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001776 @Override
1777 public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07001778 FileDescriptor err, String[] args, ShellCallback callback,
1779 ResultReceiver resultReceiver) {
1780 (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
Michael Wrightd5f7ed92016-01-19 11:23:51 -08001781 }
1782
1783 public int onShellCommand(Shell shell, String cmd) {
1784 if (TextUtils.isEmpty(cmd)) {
1785 shell.onHelp();
1786 return 1;
1787 }
1788 if (cmd.equals("setlayout")) {
1789 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1790 "onShellCommand()")) {
1791 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1792 }
1793 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
1794 shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired()));
1795 String descriptor = shell.getNextArgRequired();
1796 int vid = Integer.decode(shell.getNextArgRequired());
1797 int pid = Integer.decode(shell.getNextArgRequired());
1798 InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid);
1799 setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired());
1800 }
1801 return 0;
1802 }
1803
1804
Jeff Brownac143512012-04-05 18:57:33 -07001805 private boolean checkCallingPermission(String permission, String func) {
1806 // Quick check: if the calling permission is me, it's all okay.
1807 if (Binder.getCallingPid() == Process.myPid()) {
1808 return true;
1809 }
1810
1811 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1812 return true;
1813 }
1814 String msg = "Permission Denial: " + func + " from pid="
1815 + Binder.getCallingPid()
1816 + ", uid=" + Binder.getCallingUid()
1817 + " requires " + permission;
1818 Slog.w(TAG, msg);
1819 return false;
1820 }
1821
Jeff Brown4532e612012-04-05 14:27:12 -07001822 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001823 @Override
Jeff Brown89ef0722011-08-10 16:25:21 -07001824 public void monitor() {
1825 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -07001826 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001827 }
1828
Jeff Brown4532e612012-04-05 14:27:12 -07001829 // Native callback.
1830 private void notifyConfigurationChanged(long whenNanos) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001831 mWindowManagerCallbacks.notifyConfigurationChanged();
Jeff Brown4532e612012-04-05 14:27:12 -07001832 }
1833
1834 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001835 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1836 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001837 if (!mInputDevicesChangedPending) {
1838 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001839 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1840 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001841 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001842
1843 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001844 }
1845 }
1846
1847 // Native callback.
Jeff Brownbcc046a2012-09-27 20:46:43 -07001848 private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1849 if (DEBUG) {
1850 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1851 + ", mask=" + Integer.toHexString(switchMask));
1852 }
1853
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001854 if ((switchMask & SW_LID_BIT) != 0) {
1855 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
Jeff Brownbcc046a2012-09-27 20:46:43 -07001856 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
Jeff Brown53384282012-08-20 20:16:01 -07001857 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001858
Michael Wright3818c922014-09-02 13:59:07 -07001859 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
Michael Wright9e10d252014-09-13 19:41:20 -07001860 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
Michael Wright3818c922014-09-02 13:59:07 -07001861 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1862 }
1863
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001864 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1865 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1866 switchMask);
1867 }
Michael Wright39e5e942015-08-19 22:52:47 +01001868
Michael Wright9209c9c2015-09-03 17:57:01 +01001869 if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
Michael Wright39e5e942015-08-19 22:52:47 +01001870 SomeArgs args = SomeArgs.obtain();
1871 args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
1872 args.argi2 = (int) (whenNanos >> 32);
1873 args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
1874 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
1875 args).sendToTarget();
1876 }
Jeff Brown4532e612012-04-05 14:27:12 -07001877 }
1878
1879 // Native callback.
1880 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001881 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
Jeff Brown4532e612012-04-05 14:27:12 -07001882 }
1883
1884 // Native callback.
1885 private long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001886 InputWindowHandle inputWindowHandle, String reason) {
1887 return mWindowManagerCallbacks.notifyANR(
1888 inputApplicationHandle, inputWindowHandle, reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001889 }
1890
1891 // Native callback.
1892 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1893 synchronized (mInputFilterLock) {
1894 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001895 try {
1896 mInputFilter.filterInputEvent(event, policyFlags);
1897 } catch (RemoteException e) {
1898 /* ignore */
1899 }
Jeff Brown4532e612012-04-05 14:27:12 -07001900 return false;
1901 }
1902 }
1903 event.recycle();
1904 return true;
1905 }
1906
1907 // Native callback.
Jeff Brown037c33e2014-04-09 00:31:55 -07001908 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1909 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001910 }
1911
1912 // Native callback.
Michael Wright70af00a2014-09-03 19:30:20 -07001913 private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
1914 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
Jeff Brown26875502014-01-30 21:47:47 -08001915 whenNanos, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001916 }
1917
1918 // Native callback.
1919 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1920 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001921 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001922 }
1923
1924 // Native callback.
1925 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1926 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001927 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001928 }
1929
1930 // Native callback.
1931 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1932 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1933 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1934 }
1935
1936 // Native callback.
1937 private int getVirtualKeyQuietTimeMillis() {
1938 return mContext.getResources().getInteger(
1939 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1940 }
1941
1942 // Native callback.
1943 private String[] getExcludedDeviceNames() {
1944 ArrayList<String> names = new ArrayList<String>();
1945
1946 // Read partner-provided list of excluded input devices
1947 XmlPullParser parser = null;
1948 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1949 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1950 FileReader confreader = null;
1951 try {
1952 confreader = new FileReader(confFile);
1953 parser = Xml.newPullParser();
1954 parser.setInput(confreader);
1955 XmlUtils.beginDocument(parser, "devices");
1956
1957 while (true) {
1958 XmlUtils.nextElement(parser);
1959 if (!"device".equals(parser.getName())) {
1960 break;
1961 }
1962 String name = parser.getAttributeValue(null, "name");
1963 if (name != null) {
1964 names.add(name);
1965 }
1966 }
1967 } catch (FileNotFoundException e) {
1968 // It's ok if the file does not exist.
1969 } catch (Exception e) {
1970 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1971 } finally {
1972 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1973 }
1974
1975 return names.toArray(new String[names.size()]);
1976 }
1977
1978 // Native callback.
1979 private int getKeyRepeatTimeout() {
1980 return ViewConfiguration.getKeyRepeatTimeout();
1981 }
1982
1983 // Native callback.
1984 private int getKeyRepeatDelay() {
1985 return ViewConfiguration.getKeyRepeatDelay();
1986 }
1987
1988 // Native callback.
1989 private int getHoverTapTimeout() {
1990 return ViewConfiguration.getHoverTapTimeout();
1991 }
1992
1993 // Native callback.
1994 private int getHoverTapSlop() {
1995 return ViewConfiguration.getHoverTapSlop();
1996 }
1997
1998 // Native callback.
1999 private int getDoubleTapTimeout() {
2000 return ViewConfiguration.getDoubleTapTimeout();
2001 }
2002
2003 // Native callback.
2004 private int getLongPressTimeout() {
2005 return ViewConfiguration.getLongPressTimeout();
2006 }
2007
2008 // Native callback.
2009 private int getPointerLayer() {
Jeff Browna9d131c2012-09-20 16:48:17 -07002010 return mWindowManagerCallbacks.getPointerLayer();
Jeff Brown4532e612012-04-05 14:27:12 -07002011 }
2012
2013 // Native callback.
2014 private PointerIcon getPointerIcon() {
2015 return PointerIcon.getDefaultIcon(mContext);
2016 }
2017
Jeff Brown6ec6f792012-04-17 16:52:41 -07002018 // Native callback.
RoboErikfb290df2013-12-16 11:27:55 -08002019 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07002020 if (!mSystemReady) {
2021 return null;
2022 }
2023
RoboErikfb290df2013-12-16 11:27:55 -08002024 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002025 if (keyboardLayoutDescriptor == null) {
2026 return null;
2027 }
2028
2029 final String[] result = new String[2];
2030 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
2031 @Override
Michael Wright07483422015-10-30 16:20:13 +00002032 public void visitKeyboardLayout(Resources resources,
2033 int keyboardLayoutResId, KeyboardLayout layout) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07002034 try {
Michael Wright07483422015-10-30 16:20:13 +00002035 result[0] = layout.getDescriptor();
Jeff Brown6ec6f792012-04-17 16:52:41 -07002036 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07002037 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07002038 } catch (IOException ex) {
2039 } catch (NotFoundException ex) {
2040 }
2041 }
2042 });
2043 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00002044 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07002045 + keyboardLayoutDescriptor + "'.");
2046 return null;
2047 }
2048 return result;
2049 }
2050
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002051 // Native callback.
2052 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07002053 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
2054 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
2055 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002056 }
2057 return null;
2058 }
2059
Jeff Brown4532e612012-04-05 14:27:12 -07002060 /**
2061 * Callback interface implemented by the Window Manager.
2062 */
Jeff Browna9d131c2012-09-20 16:48:17 -07002063 public interface WindowManagerCallbacks {
Jeff Brown4532e612012-04-05 14:27:12 -07002064 public void notifyConfigurationChanged();
2065
2066 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
2067
Michael Wright3818c922014-09-02 13:59:07 -07002068 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
2069
Jeff Brown4532e612012-04-05 14:27:12 -07002070 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
2071
2072 public long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07002073 InputWindowHandle inputWindowHandle, String reason);
Jeff Brown4532e612012-04-05 14:27:12 -07002074
Jeff Brown037c33e2014-04-09 00:31:55 -07002075 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002076
Michael Wright70af00a2014-09-03 19:30:20 -07002077 public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002078
2079 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
2080 KeyEvent event, int policyFlags);
2081
2082 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
2083 KeyEvent event, int policyFlags);
2084
2085 public int getPointerLayer();
2086 }
2087
2088 /**
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002089 * Callback interface implemented by WiredAccessoryObserver.
2090 */
2091 public interface WiredAccessoryCallbacks {
2092 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002093 public void systemReady();
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002094 }
2095
2096 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002097 * Private handler for the input manager.
2098 */
2099 private final class InputManagerHandler extends Handler {
Jeff Browna9d131c2012-09-20 16:48:17 -07002100 public InputManagerHandler(Looper looper) {
2101 super(looper, null, true /*async*/);
Jeff Browna2910d02012-08-25 12:29:46 -07002102 }
2103
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002104 @Override
2105 public void handleMessage(Message msg) {
2106 switch (msg.what) {
2107 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07002108 deliverInputDevicesChanged((InputDevice[])msg.obj);
2109 break;
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002110 case MSG_SWITCH_KEYBOARD_LAYOUT: {
2111 SomeArgs args = (SomeArgs)msg.obj;
2112 handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1,
2113 (InputMethodSubtypeHandle)args.arg2);
Jeff Browncf39bdf2012-05-18 14:41:19 -07002114 break;
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002115 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07002116 case MSG_RELOAD_KEYBOARD_LAYOUTS:
2117 reloadKeyboardLayouts();
2118 break;
2119 case MSG_UPDATE_KEYBOARD_LAYOUTS:
2120 updateKeyboardLayouts();
2121 break;
2122 case MSG_RELOAD_DEVICE_ALIASES:
2123 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002124 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08002125 case MSG_DELIVER_TABLET_MODE_CHANGED: {
Michael Wright39e5e942015-08-19 22:52:47 +01002126 SomeArgs args = (SomeArgs) msg.obj;
2127 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
2128 boolean inTabletMode = (boolean) args.arg1;
2129 deliverTabletModeChanged(whenNanos, inTabletMode);
2130 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08002131 }
2132 case MSG_INPUT_METHOD_SUBTYPE_CHANGED: {
2133 final int userId = msg.arg1;
2134 final SomeArgs args = (SomeArgs) msg.obj;
2135 final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1;
2136 final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2;
2137 args.recycle();
2138 handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype);
2139 break;
2140 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002141 }
2142 }
2143 }
2144
2145 /**
Jeff Brown4532e612012-04-05 14:27:12 -07002146 * Hosting interface for input filters to call back into the input manager.
2147 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07002148 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07002149 private boolean mDisconnected;
2150
2151 public void disconnectLocked() {
2152 mDisconnected = true;
2153 }
2154
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002155 @Override
Jeff Brown0029c662011-03-30 02:25:18 -07002156 public void sendInputEvent(InputEvent event, int policyFlags) {
2157 if (event == null) {
2158 throw new IllegalArgumentException("event must not be null");
2159 }
2160
2161 synchronized (mInputFilterLock) {
2162 if (!mDisconnected) {
Jeff Brownca9bc702014-02-11 14:32:56 -08002163 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
Jeff Brownac143512012-04-05 18:57:33 -07002164 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07002165 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
2166 }
2167 }
2168 }
2169 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07002170
2171 private static final class KeyboardLayoutDescriptor {
2172 public String packageName;
2173 public String receiverName;
2174 public String keyboardLayoutName;
2175
2176 public static String format(String packageName,
2177 String receiverName, String keyboardName) {
2178 return packageName + "/" + receiverName + "/" + keyboardName;
2179 }
2180
2181 public static KeyboardLayoutDescriptor parse(String descriptor) {
2182 int pos = descriptor.indexOf('/');
2183 if (pos < 0 || pos + 1 == descriptor.length()) {
2184 return null;
2185 }
2186 int pos2 = descriptor.indexOf('/', pos + 1);
2187 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
2188 return null;
2189 }
2190
2191 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
2192 result.packageName = descriptor.substring(0, pos);
2193 result.receiverName = descriptor.substring(pos + 1, pos2);
2194 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
2195 return result;
2196 }
2197 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002198
Jeff Brown6ec6f792012-04-17 16:52:41 -07002199 private interface KeyboardLayoutVisitor {
Michael Wright07483422015-10-30 16:20:13 +00002200 void visitKeyboardLayout(Resources resources,
2201 int keyboardLayoutResId, KeyboardLayout layout);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002202 }
2203
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002204 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
2205 private final int mPid;
2206 private final IInputDevicesChangedListener mListener;
2207
2208 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
2209 mPid = pid;
2210 mListener = listener;
2211 }
2212
2213 @Override
2214 public void binderDied() {
2215 if (DEBUG) {
2216 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
2217 }
2218 onInputDevicesChangedListenerDied(mPid);
2219 }
2220
2221 public void notifyInputDevicesChanged(int[] info) {
2222 try {
2223 mListener.onInputDevicesChanged(info);
2224 } catch (RemoteException ex) {
2225 Slog.w(TAG, "Failed to notify process "
2226 + mPid + " that input devices changed, assuming it died.", ex);
2227 binderDied();
2228 }
2229 }
2230 }
Jeff Browna47425a2012-04-13 04:09:27 -07002231
Michael Wright39e5e942015-08-19 22:52:47 +01002232 private final class TabletModeChangedListenerRecord implements DeathRecipient {
2233 private final int mPid;
2234 private final ITabletModeChangedListener mListener;
2235
2236 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
2237 mPid = pid;
2238 mListener = listener;
2239 }
2240
2241 @Override
2242 public void binderDied() {
2243 if (DEBUG) {
2244 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
2245 }
2246 onTabletModeChangedListenerDied(mPid);
2247 }
2248
2249 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
2250 try {
2251 mListener.onTabletModeChanged(whenNanos, inTabletMode);
2252 } catch (RemoteException ex) {
2253 Slog.w(TAG, "Failed to notify process " + mPid +
2254 " that tablet mode changed, assuming it died.", ex);
2255 binderDied();
2256 }
2257 }
2258 }
2259
Jeff Browna47425a2012-04-13 04:09:27 -07002260 private final class VibratorToken implements DeathRecipient {
2261 public final int mDeviceId;
2262 public final IBinder mToken;
2263 public final int mTokenValue;
2264
2265 public boolean mVibrating;
2266
2267 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
2268 mDeviceId = deviceId;
2269 mToken = token;
2270 mTokenValue = tokenValue;
2271 }
2272
2273 @Override
2274 public void binderDied() {
2275 if (DEBUG) {
2276 Slog.d(TAG, "Vibrator token died.");
2277 }
2278 onVibratorTokenDied(this);
2279 }
2280 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002281
Michael Wrightd5f7ed92016-01-19 11:23:51 -08002282 private class Shell extends ShellCommand {
2283 @Override
2284 public int onCommand(String cmd) {
2285 return onShellCommand(this, cmd);
2286 }
2287
2288 @Override
2289 public void onHelp() {
2290 final PrintWriter pw = getOutPrintWriter();
2291 pw.println("Input manager commands:");
2292 pw.println(" help");
2293 pw.println(" Print this help text.");
2294 pw.println("");
2295 pw.println(" setlayout IME_ID IME_SUPTYPE_HASH_CODE"
2296 + " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR");
2297 pw.println(" Sets a keyboard layout for a given IME subtype and input device pair");
2298 }
2299 }
2300
Jeff Brown4ccb8232014-01-16 22:16:42 -08002301 private final class LocalService extends InputManagerInternal {
2302 @Override
2303 public void setDisplayViewports(
2304 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
2305 setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
2306 }
Jeff Brownca9bc702014-02-11 14:32:56 -08002307
2308 @Override
2309 public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
2310 return injectInputEventInternal(event, displayId, mode);
2311 }
Jeff Brown037c33e2014-04-09 00:31:55 -07002312
2313 @Override
2314 public void setInteractive(boolean interactive) {
2315 nativeSetInteractive(mPtr, interactive);
2316 }
Yohei Yukawab097b822015-12-01 10:43:08 -08002317
2318 @Override
2319 public void onInputMethodSubtypeChanged(int userId,
2320 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
2321 final SomeArgs someArgs = SomeArgs.obtain();
2322 someArgs.arg1 = inputMethodInfo;
2323 someArgs.arg2 = subtype;
2324 mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs)
2325 .sendToTarget();
2326 }
Andrii Kulian112d0562016-03-08 10:44:22 -08002327
2328 @Override
2329 public void toggleCapsLock(int deviceId) {
2330 nativeToggleCapsLock(mPtr, deviceId);
2331 }
Adrian Roos99182342016-06-15 15:30:46 -07002332
2333 @Override
2334 public void setPulseGestureEnabled(boolean enabled) {
2335 if (mDoubleTouchGestureEnableFile != null) {
2336 FileWriter writer = null;
2337 try {
2338 writer = new FileWriter(mDoubleTouchGestureEnableFile);
2339 writer.write(enabled ? "1" : "0");
2340 } catch (IOException e) {
2341 Log.wtf(TAG, "Unable to setPulseGestureEnabled", e);
2342 } finally {
2343 IoUtils.closeQuietly(writer);
2344 }
2345 }
2346 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002347 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07002348}