blob: a8f706cdd62973b7ac68bd53d232b77e51695d7f [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;
Arthur Hungc9f383b2019-12-04 17:02:19 +080086import com.android.internal.annotations.GuardedBy;
Arthur Hung39134b22018-08-14 11:58:28 +080087import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
88import com.android.internal.notification.SystemNotificationChannels;
89import com.android.internal.os.SomeArgs;
90import com.android.internal.util.DumpUtils;
Arthur Hung39134b22018-08-14 11:58:28 +080091import 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;
Arthur Hungc9f383b2019-12-04 17:02:19 +0800189 private final Object mAssociationsLock = new Object();
190 @GuardedBy("mAssociationLock")
191 private final Map<String, Integer> mRuntimeAssociations = new HashMap<String, Integer>();
Arthur Hungcf6070e2019-12-04 16:09:42 +0800192
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000193 private static native long nativeInit(InputManagerService service,
Jeff Brown4532e612012-04-05 14:27:12 -0700194 Context context, MessageQueue messageQueue);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000195 private static native void nativeStart(long ptr);
Siarhei Vishniakou2eb0f8f2018-07-06 23:30:12 +0100196 private static native void nativeSetDisplayViewports(long ptr,
Santos Cordonee8931e2017-04-05 10:31:15 -0700197 DisplayViewport[] viewports);
Jeff Brownd728bf52012-09-08 18:05:28 -0700198
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000199 private static native int nativeGetScanCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700200 int deviceId, int sourceMask, int scanCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000201 private static native int nativeGetKeyCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700202 int deviceId, int sourceMask, int keyCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000203 private static native int nativeGetSwitchState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700204 int deviceId, int sourceMask, int sw);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000205 private static native boolean nativeHasKeys(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700206 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
Siarhei Vishniakou2d759f52019-10-11 19:12:08 -0700207 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel);
Michael Wrightc7995232019-02-14 12:33:46 +0000208 private static native void nativeRegisterInputMonitor(long ptr, InputChannel inputChannel,
209 int displayId, boolean isGestureMonitor);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000210 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
Michael Wrightc7995232019-02-14 12:33:46 +0000211 private static native void nativePilferPointers(long ptr, IBinder token);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000212 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
Siarhei Vishniakouc570bfd2019-11-25 13:54:40 -0800213 private static native void nativeSetInTouchMode(long ptr, boolean inTouchMode);
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800214 private static native int nativeInjectInputEvent(long ptr, InputEvent event,
Jeff Brown0029c662011-03-30 02:25:18 -0700215 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
216 int policyFlags);
Andrii Kulian112d0562016-03-08 10:44:22 -0800217 private static native void nativeToggleCapsLock(long ptr, int deviceId);
Arthur Hung39134b22018-08-14 11:58:28 +0800218 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles,
219 int displayId);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000220 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
221 private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
222 private static native void nativeSetFocusedApplication(long ptr,
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800223 int displayId, InputApplicationHandle application);
224 private static native void nativeSetFocusedDisplay(long ptr, int displayId);
Arthur Hungfd9d94d2019-08-28 16:06:07 +0800225 private static native boolean nativeTransferTouchFocus(long ptr,
Svet Ganov17d9d2f2020-01-18 10:12:11 -0800226 IBinder fromChannelToken, IBinder toChannelToken);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000227 private static native void nativeSetPointerSpeed(long ptr, int speed);
228 private static native void nativeSetShowTouches(long ptr, boolean enabled);
Jeff Brown037c33e2014-04-09 00:31:55 -0700229 private static native void nativeSetInteractive(long ptr, boolean interactive);
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800230 private static native void nativeReloadCalibration(long ptr);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000231 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
Jeff Browna47425a2012-04-13 04:09:27 -0700232 int repeat, int token);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000233 private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
234 private static native void nativeReloadKeyboardLayouts(long ptr);
235 private static native void nativeReloadDeviceAliases(long ptr);
236 private static native String nativeDump(long ptr);
237 private static native void nativeMonitor(long ptr);
Siarhei Vishniakoua7f99b52017-03-21 17:39:40 -0700238 private static native boolean nativeIsInputDeviceEnabled(long ptr, int deviceId);
239 private static native void nativeEnableInputDevice(long ptr, int deviceId);
240 private static native void nativeDisableInputDevice(long ptr, int deviceId);
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100241 private static native void nativeSetPointerIconType(long ptr, int iconId);
Jun Mukai19a56012015-11-24 11:25:52 -0800242 private static native void nativeReloadPointerIcons(long ptr);
Jun Mukaid4eaef72015-10-30 15:54:33 -0700243 private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -0800244 private static native void nativeSetPointerCapture(long ptr, boolean detached);
Arthur Hung82bbfc32018-11-29 20:24:51 +0800245 private static native boolean nativeCanDispatchToDisplay(long ptr, int deviceId, int displayId);
Arthur Hungc9f383b2019-12-04 17:02:19 +0800246 private static native void nativeNotifyPortAssociationsChanged(long ptr);
Jeff Brown4532e612012-04-05 14:27:12 -0700247
Jeff Brownac143512012-04-05 18:57:33 -0700248 // Input event injection constants defined in InputDispatcher.h.
249 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
250 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
251 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
252 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
253
254 // Maximum number of milliseconds to wait for input event injection.
255 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
256
Jeff Brown6d0fec22010-07-23 21:28:06 -0700257 // Key states (may be returned by queries about the current state of a
258 // particular key code, scan code or switch).
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700259
Jeff Brown6d0fec22010-07-23 21:28:06 -0700260 /** The key state is unknown or the requested key itself is not supported. */
261 public static final int KEY_STATE_UNKNOWN = -1;
262
263 /** The key is up. /*/
264 public static final int KEY_STATE_UP = 0;
265
266 /** The key is down. */
267 public static final int KEY_STATE_DOWN = 1;
268
269 /** The key is down but is a virtual key press that is being emulated by the system. */
270 public static final int KEY_STATE_VIRTUAL = 2;
271
Jeff Brownc458ce92012-04-30 14:58:40 -0700272 /** Scan code: Mouse / trackball button. */
273 public static final int BTN_MOUSE = 0x110;
274
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700275 // Switch code values must match bionic/libc/kernel/common/linux/input.h
Jeff Brownc458ce92012-04-30 14:58:40 -0700276 /** Switch code: Lid switch. When set, lid is shut. */
277 public static final int SW_LID = 0x00;
278
Michael Wright39e5e942015-08-19 22:52:47 +0100279 /** Switch code: Tablet mode switch.
280 * When set, the device is in tablet mode (i.e. no keyboard is connected).
281 */
282 public static final int SW_TABLET_MODE = 0x01;
283
Jeff Brownc458ce92012-04-30 14:58:40 -0700284 /** Switch code: Keypad slide. When set, keyboard is exposed. */
285 public static final int SW_KEYPAD_SLIDE = 0x0a;
286
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700287 /** Switch code: Headphone. When set, headphone is inserted. */
288 public static final int SW_HEADPHONE_INSERT = 0x02;
289
290 /** Switch code: Microphone. When set, microphone is inserted. */
291 public static final int SW_MICROPHONE_INSERT = 0x04;
292
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500293 /** Switch code: Line out. When set, Line out (hi-Z) is inserted. */
294 public static final int SW_LINEOUT_INSERT = 0x06;
295
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700296 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */
297 public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
298
Michael Wright3818c922014-09-02 13:59:07 -0700299 /** Switch code: Camera lens cover. When set the lens is covered. */
300 public static final int SW_CAMERA_LENS_COVER = 0x09;
301
Dmitry Shmidtd6cf4d92019-09-20 15:50:36 -0700302 /** Switch code: Microphone. When set it is off. */
303 public static final int SW_MUTE_DEVICE = 0x0e;
304
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700305 public static final int SW_LID_BIT = 1 << SW_LID;
Michael Wright39e5e942015-08-19 22:52:47 +0100306 public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700307 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
308 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
309 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500310 public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700311 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
312 public static final int SW_JACK_BITS =
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500313 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
Michael Wright3818c922014-09-02 13:59:07 -0700314 public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
Dmitry Shmidtd6cf4d92019-09-20 15:50:36 -0700315 public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700316
317 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
318 final boolean mUseDevInputEventForAudioJack;
319
Jeff Brown4ccb8232014-01-16 22:16:42 -0800320 public InputManagerService(Context context) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700321 this.mContext = context;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800322 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
Jeff Brown05dc66a2011-03-02 14:41:58 -0800323
Winson Chung626240f2019-12-20 15:04:27 -0800324 mStaticAssociations = loadStaticInputPortAssociations();
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700325 mUseDevInputEventForAudioJack =
326 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
327 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
328 + mUseDevInputEventForAudioJack);
Jeff Brown4532e612012-04-05 14:27:12 -0700329 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown4ccb8232014-01-16 22:16:42 -0800330
Adrian Roos99182342016-06-15 15:30:46 -0700331 String doubleTouchGestureEnablePath = context.getResources().getString(
332 R.string.config_doubleTouchGestureEnableFile);
333 mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
334 new File(doubleTouchGestureEnablePath);
335
Jeff Brown4ccb8232014-01-16 22:16:42 -0800336 LocalServices.addService(InputManagerInternal.class, new LocalService());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700337 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700338
Jeff Browna9d131c2012-09-20 16:48:17 -0700339 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
340 mWindowManagerCallbacks = callbacks;
341 }
342
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700343 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
344 mWiredAccessoryCallbacks = callbacks;
345 }
346
Jeff Brown46b9ac02010-04-22 18:58:52 -0700347 public void start() {
348 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700349 nativeStart(mPtr);
350
351 // Add ourself to the Watchdog monitors.
352 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700353
354 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700355 registerShowTouchesSettingObserver();
Jun Mukai19a56012015-11-24 11:25:52 -0800356 registerAccessibilityLargePointerSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700357
Jeff Brownd4935962012-09-25 13:27:20 -0700358 mContext.registerReceiver(new BroadcastReceiver() {
359 @Override
360 public void onReceive(Context context, Intent intent) {
361 updatePointerSpeedFromSettings();
362 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800363 updateAccessibilityLargePointerFromSettings();
Jeff Brownd4935962012-09-25 13:27:20 -0700364 }
365 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
366
Jeff Brown1a84fd12011-06-02 01:26:32 -0700367 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700368 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800369 updateAccessibilityLargePointerFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700370 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700371
Siarhei Vishniakouc8631852018-07-06 11:33:56 +0100372 // TODO(BT) Pass in parameter for bluetooth system
Svetoslav Ganova0027152013-06-25 14:59:53 -0700373 public void systemRunning() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700374 if (DEBUG) {
375 Slog.d(TAG, "System ready.");
376 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700377 mNotificationManager = (NotificationManager)mContext.getSystemService(
378 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700379 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700380
381 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
382 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
383 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Jeff Brown69b07162013-11-07 00:30:16 -0800384 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700385 filter.addDataScheme("package");
386 mContext.registerReceiver(new BroadcastReceiver() {
387 @Override
388 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700389 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700390 }
391 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700392
393 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
394 mContext.registerReceiver(new BroadcastReceiver() {
395 @Override
396 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700397 reloadDeviceAliases();
398 }
399 }, filter, null, mHandler);
400
Jeff Browncf39bdf2012-05-18 14:41:19 -0700401 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
402 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700403
404 if (mWiredAccessoryCallbacks != null) {
405 mWiredAccessoryCallbacks.systemReady();
406 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700407 }
408
409 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700410 if (DEBUG) {
411 Slog.d(TAG, "Reloading keyboard layouts.");
412 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700413 nativeReloadKeyboardLayouts(mPtr);
414 }
415
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700416 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700417 if (DEBUG) {
418 Slog.d(TAG, "Reloading device names.");
419 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700420 nativeReloadDeviceAliases(mPtr);
421 }
422
Siarhei Vishniakou2eb0f8f2018-07-06 23:30:12 +0100423 private void setDisplayViewportsInternal(List<DisplayViewport> viewports) {
424 nativeSetDisplayViewports(mPtr, viewports.toArray(new DisplayViewport[0]));
Jeff Brown46b9ac02010-04-22 18:58:52 -0700425 }
Jeff Brownac143512012-04-05 18:57:33 -0700426
Jeff Brown6d0fec22010-07-23 21:28:06 -0700427 /**
428 * Gets the current state of a key or button by key code.
429 * @param deviceId The input device id, or -1 to consult all devices.
430 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
431 * consider all input sources. An input device is consulted if at least one of its
432 * non-class input source bits matches the specified source mask.
433 * @param keyCode The key code to check.
434 * @return The key state.
435 */
436 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700437 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700438 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700439
Jeff Brown6d0fec22010-07-23 21:28:06 -0700440 /**
441 * Gets the current state of a key or button by scan code.
442 * @param deviceId The input device id, or -1 to consult all devices.
443 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
444 * consider all input sources. An input device is consulted if at least one of its
445 * non-class input source bits matches the specified source mask.
446 * @param scanCode The scan code to check.
447 * @return The key state.
448 */
449 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700450 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700451 }
RoboErikfb290df2013-12-16 11:27:55 -0800452
Jeff Brown6d0fec22010-07-23 21:28:06 -0700453 /**
454 * Gets the current state of a switch by switch code.
455 * @param deviceId The input device id, or -1 to consult all devices.
456 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
457 * consider all input sources. An input device is consulted if at least one of its
458 * non-class input source bits matches the specified source mask.
459 * @param switchCode The switch code to check.
460 * @return The switch state.
461 */
462 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700463 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700464 }
465
Jeff Brown6d0fec22010-07-23 21:28:06 -0700466 /**
467 * Determines whether the specified key codes are supported by a particular device.
468 * @param deviceId The input device id, or -1 to consult all devices.
469 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
470 * consider all input sources. An input device is consulted if at least one of its
471 * non-class input source bits matches the specified source mask.
472 * @param keyCodes The array of key codes to check.
473 * @param keyExists An array at least as large as keyCodes whose entries will be set
474 * to true or false based on the presence or absence of support for the corresponding
475 * key codes.
476 * @return True if the lookup was successful, false otherwise.
477 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700478 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700479 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700480 if (keyCodes == null) {
481 throw new IllegalArgumentException("keyCodes must not be null.");
482 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700483 if (keyExists == null || keyExists.length < keyCodes.length) {
484 throw new IllegalArgumentException("keyExists must not be null and must be at "
485 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700486 }
RoboErikfb290df2013-12-16 11:27:55 -0800487
Jeff Brown4532e612012-04-05 14:27:12 -0700488 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700489 }
RoboErikfb290df2013-12-16 11:27:55 -0800490
Jeff Browna41ca772010-08-11 14:46:32 -0700491 /**
492 * Creates an input channel that will receive all input from the input dispatcher.
493 * @param inputChannelName The input channel name.
Arthur Hungbe5ce212018-09-13 18:41:56 +0800494 * @param displayId Target display id.
Jeff Browna41ca772010-08-11 14:46:32 -0700495 * @return The input channel.
496 */
Arthur Hungbe5ce212018-09-13 18:41:56 +0800497 public InputChannel monitorInput(String inputChannelName, int displayId) {
Jeff Browna41ca772010-08-11 14:46:32 -0700498 if (inputChannelName == null) {
499 throw new IllegalArgumentException("inputChannelName must not be null.");
500 }
RoboErikfb290df2013-12-16 11:27:55 -0800501
Arthur Hungbe5ce212018-09-13 18:41:56 +0800502 if (displayId < Display.DEFAULT_DISPLAY) {
503 throw new IllegalArgumentException("displayId must >= 0.");
504 }
505
Jeff Browna41ca772010-08-11 14:46:32 -0700506 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Michael Wrightc7995232019-02-14 12:33:46 +0000507 nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId, false /*isGestureMonitor*/);
Jeff Browna41ca772010-08-11 14:46:32 -0700508 inputChannels[0].dispose(); // don't need to retain the Java object reference
509 return inputChannels[1];
510 }
511
512 /**
Michael Wrightc7995232019-02-14 12:33:46 +0000513 * Creates an input monitor that will receive pointer events for the purposes of system-wide
514 * gesture interpretation.
515 *
516 * @param inputChannelName The input channel name.
517 * @param displayId Target display id.
518 * @return The input channel.
519 */
520 @Override // Binder call
521 public InputMonitor monitorGestureInput(String inputChannelName, int displayId) {
522 if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT,
523 "monitorInputRegion()")) {
524 throw new SecurityException("Requires MONITOR_INPUT permission");
525 }
526
527 Objects.requireNonNull(inputChannelName, "inputChannelName must not be null.");
528
529 if (displayId < Display.DEFAULT_DISPLAY) {
530 throw new IllegalArgumentException("displayId must >= 0.");
531 }
532
Michael Wrightad3a6bf2019-04-04 14:17:09 +0100533 final long ident = Binder.clearCallingIdentity();
534 try {
535 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
536 InputMonitorHost host = new InputMonitorHost(inputChannels[0]);
Michael Wrightad3a6bf2019-04-04 14:17:09 +0100537 nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId,
538 true /*isGestureMonitor*/);
Siarhei Vishniakou7480ae22019-10-15 15:18:55 -0700539 return new InputMonitor(inputChannels[1], host);
Michael Wrightad3a6bf2019-04-04 14:17:09 +0100540 } finally {
541 Binder.restoreCallingIdentity(ident);
542 }
Michael Wrightc7995232019-02-14 12:33:46 +0000543 }
544
545 /**
Vishnu Nair18782162019-10-08 14:57:16 -0700546 * Registers an input channel so that it can be used as an input event target. The channel is
547 * registered with a generated token.
548 *
Jeff Browna41ca772010-08-11 14:46:32 -0700549 * @param inputChannel The input channel to register.
550 */
Vishnu Nair18782162019-10-08 14:57:16 -0700551 public void registerInputChannel(InputChannel inputChannel) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700552 if (inputChannel == null) {
553 throw new IllegalArgumentException("inputChannel must not be null.");
554 }
Robert Carre0a353c2018-08-02 16:38:04 -0700555
Siarhei Vishniakou2d759f52019-10-11 19:12:08 -0700556 nativeRegisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700557 }
RoboErikfb290df2013-12-16 11:27:55 -0800558
Jeff Browna41ca772010-08-11 14:46:32 -0700559 /**
560 * Unregisters an input channel.
561 * @param inputChannel The input channel to unregister.
562 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700563 public void unregisterInputChannel(InputChannel inputChannel) {
564 if (inputChannel == null) {
565 throw new IllegalArgumentException("inputChannel must not be null.");
566 }
RoboErikfb290df2013-12-16 11:27:55 -0800567
Jeff Brown4532e612012-04-05 14:27:12 -0700568 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700569 }
Jeff Brown0029c662011-03-30 02:25:18 -0700570
571 /**
572 * Sets an input filter that will receive all input events before they are dispatched.
573 * The input filter may then reinterpret input events or inject new ones.
574 *
575 * To ensure consistency, the input dispatcher automatically drops all events
576 * in progress whenever an input filter is installed or uninstalled. After an input
577 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
578 * Any events it attempts to send after it has been uninstalled will be dropped.
579 *
580 * @param filter The input filter, or null to remove the current filter.
581 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700582 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700583 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700584 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700585 if (oldFilter == filter) {
586 return; // nothing to do
587 }
588
589 if (oldFilter != null) {
590 mInputFilter = null;
591 mInputFilterHost.disconnectLocked();
592 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700593 try {
594 oldFilter.uninstall();
595 } catch (RemoteException re) {
596 /* ignore */
597 }
Jeff Brown0029c662011-03-30 02:25:18 -0700598 }
599
600 if (filter != null) {
601 mInputFilter = filter;
602 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700603 try {
604 filter.install(mInputFilterHost);
605 } catch (RemoteException re) {
606 /* ignore */
607 }
Jeff Brown0029c662011-03-30 02:25:18 -0700608 }
609
Jeff Brown4532e612012-04-05 14:27:12 -0700610 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700611 }
612 }
613
Siarhei Vishniakouc570bfd2019-11-25 13:54:40 -0800614 /**
615 * Set the state of the touch mode.
616 *
617 * WindowManager remains the source of truth of the touch mode state.
618 * However, we need to keep a copy of this state in input.
619 *
620 * The apps determine the touch mode state. Therefore, a single app will
621 * affect the global state. That state change needs to be propagated to
622 * other apps, when they become focused.
623 *
624 * When input dispatches focus to the apps, the touch mode state
625 * will be sent together with the focus change.
626 *
627 * @param inTouchMode true if the device is in touch mode.
628 */
629 public void setInTouchMode(boolean inTouchMode) {
630 nativeSetInTouchMode(mPtr, inTouchMode);
631 }
632
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700633 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700634 public boolean injectInputEvent(InputEvent event, int mode) {
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800635 return injectInputEventInternal(event, mode);
Jeff Brownca9bc702014-02-11 14:32:56 -0800636 }
637
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800638 private boolean injectInputEventInternal(InputEvent event, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700639 if (event == null) {
640 throw new IllegalArgumentException("event must not be null");
641 }
Jeff Brownac143512012-04-05 18:57:33 -0700642 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
643 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
644 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
645 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700646 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700647
Jeff Brownac143512012-04-05 18:57:33 -0700648 final int pid = Binder.getCallingPid();
649 final int uid = Binder.getCallingUid();
650 final long ident = Binder.clearCallingIdentity();
651 final int result;
652 try {
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800653 result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
Jeff Brownac143512012-04-05 18:57:33 -0700654 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
655 } finally {
656 Binder.restoreCallingIdentity(ident);
657 }
658 switch (result) {
659 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
660 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
661 throw new SecurityException(
662 "Injecting to another application requires INJECT_EVENTS permission");
663 case INPUT_EVENT_INJECTION_SUCCEEDED:
664 return true;
665 case INPUT_EVENT_INJECTION_TIMED_OUT:
666 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
667 return false;
668 case INPUT_EVENT_INJECTION_FAILED:
669 default:
670 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
671 return false;
672 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700673 }
Jeff Brown0029c662011-03-30 02:25:18 -0700674
Jeff Brown8d608662010-08-30 03:02:23 -0700675 /**
676 * Gets information about the input device with the specified id.
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700677 * @param deviceId The device id.
Jeff Brown8d608662010-08-30 03:02:23 -0700678 * @return The input device or null if not found.
679 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700680 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700681 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700682 synchronized (mInputDevicesLock) {
683 final int count = mInputDevices.length;
684 for (int i = 0; i < count; i++) {
685 final InputDevice inputDevice = mInputDevices[i];
686 if (inputDevice.getId() == deviceId) {
687 return inputDevice;
688 }
689 }
690 }
691 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700692 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700693
Siarhei Vishniakoua7f99b52017-03-21 17:39:40 -0700694 // Binder call
695 @Override
696 public boolean isInputDeviceEnabled(int deviceId) {
697 return nativeIsInputDeviceEnabled(mPtr, deviceId);
698 }
699
700 // Binder call
701 @Override
702 public void enableInputDevice(int deviceId) {
703 if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
704 "enableInputDevice()")) {
705 throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
706 }
707 nativeEnableInputDevice(mPtr, deviceId);
708 }
709
710 // Binder call
711 @Override
712 public void disableInputDevice(int deviceId) {
713 if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
714 "disableInputDevice()")) {
715 throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
716 }
717 nativeDisableInputDevice(mPtr, deviceId);
718 }
719
Jeff Brown8d608662010-08-30 03:02:23 -0700720 /**
721 * Gets the ids of all input devices in the system.
722 * @return The input device ids.
723 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700724 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700725 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700726 synchronized (mInputDevicesLock) {
727 final int count = mInputDevices.length;
728 int[] ids = new int[count];
729 for (int i = 0; i < count; i++) {
730 ids[i] = mInputDevices[i].getId();
731 }
732 return ids;
733 }
734 }
735
Jeff Browndaa37532012-05-01 15:54:03 -0700736 /**
737 * Gets all input devices in the system.
738 * @return The array of input devices.
739 */
740 public InputDevice[] getInputDevices() {
741 synchronized (mInputDevicesLock) {
742 return mInputDevices;
743 }
744 }
745
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700746 @Override // Binder call
747 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
748 if (listener == null) {
749 throw new IllegalArgumentException("listener must not be null");
750 }
751
752 synchronized (mInputDevicesLock) {
753 int callingPid = Binder.getCallingPid();
754 if (mInputDevicesChangedListeners.get(callingPid) != null) {
755 throw new SecurityException("The calling process has already "
756 + "registered an InputDevicesChangedListener.");
757 }
758
759 InputDevicesChangedListenerRecord record =
760 new InputDevicesChangedListenerRecord(callingPid, listener);
761 try {
762 IBinder binder = listener.asBinder();
763 binder.linkToDeath(record, 0);
764 } catch (RemoteException ex) {
765 // give up
766 throw new RuntimeException(ex);
767 }
768
769 mInputDevicesChangedListeners.put(callingPid, record);
770 }
771 }
772
773 private void onInputDevicesChangedListenerDied(int pid) {
774 synchronized (mInputDevicesLock) {
775 mInputDevicesChangedListeners.remove(pid);
776 }
777 }
778
779 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700780 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
781 // Scan for changes.
782 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700783 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700784 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700785 final int numListeners;
786 final int[] deviceIdAndGeneration;
787 synchronized (mInputDevicesLock) {
788 if (!mInputDevicesChangedPending) {
789 return;
790 }
791 mInputDevicesChangedPending = false;
792
793 numListeners = mInputDevicesChangedListeners.size();
794 for (int i = 0; i < numListeners; i++) {
795 mTempInputDevicesChangedListenersToNotify.add(
796 mInputDevicesChangedListeners.valueAt(i));
797 }
798
799 final int numDevices = mInputDevices.length;
800 deviceIdAndGeneration = new int[numDevices * 2];
801 for (int i = 0; i < numDevices; i++) {
802 final InputDevice inputDevice = mInputDevices[i];
803 deviceIdAndGeneration[i * 2] = inputDevice.getId();
804 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700805
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700806 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700807 if (!containsInputDeviceWithDescriptor(oldInputDevices,
808 inputDevice.getDescriptor())) {
809 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
810 } else {
811 mTempFullKeyboards.add(inputDevice);
812 }
813 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700814 }
815 }
816
Jeff Browncf39bdf2012-05-18 14:41:19 -0700817 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700818 for (int i = 0; i < numListeners; i++) {
819 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
820 deviceIdAndGeneration);
821 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700822 mTempInputDevicesChangedListenersToNotify.clear();
823
824 // Check for missing keyboard layouts.
Michael Wright07483422015-10-30 16:20:13 +0000825 List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
826 final int numFullKeyboards = mTempFullKeyboards.size();
827 synchronized (mDataStore) {
828 for (int i = 0; i < numFullKeyboards; i++) {
829 final InputDevice inputDevice = mTempFullKeyboards.get(i);
830 String layout =
831 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
832 if (layout == null) {
833 layout = getDefaultKeyboardLayout(inputDevice);
834 if (layout != null) {
835 setCurrentKeyboardLayoutForInputDevice(
836 inputDevice.getIdentifier(), layout);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700837 }
838 }
Michael Wright07483422015-10-30 16:20:13 +0000839 if (layout == null) {
840 keyboardsMissingLayout.add(inputDevice);
841 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700842 }
Michael Wright07483422015-10-30 16:20:13 +0000843 }
844
845 if (mNotificationManager != null) {
846 if (!keyboardsMissingLayout.isEmpty()) {
847 if (keyboardsMissingLayout.size() > 1) {
848 // We have more than one keyboard missing a layout, so drop the
849 // user at the generic input methods page so they can pick which
850 // one to set.
851 showMissingKeyboardLayoutNotification(null);
852 } else {
853 showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
Jeff Browncf39bdf2012-05-18 14:41:19 -0700854 }
855 } else if (mKeyboardLayoutNotificationShown) {
856 hideMissingKeyboardLayoutNotification();
857 }
858 }
859 mTempFullKeyboards.clear();
860 }
861
Michael Wright07483422015-10-30 16:20:13 +0000862 private String getDefaultKeyboardLayout(final InputDevice d) {
863 final Locale systemLocale = mContext.getResources().getConfiguration().locale;
864 // If our locale doesn't have a language for some reason, then we don't really have a
865 // reasonable default.
866 if (TextUtils.isEmpty(systemLocale.getLanguage())) {
867 return null;
868 }
869 final List<KeyboardLayout> layouts = new ArrayList<>();
870 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
871 @Override
872 public void visitKeyboardLayout(Resources resources,
873 int keyboardLayoutResId, KeyboardLayout layout) {
874 // Only select a default when we know the layout is appropriate. For now, this
875 // means its a custom layout for a specific keyboard.
876 if (layout.getVendorId() != d.getVendorId()
877 || layout.getProductId() != d.getProductId()) {
878 return;
879 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800880 final LocaleList locales = layout.getLocales();
881 final int numLocales = locales.size();
882 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
883 if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
Michael Wright07483422015-10-30 16:20:13 +0000884 layouts.add(layout);
885 break;
886 }
887 }
888 }
889 });
890
891 if (layouts.isEmpty()) {
892 return null;
893 }
894
895 // First sort so that ones with higher priority are listed at the top
896 Collections.sort(layouts);
897 // Next we want to try to find an exact match of language, country and variant.
898 final int N = layouts.size();
899 for (int i = 0; i < N; i++) {
900 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800901 final LocaleList locales = layout.getLocales();
902 final int numLocales = locales.size();
903 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
904 final Locale locale = locales.get(localeIndex);
905 if (locale.getCountry().equals(systemLocale.getCountry())
906 && locale.getVariant().equals(systemLocale.getVariant())) {
Michael Wright07483422015-10-30 16:20:13 +0000907 return layout.getDescriptor();
908 }
909 }
910 }
911 // Then try an exact match of language and country
912 for (int i = 0; i < N; i++) {
913 KeyboardLayout layout = layouts.get(i);
Yohei Yukawa5660fad2016-01-27 22:04:09 -0800914 final LocaleList locales = layout.getLocales();
915 final int numLocales = locales.size();
916 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
917 final Locale locale = locales.get(localeIndex);
918 if (locale.getCountry().equals(systemLocale.getCountry())) {
Michael Wright07483422015-10-30 16:20:13 +0000919 return layout.getDescriptor();
920 }
921 }
922 }
923
924 // Give up and just use the highest priority layout with matching language
925 return layouts.get(0).getDescriptor();
926 }
927
928 private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
929 // Different languages are never compatible
930 if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
931 return false;
932 }
933 // If both the system and the keyboard layout have a country specifier, they must be equal.
934 if (!TextUtils.isEmpty(systemLocale.getCountry())
935 && !TextUtils.isEmpty(keyboardLocale.getCountry())
936 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
937 return false;
938 }
939 return true;
940 }
941
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800942 @Override // Binder call & native callback
Jason Gerecked5220742014-03-10 09:47:59 -0700943 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
944 int surfaceRotation) {
Jason Gerecked6396d62014-01-27 18:30:37 -0800945 if (inputDeviceDescriptor == null) {
946 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
947 }
948
949 synchronized (mDataStore) {
Jason Gerecked5220742014-03-10 09:47:59 -0700950 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
Jason Gerecked6396d62014-01-27 18:30:37 -0800951 }
952 }
953
954 @Override // Binder call
Jason Gerecked5220742014-03-10 09:47:59 -0700955 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
Jason Gerecked6396d62014-01-27 18:30:37 -0800956 TouchCalibration calibration) {
957 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
958 "setTouchCalibrationForInputDevice()")) {
959 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
960 }
961 if (inputDeviceDescriptor == null) {
962 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
963 }
964 if (calibration == null) {
965 throw new IllegalArgumentException("calibration must not be null");
966 }
Jason Gerecked5220742014-03-10 09:47:59 -0700967 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
968 throw new IllegalArgumentException("surfaceRotation value out of bounds");
969 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800970
971 synchronized (mDataStore) {
972 try {
Jason Gerecked5220742014-03-10 09:47:59 -0700973 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
974 calibration)) {
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800975 nativeReloadCalibration(mPtr);
976 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800977 } finally {
978 mDataStore.saveIfNeeded();
979 }
980 }
981 }
982
Michael Wright39e5e942015-08-19 22:52:47 +0100983 @Override // Binder call
Michael Wright9209c9c2015-09-03 17:57:01 +0100984 public int isInTabletMode() {
985 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
986 "isInTabletMode()")) {
987 throw new SecurityException("Requires TABLET_MODE permission");
988 }
989 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
990 }
991
992 @Override // Binder call
Dmitry Shmidtd6cf4d92019-09-20 15:50:36 -0700993 public int isMicMuted() {
994 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MUTE_DEVICE);
995 }
996
997 @Override // Binder call
Michael Wright39e5e942015-08-19 22:52:47 +0100998 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
Michael Wright9209c9c2015-09-03 17:57:01 +0100999 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
Michael Wright39e5e942015-08-19 22:52:47 +01001000 "registerTabletModeChangedListener()")) {
1001 throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
1002 }
1003 if (listener == null) {
1004 throw new IllegalArgumentException("listener must not be null");
1005 }
1006
1007 synchronized (mTabletModeLock) {
1008 final int callingPid = Binder.getCallingPid();
1009 if (mTabletModeChangedListeners.get(callingPid) != null) {
1010 throw new IllegalStateException("The calling process has already registered "
1011 + "a TabletModeChangedListener.");
1012 }
1013 TabletModeChangedListenerRecord record =
1014 new TabletModeChangedListenerRecord(callingPid, listener);
1015 try {
1016 IBinder binder = listener.asBinder();
1017 binder.linkToDeath(record, 0);
1018 } catch (RemoteException ex) {
1019 throw new RuntimeException(ex);
1020 }
1021 mTabletModeChangedListeners.put(callingPid, record);
1022 }
1023 }
1024
1025 private void onTabletModeChangedListenerDied(int pid) {
1026 synchronized (mTabletModeLock) {
1027 mTabletModeChangedListeners.remove(pid);
1028 }
1029 }
1030
1031 // Must be called on handler
1032 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
1033 mTempTabletModeChangedListenersToNotify.clear();
1034 final int numListeners;
1035 synchronized (mTabletModeLock) {
1036 numListeners = mTabletModeChangedListeners.size();
1037 for (int i = 0; i < numListeners; i++) {
1038 mTempTabletModeChangedListenersToNotify.add(
1039 mTabletModeChangedListeners.valueAt(i));
1040 }
1041 }
1042 for (int i = 0; i < numListeners; i++) {
1043 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
1044 whenNanos, inTabletMode);
1045 }
1046 }
1047
Jeff Browncf39bdf2012-05-18 14:41:19 -07001048 // Must be called on handler.
Michael Wrightc93fbd12014-09-22 20:07:59 -07001049 private void showMissingKeyboardLayoutNotification(InputDevice device) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001050 if (!mKeyboardLayoutNotificationShown) {
Yohei Yukawa2bff4902016-03-30 01:06:37 -07001051 final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
Michael Wrightc93fbd12014-09-22 20:07:59 -07001052 if (device != null) {
1053 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001054 }
Michael Wrightc93fbd12014-09-22 20:07:59 -07001055 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1056 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
1057 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
1058 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
1059 intent, 0, null, UserHandle.CURRENT);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001060
1061 Resources r = mContext.getResources();
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001062 Notification notification =
1063 new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
1064 .setContentTitle(r.getString(
1065 R.string.select_keyboard_layout_notification_title))
1066 .setContentText(r.getString(
1067 R.string.select_keyboard_layout_notification_message))
1068 .setContentIntent(keyboardLayoutIntent)
1069 .setSmallIcon(R.drawable.ic_settings_language)
1070 .setColor(mContext.getColor(
1071 com.android.internal.R.color.system_notification_accent_color))
1072 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001073 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04001074 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001075 notification, UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001076 mKeyboardLayoutNotificationShown = true;
1077 }
1078 }
1079
1080 // Must be called on handler.
1081 private void hideMissingKeyboardLayoutNotification() {
1082 if (mKeyboardLayoutNotificationShown) {
1083 mKeyboardLayoutNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001084 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04001085 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -07001086 UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001087 }
1088 }
1089
1090 // Must be called on handler.
1091 private void updateKeyboardLayouts() {
1092 // Scan all input devices state for keyboard layouts that have been uninstalled.
1093 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
1094 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1095 @Override
Michael Wright07483422015-10-30 16:20:13 +00001096 public void visitKeyboardLayout(Resources resources,
1097 int keyboardLayoutResId, KeyboardLayout layout) {
1098 availableKeyboardLayouts.add(layout.getDescriptor());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001099 }
1100 });
1101 synchronized (mDataStore) {
1102 try {
1103 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
1104 } finally {
1105 mDataStore.saveIfNeeded();
1106 }
1107 }
1108
1109 // Reload keyboard layouts.
1110 reloadKeyboardLayouts();
1111 }
1112
Jeff Browncf39bdf2012-05-18 14:41:19 -07001113 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
1114 String descriptor) {
1115 final int numDevices = inputDevices.length;
1116 for (int i = 0; i < numDevices; i++) {
1117 final InputDevice inputDevice = inputDevices[i];
1118 if (inputDevice.getDescriptor().equals(descriptor)) {
1119 return true;
1120 }
1121 }
1122 return false;
Jeff Brown8d608662010-08-30 03:02:23 -07001123 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001124
1125 @Override // Binder call
1126 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001127 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
1128 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1129 @Override
Michael Wright07483422015-10-30 16:20:13 +00001130 public void visitKeyboardLayout(Resources resources,
1131 int keyboardLayoutResId, KeyboardLayout layout) {
1132 list.add(layout);
1133 }
1134 });
1135 return list.toArray(new KeyboardLayout[list.size()]);
1136 }
1137
Michael Wrightb0e804a2016-01-04 16:48:53 -05001138 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001139 public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1140 final InputDeviceIdentifier identifier) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001141 final String[] enabledLayoutDescriptors =
1142 getEnabledKeyboardLayoutsForInputDevice(identifier);
1143 final ArrayList<KeyboardLayout> enabledLayouts =
1144 new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length);
1145 final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>();
Michael Wright07483422015-10-30 16:20:13 +00001146 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1147 boolean mHasSeenDeviceSpecificLayout;
1148
1149 @Override
1150 public void visitKeyboardLayout(Resources resources,
1151 int keyboardLayoutResId, KeyboardLayout layout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001152 // First check if it's enabled. If the keyboard layout is enabled then we always
1153 // want to return it as a possible layout for the device.
1154 for (String s : enabledLayoutDescriptors) {
1155 if (s != null && s.equals(layout.getDescriptor())) {
1156 enabledLayouts.add(layout);
1157 return;
1158 }
1159 }
1160 // Next find any potential layouts that aren't yet enabled for the device. For
1161 // devices that have special layouts we assume there's a reason that the generic
1162 // layouts don't work for them so we don't want to return them since it's likely
1163 // to result in a poor user experience.
Michael Wright07483422015-10-30 16:20:13 +00001164 if (layout.getVendorId() == identifier.getVendorId()
1165 && layout.getProductId() == identifier.getProductId()) {
1166 if (!mHasSeenDeviceSpecificLayout) {
1167 mHasSeenDeviceSpecificLayout = true;
Michael Wrightb0e804a2016-01-04 16:48:53 -05001168 potentialLayouts.clear();
Michael Wright07483422015-10-30 16:20:13 +00001169 }
Michael Wrightb0e804a2016-01-04 16:48:53 -05001170 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001171 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
1172 && !mHasSeenDeviceSpecificLayout) {
Michael Wrightb0e804a2016-01-04 16:48:53 -05001173 potentialLayouts.add(layout);
Michael Wright07483422015-10-30 16:20:13 +00001174 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001175 }
1176 });
Michael Wrightb0e804a2016-01-04 16:48:53 -05001177 final int enabledLayoutSize = enabledLayouts.size();
1178 final int potentialLayoutSize = potentialLayouts.size();
1179 KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
1180 enabledLayouts.toArray(layouts);
1181 for (int i = 0; i < potentialLayoutSize; i++) {
1182 layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
1183 }
1184 return layouts;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001185 }
1186
1187 @Override // Binder call
1188 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
1189 if (keyboardLayoutDescriptor == null) {
1190 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1191 }
1192
Jeff Brown6ec6f792012-04-17 16:52:41 -07001193 final KeyboardLayout[] result = new KeyboardLayout[1];
1194 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1195 @Override
Michael Wright07483422015-10-30 16:20:13 +00001196 public void visitKeyboardLayout(Resources resources,
1197 int keyboardLayoutResId, KeyboardLayout layout) {
1198 result[0] = layout;
Jeff Brown6ec6f792012-04-17 16:52:41 -07001199 }
1200 });
1201 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00001202 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07001203 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001204 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001205 return result[0];
1206 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001207
Jeff Brown6ec6f792012-04-17 16:52:41 -07001208 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001209 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001210 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
1211 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001212 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
1213 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
Michael Wright8ebac232014-09-18 18:29:49 -07001214 final ActivityInfo activityInfo = resolveInfo.activityInfo;
1215 final int priority = resolveInfo.priority;
1216 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001217 }
1218 }
1219
Jeff Brown6ec6f792012-04-17 16:52:41 -07001220 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
1221 KeyboardLayoutVisitor visitor) {
1222 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
1223 if (d != null) {
1224 final PackageManager pm = mContext.getPackageManager();
1225 try {
1226 ActivityInfo receiver = pm.getReceiverInfo(
1227 new ComponentName(d.packageName, d.receiverName),
Jeff Sharkey5217cac2015-12-20 15:34:01 -07001228 PackageManager.GET_META_DATA
Jeff Sharkey8a372a02016-03-16 16:25:45 -06001229 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1230 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Michael Wright8ebac232014-09-18 18:29:49 -07001231 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001232 } catch (NameNotFoundException ex) {
1233 }
1234 }
1235 }
1236
1237 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
Michael Wright8ebac232014-09-18 18:29:49 -07001238 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001239 Bundle metaData = receiver.metaData;
1240 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001241 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001242 }
1243
1244 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1245 if (configResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001246 Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001247 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001248 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001249 }
1250
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001251 CharSequence receiverLabel = receiver.loadLabel(pm);
1252 String collection = receiverLabel != null ? receiverLabel.toString() : "";
Michael Wright8ebac232014-09-18 18:29:49 -07001253 int priority;
1254 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1255 priority = requestedPriority;
1256 } else {
1257 priority = 0;
1258 }
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001259
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001260 try {
1261 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1262 XmlResourceParser parser = resources.getXml(configResId);
1263 try {
1264 XmlUtils.beginDocument(parser, "keyboard-layouts");
1265
1266 for (;;) {
1267 XmlUtils.nextElement(parser);
1268 String element = parser.getName();
1269 if (element == null) {
1270 break;
1271 }
1272 if (element.equals("keyboard-layout")) {
1273 TypedArray a = resources.obtainAttributes(
1274 parser, com.android.internal.R.styleable.KeyboardLayout);
1275 try {
1276 String name = a.getString(
1277 com.android.internal.R.styleable.KeyboardLayout_name);
1278 String label = a.getString(
1279 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -07001280 int keyboardLayoutResId = a.getResourceId(
1281 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1282 0);
Michael Wright07483422015-10-30 16:20:13 +00001283 String languageTags = a.getString(
1284 com.android.internal.R.styleable.KeyboardLayout_locale);
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001285 LocaleList locales = getLocalesFromLanguageTags(languageTags);
Michael Wright07483422015-10-30 16:20:13 +00001286 int vid = a.getInt(
1287 com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
1288 int pid = a.getInt(
1289 com.android.internal.R.styleable.KeyboardLayout_productId, -1);
1290
Jeff Brown2f095762012-05-10 21:29:33 -07001291 if (name == null || label == null || keyboardLayoutResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001292 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001293 + "attributes in keyboard layout "
1294 + "resource from receiver "
1295 + receiver.packageName + "/" + receiver.name);
1296 } else {
1297 String descriptor = KeyboardLayoutDescriptor.format(
1298 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001299 if (keyboardName == null || name.equals(keyboardName)) {
Michael Wright07483422015-10-30 16:20:13 +00001300 KeyboardLayout layout = new KeyboardLayout(
1301 descriptor, label, collection, priority,
1302 locales, vid, pid);
1303 visitor.visitKeyboardLayout(
1304 resources, keyboardLayoutResId, layout);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001305 }
1306 }
1307 } finally {
1308 a.recycle();
1309 }
1310 } else {
Michael Wright07483422015-10-30 16:20:13 +00001311 Slog.w(TAG, "Skipping unrecognized element '" + element
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001312 + "' in keyboard layout resource from receiver "
1313 + receiver.packageName + "/" + receiver.name);
1314 }
1315 }
1316 } finally {
1317 parser.close();
1318 }
1319 } catch (Exception ex) {
Michael Wright07483422015-10-30 16:20:13 +00001320 Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001321 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001322 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001323 }
1324
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001325 @NonNull
1326 private static LocaleList getLocalesFromLanguageTags(String languageTags) {
Michael Wright07483422015-10-30 16:20:13 +00001327 if (TextUtils.isEmpty(languageTags)) {
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001328 return LocaleList.getEmptyLocaleList();
Michael Wright07483422015-10-30 16:20:13 +00001329 }
Yohei Yukawa5660fad2016-01-27 22:04:09 -08001330 return LocaleList.forLanguageTags(languageTags.replace('|', ','));
Michael Wright07483422015-10-30 16:20:13 +00001331 }
1332
RoboErikfb290df2013-12-16 11:27:55 -08001333 /**
1334 * Builds a layout descriptor for the vendor/product. This returns the
1335 * descriptor for ids that aren't useful (such as the default 0, 0).
1336 */
1337 private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1338 if (identifier == null || identifier.getDescriptor() == null) {
1339 throw new IllegalArgumentException("identifier and descriptor must not be null");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001340 }
1341
RoboErikfb290df2013-12-16 11:27:55 -08001342 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1343 return identifier.getDescriptor();
1344 }
1345 StringBuilder bob = new StringBuilder();
1346 bob.append("vendor:").append(identifier.getVendorId());
1347 bob.append(",product:").append(identifier.getProductId());
1348 return bob.toString();
1349 }
1350
1351 @Override // Binder call
1352 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1353
1354 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001355 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001356 String layout = null;
1357 // try loading it using the layout descriptor if we have it
1358 layout = mDataStore.getCurrentKeyboardLayout(key);
1359 if (layout == null && !key.equals(identifier.getDescriptor())) {
1360 // if it doesn't exist fall back to the device descriptor
1361 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1362 }
1363 if (DEBUG) {
1364 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1365 + layout);
1366 }
1367 return layout;
Jeff Browna3bc5652012-04-17 11:42:25 -07001368 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001369 }
1370
1371 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001372 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001373 String keyboardLayoutDescriptor) {
1374 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001375 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001376 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1377 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001378 if (keyboardLayoutDescriptor == null) {
1379 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1380 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001381
RoboErikfb290df2013-12-16 11:27:55 -08001382 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001383 synchronized (mDataStore) {
1384 try {
RoboErikfb290df2013-12-16 11:27:55 -08001385 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1386 if (DEBUG) {
1387 Slog.d(TAG, "Saved keyboard layout using " + key);
1388 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001389 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1390 }
Jeff Browna3bc5652012-04-17 11:42:25 -07001391 } finally {
1392 mDataStore.saveIfNeeded();
1393 }
1394 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001395 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001396
Jeff Browncf39bdf2012-05-18 14:41:19 -07001397 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001398 public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
RoboErikfb290df2013-12-16 11:27:55 -08001399 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001400 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001401 String[] layouts = mDataStore.getKeyboardLayouts(key);
1402 if ((layouts == null || layouts.length == 0)
1403 && !key.equals(identifier.getDescriptor())) {
1404 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1405 }
1406 return layouts;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001407 }
1408 }
1409
1410 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001411 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001412 String keyboardLayoutDescriptor) {
1413 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1414 "addKeyboardLayoutForInputDevice()")) {
1415 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1416 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001417 if (keyboardLayoutDescriptor == null) {
1418 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1419 }
1420
RoboErikfb290df2013-12-16 11:27:55 -08001421 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001422 synchronized (mDataStore) {
1423 try {
RoboErikfb290df2013-12-16 11:27:55 -08001424 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1425 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1426 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1427 }
1428 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001429 && !Objects.equals(oldLayout,
1430 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001431 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1432 }
1433 } finally {
1434 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001435 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001436 }
1437 }
1438
1439 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001440 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001441 String keyboardLayoutDescriptor) {
1442 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1443 "removeKeyboardLayoutForInputDevice()")) {
1444 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1445 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001446 if (keyboardLayoutDescriptor == null) {
1447 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1448 }
1449
RoboErikfb290df2013-12-16 11:27:55 -08001450 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001451 synchronized (mDataStore) {
1452 try {
RoboErikfb290df2013-12-16 11:27:55 -08001453 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1454 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1455 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1456 }
1457 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1458 if (!key.equals(identifier.getDescriptor())) {
1459 // We need to remove from both places to ensure it is gone
1460 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1461 keyboardLayoutDescriptor);
1462 }
Narayan Kamath607223f2018-02-19 14:09:02 +00001463 if (removed && !Objects.equals(oldLayout,
RoboErikfb290df2013-12-16 11:27:55 -08001464 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001465 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1466 }
1467 } finally {
1468 mDataStore.saveIfNeeded();
1469 }
1470 }
1471 }
1472
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001473 public void switchKeyboardLayout(int deviceId, int direction) {
1474 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001475 }
1476
1477 // Must be called on handler.
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001478 private void handleSwitchKeyboardLayout(int deviceId, int direction) {
1479 final InputDevice device = getInputDevice(deviceId);
1480 if (device != null) {
1481 final boolean changed;
1482 final String keyboardLayoutDescriptor;
1483
1484 String key = getLayoutDescriptor(device.getIdentifier());
1485 synchronized (mDataStore) {
1486 try {
1487 changed = mDataStore.switchKeyboardLayout(key, direction);
1488 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
1489 key);
1490 } finally {
1491 mDataStore.saveIfNeeded();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001492 }
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001493 }
1494
1495 if (changed) {
1496 if (mSwitchedKeyboardLayoutToast != null) {
1497 mSwitchedKeyboardLayoutToast.cancel();
1498 mSwitchedKeyboardLayoutToast = null;
1499 }
1500 if (keyboardLayoutDescriptor != null) {
1501 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
1502 if (keyboardLayout != null) {
1503 mSwitchedKeyboardLayoutToast = Toast.makeText(
1504 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
1505 mSwitchedKeyboardLayoutToast.show();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001506 }
1507 }
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001508
1509 reloadKeyboardLayouts();
Jeff Browncf39bdf2012-05-18 14:41:19 -07001510 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001511 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001512 }
1513
Tiger Huang1e5b10a2018-07-30 20:19:51 +08001514 public void setFocusedApplication(int displayId, InputApplicationHandle application) {
1515 nativeSetFocusedApplication(mPtr, displayId, application);
1516 }
1517
Tiger Huang1e5b10a2018-07-30 20:19:51 +08001518 public void setFocusedDisplay(int displayId) {
1519 nativeSetFocusedDisplay(mPtr, displayId);
Jeff Brown349703e2010-06-22 01:27:15 -07001520 }
RoboErikfb290df2013-12-16 11:27:55 -08001521
Riddle Hsu3f2de742019-02-25 15:21:38 +08001522 /** Clean up input window handles of the given display. */
1523 public void onDisplayRemoved(int displayId) {
1524 nativeSetInputWindows(mPtr, null /* windowHandles */, displayId);
1525 }
1526
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001527 @Override
1528 public void requestPointerCapture(IBinder windowToken, boolean enabled) {
Vishnu Nair18782162019-10-08 14:57:16 -07001529 boolean requestConfigurationRefresh =
1530 mWindowManagerCallbacks.requestPointerCapture(windowToken, enabled);
1531 if (requestConfigurationRefresh) {
Tiger Huang1e5b10a2018-07-30 20:19:51 +08001532 nativeSetPointerCapture(mPtr, enabled);
1533 }
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -08001534 }
1535
Jeff Brown349703e2010-06-22 01:27:15 -07001536 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001537 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001538 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001539
1540 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001541 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001542 }
1543
Arthur Hungfd9d94d2019-08-28 16:06:07 +08001544 /**
1545 * Atomically transfers touch focus from one window to another as identified by
1546 * their input channels. It is possible for multiple windows to have
1547 * touch focus if they support split touch dispatch
1548 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1549 * method only transfers touch focus of the specified window without affecting
1550 * other windows that may also have touch focus at the same time.
1551 * @param fromChannel The channel of a window that currently has touch focus.
1552 * @param toChannel The channel of the window that should receive touch focus in
1553 * place of the first.
1554 * @return True if the transfer was successful. False if the window with the
1555 * specified channel did not actually have touch focus at the time of the request.
1556 */
Svet Ganov17d9d2f2020-01-18 10:12:11 -08001557 public boolean transferTouchFocus(@NonNull InputChannel fromChannel,
1558 @NonNull InputChannel toChannel) {
1559 return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken());
1560 }
1561
1562 /**
1563 * Atomically transfers touch focus from one window to another as identified by
1564 * their input channels. It is possible for multiple windows to have
1565 * touch focus if they support split touch dispatch
1566 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1567 * method only transfers touch focus of the specified window without affecting
1568 * other windows that may also have touch focus at the same time.
1569 * @param fromChannelToken The channel token of a window that currently has touch focus.
1570 * @param toChannelToken The channel token of the window that should receive touch focus in
1571 * place of the first.
1572 * @return True if the transfer was successful. False if the window with the
1573 * specified channel did not actually have touch focus at the time of the request.
1574 */
1575 public boolean transferTouchFocus(@NonNull IBinder fromChannelToken,
1576 @NonNull IBinder toChannelToken) {
1577 Objects.nonNull(fromChannelToken);
1578 Objects.nonNull(toChannelToken);
1579 return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken);
Arthur Hungfd9d94d2019-08-28 16:06:07 +08001580 }
1581
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001582 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001583 public void tryPointerSpeed(int speed) {
1584 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1585 "tryPointerSpeed()")) {
1586 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1587 }
1588
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001589 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1590 throw new IllegalArgumentException("speed out of range");
1591 }
1592
Jeff Brownac143512012-04-05 18:57:33 -07001593 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001594 }
1595
1596 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001597 int speed = getPointerSpeedSetting();
1598 setPointerSpeedUnchecked(speed);
1599 }
1600
1601 private void setPointerSpeedUnchecked(int speed) {
1602 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1603 InputManager.MAX_POINTER_SPEED);
1604 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001605 }
1606
1607 private void registerPointerSpeedSettingObserver() {
1608 mContext.getContentResolver().registerContentObserver(
1609 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001610 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001611 @Override
1612 public void onChange(boolean selfChange) {
1613 updatePointerSpeedFromSettings();
1614 }
Jeff Brownd4935962012-09-25 13:27:20 -07001615 }, UserHandle.USER_ALL);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001616 }
1617
Jeff Brownac143512012-04-05 18:57:33 -07001618 private int getPointerSpeedSetting() {
1619 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001620 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001621 speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1622 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001623 } catch (SettingNotFoundException snfe) {
1624 }
1625 return speed;
1626 }
1627
Jeff Browndaf4a122011-08-26 17:14:14 -07001628 public void updateShowTouchesFromSettings() {
1629 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001630 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001631 }
1632
1633 private void registerShowTouchesSettingObserver() {
1634 mContext.getContentResolver().registerContentObserver(
1635 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001636 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001637 @Override
1638 public void onChange(boolean selfChange) {
1639 updateShowTouchesFromSettings();
1640 }
Jeff Brownd4935962012-09-25 13:27:20 -07001641 }, UserHandle.USER_ALL);
Jeff Browndaf4a122011-08-26 17:14:14 -07001642 }
1643
Jun Mukaie4e75da2015-12-15 16:19:20 -08001644 public void updateAccessibilityLargePointerFromSettings() {
1645 final int accessibilityConfig = Settings.Secure.getIntForUser(
1646 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1647 0, UserHandle.USER_CURRENT);
Jun Mukai1f3dbff2015-12-16 14:41:25 -08001648 PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
Jun Mukaie4e75da2015-12-15 16:19:20 -08001649 nativeReloadPointerIcons(mPtr);
1650 }
1651
Jun Mukai19a56012015-11-24 11:25:52 -08001652 private void registerAccessibilityLargePointerSettingObserver() {
1653 mContext.getContentResolver().registerContentObserver(
1654 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1655 new ContentObserver(mHandler) {
1656 @Override
1657 public void onChange(boolean selfChange) {
Jun Mukaie4e75da2015-12-15 16:19:20 -08001658 updateAccessibilityLargePointerFromSettings();
Jun Mukai19a56012015-11-24 11:25:52 -08001659 }
1660 }, UserHandle.USER_ALL);
1661 }
1662
Jeff Browndaf4a122011-08-26 17:14:14 -07001663 private int getShowTouchesSetting(int defaultValue) {
1664 int result = defaultValue;
1665 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001666 result = Settings.System.getIntForUser(mContext.getContentResolver(),
1667 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
Jeff Browndaf4a122011-08-26 17:14:14 -07001668 } catch (SettingNotFoundException snfe) {
1669 }
1670 return result;
1671 }
1672
Jeff Browna47425a2012-04-13 04:09:27 -07001673 // Binder call
1674 @Override
1675 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1676 if (repeat >= pattern.length) {
1677 throw new ArrayIndexOutOfBoundsException();
1678 }
1679
1680 VibratorToken v;
1681 synchronized (mVibratorLock) {
1682 v = mVibratorTokens.get(token);
1683 if (v == null) {
1684 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1685 try {
1686 token.linkToDeath(v, 0);
1687 } catch (RemoteException ex) {
1688 // give up
1689 throw new RuntimeException(ex);
1690 }
1691 mVibratorTokens.put(token, v);
1692 }
1693 }
1694
1695 synchronized (v) {
1696 v.mVibrating = true;
1697 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1698 }
1699 }
1700
1701 // Binder call
1702 @Override
1703 public void cancelVibrate(int deviceId, IBinder token) {
1704 VibratorToken v;
1705 synchronized (mVibratorLock) {
1706 v = mVibratorTokens.get(token);
1707 if (v == null || v.mDeviceId != deviceId) {
1708 return; // nothing to cancel
1709 }
1710 }
1711
1712 cancelVibrateIfNeeded(v);
1713 }
1714
1715 void onVibratorTokenDied(VibratorToken v) {
1716 synchronized (mVibratorLock) {
1717 mVibratorTokens.remove(v.mToken);
1718 }
1719
1720 cancelVibrateIfNeeded(v);
1721 }
1722
1723 private void cancelVibrateIfNeeded(VibratorToken v) {
1724 synchronized (v) {
1725 if (v.mVibrating) {
1726 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1727 v.mVibrating = false;
1728 }
1729 }
1730 }
1731
Jun Mukai19a56012015-11-24 11:25:52 -08001732 // Binder call
1733 @Override
Michael Wrightf9d9ce772016-05-13 17:44:16 +01001734 public void setPointerIconType(int iconId) {
1735 nativeSetPointerIconType(mPtr, iconId);
Jun Mukai19a56012015-11-24 11:25:52 -08001736 }
Jun Mukai1db53972015-09-11 18:08:31 -07001737
Jun Mukaid4eaef72015-10-30 15:54:33 -07001738 // Binder call
1739 @Override
1740 public void setCustomPointerIcon(PointerIcon icon) {
Daulet Zhanguzinf894cbb2020-01-02 17:37:39 +00001741 Objects.requireNonNull(icon);
Jun Mukaid4eaef72015-10-30 15:54:33 -07001742 nativeSetCustomPointerIcon(mPtr, icon);
1743 }
1744
Arthur Hungc9f383b2019-12-04 17:02:19 +08001745 /**
1746 * Add a runtime association between the input port and the display port. This overrides any
1747 * static associations.
1748 * @param inputPort The port of the input device.
1749 * @param displayPort The physical port of the associated display.
1750 */
1751 @Override // Binder call
1752 public void addPortAssociation(@NonNull String inputPort, int displayPort) {
1753 if (!checkCallingPermission(
1754 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT,
1755 "addPortAssociation()")) {
1756 throw new SecurityException(
1757 "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT permission");
1758 }
1759
1760 Objects.requireNonNull(inputPort);
1761 synchronized (mAssociationsLock) {
1762 mRuntimeAssociations.put(inputPort, displayPort);
1763 }
1764 nativeNotifyPortAssociationsChanged(mPtr);
1765 }
1766
1767 /**
1768 * Remove the runtime association between the input port and the display port. Any existing
1769 * static association for the cleared input port will be restored.
1770 * @param inputPort The port of the input device to be cleared.
1771 */
1772 @Override // Binder call
1773 public void removePortAssociation(@NonNull String inputPort) {
1774 if (!checkCallingPermission(
1775 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT,
1776 "clearPortAssociations()")) {
1777 throw new SecurityException(
1778 "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT permission");
1779 }
1780
1781 Objects.requireNonNull(inputPort);
1782 synchronized (mAssociationsLock) {
1783 mRuntimeAssociations.remove(inputPort);
1784 }
1785 nativeNotifyPortAssociationsChanged(mPtr);
1786 }
1787
Jeff Brown4532e612012-04-05 14:27:12 -07001788 @Override
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08001789 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001790 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Jeff Brown4532e612012-04-05 14:27:12 -07001791
1792 pw.println("INPUT MANAGER (dumpsys input)\n");
1793 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001794 if (dumpStr != null) {
1795 pw.println(dumpStr);
Arthur Hungcf6070e2019-12-04 16:09:42 +08001796 dumpAssociations(pw);
1797 }
1798 }
1799
1800 private void dumpAssociations(PrintWriter pw) {
1801 if (!mStaticAssociations.isEmpty()) {
1802 pw.println("Static Associations:");
1803 mStaticAssociations.forEach((k, v) -> {
1804 pw.print(" port: " + k);
1805 pw.println(" display: " + v);
1806 });
Jeff Browne33348b2010-07-15 23:54:05 -07001807 }
Arthur Hungc9f383b2019-12-04 17:02:19 +08001808
1809 synchronized (mAssociationsLock) {
1810 if (!mRuntimeAssociations.isEmpty()) {
1811 pw.println("Runtime Associations:");
1812 mRuntimeAssociations.forEach((k, v) -> {
1813 pw.print(" port: " + k);
1814 pw.println(" display: " + v);
1815 });
1816 }
1817 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001818 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001819
Jeff Brownac143512012-04-05 18:57:33 -07001820 private boolean checkCallingPermission(String permission, String func) {
1821 // Quick check: if the calling permission is me, it's all okay.
1822 if (Binder.getCallingPid() == Process.myPid()) {
1823 return true;
1824 }
1825
1826 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1827 return true;
1828 }
1829 String msg = "Permission Denial: " + func + " from pid="
1830 + Binder.getCallingPid()
1831 + ", uid=" + Binder.getCallingUid()
1832 + " requires " + permission;
1833 Slog.w(TAG, msg);
1834 return false;
1835 }
1836
Jeff Brown4532e612012-04-05 14:27:12 -07001837 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001838 @Override
Jeff Brown89ef0722011-08-10 16:25:21 -07001839 public void monitor() {
1840 synchronized (mInputFilterLock) { }
Arthur Hungc9f383b2019-12-04 17:02:19 +08001841 synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
Jeff Brown4532e612012-04-05 14:27:12 -07001842 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001843 }
1844
Jeff Brown4532e612012-04-05 14:27:12 -07001845 // Native callback.
1846 private void notifyConfigurationChanged(long whenNanos) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001847 mWindowManagerCallbacks.notifyConfigurationChanged();
Jeff Brown4532e612012-04-05 14:27:12 -07001848 }
1849
1850 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001851 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1852 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001853 if (!mInputDevicesChangedPending) {
1854 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001855 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1856 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001857 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001858
1859 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001860 }
1861 }
1862
1863 // Native callback.
Jeff Brownbcc046a2012-09-27 20:46:43 -07001864 private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1865 if (DEBUG) {
1866 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1867 + ", mask=" + Integer.toHexString(switchMask));
1868 }
1869
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001870 if ((switchMask & SW_LID_BIT) != 0) {
1871 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
Jeff Brownbcc046a2012-09-27 20:46:43 -07001872 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
Jeff Brown53384282012-08-20 20:16:01 -07001873 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001874
Michael Wright3818c922014-09-02 13:59:07 -07001875 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
Michael Wright9e10d252014-09-13 19:41:20 -07001876 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
Michael Wright3818c922014-09-02 13:59:07 -07001877 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1878 }
1879
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001880 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1881 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1882 switchMask);
1883 }
Michael Wright39e5e942015-08-19 22:52:47 +01001884
Michael Wright9209c9c2015-09-03 17:57:01 +01001885 if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
Michael Wright39e5e942015-08-19 22:52:47 +01001886 SomeArgs args = SomeArgs.obtain();
1887 args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
1888 args.argi2 = (int) (whenNanos >> 32);
1889 args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
1890 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
1891 args).sendToTarget();
1892 }
Dmitry Shmidt38ab71c2019-09-19 15:28:30 -07001893
1894 if ((switchMask & SW_MUTE_DEVICE_BIT) != 0) {
1895 final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0);
1896 AudioManager audioManager = mContext.getSystemService(AudioManager.class);
1897 audioManager.setMicrophoneMuteFromSwitch(micMute);
1898 }
Jeff Brown4532e612012-04-05 14:27:12 -07001899 }
1900
1901 // Native callback.
Robert Carre0a353c2018-08-02 16:38:04 -07001902 private void notifyInputChannelBroken(IBinder token) {
1903 mWindowManagerCallbacks.notifyInputChannelBroken(token);
Jeff Brown4532e612012-04-05 14:27:12 -07001904 }
1905
Robert Carrbd26e652018-08-21 15:46:28 -07001906 // Native callback
chaviw91089862019-01-09 15:49:11 -08001907 private void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
Vishnu Nair18782162019-10-08 14:57:16 -07001908 final boolean requestConfigurationRefresh =
1909 mWindowManagerCallbacks.notifyFocusChanged(oldToken, newToken);
1910 if (requestConfigurationRefresh) {
1911 nativeSetPointerCapture(mPtr, false);
Robert Carrbd26e652018-08-21 15:46:28 -07001912 }
1913 }
1914
Jeff Brown4532e612012-04-05 14:27:12 -07001915 // Native callback.
Vishnu Nair19479df2019-10-30 08:03:15 -07001916 private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
1917 String reason) {
1918 return mWindowManagerCallbacks.notifyANR(inputApplicationHandle,
Robert Carr679ccb02018-08-08 15:32:35 -07001919 token, reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001920 }
1921
1922 // Native callback.
1923 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1924 synchronized (mInputFilterLock) {
1925 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001926 try {
1927 mInputFilter.filterInputEvent(event, policyFlags);
1928 } catch (RemoteException e) {
1929 /* ignore */
1930 }
Jeff Brown4532e612012-04-05 14:27:12 -07001931 return false;
1932 }
1933 }
1934 event.recycle();
1935 return true;
1936 }
1937
1938 // Native callback.
Jeff Brown037c33e2014-04-09 00:31:55 -07001939 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1940 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001941 }
1942
1943 // Native callback.
Charles Chen4cc014e12019-01-28 16:17:16 +08001944 private int interceptMotionBeforeQueueingNonInteractive(int displayId,
1945 long whenNanos, int policyFlags) {
Michael Wright70af00a2014-09-03 19:30:20 -07001946 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
Charles Chen4cc014e12019-01-28 16:17:16 +08001947 displayId, whenNanos, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001948 }
1949
1950 // Native callback.
Robert Carr679ccb02018-08-08 15:32:35 -07001951 private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001952 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001953 }
1954
1955 // Native callback.
Robert Carr679ccb02018-08-08 15:32:35 -07001956 private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001957 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001958 }
1959
1960 // Native callback.
1961 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1962 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1963 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1964 }
1965
1966 // Native callback.
chaviw17902c52019-03-25 13:21:56 -07001967 private void onPointerDownOutsideFocus(IBinder touchedToken) {
chaviwfa2f0042019-03-25 13:48:58 -07001968 mWindowManagerCallbacks.onPointerDownOutsideFocus(touchedToken);
chaviw17902c52019-03-25 13:21:56 -07001969 }
1970
1971 // Native callback.
Jeff Brown4532e612012-04-05 14:27:12 -07001972 private int getVirtualKeyQuietTimeMillis() {
1973 return mContext.getResources().getInteger(
1974 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1975 }
1976
1977 // Native callback.
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001978 private static String[] getExcludedDeviceNames() {
1979 List<String> names = new ArrayList<>();
Jeff Brown4532e612012-04-05 14:27:12 -07001980 // Read partner-provided list of excluded input devices
Jeff Brown4532e612012-04-05 14:27:12 -07001981 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
Tsukasa Hashimotoea12b552018-09-11 16:47:22 +09001982 final File[] baseDirs = {
1983 Environment.getRootDirectory(),
1984 Environment.getVendorDirectory()
1985 };
1986 for (File baseDir: baseDirs) {
1987 File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH);
Tsukasa Hashimotoea12b552018-09-11 16:47:22 +09001988 try {
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001989 InputStream stream = new FileInputStream(confFile);
1990 names.addAll(ConfigurationProcessor.processExcludedDeviceNames(stream));
Tsukasa Hashimotoea12b552018-09-11 16:47:22 +09001991 } catch (FileNotFoundException e) {
1992 // It's ok if the file does not exist.
1993 } catch (Exception e) {
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001994 Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
Jeff Brown4532e612012-04-05 14:27:12 -07001995 }
Jeff Brown4532e612012-04-05 14:27:12 -07001996 }
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07001997 return names.toArray(new String[0]);
1998 }
Jeff Brown4532e612012-04-05 14:27:12 -07001999
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07002000 /**
Arthur Hungcf6070e2019-12-04 16:09:42 +08002001 * Flatten a map into a string list, with value positioned directly next to the
2002 * key.
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07002003 * @return Flattened list
2004 */
Arthur Hungcf6070e2019-12-04 16:09:42 +08002005 private static List<String> flatten(@NonNull Map<String, Integer> map) {
Arthur Hungc9f383b2019-12-04 17:02:19 +08002006 final List<String> list = new ArrayList<>(map.size() * 2);
Arthur Hungcf6070e2019-12-04 16:09:42 +08002007 map.forEach((k, v)-> {
2008 list.add(k);
2009 list.add(v.toString());
2010 });
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07002011 return list;
2012 }
2013
2014 /**
2015 * Ports are highly platform-specific, so only allow these to be specified in the vendor
2016 * directory.
2017 */
Arthur Hungcf6070e2019-12-04 16:09:42 +08002018 private static Map<String, Integer> loadStaticInputPortAssociations() {
Arthur Hungc9f383b2019-12-04 17:02:19 +08002019 final File baseDir = Environment.getVendorDirectory();
2020 final File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07002021
2022 try {
Arthur Hungc9f383b2019-12-04 17:02:19 +08002023 final InputStream stream = new FileInputStream(confFile);
Arthur Hungcf6070e2019-12-04 16:09:42 +08002024 return ConfigurationProcessor.processInputPortAssociations(stream);
Siarhei Vishniakou15a412d2018-10-04 19:01:04 -07002025 } catch (FileNotFoundException e) {
2026 // Most of the time, file will not exist, which is expected.
2027 } catch (Exception e) {
2028 Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);
2029 }
Arthur Hungcf6070e2019-12-04 16:09:42 +08002030
2031 return new HashMap<>();
2032 }
2033
2034 // Native callback
2035 private String[] getInputPortAssociations() {
Arthur Hungc9f383b2019-12-04 17:02:19 +08002036 final Map<String, Integer> associations = new HashMap<>(mStaticAssociations);
2037
2038 // merge the runtime associations.
2039 synchronized (mAssociationsLock) {
2040 associations.putAll(mRuntimeAssociations);
2041 }
2042
2043 final List<String> associationList = flatten(associations);
Arthur Hungcf6070e2019-12-04 16:09:42 +08002044 return associationList.toArray(new String[0]);
Jeff Brown4532e612012-04-05 14:27:12 -07002045 }
2046
Arthur Hung82bbfc32018-11-29 20:24:51 +08002047 /**
2048 * Gets if an input device could dispatch to the given display".
2049 * @param deviceId The input device id.
2050 * @param displayId The specific display id.
2051 * @return True if the device could dispatch to the given display, false otherwise.
2052 */
2053 public boolean canDispatchToDisplay(int deviceId, int displayId) {
2054 return nativeCanDispatchToDisplay(mPtr, deviceId, displayId);
2055 }
2056
Jeff Brown4532e612012-04-05 14:27:12 -07002057 // Native callback.
2058 private int getKeyRepeatTimeout() {
2059 return ViewConfiguration.getKeyRepeatTimeout();
2060 }
2061
2062 // Native callback.
2063 private int getKeyRepeatDelay() {
2064 return ViewConfiguration.getKeyRepeatDelay();
2065 }
2066
2067 // Native callback.
2068 private int getHoverTapTimeout() {
2069 return ViewConfiguration.getHoverTapTimeout();
2070 }
2071
2072 // Native callback.
2073 private int getHoverTapSlop() {
2074 return ViewConfiguration.getHoverTapSlop();
2075 }
2076
2077 // Native callback.
2078 private int getDoubleTapTimeout() {
2079 return ViewConfiguration.getDoubleTapTimeout();
2080 }
2081
2082 // Native callback.
2083 private int getLongPressTimeout() {
2084 return ViewConfiguration.getLongPressTimeout();
2085 }
2086
2087 // Native callback.
2088 private int getPointerLayer() {
Jeff Browna9d131c2012-09-20 16:48:17 -07002089 return mWindowManagerCallbacks.getPointerLayer();
Jeff Brown4532e612012-04-05 14:27:12 -07002090 }
2091
2092 // Native callback.
Andrii Kulianfd8666d2018-10-05 16:58:39 -07002093 private PointerIcon getPointerIcon(int displayId) {
2094 return PointerIcon.getDefaultIcon(getContextForDisplay(displayId));
2095 }
2096
2097 private Context getContextForDisplay(int displayId) {
2098 if (mDisplayContext != null && mDisplayContext.getDisplay().getDisplayId() == displayId) {
2099 return mDisplayContext;
2100 }
2101
2102 if (mContext.getDisplay().getDisplayId() == displayId) {
2103 mDisplayContext = mContext;
2104 return mDisplayContext;
2105 }
2106
2107 // Create and cache context for non-default display.
2108 final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
2109 final Display display = displayManager.getDisplay(displayId);
2110 mDisplayContext = mContext.createDisplayContext(display);
2111 return mDisplayContext;
Jeff Brown4532e612012-04-05 14:27:12 -07002112 }
2113
Jeff Brown6ec6f792012-04-17 16:52:41 -07002114 // Native callback.
Arthur Hungb9b32002018-12-18 17:39:43 +08002115 private int getPointerDisplayId() {
2116 return mWindowManagerCallbacks.getPointerDisplayId();
2117 }
2118
2119 // Native callback.
RoboErikfb290df2013-12-16 11:27:55 -08002120 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07002121 if (!mSystemReady) {
2122 return null;
2123 }
2124
RoboErikfb290df2013-12-16 11:27:55 -08002125 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002126 if (keyboardLayoutDescriptor == null) {
2127 return null;
2128 }
2129
2130 final String[] result = new String[2];
2131 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
2132 @Override
Michael Wright07483422015-10-30 16:20:13 +00002133 public void visitKeyboardLayout(Resources resources,
2134 int keyboardLayoutResId, KeyboardLayout layout) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07002135 try {
Michael Wright07483422015-10-30 16:20:13 +00002136 result[0] = layout.getDescriptor();
Jeff Brown6ec6f792012-04-17 16:52:41 -07002137 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07002138 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07002139 } catch (IOException ex) {
2140 } catch (NotFoundException ex) {
2141 }
2142 }
2143 });
2144 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00002145 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07002146 + keyboardLayoutDescriptor + "'.");
2147 return null;
2148 }
2149 return result;
2150 }
2151
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002152 // Native callback.
2153 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07002154 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
2155 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
2156 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07002157 }
2158 return null;
2159 }
2160
Jeff Brown4532e612012-04-05 14:27:12 -07002161 /**
2162 * Callback interface implemented by the Window Manager.
2163 */
Jeff Browna9d131c2012-09-20 16:48:17 -07002164 public interface WindowManagerCallbacks {
Jeff Brown4532e612012-04-05 14:27:12 -07002165 public void notifyConfigurationChanged();
2166
2167 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
2168
Michael Wright3818c922014-09-02 13:59:07 -07002169 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
2170
Robert Carre0a353c2018-08-02 16:38:04 -07002171 public void notifyInputChannelBroken(IBinder token);
Jeff Brown4532e612012-04-05 14:27:12 -07002172
Vishnu Nair19479df2019-10-30 08:03:15 -07002173 /**
2174 * Notifies the window manager about an application that is not responding.
2175 * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
2176 */
2177 long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
2178 String reason);
Jeff Brown4532e612012-04-05 14:27:12 -07002179
Jeff Brown037c33e2014-04-09 00:31:55 -07002180 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002181
Charles Chen4cc014e12019-01-28 16:17:16 +08002182 /**
2183 * Provides an opportunity for the window manager policy to intercept early motion event
2184 * processing when the device is in a non-interactive state since these events are normally
2185 * dropped.
2186 */
2187 int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
2188 int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07002189
Robert Carre0a353c2018-08-02 16:38:04 -07002190 public long interceptKeyBeforeDispatching(IBinder token,
Jeff Brown4532e612012-04-05 14:27:12 -07002191 KeyEvent event, int policyFlags);
2192
Robert Carre0a353c2018-08-02 16:38:04 -07002193 public KeyEvent dispatchUnhandledKey(IBinder token,
Jeff Brown4532e612012-04-05 14:27:12 -07002194 KeyEvent event, int policyFlags);
2195
2196 public int getPointerLayer();
Arthur Hungb9b32002018-12-18 17:39:43 +08002197
2198 public int getPointerDisplayId();
chaviwfa2f0042019-03-25 13:48:58 -07002199
2200 /**
2201 * Notifies window manager that a {@link android.view.MotionEvent#ACTION_DOWN} pointer event
2202 * occurred on a window that did not have focus.
2203 *
2204 * @param touchedToken The token for the window that received the input event.
2205 */
2206 void onPointerDownOutsideFocus(IBinder touchedToken);
Vishnu Nair18782162019-10-08 14:57:16 -07002207
2208 /**
2209 * Called when the focused window has changed.
2210 *
2211 * @return true if we want to request a configuration refresh.
2212 */
2213 boolean notifyFocusChanged(IBinder oldToken, IBinder newToken);
2214
2215 /**
2216 * Called by the client to request pointer capture.
2217 *
2218 * @return true if we want to request a configuration refresh.
2219 */
2220 boolean requestPointerCapture(IBinder windowToken, boolean enabled);
Jeff Brown4532e612012-04-05 14:27:12 -07002221 }
2222
2223 /**
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002224 * Callback interface implemented by WiredAccessoryObserver.
2225 */
2226 public interface WiredAccessoryCallbacks {
2227 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002228 public void systemReady();
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002229 }
2230
2231 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002232 * Private handler for the input manager.
2233 */
2234 private final class InputManagerHandler extends Handler {
Jeff Browna9d131c2012-09-20 16:48:17 -07002235 public InputManagerHandler(Looper looper) {
2236 super(looper, null, true /*async*/);
Jeff Browna2910d02012-08-25 12:29:46 -07002237 }
2238
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002239 @Override
2240 public void handleMessage(Message msg) {
2241 switch (msg.what) {
2242 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07002243 deliverInputDevicesChanged((InputDevice[])msg.obj);
2244 break;
Yohei Yukawa2d9accb2018-03-07 19:15:15 -08002245 case MSG_SWITCH_KEYBOARD_LAYOUT:
2246 handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
Jeff Browncf39bdf2012-05-18 14:41:19 -07002247 break;
2248 case MSG_RELOAD_KEYBOARD_LAYOUTS:
2249 reloadKeyboardLayouts();
2250 break;
2251 case MSG_UPDATE_KEYBOARD_LAYOUTS:
2252 updateKeyboardLayouts();
2253 break;
2254 case MSG_RELOAD_DEVICE_ALIASES:
2255 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002256 break;
Yohei Yukawa19a40002018-03-07 19:15:38 -08002257 case MSG_DELIVER_TABLET_MODE_CHANGED:
Michael Wright39e5e942015-08-19 22:52:47 +01002258 SomeArgs args = (SomeArgs) msg.obj;
2259 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
2260 boolean inTabletMode = (boolean) args.arg1;
2261 deliverTabletModeChanged(whenNanos, inTabletMode);
2262 break;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002263 }
2264 }
2265 }
2266
2267 /**
Jeff Brown4532e612012-04-05 14:27:12 -07002268 * Hosting interface for input filters to call back into the input manager.
2269 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07002270 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07002271 private boolean mDisconnected;
2272
2273 public void disconnectLocked() {
2274 mDisconnected = true;
2275 }
2276
Craig Mautner2f39e9f2012-09-21 11:39:54 -07002277 @Override
Jeff Brown0029c662011-03-30 02:25:18 -07002278 public void sendInputEvent(InputEvent event, int policyFlags) {
2279 if (event == null) {
2280 throw new IllegalArgumentException("event must not be null");
2281 }
2282
2283 synchronized (mInputFilterLock) {
2284 if (!mDisconnected) {
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -08002285 nativeInjectInputEvent(mPtr, event, 0, 0,
Jeff Brownac143512012-04-05 18:57:33 -07002286 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07002287 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
2288 }
2289 }
2290 }
2291 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07002292
Michael Wrightc7995232019-02-14 12:33:46 +00002293 /**
2294 * Interface for the system to handle request from InputMonitors.
2295 */
2296 private final class InputMonitorHost extends IInputMonitorHost.Stub {
2297 private final InputChannel mInputChannel;
2298
2299 InputMonitorHost(InputChannel channel) {
2300 mInputChannel = channel;
2301 }
2302
2303 @Override
2304 public void pilferPointers() {
Siarhei Vishniakou67429832019-10-15 16:58:33 -07002305 nativePilferPointers(mPtr, mInputChannel.getToken());
Michael Wrightc7995232019-02-14 12:33:46 +00002306 }
2307
2308 @Override
2309 public void dispose() {
2310 nativeUnregisterInputChannel(mPtr, mInputChannel);
2311 mInputChannel.dispose();
2312 }
2313 }
2314
Jeff Brown9f25b7f2012-04-10 14:30:49 -07002315 private static final class KeyboardLayoutDescriptor {
2316 public String packageName;
2317 public String receiverName;
2318 public String keyboardLayoutName;
2319
2320 public static String format(String packageName,
2321 String receiverName, String keyboardName) {
2322 return packageName + "/" + receiverName + "/" + keyboardName;
2323 }
2324
2325 public static KeyboardLayoutDescriptor parse(String descriptor) {
2326 int pos = descriptor.indexOf('/');
2327 if (pos < 0 || pos + 1 == descriptor.length()) {
2328 return null;
2329 }
2330 int pos2 = descriptor.indexOf('/', pos + 1);
2331 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
2332 return null;
2333 }
2334
2335 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
2336 result.packageName = descriptor.substring(0, pos);
2337 result.receiverName = descriptor.substring(pos + 1, pos2);
2338 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
2339 return result;
2340 }
2341 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002342
Jeff Brown6ec6f792012-04-17 16:52:41 -07002343 private interface KeyboardLayoutVisitor {
Michael Wright07483422015-10-30 16:20:13 +00002344 void visitKeyboardLayout(Resources resources,
2345 int keyboardLayoutResId, KeyboardLayout layout);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002346 }
2347
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002348 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
2349 private final int mPid;
2350 private final IInputDevicesChangedListener mListener;
2351
2352 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
2353 mPid = pid;
2354 mListener = listener;
2355 }
2356
2357 @Override
2358 public void binderDied() {
2359 if (DEBUG) {
2360 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
2361 }
2362 onInputDevicesChangedListenerDied(mPid);
2363 }
2364
2365 public void notifyInputDevicesChanged(int[] info) {
2366 try {
2367 mListener.onInputDevicesChanged(info);
2368 } catch (RemoteException ex) {
2369 Slog.w(TAG, "Failed to notify process "
2370 + mPid + " that input devices changed, assuming it died.", ex);
2371 binderDied();
2372 }
2373 }
2374 }
Jeff Browna47425a2012-04-13 04:09:27 -07002375
Michael Wright39e5e942015-08-19 22:52:47 +01002376 private final class TabletModeChangedListenerRecord implements DeathRecipient {
2377 private final int mPid;
2378 private final ITabletModeChangedListener mListener;
2379
2380 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
2381 mPid = pid;
2382 mListener = listener;
2383 }
2384
2385 @Override
2386 public void binderDied() {
2387 if (DEBUG) {
2388 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
2389 }
2390 onTabletModeChangedListenerDied(mPid);
2391 }
2392
2393 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
2394 try {
2395 mListener.onTabletModeChanged(whenNanos, inTabletMode);
2396 } catch (RemoteException ex) {
2397 Slog.w(TAG, "Failed to notify process " + mPid +
2398 " that tablet mode changed, assuming it died.", ex);
2399 binderDied();
2400 }
2401 }
2402 }
2403
Jeff Browna47425a2012-04-13 04:09:27 -07002404 private final class VibratorToken implements DeathRecipient {
2405 public final int mDeviceId;
2406 public final IBinder mToken;
2407 public final int mTokenValue;
2408
2409 public boolean mVibrating;
2410
2411 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
2412 mDeviceId = deviceId;
2413 mToken = token;
2414 mTokenValue = tokenValue;
2415 }
2416
2417 @Override
2418 public void binderDied() {
2419 if (DEBUG) {
2420 Slog.d(TAG, "Vibrator token died.");
2421 }
2422 onVibratorTokenDied(this);
2423 }
2424 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002425
2426 private final class LocalService extends InputManagerInternal {
2427 @Override
Siarhei Vishniakou2eb0f8f2018-07-06 23:30:12 +01002428 public void setDisplayViewports(List<DisplayViewport> viewports) {
2429 setDisplayViewportsInternal(viewports);
Jeff Brown4ccb8232014-01-16 22:16:42 -08002430 }
Jeff Brownca9bc702014-02-11 14:32:56 -08002431
2432 @Override
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -08002433 public boolean injectInputEvent(InputEvent event, int mode) {
2434 return injectInputEventInternal(event, mode);
Jeff Brownca9bc702014-02-11 14:32:56 -08002435 }
Jeff Brown037c33e2014-04-09 00:31:55 -07002436
2437 @Override
2438 public void setInteractive(boolean interactive) {
2439 nativeSetInteractive(mPtr, interactive);
2440 }
Yohei Yukawab097b822015-12-01 10:43:08 -08002441
2442 @Override
Andrii Kulian112d0562016-03-08 10:44:22 -08002443 public void toggleCapsLock(int deviceId) {
2444 nativeToggleCapsLock(mPtr, deviceId);
2445 }
Adrian Roos99182342016-06-15 15:30:46 -07002446
2447 @Override
2448 public void setPulseGestureEnabled(boolean enabled) {
2449 if (mDoubleTouchGestureEnableFile != null) {
2450 FileWriter writer = null;
2451 try {
2452 writer = new FileWriter(mDoubleTouchGestureEnableFile);
2453 writer.write(enabled ? "1" : "0");
2454 } catch (IOException e) {
2455 Log.wtf(TAG, "Unable to setPulseGestureEnabled", e);
2456 } finally {
2457 IoUtils.closeQuietly(writer);
2458 }
2459 }
2460 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002461 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07002462}