blob: bf73aa39c581b3079ffcdf8334db735b5b406075 [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;
Jeff Browncf39bdf2012-05-18 14:41:19 -070020import android.app.Notification;
21import android.app.NotificationManager;
22import android.app.PendingIntent;
Jeff Brown5bbd4b42012-04-20 19:28:00 -070023import android.bluetooth.BluetoothAdapter;
24import android.bluetooth.BluetoothDevice;
Jeff Brown6ec6f792012-04-17 16:52:41 -070025import android.content.BroadcastReceiver;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070026import android.content.ComponentName;
Jeff Brown46b9ac02010-04-22 18:58:52 -070027import android.content.Context;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070028import android.content.Intent;
Jeff Brown6ec6f792012-04-17 16:52:41 -070029import android.content.IntentFilter;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070030import android.content.pm.ActivityInfo;
Michael Wright8ebac232014-09-18 18:29:49 -070031import android.content.pm.ApplicationInfo;
Jeff Brown349703e2010-06-22 01:27:15 -070032import android.content.pm.PackageManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070033import android.content.pm.PackageManager.NameNotFoundException;
Arthur Hung39134b22018-08-14 11:58:28 +080034import android.content.pm.ResolveInfo;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070035import android.content.res.Resources;
Jeff Brown6ec6f792012-04-17 16:52:41 -070036import android.content.res.Resources.NotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070037import android.content.res.TypedArray;
38import android.content.res.XmlResourceParser;
Jeff Brown1a84fd12011-06-02 01:26:32 -070039import android.database.ContentObserver;
Andrii Kulianed76e742017-06-26 14:57:02 -070040import android.hardware.display.DisplayManager;
Jeff Brown4ccb8232014-01-16 22:16:42 -080041import android.hardware.display.DisplayViewport;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070042import android.hardware.input.IInputDevicesChangedListener;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070043import android.hardware.input.IInputManager;
Arthur Hung39134b22018-08-14 11:58:28 +080044import android.hardware.input.ITabletModeChangedListener;
RoboErikfb290df2013-12-16 11:27:55 -080045import android.hardware.input.InputDeviceIdentifier;
Jeff Brownac143512012-04-05 18:57:33 -070046import android.hardware.input.InputManager;
Jeff Brown4ccb8232014-01-16 22:16:42 -080047import android.hardware.input.InputManagerInternal;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070048import android.hardware.input.KeyboardLayout;
Jason Gerecked6396d62014-01-27 18:30:37 -080049import android.hardware.input.TouchCalibration;
Dmitry Shmidt38ab71c2019-09-19 15:28:30 -070050import android.media.AudioManager;
Jeff Brown4532e612012-04-05 14:27:12 -070051import android.os.Binder;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070052import android.os.Bundle;
Jeff Brown46b9ac02010-04-22 18:58:52 -070053import android.os.Environment;
Jeff Brown4532e612012-04-05 14:27:12 -070054import android.os.Handler;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070055import android.os.IBinder;
Arthur Hung39134b22018-08-14 11:58:28 +080056import android.os.LocaleList;
Jeff Browna9d131c2012-09-20 16:48:17 -070057import android.os.Looper;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070058import android.os.Message;
Jeff Brown05dc66a2011-03-02 14:41:58 -080059import android.os.MessageQueue;
Jeff Brownac143512012-04-05 18:57:33 -070060import android.os.Process;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070061import android.os.RemoteException;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070062import android.os.UserHandle;
Jeff Brown1a84fd12011-06-02 01:26:32 -070063import android.provider.Settings;
64import android.provider.Settings.SettingNotFoundException;
Michael Wright07483422015-10-30 16:20:13 +000065import android.text.TextUtils;
Arthur Hung39134b22018-08-14 11:58:28 +080066import android.util.Log;
Jeff Brown46b9ac02010-04-22 18:58:52 -070067import android.util.Slog;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070068import android.util.SparseArray;
Andrii Kulianed76e742017-06-26 14:57:02 -070069import android.view.Display;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070070import android.view.IInputFilter;
71import android.view.IInputFilterHost;
Michael Wrightc7995232019-02-14 12:33:46 +000072import android.view.IInputMonitorHost;
Robert Carr788f5742018-07-30 17:46:45 -070073import android.view.InputApplicationHandle;
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -070074import android.view.InputChannel;
Jeff Brown8d608662010-08-30 03:02:23 -070075import android.view.InputDevice;
Jeff Brown6ec402b2010-07-28 15:48:59 -070076import android.view.InputEvent;
Michael Wrightc7995232019-02-14 12:33:46 +000077import android.view.InputMonitor;
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -070078import android.view.InputWindowHandle;
Jeff Brown1f245102010-11-18 20:53:46 -080079import android.view.KeyEvent;
Jeff Brown2352b972011-04-12 22:39:53 -070080import android.view.PointerIcon;
Jason Gerecked5220742014-03-10 09:47:59 -070081import android.view.Surface;
Jeff Browna4547672011-03-02 21:38:11 -080082import android.view.ViewConfiguration;
Yohei Yukawa2d9accb2018-03-07 19:15:15 -080083import android.widget.Toast;
Jeff Brown46b9ac02010-04-22 18:58:52 -070084
Arthur Hung39134b22018-08-14 11:58:28 +080085import com.android.internal.R;
86import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
87import com.android.internal.notification.SystemNotificationChannels;
88import com.android.internal.os.SomeArgs;
89import com.android.internal.util.DumpUtils;
90import com.android.internal.util.Preconditions;
91import com.android.internal.util.XmlUtils;
92import com.android.server.DisplayThread;
93import com.android.server.LocalServices;
94import com.android.server.Watchdog;
95import com.android.server.policy.WindowManagerPolicy;
96
97import libcore.io.IoUtils;
98import libcore.io.Streams;
99
Jeff Brown46b9ac02010-04-22 18:58:52 -0700100import java.io.File;
Jeff Brown4532e612012-04-05 14:27:12 -0700101import java.io.FileDescriptor;
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -0700102import java.io.FileInputStream;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700103import java.io.FileNotFoundException;
Adrian Roos99182342016-06-15 15:30:46 -0700104import java.io.FileWriter;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700105import java.io.IOException;
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -0700106import java.io.InputStream;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700107import java.io.InputStreamReader;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700108import java.io.PrintWriter;
109import java.util.ArrayList;
Michael Wright07483422015-10-30 16:20:13 +0000110import java.util.Collections;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700111import java.util.HashMap;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700112import java.util.HashSet;
Michael Wright39e5e942015-08-19 22:52:47 +0100113import java.util.List;
Michael Wright07483422015-10-30 16:20:13 +0000114import java.util.Locale;
Arthur Hungcf6070e2019-12-04 16:09:42 +0800115import java.util.Map;
Narayan Kamath607223f2018-02-19 14:09:02 +0000116import java.util.Objects;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700117/*
118 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -0700119 */
Jeff Brownd728bf52012-09-08 18:05:28 -0700120public class InputManagerService extends IInputManager.Stub
Jeff Brown4ccb8232014-01-16 22:16:42 -0800121 implements Watchdog.Monitor {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700122 static final String TAG = "InputManager";
Jeff Brown1b9ba572012-05-21 10:54:18 -0700123 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -0700124
Jeff Brown4532e612012-04-05 14:27:12 -0700125 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -0700126 private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml";
Jeff Brown4532e612012-04-05 14:27:12 -0700127
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700128 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700129 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
130 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
131 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
132 private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
Michael Wright39e5e942015-08-19 22:52:47 +0100133 private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700134
Jeff Brown4532e612012-04-05 14:27:12 -0700135 // Pointer to native input manager service object.
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000136 private final long mPtr;
Jeff Brown4532e612012-04-05 14:27:12 -0700137
Jeff Brown46b9ac02010-04-22 18:58:52 -0700138 private final Context mContext;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700139 private final InputManagerHandler mHandler;
Jeff Browna9d131c2012-09-20 16:48:17 -0700140
Andrii Kulianfd8666d2018-10-05 16:58:39 -0700141 // Context cache used for loading pointer resources.
142 private Context mDisplayContext;
143
Adrian Roos99182342016-06-15 15:30:46 -0700144 private final File mDoubleTouchGestureEnableFile;
145
Jeff Browna9d131c2012-09-20 16:48:17 -0700146 private WindowManagerCallbacks mWindowManagerCallbacks;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700147 private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700148 private boolean mSystemReady;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700149 private NotificationManager mNotificationManager;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700150
Michael Wright39e5e942015-08-19 22:52:47 +0100151 private final Object mTabletModeLock = new Object();
152 // List of currently registered tablet mode changed listeners by process id
153 private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
154 new SparseArray<>(); // guarded by mTabletModeLock
155 private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
156 new ArrayList<>();
157
Jeff Browna3bc5652012-04-17 11:42:25 -0700158 // Persistent data store. Must be locked each time during use.
159 private final PersistentDataStore mDataStore = new PersistentDataStore();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700160
161 // List of currently registered input devices changed listeners by process id.
162 private Object mInputDevicesLock = new Object();
163 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
164 private InputDevice[] mInputDevices = new InputDevice[0];
165 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
166 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
167 private final ArrayList<InputDevicesChangedListenerRecord>
168 mTempInputDevicesChangedListenersToNotify =
169 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
Jeff Browncf39bdf2012-05-18 14:41:19 -0700170 private final ArrayList<InputDevice>
171 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
172 private boolean mKeyboardLayoutNotificationShown;
Yohei Yukawa2d9accb2018-03-07 19:15:15 -0800173 private Toast mSwitchedKeyboardLayoutToast;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700174
Jeff Browna47425a2012-04-13 04:09:27 -0700175 // State for vibrator tokens.
176 private Object mVibratorLock = new Object();
177 private HashMap<IBinder, VibratorToken> mVibratorTokens =
178 new HashMap<IBinder, VibratorToken>();
179 private int mNextVibratorTokenValue;
180
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700181 // State for the currently installed input filter.
182 final Object mInputFilterLock = new Object();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700183 IInputFilter mInputFilter; // guarded by mInputFilterLock
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700184 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
Jeff Brown1a84fd12011-06-02 01:26:32 -0700185
Arthur Hungcf6070e2019-12-04 16:09:42 +0800186 // The associations of input devices to displays by port. Maps from input device port (String)
187 // to display id (int). Currently only accessed by InputReader.
188 private final Map<String, Integer> mStaticAssociations;
189
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000190 private static native long nativeInit(InputManagerService service,
Jeff Brown4532e612012-04-05 14:27:12 -0700191 Context context, MessageQueue messageQueue);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000192 private static native void nativeStart(long ptr);
Siarhei Vishniakou2eb0f8f2018-07-06 23:30:12 +0100193 private static native void nativeSetDisplayViewports(long ptr,
Santos Cordonee8931e2017-04-05 10:31:15 -0700194 DisplayViewport[] viewports);
Jeff Brownd728bf52012-09-08 18:05:28 -0700195
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000196 private static native int nativeGetScanCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700197 int deviceId, int sourceMask, int scanCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000198 private static native int nativeGetKeyCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700199 int deviceId, int sourceMask, int keyCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000200 private static native int nativeGetSwitchState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700201 int deviceId, int sourceMask, int sw);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000202 private static native boolean nativeHasKeys(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700203 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
Siarhei Vishniakou2d759f52019-10-11 19:12:08 -0700204 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel);
Michael Wrightc7995232019-02-14 12:33:46 +0000205 private static native void nativeRegisterInputMonitor(long ptr, InputChannel inputChannel,
206 int displayId, boolean isGestureMonitor);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000207 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
Michael Wrightc7995232019-02-14 12:33:46 +0000208 private static native void nativePilferPointers(long ptr, IBinder token);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000209 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
Siarhei Vishniakouc570bfd2019-11-25 13:54:40 -0800210 private static native void nativeSetInTouchMode(long ptr, boolean inTouchMode);
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800211 private static native int nativeInjectInputEvent(long ptr, InputEvent event,
Jeff Brown0029c662011-03-30 02:25:18 -0700212 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
213 int policyFlags);
Andrii Kulian112d0562016-03-08 10:44:22 -0800214 private static native void nativeToggleCapsLock(long ptr, int deviceId);
Arthur Hung39134b22018-08-14 11:58:28 +0800215 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles,
216 int displayId);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000217 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
218 private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
219 private static native void nativeSetFocusedApplication(long ptr,
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800220 int displayId, InputApplicationHandle application);
221 private static native void nativeSetFocusedDisplay(long ptr, int displayId);
Arthur Hungfd9d94d2019-08-28 16:06:07 +0800222 private static native boolean nativeTransferTouchFocus(long ptr,
223 InputChannel fromChannel, InputChannel toChannel);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000224 private static native void nativeSetPointerSpeed(long ptr, int speed);
225 private static native void nativeSetShowTouches(long ptr, boolean enabled);
Jeff Brown037c33e2014-04-09 00:31:55 -0700226 private static native void nativeSetInteractive(long ptr, boolean interactive);
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800227 private static native void nativeReloadCalibration(long ptr);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000228 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
Jeff Browna47425a2012-04-13 04:09:27 -0700229 int repeat, int token);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000230 private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
231 private static native void nativeReloadKeyboardLayouts(long ptr);
232 private static native void nativeReloadDeviceAliases(long ptr);
233 private static native String nativeDump(long ptr);
234 private static native void nativeMonitor(long ptr);
Siarhei Vishniakoua7f99b52017-03-21 17:39:40 -0700235 private static native boolean nativeIsInputDeviceEnabled(long ptr, int deviceId);
236 private static native void nativeEnableInputDevice(long ptr, int deviceId);
237 private static native void nativeDisableInputDevice(long ptr, int deviceId);
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100238 private static native void nativeSetPointerIconType(long ptr, int iconId);
Jun Mukai19a56012015-11-24 11:25:52 -0800239 private static native void nativeReloadPointerIcons(long ptr);
Jun Mukaid4eaef72015-10-30 15:54:33 -0700240 private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -0800241 private static native void nativeSetPointerCapture(long ptr, boolean detached);
Arthur Hung82bbfc32018-11-29 20:24:51 +0800242 private static native boolean nativeCanDispatchToDisplay(long ptr, int deviceId, int displayId);
Jeff Brown4532e612012-04-05 14:27:12 -0700243
Jeff Brownac143512012-04-05 18:57:33 -0700244 // Input event injection constants defined in InputDispatcher.h.
245 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
246 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
247 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
248 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
249
250 // Maximum number of milliseconds to wait for input event injection.
251 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
252
Jeff Brown6d0fec22010-07-23 21:28:06 -0700253 // Key states (may be returned by queries about the current state of a
254 // particular key code, scan code or switch).
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700255
Jeff Brown6d0fec22010-07-23 21:28:06 -0700256 /** The key state is unknown or the requested key itself is not supported. */
257 public static final int KEY_STATE_UNKNOWN = -1;
258
259 /** The key is up. /*/
260 public static final int KEY_STATE_UP = 0;
261
262 /** The key is down. */
263 public static final int KEY_STATE_DOWN = 1;
264
265 /** The key is down but is a virtual key press that is being emulated by the system. */
266 public static final int KEY_STATE_VIRTUAL = 2;
267
Jeff Brownc458ce92012-04-30 14:58:40 -0700268 /** Scan code: Mouse / trackball button. */
269 public static final int BTN_MOUSE = 0x110;
270
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700271 // Switch code values must match bionic/libc/kernel/common/linux/input.h
Jeff Brownc458ce92012-04-30 14:58:40 -0700272 /** Switch code: Lid switch. When set, lid is shut. */
273 public static final int SW_LID = 0x00;
274
Michael Wright39e5e942015-08-19 22:52:47 +0100275 /** Switch code: Tablet mode switch.
276 * When set, the device is in tablet mode (i.e. no keyboard is connected).
277 */
278 public static final int SW_TABLET_MODE = 0x01;
279
Jeff Brownc458ce92012-04-30 14:58:40 -0700280 /** Switch code: Keypad slide. When set, keyboard is exposed. */
281 public static final int SW_KEYPAD_SLIDE = 0x0a;
282
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700283 /** Switch code: Headphone. When set, headphone is inserted. */
284 public static final int SW_HEADPHONE_INSERT = 0x02;
285
286 /** Switch code: Microphone. When set, microphone is inserted. */
287 public static final int SW_MICROPHONE_INSERT = 0x04;
288
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500289 /** Switch code: Line out. When set, Line out (hi-Z) is inserted. */
290 public static final int SW_LINEOUT_INSERT = 0x06;
291
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700292 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */
293 public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
294
Michael Wright3818c922014-09-02 13:59:07 -0700295 /** Switch code: Camera lens cover. When set the lens is covered. */
296 public static final int SW_CAMERA_LENS_COVER = 0x09;
297
Dmitry Shmidtd6cf4d92019-09-20 15:50:36 -0700298 /** Switch code: Microphone. When set it is off. */
299 public static final int SW_MUTE_DEVICE = 0x0e;
300
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700301 public static final int SW_LID_BIT = 1 << SW_LID;
Michael Wright39e5e942015-08-19 22:52:47 +0100302 public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700303 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
304 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
305 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500306 public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700307 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
308 public static final int SW_JACK_BITS =
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500309 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
Michael Wright3818c922014-09-02 13:59:07 -0700310 public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
Dmitry Shmidtd6cf4d92019-09-20 15:50:36 -0700311 public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700312
313 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
314 final boolean mUseDevInputEventForAudioJack;
315
Jeff Brown4ccb8232014-01-16 22:16:42 -0800316 public InputManagerService(Context context) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700317 this.mContext = context;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800318 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
Jeff Brown05dc66a2011-03-02 14:41:58 -0800319
Winson Chung626240f2019-12-20 15:04:27 -0800320 mStaticAssociations = loadStaticInputPortAssociations();
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700321 mUseDevInputEventForAudioJack =
322 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
323 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
324 + mUseDevInputEventForAudioJack);
Jeff Brown4532e612012-04-05 14:27:12 -0700325 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown4ccb8232014-01-16 22:16:42 -0800326
Adrian Roos99182342016-06-15 15:30:46 -0700327 String doubleTouchGestureEnablePath = context.getResources().getString(
328 R.string.config_doubleTouchGestureEnableFile);
329 mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
330 new File(doubleTouchGestureEnablePath);
331
Jeff Brown4ccb8232014-01-16 22:16:42 -0800332 LocalServices.addService(InputManagerInternal.class, new LocalService());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700333 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700334
Jeff Browna9d131c2012-09-20 16:48:17 -0700335 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
336 mWindowManagerCallbacks = callbacks;
337 }
338
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700339 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
340 mWiredAccessoryCallbacks = callbacks;
341 }
342
Jeff Brown46b9ac02010-04-22 18:58:52 -0700343 public void start() {
344 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700345 nativeStart(mPtr);
346
347 // Add ourself to the Watchdog monitors.
348 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700349
350 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700351 registerShowTouchesSettingObserver();
Jun Mukai19a56012015-11-24 11:25:52 -0800352 registerAccessibilityLargePointerSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700353
Jeff Brownd4935962012-09-25 13:27:20 -0700354 mContext.registerReceiver(new BroadcastReceiver() {
355 @Override
356 public void onReceive(Context context, Intent intent) {
357 updatePointerSpeedFromSettings();
358 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800359 updateAccessibilityLargePointerFromSettings();
Jeff Brownd4935962012-09-25 13:27:20 -0700360 }
361 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
362
Jeff Brown1a84fd12011-06-02 01:26:32 -0700363 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700364 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800365 updateAccessibilityLargePointerFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700366 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700367
Siarhei Vishniakouc8631852018-07-06 11:33:56 +0100368 // TODO(BT) Pass in parameter for bluetooth system
Svetoslav Ganova0027152013-06-25 14:59:53 -0700369 public void systemRunning() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700370 if (DEBUG) {
371 Slog.d(TAG, "System ready.");
372 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700373 mNotificationManager = (NotificationManager)mContext.getSystemService(
374 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700375 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700376
377 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
378 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
379 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Jeff Brown69b07162013-11-07 00:30:16 -0800380 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700381 filter.addDataScheme("package");
382 mContext.registerReceiver(new BroadcastReceiver() {
383 @Override
384 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700385 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700386 }
387 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700388
389 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
390 mContext.registerReceiver(new BroadcastReceiver() {
391 @Override
392 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700393 reloadDeviceAliases();
394 }
395 }, filter, null, mHandler);
396
Jeff Browncf39bdf2012-05-18 14:41:19 -0700397 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
398 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700399
400 if (mWiredAccessoryCallbacks != null) {
401 mWiredAccessoryCallbacks.systemReady();
402 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700403 }
404
405 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700406 if (DEBUG) {
407 Slog.d(TAG, "Reloading keyboard layouts.");
408 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700409 nativeReloadKeyboardLayouts(mPtr);
410 }
411
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700412 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700413 if (DEBUG) {
414 Slog.d(TAG, "Reloading device names.");
415 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700416 nativeReloadDeviceAliases(mPtr);
417 }
418
Siarhei Vishniakou2eb0f8f2018-07-06 23:30:12 +0100419 private void setDisplayViewportsInternal(List<DisplayViewport> viewports) {
420 nativeSetDisplayViewports(mPtr, viewports.toArray(new DisplayViewport[0]));
Jeff Brown46b9ac02010-04-22 18:58:52 -0700421 }
Jeff Brownac143512012-04-05 18:57:33 -0700422
Jeff Brown6d0fec22010-07-23 21:28:06 -0700423 /**
424 * Gets the current state of a key or button by key code.
425 * @param deviceId The input device id, or -1 to consult all devices.
426 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
427 * consider all input sources. An input device is consulted if at least one of its
428 * non-class input source bits matches the specified source mask.
429 * @param keyCode The key code to check.
430 * @return The key state.
431 */
432 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700433 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700434 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700435
Jeff Brown6d0fec22010-07-23 21:28:06 -0700436 /**
437 * Gets the current state of a key or button by scan code.
438 * @param deviceId The input device id, or -1 to consult all devices.
439 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
440 * consider all input sources. An input device is consulted if at least one of its
441 * non-class input source bits matches the specified source mask.
442 * @param scanCode The scan code to check.
443 * @return The key state.
444 */
445 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700446 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700447 }
RoboErikfb290df2013-12-16 11:27:55 -0800448
Jeff Brown6d0fec22010-07-23 21:28:06 -0700449 /**
450 * Gets the current state of a switch by switch code.
451 * @param deviceId The input device id, or -1 to consult all devices.
452 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
453 * consider all input sources. An input device is consulted if at least one of its
454 * non-class input source bits matches the specified source mask.
455 * @param switchCode The switch code to check.
456 * @return The switch state.
457 */
458 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700459 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700460 }
461
Jeff Brown6d0fec22010-07-23 21:28:06 -0700462 /**
463 * Determines whether the specified key codes are supported by a particular device.
464 * @param deviceId The input device id, or -1 to consult all devices.
465 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
466 * consider all input sources. An input device is consulted if at least one of its
467 * non-class input source bits matches the specified source mask.
468 * @param keyCodes The array of key codes to check.
469 * @param keyExists An array at least as large as keyCodes whose entries will be set
470 * to true or false based on the presence or absence of support for the corresponding
471 * key codes.
472 * @return True if the lookup was successful, false otherwise.
473 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700474 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700475 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700476 if (keyCodes == null) {
477 throw new IllegalArgumentException("keyCodes must not be null.");
478 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700479 if (keyExists == null || keyExists.length < keyCodes.length) {
480 throw new IllegalArgumentException("keyExists must not be null and must be at "
481 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700482 }
RoboErikfb290df2013-12-16 11:27:55 -0800483
Jeff Brown4532e612012-04-05 14:27:12 -0700484 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700485 }
RoboErikfb290df2013-12-16 11:27:55 -0800486
Jeff Browna41ca772010-08-11 14:46:32 -0700487 /**
488 * Creates an input channel that will receive all input from the input dispatcher.
489 * @param inputChannelName The input channel name.
Arthur Hungbe5ce212018-09-13 18:41:56 +0800490 * @param displayId Target display id.
Jeff Browna41ca772010-08-11 14:46:32 -0700491 * @return The input channel.
492 */
Arthur Hungbe5ce212018-09-13 18:41:56 +0800493 public InputChannel monitorInput(String inputChannelName, int displayId) {
Jeff Browna41ca772010-08-11 14:46:32 -0700494 if (inputChannelName == null) {
495 throw new IllegalArgumentException("inputChannelName must not be null.");
496 }
RoboErikfb290df2013-12-16 11:27:55 -0800497
Arthur Hungbe5ce212018-09-13 18:41:56 +0800498 if (displayId < Display.DEFAULT_DISPLAY) {
499 throw new IllegalArgumentException("displayId must >= 0.");
500 }
501
Jeff Browna41ca772010-08-11 14:46:32 -0700502 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Michael Wrightc7995232019-02-14 12:33:46 +0000503 nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId, false /*isGestureMonitor*/);
Jeff Browna41ca772010-08-11 14:46:32 -0700504 inputChannels[0].dispose(); // don't need to retain the Java object reference
505 return inputChannels[1];
506 }
507
508 /**
Michael Wrightc7995232019-02-14 12:33:46 +0000509 * Creates an input monitor that will receive pointer events for the purposes of system-wide
510 * gesture interpretation.
511 *
512 * @param inputChannelName The input channel name.
513 * @param displayId Target display id.
514 * @return The input channel.
515 */
516 @Override // Binder call
517 public InputMonitor monitorGestureInput(String inputChannelName, int displayId) {
518 if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT,
519 "monitorInputRegion()")) {
520 throw new SecurityException("Requires MONITOR_INPUT permission");
521 }
522
523 Objects.requireNonNull(inputChannelName, "inputChannelName must not be null.");
524
525 if (displayId < Display.DEFAULT_DISPLAY) {
526 throw new IllegalArgumentException("displayId must >= 0.");
527 }
528
Michael Wrightad3a6bf2019-04-04 14:17:09 +0100529 final long ident = Binder.clearCallingIdentity();
530 try {
531 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
532 InputMonitorHost host = new InputMonitorHost(inputChannels[0]);
Michael Wrightad3a6bf2019-04-04 14:17:09 +0100533 nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId,
534 true /*isGestureMonitor*/);
Siarhei Vishniakou7480ae22019-10-15 15:18:55 -0700535 return new InputMonitor(inputChannels[1], host);
Michael Wrightad3a6bf2019-04-04 14:17:09 +0100536 } finally {
537 Binder.restoreCallingIdentity(ident);
538 }
Michael Wrightc7995232019-02-14 12:33:46 +0000539 }
540
541 /**
Vishnu Nair18782162019-10-08 14:57:16 -0700542 * Registers an input channel so that it can be used as an input event target. The channel is
543 * registered with a generated token.
544 *
Jeff Browna41ca772010-08-11 14:46:32 -0700545 * @param inputChannel The input channel to register.
546 */
Vishnu Nair18782162019-10-08 14:57:16 -0700547 public void registerInputChannel(InputChannel inputChannel) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700548 if (inputChannel == null) {
549 throw new IllegalArgumentException("inputChannel must not be null.");
550 }
Robert Carre0a353c2018-08-02 16:38:04 -0700551
Siarhei Vishniakou2d759f52019-10-11 19:12:08 -0700552 nativeRegisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700553 }
RoboErikfb290df2013-12-16 11:27:55 -0800554
Jeff Browna41ca772010-08-11 14:46:32 -0700555 /**
556 * Unregisters an input channel.
557 * @param inputChannel The input channel to unregister.
558 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700559 public void unregisterInputChannel(InputChannel inputChannel) {
560 if (inputChannel == null) {
561 throw new IllegalArgumentException("inputChannel must not be null.");
562 }
RoboErikfb290df2013-12-16 11:27:55 -0800563
Jeff Brown4532e612012-04-05 14:27:12 -0700564 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700565 }
Jeff Brown0029c662011-03-30 02:25:18 -0700566
567 /**
568 * Sets an input filter that will receive all input events before they are dispatched.
569 * The input filter may then reinterpret input events or inject new ones.
570 *
571 * To ensure consistency, the input dispatcher automatically drops all events
572 * in progress whenever an input filter is installed or uninstalled. After an input
573 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
574 * Any events it attempts to send after it has been uninstalled will be dropped.
575 *
576 * @param filter The input filter, or null to remove the current filter.
577 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700578 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700579 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700580 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700581 if (oldFilter == filter) {
582 return; // nothing to do
583 }
584
585 if (oldFilter != null) {
586 mInputFilter = null;
587 mInputFilterHost.disconnectLocked();
588 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700589 try {
590 oldFilter.uninstall();
591 } catch (RemoteException re) {
592 /* ignore */
593 }
Jeff Brown0029c662011-03-30 02:25:18 -0700594 }
595
596 if (filter != null) {
597 mInputFilter = filter;
598 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700599 try {
600 filter.install(mInputFilterHost);
601 } catch (RemoteException re) {
602 /* ignore */
603 }
Jeff Brown0029c662011-03-30 02:25:18 -0700604 }
605
Jeff Brown4532e612012-04-05 14:27:12 -0700606 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700607 }
608 }
609
Siarhei Vishniakouc570bfd2019-11-25 13:54:40 -0800610 /**
611 * Set the state of the touch mode.
612 *
613 * WindowManager remains the source of truth of the touch mode state.
614 * However, we need to keep a copy of this state in input.
615 *
616 * The apps determine the touch mode state. Therefore, a single app will
617 * affect the global state. That state change needs to be propagated to
618 * other apps, when they become focused.
619 *
620 * When input dispatches focus to the apps, the touch mode state
621 * will be sent together with the focus change.
622 *
623 * @param inTouchMode true if the device is in touch mode.
624 */
625 public void setInTouchMode(boolean inTouchMode) {
626 nativeSetInTouchMode(mPtr, inTouchMode);
627 }
628
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700629 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700630 public boolean injectInputEvent(InputEvent event, int mode) {
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800631 return injectInputEventInternal(event, mode);
Jeff Brownca9bc702014-02-11 14:32:56 -0800632 }
633
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800634 private boolean injectInputEventInternal(InputEvent event, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700635 if (event == null) {
636 throw new IllegalArgumentException("event must not be null");
637 }
Jeff Brownac143512012-04-05 18:57:33 -0700638 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
639 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
640 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
641 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700642 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700643
Jeff Brownac143512012-04-05 18:57:33 -0700644 final int pid = Binder.getCallingPid();
645 final int uid = Binder.getCallingUid();
646 final long ident = Binder.clearCallingIdentity();
647 final int result;
648 try {
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800649 result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
Jeff Brownac143512012-04-05 18:57:33 -0700650 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
651 } finally {
652 Binder.restoreCallingIdentity(ident);
653 }
654 switch (result) {
655 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
656 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
657 throw new SecurityException(
658 "Injecting to another application requires INJECT_EVENTS permission");
659 case INPUT_EVENT_INJECTION_SUCCEEDED:
660 return true;
661 case INPUT_EVENT_INJECTION_TIMED_OUT:
662 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
663 return false;
664 case INPUT_EVENT_INJECTION_FAILED:
665 default:
666 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
667 return false;
668 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700669 }
Jeff Brown0029c662011-03-30 02:25:18 -0700670
Jeff Brown8d608662010-08-30 03:02:23 -0700671 /**
672 * Gets information about the input device with the specified id.
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700673 * @param deviceId The device id.
Jeff Brown8d608662010-08-30 03:02:23 -0700674 * @return The input device or null if not found.
675 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700676 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700677 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700678 synchronized (mInputDevicesLock) {
679 final int count = mInputDevices.length;
680 for (int i = 0; i < count; i++) {
681 final InputDevice inputDevice = mInputDevices[i];
682 if (inputDevice.getId() == deviceId) {
683 return inputDevice;
684 }
685 }
686 }
687 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700688 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700689
Siarhei Vishniakoua7f99b52017-03-21 17:39:40 -0700690 // Binder call
691 @Override
692 public boolean isInputDeviceEnabled(int deviceId) {
693 return nativeIsInputDeviceEnabled(mPtr, deviceId);
694 }
695
696 // Binder call
697 @Override
698 public void enableInputDevice(int deviceId) {
699 if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
700 "enableInputDevice()")) {
701 throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
702 }
703 nativeEnableInputDevice(mPtr, deviceId);
704 }
705
706 // Binder call
707 @Override
708 public void disableInputDevice(int deviceId) {
709 if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
710 "disableInputDevice()")) {
711 throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
712 }
713 nativeDisableInputDevice(mPtr, deviceId);
714 }
715
Jeff Brown8d608662010-08-30 03:02:23 -0700716 /**
717 * Gets the ids of all input devices in the system.
718 * @return The input device ids.
719 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700720 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700721 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700722 synchronized (mInputDevicesLock) {
723 final int count = mInputDevices.length;
724 int[] ids = new int[count];
725 for (int i = 0; i < count; i++) {
726 ids[i] = mInputDevices[i].getId();
727 }
728 return ids;
729 }
730 }
731
Jeff Browndaa37532012-05-01 15:54:03 -0700732 /**
733 * Gets all input devices in the system.
734 * @return The array of input devices.
735 */
736 public InputDevice[] getInputDevices() {
737 synchronized (mInputDevicesLock) {
738 return mInputDevices;
739 }
740 }
741
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700742 @Override // Binder call
743 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
744 if (listener == null) {
745 throw new IllegalArgumentException("listener must not be null");
746 }
747
748 synchronized (mInputDevicesLock) {
749 int callingPid = Binder.getCallingPid();
750 if (mInputDevicesChangedListeners.get(callingPid) != null) {
751 throw new SecurityException("The calling process has already "
752 + "registered an InputDevicesChangedListener.");
753 }
754
755 InputDevicesChangedListenerRecord record =
756 new InputDevicesChangedListenerRecord(callingPid, listener);
757 try {
758 IBinder binder = listener.asBinder();
759 binder.linkToDeath(record, 0);
760 } catch (RemoteException ex) {
761 // give up
762 throw new RuntimeException(ex);
763 }
764
765 mInputDevicesChangedListeners.put(callingPid, record);
766 }
767 }
768
769 private void onInputDevicesChangedListenerDied(int pid) {
770 synchronized (mInputDevicesLock) {
771 mInputDevicesChangedListeners.remove(pid);
772 }
773 }
774
775 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700776 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
777 // Scan for changes.
778 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700779 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700780 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700781 final int numListeners;
782 final int[] deviceIdAndGeneration;
783 synchronized (mInputDevicesLock) {
784 if (!mInputDevicesChangedPending) {
785 return;
786 }
787 mInputDevicesChangedPending = false;
788
789 numListeners = mInputDevicesChangedListeners.size();
790 for (int i = 0; i < numListeners; i++) {
791 mTempInputDevicesChangedListenersToNotify.add(
792 mInputDevicesChangedListeners.valueAt(i));
793 }
794
795 final int numDevices = mInputDevices.length;
796 deviceIdAndGeneration = new int[numDevices * 2];
797 for (int i = 0; i < numDevices; i++) {
798 final InputDevice inputDevice = mInputDevices[i];
799 deviceIdAndGeneration[i * 2] = inputDevice.getId();
800 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700801
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700802 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700803 if (!containsInputDeviceWithDescriptor(oldInputDevices,
804 inputDevice.getDescriptor())) {
805 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
806 } else {
807 mTempFullKeyboards.add(inputDevice);
808 }
809 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700810 }
811 }
812
Jeff Browncf39bdf2012-05-18 14:41:19 -0700813 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700814 for (int i = 0; i < numListeners; i++) {
815 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
816 deviceIdAndGeneration);
817 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700818 mTempInputDevicesChangedListenersToNotify.clear();
819
820 // Check for missing keyboard layouts.
Michael Wright07483422015-10-30 16:20:13 +0000821 List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
822 final int numFullKeyboards = mTempFullKeyboards.size();
823 synchronized (mDataStore) {
824 for (int i = 0; i < numFullKeyboards; i++) {
825 final InputDevice inputDevice = mTempFullKeyboards.get(i);
826 String layout =
827 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
828 if (layout == null) {
829 layout = getDefaultKeyboardLayout(inputDevice);
830 if (layout != null) {
831 setCurrentKeyboardLayoutForInputDevice(
832 inputDevice.getIdentifier(), layout);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700833 }
834 }
Michael Wright07483422015-10-30 16:20:13 +0000835 if (layout == null) {
836 keyboardsMissingLayout.add(inputDevice);
837 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700838 }
Michael Wright07483422015-10-30 16:20:13 +0000839 }
840
841 if (mNotificationManager != null) {
842 if (!keyboardsMissingLayout.isEmpty()) {
843 if (keyboardsMissingLayout.size() > 1) {
844 // We have more than one keyboard missing a layout, so drop the
845 // user at the generic input methods page so they can pick which
846 // one to set.
847 showMissingKeyboardLayoutNotification(null);
848 } else {
849 showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
Jeff Browncf39bdf2012-05-18 14:41:19 -0700850 }
851 } else if (mKeyboardLayoutNotificationShown) {
852 hideMissingKeyboardLayoutNotification();
853 }
854 }
855 mTempFullKeyboards.clear();
856 }
857
Michael Wright07483422015-10-30 16:20:13 +0000858 private String getDefaultKeyboardLayout(final InputDevice d) {
859 final Locale systemLocale = mContext.getResources().getConfiguration().locale;
860 // If our locale doesn't have a language for some reason, then we don't really have a
861 // reasonable default.
862 if (TextUtils.isEmpty(systemLocale.getLanguage())) {
863 return null;
864 }
865 final List<KeyboardLayout> layouts = new ArrayList<>();
866 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
867 @Override
868 public void visitKeyboardLayout(Resources resources,
869 int keyboardLayoutResId, KeyboardLayout layout) {
870 // Only select a default when we know the layout is appropriate. For now, this
871 // means its a custom layout for a specific keyboard.
872 if (layout.getVendorId() != d.getVendorId()
873 || layout.getProductId() != d.getProductId()) {
874 return;
875 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800876 final LocaleList locales = layout.getLocales();
877 final int numLocales = locales.size();
878 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
879 if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
Michael Wright07483422015-10-30 16:20:13 +0000880 layouts.add(layout);
881 break;
882 }
883 }
884 }
885 });
886
887 if (layouts.isEmpty()) {
888 return null;
889 }
890
891 // First sort so that ones with higher priority are listed at the top
892 Collections.sort(layouts);
893 // Next we want to try to find an exact match of language, country and variant.
894 final int N = layouts.size();
895 for (int i = 0; i < N; i++) {
896 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800897 final LocaleList locales = layout.getLocales();
898 final int numLocales = locales.size();
899 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
900 final Locale locale = locales.get(localeIndex);
901 if (locale.getCountry().equals(systemLocale.getCountry())
902 && locale.getVariant().equals(systemLocale.getVariant())) {
Michael Wright07483422015-10-30 16:20:13 +0000903 return layout.getDescriptor();
904 }
905 }
906 }
907 // Then try an exact match of language and country
908 for (int i = 0; i < N; i++) {
909 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800910 final LocaleList locales = layout.getLocales();
911 final int numLocales = locales.size();
912 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
913 final Locale locale = locales.get(localeIndex);
914 if (locale.getCountry().equals(systemLocale.getCountry())) {
Michael Wright07483422015-10-30 16:20:13 +0000915 return layout.getDescriptor();
916 }
917 }
918 }
919
920 // Give up and just use the highest priority layout with matching language
921 return layouts.get(0).getDescriptor();
922 }
923
924 private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
925 // Different languages are never compatible
926 if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
927 return false;
928 }
929 // If both the system and the keyboard layout have a country specifier, they must be equal.
930 if (!TextUtils.isEmpty(systemLocale.getCountry())
931 && !TextUtils.isEmpty(keyboardLocale.getCountry())
932 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
933 return false;
934 }
935 return true;
936 }
937
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800938 @Override // Binder call & native callback
Jason Gerecked5220742014-03-10 09:47:59 -0700939 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
940 int surfaceRotation) {
Jason Gerecked6396d62014-01-27 18:30:37 -0800941 if (inputDeviceDescriptor == null) {
942 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
943 }
944
945 synchronized (mDataStore) {
Jason Gerecked5220742014-03-10 09:47:59 -0700946 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
Jason Gerecked6396d62014-01-27 18:30:37 -0800947 }
948 }
949
950 @Override // Binder call
Jason Gerecked5220742014-03-10 09:47:59 -0700951 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
Jason Gerecked6396d62014-01-27 18:30:37 -0800952 TouchCalibration calibration) {
953 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
954 "setTouchCalibrationForInputDevice()")) {
955 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
956 }
957 if (inputDeviceDescriptor == null) {
958 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
959 }
960 if (calibration == null) {
961 throw new IllegalArgumentException("calibration must not be null");
962 }
Jason Gerecked5220742014-03-10 09:47:59 -0700963 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
964 throw new IllegalArgumentException("surfaceRotation value out of bounds");
965 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800966
967 synchronized (mDataStore) {
968 try {
Jason Gerecked5220742014-03-10 09:47:59 -0700969 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
970 calibration)) {
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800971 nativeReloadCalibration(mPtr);
972 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800973 } finally {
974 mDataStore.saveIfNeeded();
975 }
976 }
977 }
978
Michael Wright39e5e942015-08-19 22:52:47 +0100979 @Override // Binder call
Michael Wright9209c9c2015-09-03 17:57:01 +0100980 public int isInTabletMode() {
981 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
982 "isInTabletMode()")) {
983 throw new SecurityException("Requires TABLET_MODE permission");
984 }
985 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
986 }
987
988 @Override // Binder call
Dmitry Shmidtd6cf4d92019-09-20 15:50:36 -0700989 public int isMicMuted() {
990 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MUTE_DEVICE);
991 }
992
993 @Override // Binder call
Michael Wright39e5e942015-08-19 22:52:47 +0100994 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
Michael Wright9209c9c2015-09-03 17:57:01 +0100995 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
Michael Wright39e5e942015-08-19 22:52:47 +0100996 "registerTabletModeChangedListener()")) {
997 throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
998 }
999 if (listener == null) {
1000 throw new IllegalArgumentException("listener must not be null");
1001 }
1002
1003 synchronized (mTabletModeLock) {
1004 final int callingPid = Binder.getCallingPid();
1005 if (mTabletModeChangedListeners.get(callingPid) != null) {
1006 throw new IllegalStateException("The calling process has already registered "
1007 + "a TabletModeChangedListener.");
1008 }
1009 TabletModeChangedListenerRecord record =
1010 new TabletModeChangedListenerRecord(callingPid, listener);
1011 try {
1012 IBinder binder = listener.asBinder();
1013 binder.linkToDeath(record, 0);
1014 } catch (RemoteException ex) {
1015 throw new RuntimeException(ex);
1016 }
1017 mTabletModeChangedListeners.put(callingPid, record);
1018 }
1019 }
1020
1021 private void onTabletModeChangedListenerDied(int pid) {
1022 synchronized (mTabletModeLock) {
1023 mTabletModeChangedListeners.remove(pid);
1024 }
1025 }
1026
1027 // Must be called on handler
1028 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
1029 mTempTabletModeChangedListenersToNotify.clear();
1030 final int numListeners;
1031 synchronized (mTabletModeLock) {
1032 numListeners = mTabletModeChangedListeners.size();
1033 for (int i = 0; i < numListeners; i++) {
1034 mTempTabletModeChangedListenersToNotify.add(
1035 mTabletModeChangedListeners.valueAt(i));
1036 }
1037 }
1038 for (int i = 0; i < numListeners; i++) {
1039 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
1040 whenNanos, inTabletMode);
1041 }
1042 }
1043
Jeff Browncf39bdf2012-05-18 14:41:19 -07001044 // Must be called on handler.
Michael Wrightc93fbd12014-09-22 20:07:59 -07001045 private void showMissingKeyboardLayoutNotification(InputDevice device) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001046 if (!mKeyboardLayoutNotificationShown) {
Yohei Yukawa2bff4902016-03-30 01:06:37 -07001047 final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
Michael Wrightc93fbd12014-09-22 20:07:59 -07001048 if (device != null) {
1049 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001050 }
Michael Wrightc93fbd12014-09-22 20:07:59 -07001051 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1052 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
1053 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
1054 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
1055 intent, 0, null, UserHandle.CURRENT);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001056
1057 Resources r = mContext.getResources();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001058 Notification notification =
1059 new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
1060 .setContentTitle(r.getString(
1061 R.string.select_keyboard_layout_notification_title))
1062 .setContentText(r.getString(
1063 R.string.select_keyboard_layout_notification_message))
1064 .setContentIntent(keyboardLayoutIntent)
1065 .setSmallIcon(R.drawable.ic_settings_language)
1066 .setColor(mContext.getColor(
1067 com.android.internal.R.color.system_notification_accent_color))
1068 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001069 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04001070 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001071 notification, UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001072 mKeyboardLayoutNotificationShown = true;
1073 }
1074 }
1075
1076 // Must be called on handler.
1077 private void hideMissingKeyboardLayoutNotification() {
1078 if (mKeyboardLayoutNotificationShown) {
1079 mKeyboardLayoutNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001080 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04001081 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001082 UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001083 }
1084 }
1085
1086 // Must be called on handler.
1087 private void updateKeyboardLayouts() {
1088 // Scan all input devices state for keyboard layouts that have been uninstalled.
1089 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
1090 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1091 @Override
Michael Wright07483422015-10-30 16:20:13 +00001092 public void visitKeyboardLayout(Resources resources,
1093 int keyboardLayoutResId, KeyboardLayout layout) {
1094 availableKeyboardLayouts.add(layout.getDescriptor());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001095 }
1096 });
1097 synchronized (mDataStore) {
1098 try {
1099 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
1100 } finally {
1101 mDataStore.saveIfNeeded();
1102 }
1103 }
1104
1105 // Reload keyboard layouts.
1106 reloadKeyboardLayouts();
1107 }
1108
Jeff Browncf39bdf2012-05-18 14:41:19 -07001109 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
1110 String descriptor) {
1111 final int numDevices = inputDevices.length;
1112 for (int i = 0; i < numDevices; i++) {
1113 final InputDevice inputDevice = inputDevices[i];
1114 if (inputDevice.getDescriptor().equals(descriptor)) {
1115 return true;
1116 }
1117 }
1118 return false;
Jeff Brown8d608662010-08-30 03:02:23 -07001119 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001120
1121 @Override // Binder call
1122 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001123 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
1124 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1125 @Override
Michael Wright07483422015-10-30 16:20:13 +00001126 public void visitKeyboardLayout(Resources resources,
1127 int keyboardLayoutResId, KeyboardLayout layout) {
1128 list.add(layout);
1129 }
1130 });
1131 return list.toArray(new KeyboardLayout[list.size()]);
1132 }
1133
Michael Wrightb0e804a2016-01-04 16:48:53 -05001134 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001135 public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1136 final InputDeviceIdentifier identifier) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001137 final String[] enabledLayoutDescriptors =
1138 getEnabledKeyboardLayoutsForInputDevice(identifier);
1139 final ArrayList<KeyboardLayout> enabledLayouts =
1140 new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length);
1141 final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>();
Michael Wright07483422015-10-30 16:20:13 +00001142 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1143 boolean mHasSeenDeviceSpecificLayout;
1144
1145 @Override
1146 public void visitKeyboardLayout(Resources resources,
1147 int keyboardLayoutResId, KeyboardLayout layout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001148 // First check if it's enabled. If the keyboard layout is enabled then we always
1149 // want to return it as a possible layout for the device.
1150 for (String s : enabledLayoutDescriptors) {
1151 if (s != null && s.equals(layout.getDescriptor())) {
1152 enabledLayouts.add(layout);
1153 return;
1154 }
1155 }
1156 // Next find any potential layouts that aren't yet enabled for the device. For
1157 // devices that have special layouts we assume there's a reason that the generic
1158 // layouts don't work for them so we don't want to return them since it's likely
1159 // to result in a poor user experience.
Michael Wright07483422015-10-30 16:20:13 +00001160 if (layout.getVendorId() == identifier.getVendorId()
1161 && layout.getProductId() == identifier.getProductId()) {
1162 if (!mHasSeenDeviceSpecificLayout) {
1163 mHasSeenDeviceSpecificLayout = true;
Michael Wrightb0e804a2016-01-04 16:48:53 -05001164 potentialLayouts.clear();
Michael Wright07483422015-10-30 16:20:13 +00001165 }
Michael Wrightb0e804a2016-01-04 16:48:53 -05001166 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001167 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
1168 && !mHasSeenDeviceSpecificLayout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001169 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001170 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001171 }
1172 });
Michael Wrightb0e804a2016-01-04 16:48:53 -05001173 final int enabledLayoutSize = enabledLayouts.size();
1174 final int potentialLayoutSize = potentialLayouts.size();
1175 KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
1176 enabledLayouts.toArray(layouts);
1177 for (int i = 0; i < potentialLayoutSize; i++) {
1178 layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
1179 }
1180 return layouts;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001181 }
1182
1183 @Override // Binder call
1184 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
1185 if (keyboardLayoutDescriptor == null) {
1186 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1187 }
1188
Jeff Brown6ec6f792012-04-17 16:52:41 -07001189 final KeyboardLayout[] result = new KeyboardLayout[1];
1190 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1191 @Override
Michael Wright07483422015-10-30 16:20:13 +00001192 public void visitKeyboardLayout(Resources resources,
1193 int keyboardLayoutResId, KeyboardLayout layout) {
1194 result[0] = layout;
Jeff Brown6ec6f792012-04-17 16:52:41 -07001195 }
1196 });
1197 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00001198 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07001199 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001200 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001201 return result[0];
1202 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001203
Jeff Brown6ec6f792012-04-17 16:52:41 -07001204 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001205 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001206 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
1207 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001208 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
1209 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
Michael Wright8ebac232014-09-18 18:29:49 -07001210 final ActivityInfo activityInfo = resolveInfo.activityInfo;
1211 final int priority = resolveInfo.priority;
1212 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001213 }
1214 }
1215
Jeff Brown6ec6f792012-04-17 16:52:41 -07001216 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
1217 KeyboardLayoutVisitor visitor) {
1218 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
1219 if (d != null) {
1220 final PackageManager pm = mContext.getPackageManager();
1221 try {
1222 ActivityInfo receiver = pm.getReceiverInfo(
1223 new ComponentName(d.packageName, d.receiverName),
Jeff Sharkey5217cac2015-12-20 15:34:01 -07001224 PackageManager.GET_META_DATA
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001225 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1226 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Michael Wright8ebac232014-09-18 18:29:49 -07001227 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001228 } catch (NameNotFoundException ex) {
1229 }
1230 }
1231 }
1232
1233 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
Michael Wright8ebac232014-09-18 18:29:49 -07001234 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001235 Bundle metaData = receiver.metaData;
1236 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001237 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001238 }
1239
1240 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1241 if (configResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001242 Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001243 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001244 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001245 }
1246
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001247 CharSequence receiverLabel = receiver.loadLabel(pm);
1248 String collection = receiverLabel != null ? receiverLabel.toString() : "";
Michael Wright8ebac232014-09-18 18:29:49 -07001249 int priority;
1250 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1251 priority = requestedPriority;
1252 } else {
1253 priority = 0;
1254 }
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001255
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001256 try {
1257 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1258 XmlResourceParser parser = resources.getXml(configResId);
1259 try {
1260 XmlUtils.beginDocument(parser, "keyboard-layouts");
1261
1262 for (;;) {
1263 XmlUtils.nextElement(parser);
1264 String element = parser.getName();
1265 if (element == null) {
1266 break;
1267 }
1268 if (element.equals("keyboard-layout")) {
1269 TypedArray a = resources.obtainAttributes(
1270 parser, com.android.internal.R.styleable.KeyboardLayout);
1271 try {
1272 String name = a.getString(
1273 com.android.internal.R.styleable.KeyboardLayout_name);
1274 String label = a.getString(
1275 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -07001276 int keyboardLayoutResId = a.getResourceId(
1277 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1278 0);
Michael Wright07483422015-10-30 16:20:13 +00001279 String languageTags = a.getString(
1280 com.android.internal.R.styleable.KeyboardLayout_locale);
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001281 LocaleList locales = getLocalesFromLanguageTags(languageTags);
Michael Wright07483422015-10-30 16:20:13 +00001282 int vid = a.getInt(
1283 com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
1284 int pid = a.getInt(
1285 com.android.internal.R.styleable.KeyboardLayout_productId, -1);
1286
Jeff Brown2f095762012-05-10 21:29:33 -07001287 if (name == null || label == null || keyboardLayoutResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001288 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001289 + "attributes in keyboard layout "
1290 + "resource from receiver "
1291 + receiver.packageName + "/" + receiver.name);
1292 } else {
1293 String descriptor = KeyboardLayoutDescriptor.format(
1294 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001295 if (keyboardName == null || name.equals(keyboardName)) {
Michael Wright07483422015-10-30 16:20:13 +00001296 KeyboardLayout layout = new KeyboardLayout(
1297 descriptor, label, collection, priority,
1298 locales, vid, pid);
1299 visitor.visitKeyboardLayout(
1300 resources, keyboardLayoutResId, layout);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001301 }
1302 }
1303 } finally {
1304 a.recycle();
1305 }
1306 } else {
Michael Wright07483422015-10-30 16:20:13 +00001307 Slog.w(TAG, "Skipping unrecognized element '" + element
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001308 + "' in keyboard layout resource from receiver "
1309 + receiver.packageName + "/" + receiver.name);
1310 }
1311 }
1312 } finally {
1313 parser.close();
1314 }
1315 } catch (Exception ex) {
Michael Wright07483422015-10-30 16:20:13 +00001316 Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001317 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001318 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001319 }
1320
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001321 @NonNull
1322 private static LocaleList getLocalesFromLanguageTags(String languageTags) {
Michael Wright07483422015-10-30 16:20:13 +00001323 if (TextUtils.isEmpty(languageTags)) {
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001324 return LocaleList.getEmptyLocaleList();
Michael Wright07483422015-10-30 16:20:13 +00001325 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001326 return LocaleList.forLanguageTags(languageTags.replace('|', ','));
Michael Wright07483422015-10-30 16:20:13 +00001327 }
1328
RoboErikfb290df2013-12-16 11:27:55 -08001329 /**
1330 * Builds a layout descriptor for the vendor/product. This returns the
1331 * descriptor for ids that aren't useful (such as the default 0, 0).
1332 */
1333 private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1334 if (identifier == null || identifier.getDescriptor() == null) {
1335 throw new IllegalArgumentException("identifier and descriptor must not be null");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001336 }
1337
RoboErikfb290df2013-12-16 11:27:55 -08001338 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1339 return identifier.getDescriptor();
1340 }
1341 StringBuilder bob = new StringBuilder();
1342 bob.append("vendor:").append(identifier.getVendorId());
1343 bob.append(",product:").append(identifier.getProductId());
1344 return bob.toString();
1345 }
1346
1347 @Override // Binder call
1348 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1349
1350 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001351 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001352 String layout = null;
1353 // try loading it using the layout descriptor if we have it
1354 layout = mDataStore.getCurrentKeyboardLayout(key);
1355 if (layout == null && !key.equals(identifier.getDescriptor())) {
1356 // if it doesn't exist fall back to the device descriptor
1357 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1358 }
1359 if (DEBUG) {
1360 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1361 + layout);
1362 }
1363 return layout;
Jeff Browna3bc5652012-04-17 11:42:25 -07001364 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001365 }
1366
1367 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001368 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001369 String keyboardLayoutDescriptor) {
1370 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001371 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001372 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1373 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001374 if (keyboardLayoutDescriptor == null) {
1375 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1376 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001377
RoboErikfb290df2013-12-16 11:27:55 -08001378 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001379 synchronized (mDataStore) {
1380 try {
RoboErikfb290df2013-12-16 11:27:55 -08001381 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1382 if (DEBUG) {
1383 Slog.d(TAG, "Saved keyboard layout using " + key);
1384 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001385 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1386 }
Jeff Browna3bc5652012-04-17 11:42:25 -07001387 } finally {
1388 mDataStore.saveIfNeeded();
1389 }
1390 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001391 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001392
Jeff Browncf39bdf2012-05-18 14:41:19 -07001393 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001394 public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
RoboErikfb290df2013-12-16 11:27:55 -08001395 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001396 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001397 String[] layouts = mDataStore.getKeyboardLayouts(key);
1398 if ((layouts == null || layouts.length == 0)
1399 && !key.equals(identifier.getDescriptor())) {
1400 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1401 }
1402 return layouts;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001403 }
1404 }
1405
1406 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001407 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001408 String keyboardLayoutDescriptor) {
1409 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1410 "addKeyboardLayoutForInputDevice()")) {
1411 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1412 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001413 if (keyboardLayoutDescriptor == null) {
1414 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1415 }
1416
RoboErikfb290df2013-12-16 11:27:55 -08001417 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001418 synchronized (mDataStore) {
1419 try {
RoboErikfb290df2013-12-16 11:27:55 -08001420 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1421 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1422 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1423 }
1424 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001425 && !Objects.equals(oldLayout,
1426 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001427 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1428 }
1429 } finally {
1430 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001431 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001432 }
1433 }
1434
1435 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001436 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001437 String keyboardLayoutDescriptor) {
1438 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1439 "removeKeyboardLayoutForInputDevice()")) {
1440 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1441 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001442 if (keyboardLayoutDescriptor == null) {
1443 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1444 }
1445
RoboErikfb290df2013-12-16 11:27:55 -08001446 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001447 synchronized (mDataStore) {
1448 try {
RoboErikfb290df2013-12-16 11:27:55 -08001449 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1450 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1451 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1452 }
1453 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1454 if (!key.equals(identifier.getDescriptor())) {
1455 // We need to remove from both places to ensure it is gone
1456 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1457 keyboardLayoutDescriptor);
1458 }
Narayan Kamath607223f2018-02-19 14:09:02 +00001459 if (removed && !Objects.equals(oldLayout,
RoboErikfb290df2013-12-16 11:27:55 -08001460 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001461 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1462 }
1463 } finally {
1464 mDataStore.saveIfNeeded();
1465 }
1466 }
1467 }
1468
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001469 public void switchKeyboardLayout(int deviceId, int direction) {
1470 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001471 }
1472
1473 // Must be called on handler.
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001474 private void handleSwitchKeyboardLayout(int deviceId, int direction) {
1475 final InputDevice device = getInputDevice(deviceId);
1476 if (device != null) {
1477 final boolean changed;
1478 final String keyboardLayoutDescriptor;
1479
1480 String key = getLayoutDescriptor(device.getIdentifier());
1481 synchronized (mDataStore) {
1482 try {
1483 changed = mDataStore.switchKeyboardLayout(key, direction);
1484 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
1485 key);
1486 } finally {
1487 mDataStore.saveIfNeeded();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001488 }
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001489 }
1490
1491 if (changed) {
1492 if (mSwitchedKeyboardLayoutToast != null) {
1493 mSwitchedKeyboardLayoutToast.cancel();
1494 mSwitchedKeyboardLayoutToast = null;
1495 }
1496 if (keyboardLayoutDescriptor != null) {
1497 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
1498 if (keyboardLayout != null) {
1499 mSwitchedKeyboardLayoutToast = Toast.makeText(
1500 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
1501 mSwitchedKeyboardLayoutToast.show();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001502 }
1503 }
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001504
1505 reloadKeyboardLayouts();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001506 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001507 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001508 }
1509
Tiger Huang1e5b10a2018-07-30 20:19:51 +08001510 public void setFocusedApplication(int displayId, InputApplicationHandle application) {
1511 nativeSetFocusedApplication(mPtr, displayId, application);
1512 }
1513
Tiger Huang1e5b10a2018-07-30 20:19:51 +08001514 public void setFocusedDisplay(int displayId) {
1515 nativeSetFocusedDisplay(mPtr, displayId);
Jeff Brown349703e2010-06-22 01:27:15 -07001516 }
RoboErikfb290df2013-12-16 11:27:55 -08001517
Riddle Hsu3f2de742019-02-25 15:21:38 +08001518 /** Clean up input window handles of the given display. */
1519 public void onDisplayRemoved(int displayId) {
1520 nativeSetInputWindows(mPtr, null /* windowHandles */, displayId);
1521 }
1522
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001523 @Override
1524 public void requestPointerCapture(IBinder windowToken, boolean enabled) {
Vishnu Nair18782162019-10-08 14:57:16 -07001525 boolean requestConfigurationRefresh =
1526 mWindowManagerCallbacks.requestPointerCapture(windowToken, enabled);
1527 if (requestConfigurationRefresh) {
Tiger Huang1e5b10a2018-07-30 20:19:51 +08001528 nativeSetPointerCapture(mPtr, enabled);
1529 }
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001530 }
1531
Jeff Brown349703e2010-06-22 01:27:15 -07001532 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001533 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001534 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001535
1536 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001537 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001538 }
1539
Arthur Hungfd9d94d2019-08-28 16:06:07 +08001540 /**
1541 * Atomically transfers touch focus from one window to another as identified by
1542 * their input channels. It is possible for multiple windows to have
1543 * touch focus if they support split touch dispatch
1544 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1545 * method only transfers touch focus of the specified window without affecting
1546 * other windows that may also have touch focus at the same time.
1547 * @param fromChannel The channel of a window that currently has touch focus.
1548 * @param toChannel The channel of the window that should receive touch focus in
1549 * place of the first.
1550 * @return True if the transfer was successful. False if the window with the
1551 * specified channel did not actually have touch focus at the time of the request.
1552 */
1553 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1554 if (fromChannel == null) {
1555 throw new IllegalArgumentException("fromChannel must not be null.");
1556 }
1557 if (toChannel == null) {
1558 throw new IllegalArgumentException("toChannel must not be null.");
1559 }
1560 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
1561 }
1562
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001563 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001564 public void tryPointerSpeed(int speed) {
1565 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1566 "tryPointerSpeed()")) {
1567 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1568 }
1569
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001570 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1571 throw new IllegalArgumentException("speed out of range");
1572 }
1573
Jeff Brownac143512012-04-05 18:57:33 -07001574 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001575 }
1576
1577 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001578 int speed = getPointerSpeedSetting();
1579 setPointerSpeedUnchecked(speed);
1580 }
1581
1582 private void setPointerSpeedUnchecked(int speed) {
1583 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1584 InputManager.MAX_POINTER_SPEED);
1585 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001586 }
1587
1588 private void registerPointerSpeedSettingObserver() {
1589 mContext.getContentResolver().registerContentObserver(
1590 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001591 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001592 @Override
1593 public void onChange(boolean selfChange) {
1594 updatePointerSpeedFromSettings();
1595 }
Jeff Brownd4935962012-09-25 13:27:20 -07001596 }, UserHandle.USER_ALL);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001597 }
1598
Jeff Brownac143512012-04-05 18:57:33 -07001599 private int getPointerSpeedSetting() {
1600 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001601 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001602 speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1603 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001604 } catch (SettingNotFoundException snfe) {
1605 }
1606 return speed;
1607 }
1608
Jeff Browndaf4a122011-08-26 17:14:14 -07001609 public void updateShowTouchesFromSettings() {
1610 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001611 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001612 }
1613
1614 private void registerShowTouchesSettingObserver() {
1615 mContext.getContentResolver().registerContentObserver(
1616 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001617 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001618 @Override
1619 public void onChange(boolean selfChange) {
1620 updateShowTouchesFromSettings();
1621 }
Jeff Brownd4935962012-09-25 13:27:20 -07001622 }, UserHandle.USER_ALL);
Jeff Browndaf4a122011-08-26 17:14:14 -07001623 }
1624
Jun Mukaie4e75da2015-12-15 16:19:20 -08001625 public void updateAccessibilityLargePointerFromSettings() {
1626 final int accessibilityConfig = Settings.Secure.getIntForUser(
1627 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1628 0, UserHandle.USER_CURRENT);
Jun Mukai1f3dbff2015-12-16 14:41:25 -08001629 PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
Jun Mukaie4e75da2015-12-15 16:19:20 -08001630 nativeReloadPointerIcons(mPtr);
1631 }
1632
Jun Mukai19a56012015-11-24 11:25:52 -08001633 private void registerAccessibilityLargePointerSettingObserver() {
1634 mContext.getContentResolver().registerContentObserver(
1635 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1636 new ContentObserver(mHandler) {
1637 @Override
1638 public void onChange(boolean selfChange) {
Jun Mukaie4e75da2015-12-15 16:19:20 -08001639 updateAccessibilityLargePointerFromSettings();
Jun Mukai19a56012015-11-24 11:25:52 -08001640 }
1641 }, UserHandle.USER_ALL);
1642 }
1643
Jeff Browndaf4a122011-08-26 17:14:14 -07001644 private int getShowTouchesSetting(int defaultValue) {
1645 int result = defaultValue;
1646 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001647 result = Settings.System.getIntForUser(mContext.getContentResolver(),
1648 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
Jeff Browndaf4a122011-08-26 17:14:14 -07001649 } catch (SettingNotFoundException snfe) {
1650 }
1651 return result;
1652 }
1653
Jeff Browna47425a2012-04-13 04:09:27 -07001654 // Binder call
1655 @Override
1656 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1657 if (repeat >= pattern.length) {
1658 throw new ArrayIndexOutOfBoundsException();
1659 }
1660
1661 VibratorToken v;
1662 synchronized (mVibratorLock) {
1663 v = mVibratorTokens.get(token);
1664 if (v == null) {
1665 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1666 try {
1667 token.linkToDeath(v, 0);
1668 } catch (RemoteException ex) {
1669 // give up
1670 throw new RuntimeException(ex);
1671 }
1672 mVibratorTokens.put(token, v);
1673 }
1674 }
1675
1676 synchronized (v) {
1677 v.mVibrating = true;
1678 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1679 }
1680 }
1681
1682 // Binder call
1683 @Override
1684 public void cancelVibrate(int deviceId, IBinder token) {
1685 VibratorToken v;
1686 synchronized (mVibratorLock) {
1687 v = mVibratorTokens.get(token);
1688 if (v == null || v.mDeviceId != deviceId) {
1689 return; // nothing to cancel
1690 }
1691 }
1692
1693 cancelVibrateIfNeeded(v);
1694 }
1695
1696 void onVibratorTokenDied(VibratorToken v) {
1697 synchronized (mVibratorLock) {
1698 mVibratorTokens.remove(v.mToken);
1699 }
1700
1701 cancelVibrateIfNeeded(v);
1702 }
1703
1704 private void cancelVibrateIfNeeded(VibratorToken v) {
1705 synchronized (v) {
1706 if (v.mVibrating) {
1707 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1708 v.mVibrating = false;
1709 }
1710 }
1711 }
1712
Jun Mukai19a56012015-11-24 11:25:52 -08001713 // Binder call
1714 @Override
Michael Wrightf9d9ce772016-05-13 17:44:16 +01001715 public void setPointerIconType(int iconId) {
1716 nativeSetPointerIconType(mPtr, iconId);
Jun Mukai19a56012015-11-24 11:25:52 -08001717 }
Jun Mukai1db53972015-09-11 18:08:31 -07001718
Jun Mukaid4eaef72015-10-30 15:54:33 -07001719 // Binder call
1720 @Override
1721 public void setCustomPointerIcon(PointerIcon icon) {
Michael Wrightb004b512017-01-18 18:09:29 +00001722 Preconditions.checkNotNull(icon);
Jun Mukaid4eaef72015-10-30 15:54:33 -07001723 nativeSetCustomPointerIcon(mPtr, icon);
1724 }
1725
Jeff Brown4532e612012-04-05 14:27:12 -07001726 @Override
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001727 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001728 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Jeff Brown4532e612012-04-05 14:27:12 -07001729
1730 pw.println("INPUT MANAGER (dumpsys input)\n");
1731 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001732 if (dumpStr != null) {
1733 pw.println(dumpStr);
Arthur Hungcf6070e2019-12-04 16:09:42 +08001734 dumpAssociations(pw);
1735 }
1736 }
1737
1738 private void dumpAssociations(PrintWriter pw) {
1739 if (!mStaticAssociations.isEmpty()) {
1740 pw.println("Static Associations:");
1741 mStaticAssociations.forEach((k, v) -> {
1742 pw.print(" port: " + k);
1743 pw.println(" display: " + v);
1744 });
Jeff Browne33348b2010-07-15 23:54:05 -07001745 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001746 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001747
Jeff Brownac143512012-04-05 18:57:33 -07001748 private boolean checkCallingPermission(String permission, String func) {
1749 // Quick check: if the calling permission is me, it's all okay.
1750 if (Binder.getCallingPid() == Process.myPid()) {
1751 return true;
1752 }
1753
1754 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1755 return true;
1756 }
1757 String msg = "Permission Denial: " + func + " from pid="
1758 + Binder.getCallingPid()
1759 + ", uid=" + Binder.getCallingUid()
1760 + " requires " + permission;
1761 Slog.w(TAG, msg);
1762 return false;
1763 }
1764
Jeff Brown4532e612012-04-05 14:27:12 -07001765 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001766 @Override
Jeff Brown89ef0722011-08-10 16:25:21 -07001767 public void monitor() {
1768 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -07001769 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001770 }
1771
Jeff Brown4532e612012-04-05 14:27:12 -07001772 // Native callback.
1773 private void notifyConfigurationChanged(long whenNanos) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001774 mWindowManagerCallbacks.notifyConfigurationChanged();
Jeff Brown4532e612012-04-05 14:27:12 -07001775 }
1776
1777 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001778 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1779 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001780 if (!mInputDevicesChangedPending) {
1781 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001782 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1783 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001784 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001785
1786 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001787 }
1788 }
1789
1790 // Native callback.
Jeff Brownbcc046a2012-09-27 20:46:43 -07001791 private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1792 if (DEBUG) {
1793 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1794 + ", mask=" + Integer.toHexString(switchMask));
1795 }
1796
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001797 if ((switchMask & SW_LID_BIT) != 0) {
1798 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
Jeff Brownbcc046a2012-09-27 20:46:43 -07001799 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
Jeff Brown53384282012-08-20 20:16:01 -07001800 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001801
Michael Wright3818c922014-09-02 13:59:07 -07001802 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
Michael Wright9e10d252014-09-13 19:41:20 -07001803 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
Michael Wright3818c922014-09-02 13:59:07 -07001804 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1805 }
1806
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001807 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1808 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1809 switchMask);
1810 }
Michael Wright39e5e942015-08-19 22:52:47 +01001811
Michael Wright9209c9c2015-09-03 17:57:01 +01001812 if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
Michael Wright39e5e942015-08-19 22:52:47 +01001813 SomeArgs args = SomeArgs.obtain();
1814 args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
1815 args.argi2 = (int) (whenNanos >> 32);
1816 args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
1817 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
1818 args).sendToTarget();
1819 }
Dmitry Shmidt38ab71c2019-09-19 15:28:30 -07001820
1821 if ((switchMask & SW_MUTE_DEVICE_BIT) != 0) {
1822 final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0);
1823 AudioManager audioManager = mContext.getSystemService(AudioManager.class);
1824 audioManager.setMicrophoneMuteFromSwitch(micMute);
1825 }
Jeff Brown4532e612012-04-05 14:27:12 -07001826 }
1827
1828 // Native callback.
Robert Carre0a353c2018-08-02 16:38:04 -07001829 private void notifyInputChannelBroken(IBinder token) {
1830 mWindowManagerCallbacks.notifyInputChannelBroken(token);
Jeff Brown4532e612012-04-05 14:27:12 -07001831 }
1832
Robert Carrbd26e652018-08-21 15:46:28 -07001833 // Native callback
chaviw91089862019-01-09 15:49:11 -08001834 private void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
Vishnu Nair18782162019-10-08 14:57:16 -07001835 final boolean requestConfigurationRefresh =
1836 mWindowManagerCallbacks.notifyFocusChanged(oldToken, newToken);
1837 if (requestConfigurationRefresh) {
1838 nativeSetPointerCapture(mPtr, false);
Robert Carrbd26e652018-08-21 15:46:28 -07001839 }
1840 }
1841
Jeff Brown4532e612012-04-05 14:27:12 -07001842 // Native callback.
Vishnu Nair19479df2019-10-30 08:03:15 -07001843 private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
1844 String reason) {
1845 return mWindowManagerCallbacks.notifyANR(inputApplicationHandle,
Robert Carr679ccb02018-08-08 15:32:35 -07001846 token, reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001847 }
1848
1849 // Native callback.
1850 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1851 synchronized (mInputFilterLock) {
1852 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001853 try {
1854 mInputFilter.filterInputEvent(event, policyFlags);
1855 } catch (RemoteException e) {
1856 /* ignore */
1857 }
Jeff Brown4532e612012-04-05 14:27:12 -07001858 return false;
1859 }
1860 }
1861 event.recycle();
1862 return true;
1863 }
1864
1865 // Native callback.
Jeff Brown037c33e2014-04-09 00:31:55 -07001866 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1867 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001868 }
1869
1870 // Native callback.
Charles Chen4cc014e12019-01-28 16:17:16 +08001871 private int interceptMotionBeforeQueueingNonInteractive(int displayId,
1872 long whenNanos, int policyFlags) {
Michael Wright70af00a2014-09-03 19:30:20 -07001873 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
Charles Chen4cc014e12019-01-28 16:17:16 +08001874 displayId, whenNanos, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001875 }
1876
1877 // Native callback.
Robert Carr679ccb02018-08-08 15:32:35 -07001878 private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001879 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001880 }
1881
1882 // Native callback.
Robert Carr679ccb02018-08-08 15:32:35 -07001883 private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001884 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001885 }
1886
1887 // Native callback.
1888 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1889 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1890 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1891 }
1892
1893 // Native callback.
chaviw17902c52019-03-25 13:21:56 -07001894 private void onPointerDownOutsideFocus(IBinder touchedToken) {
chaviwfa2f0042019-03-25 13:48:58 -07001895 mWindowManagerCallbacks.onPointerDownOutsideFocus(touchedToken);
chaviw17902c52019-03-25 13:21:56 -07001896 }
1897
1898 // Native callback.
Jeff Brown4532e612012-04-05 14:27:12 -07001899 private int getVirtualKeyQuietTimeMillis() {
1900 return mContext.getResources().getInteger(
1901 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1902 }
1903
1904 // Native callback.
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001905 private static String[] getExcludedDeviceNames() {
1906 List<String> names = new ArrayList<>();
Jeff Brown4532e612012-04-05 14:27:12 -07001907 // Read partner-provided list of excluded input devices
Jeff Brown4532e612012-04-05 14:27:12 -07001908 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
Tsukasa Hashimotoea12b552018-09-11 16:47:22 +09001909 final File[] baseDirs = {
1910 Environment.getRootDirectory(),
1911 Environment.getVendorDirectory()
1912 };
1913 for (File baseDir: baseDirs) {
1914 File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH);
Tsukasa Hashimotoea12b552018-09-11 16:47:22 +09001915 try {
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001916 InputStream stream = new FileInputStream(confFile);
1917 names.addAll(ConfigurationProcessor.processExcludedDeviceNames(stream));
Tsukasa Hashimotoea12b552018-09-11 16:47:22 +09001918 } catch (FileNotFoundException e) {
1919 // It's ok if the file does not exist.
1920 } catch (Exception e) {
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001921 Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
Jeff Brown4532e612012-04-05 14:27:12 -07001922 }
Jeff Brown4532e612012-04-05 14:27:12 -07001923 }
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001924 return names.toArray(new String[0]);
1925 }
Jeff Brown4532e612012-04-05 14:27:12 -07001926
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001927 /**
Arthur Hungcf6070e2019-12-04 16:09:42 +08001928 * Flatten a map into a string list, with value positioned directly next to the
1929 * key.
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001930 * @return Flattened list
1931 */
Arthur Hungcf6070e2019-12-04 16:09:42 +08001932 private static List<String> flatten(@NonNull Map<String, Integer> map) {
1933 List<String> list = new ArrayList<>(map.size() * 2);
1934 map.forEach((k, v)-> {
1935 list.add(k);
1936 list.add(v.toString());
1937 });
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001938 return list;
1939 }
1940
1941 /**
1942 * Ports are highly platform-specific, so only allow these to be specified in the vendor
1943 * directory.
1944 */
Arthur Hungcf6070e2019-12-04 16:09:42 +08001945 private static Map<String, Integer> loadStaticInputPortAssociations() {
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001946 File baseDir = Environment.getVendorDirectory();
1947 File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
1948
1949 try {
1950 InputStream stream = new FileInputStream(confFile);
Arthur Hungcf6070e2019-12-04 16:09:42 +08001951 return ConfigurationProcessor.processInputPortAssociations(stream);
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001952 } catch (FileNotFoundException e) {
1953 // Most of the time, file will not exist, which is expected.
1954 } catch (Exception e) {
1955 Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
1956 }
Arthur Hungcf6070e2019-12-04 16:09:42 +08001957
1958 return new HashMap<>();
1959 }
1960
1961 // Native callback
1962 private String[] getInputPortAssociations() {
1963 List<String> associationList = flatten(mStaticAssociations);
1964 return associationList.toArray(new String[0]);
Jeff Brown4532e612012-04-05 14:27:12 -07001965 }
1966
Arthur Hung82bbfc32018-11-29 20:24:51 +08001967 /**
1968 * Gets if an input device could dispatch to the given display".
1969 * @param deviceId The input device id.
1970 * @param displayId The specific display id.
1971 * @return True if the device could dispatch to the given display, false otherwise.
1972 */
1973 public boolean canDispatchToDisplay(int deviceId, int displayId) {
1974 return nativeCanDispatchToDisplay(mPtr, deviceId, displayId);
1975 }
1976
Jeff Brown4532e612012-04-05 14:27:12 -07001977 // Native callback.
1978 private int getKeyRepeatTimeout() {
1979 return ViewConfiguration.getKeyRepeatTimeout();
1980 }
1981
1982 // Native callback.
1983 private int getKeyRepeatDelay() {
1984 return ViewConfiguration.getKeyRepeatDelay();
1985 }
1986
1987 // Native callback.
1988 private int getHoverTapTimeout() {
1989 return ViewConfiguration.getHoverTapTimeout();
1990 }
1991
1992 // Native callback.
1993 private int getHoverTapSlop() {
1994 return ViewConfiguration.getHoverTapSlop();
1995 }
1996
1997 // Native callback.
1998 private int getDoubleTapTimeout() {
1999 return ViewConfiguration.getDoubleTapTimeout();
2000 }
2001
2002 // Native callback.
2003 private int getLongPressTimeout() {
2004 return ViewConfiguration.getLongPressTimeout();
2005 }
2006
2007 // Native callback.
2008 private int getPointerLayer() {
Jeff Browna9d131c2012-09-20 16:48:17 -07002009 return mWindowManagerCallbacks.getPointerLayer();
Jeff Brown4532e612012-04-05 14:27:12 -07002010 }
2011
2012 // Native callback.
Andrii Kulianfd8666d2018-10-05 16:58:39 -07002013 private PointerIcon getPointerIcon(int displayId) {
2014 return PointerIcon.getDefaultIcon(getContextForDisplay(displayId));
2015 }
2016
2017 private Context getContextForDisplay(int displayId) {
2018 if (mDisplayContext != null && mDisplayContext.getDisplay().getDisplayId() == displayId) {
2019 return mDisplayContext;
2020 }
2021
2022 if (mContext.getDisplay().getDisplayId() == displayId) {
2023 mDisplayContext = mContext;
2024 return mDisplayContext;
2025 }
2026
2027 // Create and cache context for non-default display.
2028 final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
2029 final Display display = displayManager.getDisplay(displayId);
2030 mDisplayContext = mContext.createDisplayContext(display);
2031 return mDisplayContext;
Jeff Brown4532e612012-04-05 14:27:12 -07002032 }
2033
Jeff Brown6ec6f792012-04-17 16:52:41 -07002034 // Native callback.
Arthur Hungb9b32002018-12-18 17:39:43 +08002035 private int getPointerDisplayId() {
2036 return mWindowManagerCallbacks.getPointerDisplayId();
2037 }
2038
2039 // Native callback.
RoboErikfb290df2013-12-16 11:27:55 -08002040 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07002041 if (!mSystemReady) {
2042 return null;
2043 }
2044
RoboErikfb290df2013-12-16 11:27:55 -08002045 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002046 if (keyboardLayoutDescriptor == null) {
2047 return null;
2048 }
2049
2050 final String[] result = new String[2];
2051 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
2052 @Override
Michael Wright07483422015-10-30 16:20:13 +00002053 public void visitKeyboardLayout(Resources resources,
2054 int keyboardLayoutResId, KeyboardLayout layout) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07002055 try {
Michael Wright07483422015-10-30 16:20:13 +00002056 result[0] = layout.getDescriptor();
Jeff Brown6ec6f792012-04-17 16:52:41 -07002057 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07002058 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07002059 } catch (IOException ex) {
2060 } catch (NotFoundException ex) {
2061 }
2062 }
2063 });
2064 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00002065 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07002066 + keyboardLayoutDescriptor + "'.");
2067 return null;
2068 }
2069 return result;
2070 }
2071
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002072 // Native callback.
2073 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07002074 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
2075 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
2076 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002077 }
2078 return null;
2079 }
2080
Jeff Brown4532e612012-04-05 14:27:12 -07002081 /**
2082 * Callback interface implemented by the Window Manager.
2083 */
Jeff Browna9d131c2012-09-20 16:48:17 -07002084 public interface WindowManagerCallbacks {
Jeff Brown4532e612012-04-05 14:27:12 -07002085 public void notifyConfigurationChanged();
2086
2087 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
2088
Michael Wright3818c922014-09-02 13:59:07 -07002089 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
2090
Robert Carre0a353c2018-08-02 16:38:04 -07002091 public void notifyInputChannelBroken(IBinder token);
Jeff Brown4532e612012-04-05 14:27:12 -07002092
Vishnu Nair19479df2019-10-30 08:03:15 -07002093 /**
2094 * Notifies the window manager about an application that is not responding.
2095 * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
2096 */
2097 long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
2098 String reason);
Jeff Brown4532e612012-04-05 14:27:12 -07002099
Jeff Brown037c33e2014-04-09 00:31:55 -07002100 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002101
Charles Chen4cc014e12019-01-28 16:17:16 +08002102 /**
2103 * Provides an opportunity for the window manager policy to intercept early motion event
2104 * processing when the device is in a non-interactive state since these events are normally
2105 * dropped.
2106 */
2107 int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
2108 int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002109
Robert Carre0a353c2018-08-02 16:38:04 -07002110 public long interceptKeyBeforeDispatching(IBinder token,
Jeff Brown4532e612012-04-05 14:27:12 -07002111 KeyEvent event, int policyFlags);
2112
Robert Carre0a353c2018-08-02 16:38:04 -07002113 public KeyEvent dispatchUnhandledKey(IBinder token,
Jeff Brown4532e612012-04-05 14:27:12 -07002114 KeyEvent event, int policyFlags);
2115
2116 public int getPointerLayer();
Arthur Hungb9b32002018-12-18 17:39:43 +08002117
2118 public int getPointerDisplayId();
chaviwfa2f0042019-03-25 13:48:58 -07002119
2120 /**
2121 * Notifies window manager that a {@link android.view.MotionEvent#ACTION_DOWN} pointer event
2122 * occurred on a window that did not have focus.
2123 *
2124 * @param touchedToken The token for the window that received the input event.
2125 */
2126 void onPointerDownOutsideFocus(IBinder touchedToken);
Vishnu Nair18782162019-10-08 14:57:16 -07002127
2128 /**
2129 * Called when the focused window has changed.
2130 *
2131 * @return true if we want to request a configuration refresh.
2132 */
2133 boolean notifyFocusChanged(IBinder oldToken, IBinder newToken);
2134
2135 /**
2136 * Called by the client to request pointer capture.
2137 *
2138 * @return true if we want to request a configuration refresh.
2139 */
2140 boolean requestPointerCapture(IBinder windowToken, boolean enabled);
Jeff Brown4532e612012-04-05 14:27:12 -07002141 }
2142
2143 /**
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002144 * Callback interface implemented by WiredAccessoryObserver.
2145 */
2146 public interface WiredAccessoryCallbacks {
2147 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002148 public void systemReady();
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002149 }
2150
2151 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002152 * Private handler for the input manager.
2153 */
2154 private final class InputManagerHandler extends Handler {
Jeff Browna9d131c2012-09-20 16:48:17 -07002155 public InputManagerHandler(Looper looper) {
2156 super(looper, null, true /*async*/);
Jeff Browna2910d02012-08-25 12:29:46 -07002157 }
2158
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002159 @Override
2160 public void handleMessage(Message msg) {
2161 switch (msg.what) {
2162 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07002163 deliverInputDevicesChanged((InputDevice[])msg.obj);
2164 break;
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08002165 case MSG_SWITCH_KEYBOARD_LAYOUT:
2166 handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
Jeff Browncf39bdf2012-05-18 14:41:19 -07002167 break;
2168 case MSG_RELOAD_KEYBOARD_LAYOUTS:
2169 reloadKeyboardLayouts();
2170 break;
2171 case MSG_UPDATE_KEYBOARD_LAYOUTS:
2172 updateKeyboardLayouts();
2173 break;
2174 case MSG_RELOAD_DEVICE_ALIASES:
2175 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002176 break;
Yohei Yukawa19a40002018-03-07 19:15:38 -08002177 case MSG_DELIVER_TABLET_MODE_CHANGED:
Michael Wright39e5e942015-08-19 22:52:47 +01002178 SomeArgs args = (SomeArgs) msg.obj;
2179 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
2180 boolean inTabletMode = (boolean) args.arg1;
2181 deliverTabletModeChanged(whenNanos, inTabletMode);
2182 break;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002183 }
2184 }
2185 }
2186
2187 /**
Jeff Brown4532e612012-04-05 14:27:12 -07002188 * Hosting interface for input filters to call back into the input manager.
2189 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07002190 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07002191 private boolean mDisconnected;
2192
2193 public void disconnectLocked() {
2194 mDisconnected = true;
2195 }
2196
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002197 @Override
Jeff Brown0029c662011-03-30 02:25:18 -07002198 public void sendInputEvent(InputEvent event, int policyFlags) {
2199 if (event == null) {
2200 throw new IllegalArgumentException("event must not be null");
2201 }
2202
2203 synchronized (mInputFilterLock) {
2204 if (!mDisconnected) {
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -08002205 nativeInjectInputEvent(mPtr, event, 0, 0,
Jeff Brownac143512012-04-05 18:57:33 -07002206 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07002207 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
2208 }
2209 }
2210 }
2211 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07002212
Michael Wrightc7995232019-02-14 12:33:46 +00002213 /**
2214 * Interface for the system to handle request from InputMonitors.
2215 */
2216 private final class InputMonitorHost extends IInputMonitorHost.Stub {
2217 private final InputChannel mInputChannel;
2218
2219 InputMonitorHost(InputChannel channel) {
2220 mInputChannel = channel;
2221 }
2222
2223 @Override
2224 public void pilferPointers() {
Siarhei Vishniakou67429832019-10-15 16:58:33 -07002225 nativePilferPointers(mPtr, mInputChannel.getToken());
Michael Wrightc7995232019-02-14 12:33:46 +00002226 }
2227
2228 @Override
2229 public void dispose() {
2230 nativeUnregisterInputChannel(mPtr, mInputChannel);
2231 mInputChannel.dispose();
2232 }
2233 }
2234
Jeff Brown9f25b7f2012-04-10 14:30:49 -07002235 private static final class KeyboardLayoutDescriptor {
2236 public String packageName;
2237 public String receiverName;
2238 public String keyboardLayoutName;
2239
2240 public static String format(String packageName,
2241 String receiverName, String keyboardName) {
2242 return packageName + "/" + receiverName + "/" + keyboardName;
2243 }
2244
2245 public static KeyboardLayoutDescriptor parse(String descriptor) {
2246 int pos = descriptor.indexOf('/');
2247 if (pos < 0 || pos + 1 == descriptor.length()) {
2248 return null;
2249 }
2250 int pos2 = descriptor.indexOf('/', pos + 1);
2251 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
2252 return null;
2253 }
2254
2255 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
2256 result.packageName = descriptor.substring(0, pos);
2257 result.receiverName = descriptor.substring(pos + 1, pos2);
2258 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
2259 return result;
2260 }
2261 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002262
Jeff Brown6ec6f792012-04-17 16:52:41 -07002263 private interface KeyboardLayoutVisitor {
Michael Wright07483422015-10-30 16:20:13 +00002264 void visitKeyboardLayout(Resources resources,
2265 int keyboardLayoutResId, KeyboardLayout layout);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002266 }
2267
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002268 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
2269 private final int mPid;
2270 private final IInputDevicesChangedListener mListener;
2271
2272 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
2273 mPid = pid;
2274 mListener = listener;
2275 }
2276
2277 @Override
2278 public void binderDied() {
2279 if (DEBUG) {
2280 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
2281 }
2282 onInputDevicesChangedListenerDied(mPid);
2283 }
2284
2285 public void notifyInputDevicesChanged(int[] info) {
2286 try {
2287 mListener.onInputDevicesChanged(info);
2288 } catch (RemoteException ex) {
2289 Slog.w(TAG, "Failed to notify process "
2290 + mPid + " that input devices changed, assuming it died.", ex);
2291 binderDied();
2292 }
2293 }
2294 }
Jeff Browna47425a2012-04-13 04:09:27 -07002295
Michael Wright39e5e942015-08-19 22:52:47 +01002296 private final class TabletModeChangedListenerRecord implements DeathRecipient {
2297 private final int mPid;
2298 private final ITabletModeChangedListener mListener;
2299
2300 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
2301 mPid = pid;
2302 mListener = listener;
2303 }
2304
2305 @Override
2306 public void binderDied() {
2307 if (DEBUG) {
2308 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
2309 }
2310 onTabletModeChangedListenerDied(mPid);
2311 }
2312
2313 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
2314 try {
2315 mListener.onTabletModeChanged(whenNanos, inTabletMode);
2316 } catch (RemoteException ex) {
2317 Slog.w(TAG, "Failed to notify process " + mPid +
2318 " that tablet mode changed, assuming it died.", ex);
2319 binderDied();
2320 }
2321 }
2322 }
2323
Jeff Browna47425a2012-04-13 04:09:27 -07002324 private final class VibratorToken implements DeathRecipient {
2325 public final int mDeviceId;
2326 public final IBinder mToken;
2327 public final int mTokenValue;
2328
2329 public boolean mVibrating;
2330
2331 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
2332 mDeviceId = deviceId;
2333 mToken = token;
2334 mTokenValue = tokenValue;
2335 }
2336
2337 @Override
2338 public void binderDied() {
2339 if (DEBUG) {
2340 Slog.d(TAG, "Vibrator token died.");
2341 }
2342 onVibratorTokenDied(this);
2343 }
2344 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002345
2346 private final class LocalService extends InputManagerInternal {
2347 @Override
Siarhei Vishniakou2eb0f8f2018-07-06 23:30:12 +01002348 public void setDisplayViewports(List<DisplayViewport> viewports) {
2349 setDisplayViewportsInternal(viewports);
Jeff Brown4ccb8232014-01-16 22:16:42 -08002350 }
Jeff Brownca9bc702014-02-11 14:32:56 -08002351
2352 @Override
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -08002353 public boolean injectInputEvent(InputEvent event, int mode) {
2354 return injectInputEventInternal(event, mode);
Jeff Brownca9bc702014-02-11 14:32:56 -08002355 }
Jeff Brown037c33e2014-04-09 00:31:55 -07002356
2357 @Override
2358 public void setInteractive(boolean interactive) {
2359 nativeSetInteractive(mPtr, interactive);
2360 }
Yohei Yukawab097b822015-12-01 10:43:08 -08002361
2362 @Override
Andrii Kulian112d0562016-03-08 10:44:22 -08002363 public void toggleCapsLock(int deviceId) {
2364 nativeToggleCapsLock(mPtr, deviceId);
2365 }
Adrian Roos99182342016-06-15 15:30:46 -07002366
2367 @Override
2368 public void setPulseGestureEnabled(boolean enabled) {
2369 if (mDoubleTouchGestureEnableFile != null) {
2370 FileWriter writer = null;
2371 try {
2372 writer = new FileWriter(mDoubleTouchGestureEnableFile);
2373 writer.write(enabled ? "1" : "0");
2374 } catch (IOException e) {
2375 Log.wtf(TAG, "Unable to setPulseGestureEnabled", e);
2376 } finally {
2377 IoUtils.closeQuietly(writer);
2378 }
2379 }
2380 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002381 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07002382}