blob: 8d0dac96c0830b31dbaebc26f6f988cd914e4e24 [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 Yukawab097b822015-12-01 10:43:08 -080019import android.annotation.Nullable;
Jeff Brownca9bc702014-02-11 14:32:56 -080020import android.view.Display;
Michael Wright39e5e942015-08-19 22:52:47 +010021import com.android.internal.os.SomeArgs;
Jeff Browncf39bdf2012-05-18 14:41:19 -070022import com.android.internal.R;
Jeff Brown46b9ac02010-04-22 18:58:52 -070023import com.android.internal.util.XmlUtils;
Jeff Brown4ccb8232014-01-16 22:16:42 -080024import com.android.server.DisplayThread;
25import com.android.server.LocalServices;
Jeff Brown89ef0722011-08-10 16:25:21 -070026import com.android.server.Watchdog;
Jeff Brown46b9ac02010-04-22 18:58:52 -070027
28import org.xmlpull.v1.XmlPullParser;
29
Jeff Browna3bc5652012-04-17 11:42:25 -070030import android.Manifest;
Jeff Browncf39bdf2012-05-18 14:41:19 -070031import android.app.Notification;
32import android.app.NotificationManager;
33import android.app.PendingIntent;
Jeff Brown5bbd4b42012-04-20 19:28:00 -070034import android.bluetooth.BluetoothAdapter;
35import android.bluetooth.BluetoothDevice;
Jeff Brown6ec6f792012-04-17 16:52:41 -070036import android.content.BroadcastReceiver;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070037import android.content.ComponentName;
Jeff Brown46b9ac02010-04-22 18:58:52 -070038import android.content.Context;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070039import android.content.Intent;
Jeff Brown6ec6f792012-04-17 16:52:41 -070040import android.content.IntentFilter;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070041import android.content.pm.ActivityInfo;
Michael Wright8ebac232014-09-18 18:29:49 -070042import android.content.pm.ApplicationInfo;
Jeff Brown349703e2010-06-22 01:27:15 -070043import android.content.pm.PackageManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070044import android.content.pm.ResolveInfo;
45import android.content.pm.PackageManager.NameNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070046import android.content.res.Resources;
Jeff Brown6ec6f792012-04-17 16:52:41 -070047import android.content.res.Resources.NotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070048import android.content.res.TypedArray;
49import android.content.res.XmlResourceParser;
Jeff Brown1a84fd12011-06-02 01:26:32 -070050import android.database.ContentObserver;
Jeff Brown4ccb8232014-01-16 22:16:42 -080051import android.hardware.display.DisplayViewport;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070052import android.hardware.input.IInputDevicesChangedListener;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070053import android.hardware.input.IInputManager;
RoboErikfb290df2013-12-16 11:27:55 -080054import android.hardware.input.InputDeviceIdentifier;
Jeff Brownac143512012-04-05 18:57:33 -070055import android.hardware.input.InputManager;
Jeff Brown4ccb8232014-01-16 22:16:42 -080056import android.hardware.input.InputManagerInternal;
Michael Wright39e5e942015-08-19 22:52:47 +010057import android.hardware.input.ITabletModeChangedListener;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070058import android.hardware.input.KeyboardLayout;
Jason Gerecked6396d62014-01-27 18:30:37 -080059import android.hardware.input.TouchCalibration;
Jeff Brown4532e612012-04-05 14:27:12 -070060import android.os.Binder;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070061import android.os.Bundle;
Jeff Brown46b9ac02010-04-22 18:58:52 -070062import android.os.Environment;
Jeff Brown4532e612012-04-05 14:27:12 -070063import android.os.Handler;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070064import android.os.IBinder;
Jeff Browna9d131c2012-09-20 16:48:17 -070065import android.os.Looper;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070066import android.os.Message;
Jeff Brown05dc66a2011-03-02 14:41:58 -080067import android.os.MessageQueue;
Jeff Brownac143512012-04-05 18:57:33 -070068import android.os.Process;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070069import android.os.RemoteException;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070070import android.os.UserHandle;
Jeff Brown1a84fd12011-06-02 01:26:32 -070071import android.provider.Settings;
72import android.provider.Settings.SettingNotFoundException;
Michael Wright07483422015-10-30 16:20:13 +000073import android.text.TextUtils;
Jeff Brown46b9ac02010-04-22 18:58:52 -070074import android.util.Slog;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070075import android.util.SparseArray;
Jeff Brown46b9ac02010-04-22 18:58:52 -070076import android.util.Xml;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070077import android.view.IInputFilter;
78import android.view.IInputFilterHost;
Jeff Brown46b9ac02010-04-22 18:58:52 -070079import android.view.InputChannel;
Jeff Brown8d608662010-08-30 03:02:23 -070080import android.view.InputDevice;
Jeff Brown6ec402b2010-07-28 15:48:59 -070081import android.view.InputEvent;
Jeff Brown1f245102010-11-18 20:53:46 -080082import android.view.KeyEvent;
Jeff Brown2352b972011-04-12 22:39:53 -070083import android.view.PointerIcon;
Jason Gerecked5220742014-03-10 09:47:59 -070084import android.view.Surface;
Jeff Browna4547672011-03-02 21:38:11 -080085import android.view.ViewConfiguration;
Jeff Brown0029c662011-03-30 02:25:18 -070086import android.view.WindowManagerPolicy;
Yohei Yukawab097b822015-12-01 10:43:08 -080087import android.view.inputmethod.InputMethod;
88import android.view.inputmethod.InputMethodInfo;
89import android.view.inputmethod.InputMethodSubtype;
Jeff Browncf39bdf2012-05-18 14:41:19 -070090import android.widget.Toast;
Jeff Brown46b9ac02010-04-22 18:58:52 -070091
Jeff Brown46b9ac02010-04-22 18:58:52 -070092import java.io.File;
Jeff Brown4532e612012-04-05 14:27:12 -070093import java.io.FileDescriptor;
Jeff Brown46b9ac02010-04-22 18:58:52 -070094import java.io.FileNotFoundException;
95import java.io.FileReader;
96import java.io.IOException;
Jeff Brown6ec6f792012-04-17 16:52:41 -070097import java.io.InputStreamReader;
Jeff Brown46b9ac02010-04-22 18:58:52 -070098import java.io.PrintWriter;
99import java.util.ArrayList;
Michael Wright07483422015-10-30 16:20:13 +0000100import java.util.Collections;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700101import java.util.HashMap;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700102import java.util.HashSet;
Michael Wright39e5e942015-08-19 22:52:47 +0100103import java.util.List;
Michael Wright07483422015-10-30 16:20:13 +0000104import java.util.Locale;
Jeff Browna3bc5652012-04-17 11:42:25 -0700105
Jeff Brown6ec6f792012-04-17 16:52:41 -0700106import libcore.io.Streams;
Jeff Browna3bc5652012-04-17 11:42:25 -0700107import libcore.util.Objects;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700108
109/*
110 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -0700111 */
Jeff Brownd728bf52012-09-08 18:05:28 -0700112public class InputManagerService extends IInputManager.Stub
Jeff Brown4ccb8232014-01-16 22:16:42 -0800113 implements Watchdog.Monitor {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700114 static final String TAG = "InputManager";
Jeff Brown1b9ba572012-05-21 10:54:18 -0700115 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -0700116
Jeff Brown4532e612012-04-05 14:27:12 -0700117 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
118
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700119 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700120 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
121 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
122 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
123 private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
Michael Wright39e5e942015-08-19 22:52:47 +0100124 private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
Yohei Yukawab097b822015-12-01 10:43:08 -0800125 private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700126
Jeff Brown4532e612012-04-05 14:27:12 -0700127 // Pointer to native input manager service object.
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000128 private final long mPtr;
Jeff Brown4532e612012-04-05 14:27:12 -0700129
Jeff Brown46b9ac02010-04-22 18:58:52 -0700130 private final Context mContext;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700131 private final InputManagerHandler mHandler;
Jeff Browna9d131c2012-09-20 16:48:17 -0700132
133 private WindowManagerCallbacks mWindowManagerCallbacks;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700134 private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700135 private boolean mSystemReady;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700136 private NotificationManager mNotificationManager;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700137
Michael Wright39e5e942015-08-19 22:52:47 +0100138 private final Object mTabletModeLock = new Object();
139 // List of currently registered tablet mode changed listeners by process id
140 private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
141 new SparseArray<>(); // guarded by mTabletModeLock
142 private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
143 new ArrayList<>();
144
Jeff Browna3bc5652012-04-17 11:42:25 -0700145 // Persistent data store. Must be locked each time during use.
146 private final PersistentDataStore mDataStore = new PersistentDataStore();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700147
148 // List of currently registered input devices changed listeners by process id.
149 private Object mInputDevicesLock = new Object();
150 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
151 private InputDevice[] mInputDevices = new InputDevice[0];
152 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
153 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
154 private final ArrayList<InputDevicesChangedListenerRecord>
155 mTempInputDevicesChangedListenersToNotify =
156 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
Jeff Browncf39bdf2012-05-18 14:41:19 -0700157 private final ArrayList<InputDevice>
158 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
159 private boolean mKeyboardLayoutNotificationShown;
160 private PendingIntent mKeyboardLayoutIntent;
161 private Toast mSwitchedKeyboardLayoutToast;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700162
Jeff Browna47425a2012-04-13 04:09:27 -0700163 // State for vibrator tokens.
164 private Object mVibratorLock = new Object();
165 private HashMap<IBinder, VibratorToken> mVibratorTokens =
166 new HashMap<IBinder, VibratorToken>();
167 private int mNextVibratorTokenValue;
168
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700169 // State for the currently installed input filter.
170 final Object mInputFilterLock = new Object();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700171 IInputFilter mInputFilter; // guarded by mInputFilterLock
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700172 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
Jeff Brown1a84fd12011-06-02 01:26:32 -0700173
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000174 private static native long nativeInit(InputManagerService service,
Jeff Brown4532e612012-04-05 14:27:12 -0700175 Context context, MessageQueue messageQueue);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000176 private static native void nativeStart(long ptr);
177 private static native void nativeSetDisplayViewport(long ptr, boolean external,
Jeff Brownd728bf52012-09-08 18:05:28 -0700178 int displayId, int rotation,
179 int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
Jeff Brown83d616a2012-09-09 20:33:43 -0700180 int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
181 int deviceWidth, int deviceHeight);
Jeff Brownd728bf52012-09-08 18:05:28 -0700182
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000183 private static native int nativeGetScanCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700184 int deviceId, int sourceMask, int scanCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000185 private static native int nativeGetKeyCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700186 int deviceId, int sourceMask, int keyCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000187 private static native int nativeGetSwitchState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700188 int deviceId, int sourceMask, int sw);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000189 private static native boolean nativeHasKeys(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700190 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000191 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
Jeff Brown928e0542011-01-10 11:17:36 -0800192 InputWindowHandle inputWindowHandle, boolean monitor);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000193 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
194 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
Jeff Brownca9bc702014-02-11 14:32:56 -0800195 private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId,
Jeff Brown0029c662011-03-30 02:25:18 -0700196 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
197 int policyFlags);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000198 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
199 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
200 private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
201 private static native void nativeSetFocusedApplication(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700202 InputApplicationHandle application);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000203 private static native boolean nativeTransferTouchFocus(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700204 InputChannel fromChannel, InputChannel toChannel);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000205 private static native void nativeSetPointerSpeed(long ptr, int speed);
206 private static native void nativeSetShowTouches(long ptr, boolean enabled);
Jeff Brown037c33e2014-04-09 00:31:55 -0700207 private static native void nativeSetInteractive(long ptr, boolean interactive);
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800208 private static native void nativeReloadCalibration(long ptr);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000209 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
Jeff Browna47425a2012-04-13 04:09:27 -0700210 int repeat, int token);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000211 private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
212 private static native void nativeReloadKeyboardLayouts(long ptr);
213 private static native void nativeReloadDeviceAliases(long ptr);
214 private static native String nativeDump(long ptr);
215 private static native void nativeMonitor(long ptr);
Jun Mukai1db53972015-09-11 18:08:31 -0700216 private static native void nativeSetPointerIconShape(long ptr, int iconId);
Jun Mukai19a56012015-11-24 11:25:52 -0800217 private static native void nativeReloadPointerIcons(long ptr);
Jun Mukaid4eaef72015-10-30 15:54:33 -0700218 private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
Jun Mukai347e5d42015-12-03 01:13:31 -0800219 private static native void nativeSetPointerIconDetached(long ptr, boolean detached);
Jeff Brown4532e612012-04-05 14:27:12 -0700220
Jeff Brownac143512012-04-05 18:57:33 -0700221 // Input event injection constants defined in InputDispatcher.h.
222 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
223 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
224 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
225 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
226
227 // Maximum number of milliseconds to wait for input event injection.
228 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
229
Jeff Brown6d0fec22010-07-23 21:28:06 -0700230 // Key states (may be returned by queries about the current state of a
231 // particular key code, scan code or switch).
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700232
Jeff Brown6d0fec22010-07-23 21:28:06 -0700233 /** The key state is unknown or the requested key itself is not supported. */
234 public static final int KEY_STATE_UNKNOWN = -1;
235
236 /** The key is up. /*/
237 public static final int KEY_STATE_UP = 0;
238
239 /** The key is down. */
240 public static final int KEY_STATE_DOWN = 1;
241
242 /** The key is down but is a virtual key press that is being emulated by the system. */
243 public static final int KEY_STATE_VIRTUAL = 2;
244
Jeff Brownc458ce92012-04-30 14:58:40 -0700245 /** Scan code: Mouse / trackball button. */
246 public static final int BTN_MOUSE = 0x110;
247
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700248 // Switch code values must match bionic/libc/kernel/common/linux/input.h
Jeff Brownc458ce92012-04-30 14:58:40 -0700249 /** Switch code: Lid switch. When set, lid is shut. */
250 public static final int SW_LID = 0x00;
251
Michael Wright39e5e942015-08-19 22:52:47 +0100252 /** Switch code: Tablet mode switch.
253 * When set, the device is in tablet mode (i.e. no keyboard is connected).
254 */
255 public static final int SW_TABLET_MODE = 0x01;
256
Jeff Brownc458ce92012-04-30 14:58:40 -0700257 /** Switch code: Keypad slide. When set, keyboard is exposed. */
258 public static final int SW_KEYPAD_SLIDE = 0x0a;
259
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700260 /** Switch code: Headphone. When set, headphone is inserted. */
261 public static final int SW_HEADPHONE_INSERT = 0x02;
262
263 /** Switch code: Microphone. When set, microphone is inserted. */
264 public static final int SW_MICROPHONE_INSERT = 0x04;
265
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500266 /** Switch code: Line out. When set, Line out (hi-Z) is inserted. */
267 public static final int SW_LINEOUT_INSERT = 0x06;
268
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700269 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */
270 public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
271
Michael Wright3818c922014-09-02 13:59:07 -0700272 /** Switch code: Camera lens cover. When set the lens is covered. */
273 public static final int SW_CAMERA_LENS_COVER = 0x09;
274
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700275 public static final int SW_LID_BIT = 1 << SW_LID;
Michael Wright39e5e942015-08-19 22:52:47 +0100276 public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700277 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
278 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
279 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500280 public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700281 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
282 public static final int SW_JACK_BITS =
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500283 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
Michael Wright3818c922014-09-02 13:59:07 -0700284 public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700285
286 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
287 final boolean mUseDevInputEventForAudioJack;
288
Jeff Brown4ccb8232014-01-16 22:16:42 -0800289 public InputManagerService(Context context) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700290 this.mContext = context;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800291 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
Jeff Brown05dc66a2011-03-02 14:41:58 -0800292
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700293 mUseDevInputEventForAudioJack =
294 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
295 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
296 + mUseDevInputEventForAudioJack);
Jeff Brown4532e612012-04-05 14:27:12 -0700297 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown4ccb8232014-01-16 22:16:42 -0800298
299 LocalServices.addService(InputManagerInternal.class, new LocalService());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700300 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700301
Jeff Browna9d131c2012-09-20 16:48:17 -0700302 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
303 mWindowManagerCallbacks = callbacks;
304 }
305
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700306 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
307 mWiredAccessoryCallbacks = callbacks;
308 }
309
Jeff Brown46b9ac02010-04-22 18:58:52 -0700310 public void start() {
311 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700312 nativeStart(mPtr);
313
314 // Add ourself to the Watchdog monitors.
315 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700316
317 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700318 registerShowTouchesSettingObserver();
Jun Mukai19a56012015-11-24 11:25:52 -0800319 registerAccessibilityLargePointerSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700320
Jeff Brownd4935962012-09-25 13:27:20 -0700321 mContext.registerReceiver(new BroadcastReceiver() {
322 @Override
323 public void onReceive(Context context, Intent intent) {
324 updatePointerSpeedFromSettings();
325 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800326 updateAccessibilityLargePointerFromSettings();
Jeff Brownd4935962012-09-25 13:27:20 -0700327 }
328 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
329
Jeff Brown1a84fd12011-06-02 01:26:32 -0700330 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700331 updateShowTouchesFromSettings();
Jun Mukaie4e75da2015-12-15 16:19:20 -0800332 updateAccessibilityLargePointerFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700333 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700334
Matthew Xie96313142012-06-29 16:57:31 -0700335 // TODO(BT) Pass in paramter for bluetooth system
Svetoslav Ganova0027152013-06-25 14:59:53 -0700336 public void systemRunning() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700337 if (DEBUG) {
338 Slog.d(TAG, "System ready.");
339 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700340 mNotificationManager = (NotificationManager)mContext.getSystemService(
341 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700342 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700343
344 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
345 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
346 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Jeff Brown69b07162013-11-07 00:30:16 -0800347 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700348 filter.addDataScheme("package");
349 mContext.registerReceiver(new BroadcastReceiver() {
350 @Override
351 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700352 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700353 }
354 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700355
356 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
357 mContext.registerReceiver(new BroadcastReceiver() {
358 @Override
359 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700360 reloadDeviceAliases();
361 }
362 }, filter, null, mHandler);
363
Jeff Browncf39bdf2012-05-18 14:41:19 -0700364 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
365 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700366
367 if (mWiredAccessoryCallbacks != null) {
368 mWiredAccessoryCallbacks.systemReady();
369 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700370 }
371
372 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700373 if (DEBUG) {
374 Slog.d(TAG, "Reloading keyboard layouts.");
375 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700376 nativeReloadKeyboardLayouts(mPtr);
377 }
378
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700379 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700380 if (DEBUG) {
381 Slog.d(TAG, "Reloading device names.");
382 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700383 nativeReloadDeviceAliases(mPtr);
384 }
385
Jeff Brown4ccb8232014-01-16 22:16:42 -0800386 private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
Jeff Brownd728bf52012-09-08 18:05:28 -0700387 DisplayViewport externalTouchViewport) {
388 if (defaultViewport.valid) {
389 setDisplayViewport(false, defaultViewport);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700390 }
Jeff Brownd728bf52012-09-08 18:05:28 -0700391
392 if (externalTouchViewport.valid) {
393 setDisplayViewport(true, externalTouchViewport);
394 } else if (defaultViewport.valid) {
395 setDisplayViewport(true, defaultViewport);
Jeff Brownb6997262010-10-08 22:31:17 -0700396 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700397 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700398
Jeff Brownd728bf52012-09-08 18:05:28 -0700399 private void setDisplayViewport(boolean external, DisplayViewport viewport) {
400 nativeSetDisplayViewport(mPtr, external,
401 viewport.displayId, viewport.orientation,
402 viewport.logicalFrame.left, viewport.logicalFrame.top,
403 viewport.logicalFrame.right, viewport.logicalFrame.bottom,
404 viewport.physicalFrame.left, viewport.physicalFrame.top,
Jeff Brown83d616a2012-09-09 20:33:43 -0700405 viewport.physicalFrame.right, viewport.physicalFrame.bottom,
406 viewport.deviceWidth, viewport.deviceHeight);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700407 }
Jeff Brownac143512012-04-05 18:57:33 -0700408
Jeff Brown6d0fec22010-07-23 21:28:06 -0700409 /**
410 * Gets the current state of a key or button by key code.
411 * @param deviceId The input device id, or -1 to consult all devices.
412 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
413 * consider all input sources. An input device is consulted if at least one of its
414 * non-class input source bits matches the specified source mask.
415 * @param keyCode The key code to check.
416 * @return The key state.
417 */
418 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700419 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700420 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700421
Jeff Brown6d0fec22010-07-23 21:28:06 -0700422 /**
423 * Gets the current state of a key or button by scan code.
424 * @param deviceId The input device id, or -1 to consult all devices.
425 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
426 * consider all input sources. An input device is consulted if at least one of its
427 * non-class input source bits matches the specified source mask.
428 * @param scanCode The scan code to check.
429 * @return The key state.
430 */
431 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700432 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700433 }
RoboErikfb290df2013-12-16 11:27:55 -0800434
Jeff Brown6d0fec22010-07-23 21:28:06 -0700435 /**
436 * Gets the current state of a switch by switch code.
437 * @param deviceId The input device id, or -1 to consult all devices.
438 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
439 * consider all input sources. An input device is consulted if at least one of its
440 * non-class input source bits matches the specified source mask.
441 * @param switchCode The switch code to check.
442 * @return The switch state.
443 */
444 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700445 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700446 }
447
Jeff Brown6d0fec22010-07-23 21:28:06 -0700448 /**
449 * Determines whether the specified key codes are supported by a particular device.
450 * @param deviceId The input device id, or -1 to consult all devices.
451 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
452 * consider all input sources. An input device is consulted if at least one of its
453 * non-class input source bits matches the specified source mask.
454 * @param keyCodes The array of key codes to check.
455 * @param keyExists An array at least as large as keyCodes whose entries will be set
456 * to true or false based on the presence or absence of support for the corresponding
457 * key codes.
458 * @return True if the lookup was successful, false otherwise.
459 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700460 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700461 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700462 if (keyCodes == null) {
463 throw new IllegalArgumentException("keyCodes must not be null.");
464 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700465 if (keyExists == null || keyExists.length < keyCodes.length) {
466 throw new IllegalArgumentException("keyExists must not be null and must be at "
467 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700468 }
RoboErikfb290df2013-12-16 11:27:55 -0800469
Jeff Brown4532e612012-04-05 14:27:12 -0700470 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700471 }
RoboErikfb290df2013-12-16 11:27:55 -0800472
Jeff Browna41ca772010-08-11 14:46:32 -0700473 /**
474 * Creates an input channel that will receive all input from the input dispatcher.
475 * @param inputChannelName The input channel name.
476 * @return The input channel.
477 */
478 public InputChannel monitorInput(String inputChannelName) {
479 if (inputChannelName == null) {
480 throw new IllegalArgumentException("inputChannelName must not be null.");
481 }
RoboErikfb290df2013-12-16 11:27:55 -0800482
Jeff Browna41ca772010-08-11 14:46:32 -0700483 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700484 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700485 inputChannels[0].dispose(); // don't need to retain the Java object reference
486 return inputChannels[1];
487 }
488
489 /**
490 * Registers an input channel so that it can be used as an input event target.
491 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800492 * @param inputWindowHandle The handle of the input window associated with the
493 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700494 */
Jeff Brown928e0542011-01-10 11:17:36 -0800495 public void registerInputChannel(InputChannel inputChannel,
496 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700497 if (inputChannel == null) {
498 throw new IllegalArgumentException("inputChannel must not be null.");
499 }
RoboErikfb290df2013-12-16 11:27:55 -0800500
Jeff Brown4532e612012-04-05 14:27:12 -0700501 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700502 }
RoboErikfb290df2013-12-16 11:27:55 -0800503
Jeff Browna41ca772010-08-11 14:46:32 -0700504 /**
505 * Unregisters an input channel.
506 * @param inputChannel The input channel to unregister.
507 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700508 public void unregisterInputChannel(InputChannel inputChannel) {
509 if (inputChannel == null) {
510 throw new IllegalArgumentException("inputChannel must not be null.");
511 }
RoboErikfb290df2013-12-16 11:27:55 -0800512
Jeff Brown4532e612012-04-05 14:27:12 -0700513 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700514 }
Jeff Brown0029c662011-03-30 02:25:18 -0700515
516 /**
517 * Sets an input filter that will receive all input events before they are dispatched.
518 * The input filter may then reinterpret input events or inject new ones.
519 *
520 * To ensure consistency, the input dispatcher automatically drops all events
521 * in progress whenever an input filter is installed or uninstalled. After an input
522 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
523 * Any events it attempts to send after it has been uninstalled will be dropped.
524 *
525 * @param filter The input filter, or null to remove the current filter.
526 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700527 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700528 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700529 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700530 if (oldFilter == filter) {
531 return; // nothing to do
532 }
533
534 if (oldFilter != null) {
535 mInputFilter = null;
536 mInputFilterHost.disconnectLocked();
537 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700538 try {
539 oldFilter.uninstall();
540 } catch (RemoteException re) {
541 /* ignore */
542 }
Jeff Brown0029c662011-03-30 02:25:18 -0700543 }
544
545 if (filter != null) {
546 mInputFilter = filter;
547 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700548 try {
549 filter.install(mInputFilterHost);
550 } catch (RemoteException re) {
551 /* ignore */
552 }
Jeff Brown0029c662011-03-30 02:25:18 -0700553 }
554
Jeff Brown4532e612012-04-05 14:27:12 -0700555 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700556 }
557 }
558
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700559 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700560 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brownca9bc702014-02-11 14:32:56 -0800561 return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
562 }
563
564 private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700565 if (event == null) {
566 throw new IllegalArgumentException("event must not be null");
567 }
Jeff Brownac143512012-04-05 18:57:33 -0700568 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
569 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
570 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
571 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700572 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700573
Jeff Brownac143512012-04-05 18:57:33 -0700574 final int pid = Binder.getCallingPid();
575 final int uid = Binder.getCallingUid();
576 final long ident = Binder.clearCallingIdentity();
577 final int result;
578 try {
Jeff Brownca9bc702014-02-11 14:32:56 -0800579 result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
Jeff Brownac143512012-04-05 18:57:33 -0700580 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
581 } finally {
582 Binder.restoreCallingIdentity(ident);
583 }
584 switch (result) {
585 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
586 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
587 throw new SecurityException(
588 "Injecting to another application requires INJECT_EVENTS permission");
589 case INPUT_EVENT_INJECTION_SUCCEEDED:
590 return true;
591 case INPUT_EVENT_INJECTION_TIMED_OUT:
592 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
593 return false;
594 case INPUT_EVENT_INJECTION_FAILED:
595 default:
596 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
597 return false;
598 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700599 }
Jeff Brown0029c662011-03-30 02:25:18 -0700600
Jeff Brown8d608662010-08-30 03:02:23 -0700601 /**
602 * Gets information about the input device with the specified id.
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700603 * @param deviceId The device id.
Jeff Brown8d608662010-08-30 03:02:23 -0700604 * @return The input device or null if not found.
605 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700606 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700607 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700608 synchronized (mInputDevicesLock) {
609 final int count = mInputDevices.length;
610 for (int i = 0; i < count; i++) {
611 final InputDevice inputDevice = mInputDevices[i];
612 if (inputDevice.getId() == deviceId) {
613 return inputDevice;
614 }
615 }
616 }
617 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700618 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700619
Jeff Brown8d608662010-08-30 03:02:23 -0700620 /**
621 * Gets the ids of all input devices in the system.
622 * @return The input device ids.
623 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700624 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700625 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700626 synchronized (mInputDevicesLock) {
627 final int count = mInputDevices.length;
628 int[] ids = new int[count];
629 for (int i = 0; i < count; i++) {
630 ids[i] = mInputDevices[i].getId();
631 }
632 return ids;
633 }
634 }
635
Jeff Browndaa37532012-05-01 15:54:03 -0700636 /**
637 * Gets all input devices in the system.
638 * @return The array of input devices.
639 */
640 public InputDevice[] getInputDevices() {
641 synchronized (mInputDevicesLock) {
642 return mInputDevices;
643 }
644 }
645
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700646 @Override // Binder call
647 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
648 if (listener == null) {
649 throw new IllegalArgumentException("listener must not be null");
650 }
651
652 synchronized (mInputDevicesLock) {
653 int callingPid = Binder.getCallingPid();
654 if (mInputDevicesChangedListeners.get(callingPid) != null) {
655 throw new SecurityException("The calling process has already "
656 + "registered an InputDevicesChangedListener.");
657 }
658
659 InputDevicesChangedListenerRecord record =
660 new InputDevicesChangedListenerRecord(callingPid, listener);
661 try {
662 IBinder binder = listener.asBinder();
663 binder.linkToDeath(record, 0);
664 } catch (RemoteException ex) {
665 // give up
666 throw new RuntimeException(ex);
667 }
668
669 mInputDevicesChangedListeners.put(callingPid, record);
670 }
671 }
672
673 private void onInputDevicesChangedListenerDied(int pid) {
674 synchronized (mInputDevicesLock) {
675 mInputDevicesChangedListeners.remove(pid);
676 }
677 }
678
679 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700680 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
681 // Scan for changes.
682 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700683 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700684 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700685 final int numListeners;
686 final int[] deviceIdAndGeneration;
687 synchronized (mInputDevicesLock) {
688 if (!mInputDevicesChangedPending) {
689 return;
690 }
691 mInputDevicesChangedPending = false;
692
693 numListeners = mInputDevicesChangedListeners.size();
694 for (int i = 0; i < numListeners; i++) {
695 mTempInputDevicesChangedListenersToNotify.add(
696 mInputDevicesChangedListeners.valueAt(i));
697 }
698
699 final int numDevices = mInputDevices.length;
700 deviceIdAndGeneration = new int[numDevices * 2];
701 for (int i = 0; i < numDevices; i++) {
702 final InputDevice inputDevice = mInputDevices[i];
703 deviceIdAndGeneration[i * 2] = inputDevice.getId();
704 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700705
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700706 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700707 if (!containsInputDeviceWithDescriptor(oldInputDevices,
708 inputDevice.getDescriptor())) {
709 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
710 } else {
711 mTempFullKeyboards.add(inputDevice);
712 }
713 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700714 }
715 }
716
Jeff Browncf39bdf2012-05-18 14:41:19 -0700717 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700718 for (int i = 0; i < numListeners; i++) {
719 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
720 deviceIdAndGeneration);
721 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700722 mTempInputDevicesChangedListenersToNotify.clear();
723
724 // Check for missing keyboard layouts.
Michael Wright07483422015-10-30 16:20:13 +0000725 List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
726 final int numFullKeyboards = mTempFullKeyboards.size();
727 synchronized (mDataStore) {
728 for (int i = 0; i < numFullKeyboards; i++) {
729 final InputDevice inputDevice = mTempFullKeyboards.get(i);
730 String layout =
731 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
732 if (layout == null) {
733 layout = getDefaultKeyboardLayout(inputDevice);
734 if (layout != null) {
735 setCurrentKeyboardLayoutForInputDevice(
736 inputDevice.getIdentifier(), layout);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700737 }
738 }
Michael Wright07483422015-10-30 16:20:13 +0000739 if (layout == null) {
740 keyboardsMissingLayout.add(inputDevice);
741 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700742 }
Michael Wright07483422015-10-30 16:20:13 +0000743 }
744
745 if (mNotificationManager != null) {
746 if (!keyboardsMissingLayout.isEmpty()) {
747 if (keyboardsMissingLayout.size() > 1) {
748 // We have more than one keyboard missing a layout, so drop the
749 // user at the generic input methods page so they can pick which
750 // one to set.
751 showMissingKeyboardLayoutNotification(null);
752 } else {
753 showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
Jeff Browncf39bdf2012-05-18 14:41:19 -0700754 }
755 } else if (mKeyboardLayoutNotificationShown) {
756 hideMissingKeyboardLayoutNotification();
757 }
758 }
759 mTempFullKeyboards.clear();
760 }
761
Michael Wright07483422015-10-30 16:20:13 +0000762 private String getDefaultKeyboardLayout(final InputDevice d) {
763 final Locale systemLocale = mContext.getResources().getConfiguration().locale;
764 // If our locale doesn't have a language for some reason, then we don't really have a
765 // reasonable default.
766 if (TextUtils.isEmpty(systemLocale.getLanguage())) {
767 return null;
768 }
769 final List<KeyboardLayout> layouts = new ArrayList<>();
770 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
771 @Override
772 public void visitKeyboardLayout(Resources resources,
773 int keyboardLayoutResId, KeyboardLayout layout) {
774 // Only select a default when we know the layout is appropriate. For now, this
775 // means its a custom layout for a specific keyboard.
776 if (layout.getVendorId() != d.getVendorId()
777 || layout.getProductId() != d.getProductId()) {
778 return;
779 }
780 for (Locale l : layout.getLocales()) {
781 if (isCompatibleLocale(systemLocale, l)) {
782 layouts.add(layout);
783 break;
784 }
785 }
786 }
787 });
788
789 if (layouts.isEmpty()) {
790 return null;
791 }
792
793 // First sort so that ones with higher priority are listed at the top
794 Collections.sort(layouts);
795 // Next we want to try to find an exact match of language, country and variant.
796 final int N = layouts.size();
797 for (int i = 0; i < N; i++) {
798 KeyboardLayout layout = layouts.get(i);
799 for (Locale l : layout.getLocales()) {
800 if (l.getCountry().equals(systemLocale.getCountry())
801 && l.getVariant().equals(systemLocale.getVariant())) {
802 return layout.getDescriptor();
803 }
804 }
805 }
806 // Then try an exact match of language and country
807 for (int i = 0; i < N; i++) {
808 KeyboardLayout layout = layouts.get(i);
809 for (Locale l : layout.getLocales()) {
810 if (l.getCountry().equals(systemLocale.getCountry())) {
811 return layout.getDescriptor();
812 }
813 }
814 }
815
816 // Give up and just use the highest priority layout with matching language
817 return layouts.get(0).getDescriptor();
818 }
819
820 private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
821 // Different languages are never compatible
822 if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
823 return false;
824 }
825 // If both the system and the keyboard layout have a country specifier, they must be equal.
826 if (!TextUtils.isEmpty(systemLocale.getCountry())
827 && !TextUtils.isEmpty(keyboardLocale.getCountry())
828 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
829 return false;
830 }
831 return true;
832 }
833
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800834 @Override // Binder call & native callback
Jason Gerecked5220742014-03-10 09:47:59 -0700835 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
836 int surfaceRotation) {
Jason Gerecked6396d62014-01-27 18:30:37 -0800837 if (inputDeviceDescriptor == null) {
838 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
839 }
840
841 synchronized (mDataStore) {
Jason Gerecked5220742014-03-10 09:47:59 -0700842 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
Jason Gerecked6396d62014-01-27 18:30:37 -0800843 }
844 }
845
846 @Override // Binder call
Jason Gerecked5220742014-03-10 09:47:59 -0700847 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
Jason Gerecked6396d62014-01-27 18:30:37 -0800848 TouchCalibration calibration) {
849 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
850 "setTouchCalibrationForInputDevice()")) {
851 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
852 }
853 if (inputDeviceDescriptor == null) {
854 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
855 }
856 if (calibration == null) {
857 throw new IllegalArgumentException("calibration must not be null");
858 }
Jason Gerecked5220742014-03-10 09:47:59 -0700859 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
860 throw new IllegalArgumentException("surfaceRotation value out of bounds");
861 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800862
863 synchronized (mDataStore) {
864 try {
Jason Gerecked5220742014-03-10 09:47:59 -0700865 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
866 calibration)) {
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800867 nativeReloadCalibration(mPtr);
868 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800869 } finally {
870 mDataStore.saveIfNeeded();
871 }
872 }
873 }
874
Michael Wright39e5e942015-08-19 22:52:47 +0100875 @Override // Binder call
Michael Wright9209c9c2015-09-03 17:57:01 +0100876 public int isInTabletMode() {
877 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
878 "isInTabletMode()")) {
879 throw new SecurityException("Requires TABLET_MODE permission");
880 }
881 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
882 }
883
884 @Override // Binder call
Michael Wright39e5e942015-08-19 22:52:47 +0100885 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
Michael Wright9209c9c2015-09-03 17:57:01 +0100886 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
Michael Wright39e5e942015-08-19 22:52:47 +0100887 "registerTabletModeChangedListener()")) {
888 throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
889 }
890 if (listener == null) {
891 throw new IllegalArgumentException("listener must not be null");
892 }
893
894 synchronized (mTabletModeLock) {
895 final int callingPid = Binder.getCallingPid();
896 if (mTabletModeChangedListeners.get(callingPid) != null) {
897 throw new IllegalStateException("The calling process has already registered "
898 + "a TabletModeChangedListener.");
899 }
900 TabletModeChangedListenerRecord record =
901 new TabletModeChangedListenerRecord(callingPid, listener);
902 try {
903 IBinder binder = listener.asBinder();
904 binder.linkToDeath(record, 0);
905 } catch (RemoteException ex) {
906 throw new RuntimeException(ex);
907 }
908 mTabletModeChangedListeners.put(callingPid, record);
909 }
910 }
911
912 private void onTabletModeChangedListenerDied(int pid) {
913 synchronized (mTabletModeLock) {
914 mTabletModeChangedListeners.remove(pid);
915 }
916 }
917
918 // Must be called on handler
919 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
920 mTempTabletModeChangedListenersToNotify.clear();
921 final int numListeners;
922 synchronized (mTabletModeLock) {
923 numListeners = mTabletModeChangedListeners.size();
924 for (int i = 0; i < numListeners; i++) {
925 mTempTabletModeChangedListenersToNotify.add(
926 mTabletModeChangedListeners.valueAt(i));
927 }
928 }
929 for (int i = 0; i < numListeners; i++) {
930 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
931 whenNanos, inTabletMode);
932 }
933 }
934
Jeff Browncf39bdf2012-05-18 14:41:19 -0700935 // Must be called on handler.
Michael Wrightc93fbd12014-09-22 20:07:59 -0700936 private void showMissingKeyboardLayoutNotification(InputDevice device) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700937 if (!mKeyboardLayoutNotificationShown) {
Michael Wrightc93fbd12014-09-22 20:07:59 -0700938 final Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
939 if (device != null) {
940 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -0700941 }
Michael Wrightc93fbd12014-09-22 20:07:59 -0700942 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
943 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
944 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
945 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
946 intent, 0, null, UserHandle.CURRENT);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700947
948 Resources r = mContext.getResources();
949 Notification notification = new Notification.Builder(mContext)
950 .setContentTitle(r.getString(
951 R.string.select_keyboard_layout_notification_title))
952 .setContentText(r.getString(
953 R.string.select_keyboard_layout_notification_message))
Michael Wrightc93fbd12014-09-22 20:07:59 -0700954 .setContentIntent(keyboardLayoutIntent)
Jeff Browncf39bdf2012-05-18 14:41:19 -0700955 .setSmallIcon(R.drawable.ic_settings_language)
956 .setPriority(Notification.PRIORITY_LOW)
Alan Viverette4a357cd2015-03-18 18:37:18 -0700957 .setColor(mContext.getColor(
Selim Cinek255dd042014-08-19 22:29:02 +0200958 com.android.internal.R.color.system_notification_accent_color))
Jeff Browncf39bdf2012-05-18 14:41:19 -0700959 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700960 mNotificationManager.notifyAsUser(null,
961 R.string.select_keyboard_layout_notification_title,
962 notification, UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700963 mKeyboardLayoutNotificationShown = true;
964 }
965 }
966
967 // Must be called on handler.
968 private void hideMissingKeyboardLayoutNotification() {
969 if (mKeyboardLayoutNotificationShown) {
970 mKeyboardLayoutNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700971 mNotificationManager.cancelAsUser(null,
972 R.string.select_keyboard_layout_notification_title,
973 UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700974 }
975 }
976
977 // Must be called on handler.
978 private void updateKeyboardLayouts() {
979 // Scan all input devices state for keyboard layouts that have been uninstalled.
980 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
981 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
982 @Override
Michael Wright07483422015-10-30 16:20:13 +0000983 public void visitKeyboardLayout(Resources resources,
984 int keyboardLayoutResId, KeyboardLayout layout) {
985 availableKeyboardLayouts.add(layout.getDescriptor());
Jeff Browncf39bdf2012-05-18 14:41:19 -0700986 }
987 });
988 synchronized (mDataStore) {
989 try {
990 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
991 } finally {
992 mDataStore.saveIfNeeded();
993 }
994 }
995
996 // Reload keyboard layouts.
997 reloadKeyboardLayouts();
998 }
999
Jeff Browncf39bdf2012-05-18 14:41:19 -07001000 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
1001 String descriptor) {
1002 final int numDevices = inputDevices.length;
1003 for (int i = 0; i < numDevices; i++) {
1004 final InputDevice inputDevice = inputDevices[i];
1005 if (inputDevice.getDescriptor().equals(descriptor)) {
1006 return true;
1007 }
1008 }
1009 return false;
Jeff Brown8d608662010-08-30 03:02:23 -07001010 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001011
1012 @Override // Binder call
1013 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001014 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
1015 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1016 @Override
Michael Wright07483422015-10-30 16:20:13 +00001017 public void visitKeyboardLayout(Resources resources,
1018 int keyboardLayoutResId, KeyboardLayout layout) {
1019 list.add(layout);
1020 }
1021 });
1022 return list.toArray(new KeyboardLayout[list.size()]);
1023 }
1024
1025 @Override
1026 public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
1027 final InputDeviceIdentifier identifier) {
1028 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
1029 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
1030 boolean mHasSeenDeviceSpecificLayout;
1031
1032 @Override
1033 public void visitKeyboardLayout(Resources resources,
1034 int keyboardLayoutResId, KeyboardLayout layout) {
1035 if (layout.getVendorId() == identifier.getVendorId()
1036 && layout.getProductId() == identifier.getProductId()) {
1037 if (!mHasSeenDeviceSpecificLayout) {
1038 mHasSeenDeviceSpecificLayout = true;
1039 list.clear();
1040 }
1041 list.add(layout);
1042 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
1043 && !mHasSeenDeviceSpecificLayout) {
1044 list.add(layout);
1045 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001046 }
1047 });
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001048 return list.toArray(new KeyboardLayout[list.size()]);
1049 }
1050
1051 @Override // Binder call
1052 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
1053 if (keyboardLayoutDescriptor == null) {
1054 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1055 }
1056
Jeff Brown6ec6f792012-04-17 16:52:41 -07001057 final KeyboardLayout[] result = new KeyboardLayout[1];
1058 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1059 @Override
Michael Wright07483422015-10-30 16:20:13 +00001060 public void visitKeyboardLayout(Resources resources,
1061 int keyboardLayoutResId, KeyboardLayout layout) {
1062 result[0] = layout;
Jeff Brown6ec6f792012-04-17 16:52:41 -07001063 }
1064 });
1065 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00001066 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07001067 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001068 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001069 return result[0];
1070 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001071
Jeff Brown6ec6f792012-04-17 16:52:41 -07001072 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001073 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001074 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
1075 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
Jeff Sharkey5217cac2015-12-20 15:34:01 -07001076 PackageManager.GET_META_DATA | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE)) {
Michael Wright8ebac232014-09-18 18:29:49 -07001077 final ActivityInfo activityInfo = resolveInfo.activityInfo;
1078 final int priority = resolveInfo.priority;
1079 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001080 }
1081 }
1082
Jeff Brown6ec6f792012-04-17 16:52:41 -07001083 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
1084 KeyboardLayoutVisitor visitor) {
1085 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
1086 if (d != null) {
1087 final PackageManager pm = mContext.getPackageManager();
1088 try {
1089 ActivityInfo receiver = pm.getReceiverInfo(
1090 new ComponentName(d.packageName, d.receiverName),
Jeff Sharkey5217cac2015-12-20 15:34:01 -07001091 PackageManager.GET_META_DATA
1092 | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
Michael Wright8ebac232014-09-18 18:29:49 -07001093 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001094 } catch (NameNotFoundException ex) {
1095 }
1096 }
1097 }
1098
1099 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
Michael Wright8ebac232014-09-18 18:29:49 -07001100 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001101 Bundle metaData = receiver.metaData;
1102 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001103 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001104 }
1105
1106 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1107 if (configResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001108 Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001109 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001110 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001111 }
1112
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001113 CharSequence receiverLabel = receiver.loadLabel(pm);
1114 String collection = receiverLabel != null ? receiverLabel.toString() : "";
Michael Wright8ebac232014-09-18 18:29:49 -07001115 int priority;
1116 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1117 priority = requestedPriority;
1118 } else {
1119 priority = 0;
1120 }
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001121
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001122 try {
1123 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1124 XmlResourceParser parser = resources.getXml(configResId);
1125 try {
1126 XmlUtils.beginDocument(parser, "keyboard-layouts");
1127
1128 for (;;) {
1129 XmlUtils.nextElement(parser);
1130 String element = parser.getName();
1131 if (element == null) {
1132 break;
1133 }
1134 if (element.equals("keyboard-layout")) {
1135 TypedArray a = resources.obtainAttributes(
1136 parser, com.android.internal.R.styleable.KeyboardLayout);
1137 try {
1138 String name = a.getString(
1139 com.android.internal.R.styleable.KeyboardLayout_name);
1140 String label = a.getString(
1141 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -07001142 int keyboardLayoutResId = a.getResourceId(
1143 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1144 0);
Michael Wright07483422015-10-30 16:20:13 +00001145 String languageTags = a.getString(
1146 com.android.internal.R.styleable.KeyboardLayout_locale);
1147 Locale[] locales = getLocalesFromLanguageTags(languageTags);
1148 int vid = a.getInt(
1149 com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
1150 int pid = a.getInt(
1151 com.android.internal.R.styleable.KeyboardLayout_productId, -1);
1152
Jeff Brown2f095762012-05-10 21:29:33 -07001153 if (name == null || label == null || keyboardLayoutResId == 0) {
Michael Wright07483422015-10-30 16:20:13 +00001154 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001155 + "attributes in keyboard layout "
1156 + "resource from receiver "
1157 + receiver.packageName + "/" + receiver.name);
1158 } else {
1159 String descriptor = KeyboardLayoutDescriptor.format(
1160 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001161 if (keyboardName == null || name.equals(keyboardName)) {
Michael Wright07483422015-10-30 16:20:13 +00001162 KeyboardLayout layout = new KeyboardLayout(
1163 descriptor, label, collection, priority,
1164 locales, vid, pid);
1165 visitor.visitKeyboardLayout(
1166 resources, keyboardLayoutResId, layout);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001167 }
1168 }
1169 } finally {
1170 a.recycle();
1171 }
1172 } else {
Michael Wright07483422015-10-30 16:20:13 +00001173 Slog.w(TAG, "Skipping unrecognized element '" + element
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001174 + "' in keyboard layout resource from receiver "
1175 + receiver.packageName + "/" + receiver.name);
1176 }
1177 }
1178 } finally {
1179 parser.close();
1180 }
1181 } catch (Exception ex) {
Michael Wright07483422015-10-30 16:20:13 +00001182 Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001183 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001184 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001185 }
1186
Michael Wright07483422015-10-30 16:20:13 +00001187 private static Locale[] getLocalesFromLanguageTags(String languageTags) {
1188 if (TextUtils.isEmpty(languageTags)) {
1189 return new Locale[0];
1190 }
1191 String[] tags = languageTags.split("\\|");
1192 Locale[] locales = new Locale[tags.length];
1193 for (int i = 0; i < tags.length; i++) {
1194 locales[i] = Locale.forLanguageTag(tags[i]);
1195 }
1196 return locales;
1197 }
1198
RoboErikfb290df2013-12-16 11:27:55 -08001199 /**
1200 * Builds a layout descriptor for the vendor/product. This returns the
1201 * descriptor for ids that aren't useful (such as the default 0, 0).
1202 */
1203 private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1204 if (identifier == null || identifier.getDescriptor() == null) {
1205 throw new IllegalArgumentException("identifier and descriptor must not be null");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001206 }
1207
RoboErikfb290df2013-12-16 11:27:55 -08001208 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1209 return identifier.getDescriptor();
1210 }
1211 StringBuilder bob = new StringBuilder();
1212 bob.append("vendor:").append(identifier.getVendorId());
1213 bob.append(",product:").append(identifier.getProductId());
1214 return bob.toString();
1215 }
1216
1217 @Override // Binder call
1218 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1219
1220 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001221 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001222 String layout = null;
1223 // try loading it using the layout descriptor if we have it
1224 layout = mDataStore.getCurrentKeyboardLayout(key);
1225 if (layout == null && !key.equals(identifier.getDescriptor())) {
1226 // if it doesn't exist fall back to the device descriptor
1227 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1228 }
1229 if (DEBUG) {
1230 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1231 + layout);
1232 }
1233 return layout;
Jeff Browna3bc5652012-04-17 11:42:25 -07001234 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001235 }
1236
1237 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001238 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001239 String keyboardLayoutDescriptor) {
1240 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001241 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001242 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1243 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001244 if (keyboardLayoutDescriptor == null) {
1245 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1246 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001247
RoboErikfb290df2013-12-16 11:27:55 -08001248 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001249 synchronized (mDataStore) {
1250 try {
RoboErikfb290df2013-12-16 11:27:55 -08001251 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1252 if (DEBUG) {
1253 Slog.d(TAG, "Saved keyboard layout using " + key);
1254 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001255 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1256 }
Jeff Browna3bc5652012-04-17 11:42:25 -07001257 } finally {
1258 mDataStore.saveIfNeeded();
1259 }
1260 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001261 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001262
Jeff Browncf39bdf2012-05-18 14:41:19 -07001263 @Override // Binder call
Michael Wright07483422015-10-30 16:20:13 +00001264 public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
RoboErikfb290df2013-12-16 11:27:55 -08001265 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001266 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001267 String[] layouts = mDataStore.getKeyboardLayouts(key);
1268 if ((layouts == null || layouts.length == 0)
1269 && !key.equals(identifier.getDescriptor())) {
1270 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1271 }
1272 return layouts;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001273 }
1274 }
1275
1276 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001277 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001278 String keyboardLayoutDescriptor) {
1279 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1280 "addKeyboardLayoutForInputDevice()")) {
1281 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1282 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001283 if (keyboardLayoutDescriptor == null) {
1284 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1285 }
1286
RoboErikfb290df2013-12-16 11:27:55 -08001287 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001288 synchronized (mDataStore) {
1289 try {
RoboErikfb290df2013-12-16 11:27:55 -08001290 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1291 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1292 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1293 }
1294 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
Jeff Browncf39bdf2012-05-18 14:41:19 -07001295 && !Objects.equal(oldLayout,
RoboErikfb290df2013-12-16 11:27:55 -08001296 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001297 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1298 }
1299 } finally {
1300 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001301 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001302 }
1303 }
1304
1305 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001306 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001307 String keyboardLayoutDescriptor) {
1308 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1309 "removeKeyboardLayoutForInputDevice()")) {
1310 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1311 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001312 if (keyboardLayoutDescriptor == null) {
1313 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1314 }
1315
RoboErikfb290df2013-12-16 11:27:55 -08001316 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001317 synchronized (mDataStore) {
1318 try {
RoboErikfb290df2013-12-16 11:27:55 -08001319 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1320 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1321 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1322 }
1323 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1324 if (!key.equals(identifier.getDescriptor())) {
1325 // We need to remove from both places to ensure it is gone
1326 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1327 keyboardLayoutDescriptor);
1328 }
1329 if (removed && !Objects.equal(oldLayout,
1330 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001331 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1332 }
1333 } finally {
1334 mDataStore.saveIfNeeded();
1335 }
1336 }
1337 }
1338
Yohei Yukawab097b822015-12-01 10:43:08 -08001339 // Must be called on handler.
1340 private void handleSwitchInputMethodSubtype(int userId,
1341 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
1342 if (DEBUG) {
1343 Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
1344 + " ime=" + inputMethodInfo + " subtype=" + subtype);
1345 }
1346 }
1347
Jeff Browncf39bdf2012-05-18 14:41:19 -07001348 public void switchKeyboardLayout(int deviceId, int direction) {
1349 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
1350 }
1351
1352 // Must be called on handler.
1353 private void handleSwitchKeyboardLayout(int deviceId, int direction) {
1354 final InputDevice device = getInputDevice(deviceId);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001355 if (device != null) {
1356 final boolean changed;
1357 final String keyboardLayoutDescriptor;
RoboErikfb290df2013-12-16 11:27:55 -08001358
1359 String key = getLayoutDescriptor(device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001360 synchronized (mDataStore) {
1361 try {
RoboErikfb290df2013-12-16 11:27:55 -08001362 changed = mDataStore.switchKeyboardLayout(key, direction);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001363 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
RoboErikfb290df2013-12-16 11:27:55 -08001364 key);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001365 } finally {
1366 mDataStore.saveIfNeeded();
1367 }
1368 }
1369
1370 if (changed) {
1371 if (mSwitchedKeyboardLayoutToast != null) {
1372 mSwitchedKeyboardLayoutToast.cancel();
1373 mSwitchedKeyboardLayoutToast = null;
1374 }
1375 if (keyboardLayoutDescriptor != null) {
1376 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
1377 if (keyboardLayout != null) {
1378 mSwitchedKeyboardLayoutToast = Toast.makeText(
1379 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
1380 mSwitchedKeyboardLayoutToast.show();
1381 }
1382 }
1383
1384 reloadKeyboardLayouts();
1385 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001386 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001387 }
1388
Jeff Brown9302c872011-07-13 22:51:29 -07001389 public void setInputWindows(InputWindowHandle[] windowHandles) {
Jeff Brown4532e612012-04-05 14:27:12 -07001390 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -07001391 }
RoboErikfb290df2013-12-16 11:27:55 -08001392
Jeff Brown9302c872011-07-13 22:51:29 -07001393 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -07001394 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -07001395 }
RoboErikfb290df2013-12-16 11:27:55 -08001396
Jun Mukai347e5d42015-12-03 01:13:31 -08001397 @Override
1398 public void setPointerIconDetached(boolean detached) {
1399 nativeSetPointerIconDetached(mPtr, detached);
1400 }
1401
Jeff Brown349703e2010-06-22 01:27:15 -07001402 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001403 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001404 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001405
1406 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001407 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001408 }
1409
Jeff Browne6504122010-09-27 14:52:15 -07001410 /**
1411 * Atomically transfers touch focus from one window to another as identified by
1412 * their input channels. It is possible for multiple windows to have
1413 * touch focus if they support split touch dispatch
1414 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1415 * method only transfers touch focus of the specified window without affecting
1416 * other windows that may also have touch focus at the same time.
1417 * @param fromChannel The channel of a window that currently has touch focus.
1418 * @param toChannel The channel of the window that should receive touch focus in
1419 * place of the first.
1420 * @return True if the transfer was successful. False if the window with the
1421 * specified channel did not actually have touch focus at the time of the request.
1422 */
1423 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1424 if (fromChannel == null) {
1425 throw new IllegalArgumentException("fromChannel must not be null.");
1426 }
1427 if (toChannel == null) {
1428 throw new IllegalArgumentException("toChannel must not be null.");
1429 }
Jeff Brown4532e612012-04-05 14:27:12 -07001430 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -07001431 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001432
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001433 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001434 public void tryPointerSpeed(int speed) {
1435 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1436 "tryPointerSpeed()")) {
1437 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1438 }
1439
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001440 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1441 throw new IllegalArgumentException("speed out of range");
1442 }
1443
Jeff Brownac143512012-04-05 18:57:33 -07001444 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001445 }
1446
1447 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001448 int speed = getPointerSpeedSetting();
1449 setPointerSpeedUnchecked(speed);
1450 }
1451
1452 private void setPointerSpeedUnchecked(int speed) {
1453 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1454 InputManager.MAX_POINTER_SPEED);
1455 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001456 }
1457
1458 private void registerPointerSpeedSettingObserver() {
1459 mContext.getContentResolver().registerContentObserver(
1460 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001461 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001462 @Override
1463 public void onChange(boolean selfChange) {
1464 updatePointerSpeedFromSettings();
1465 }
Jeff Brownd4935962012-09-25 13:27:20 -07001466 }, UserHandle.USER_ALL);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001467 }
1468
Jeff Brownac143512012-04-05 18:57:33 -07001469 private int getPointerSpeedSetting() {
1470 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001471 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001472 speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1473 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001474 } catch (SettingNotFoundException snfe) {
1475 }
1476 return speed;
1477 }
1478
Jeff Browndaf4a122011-08-26 17:14:14 -07001479 public void updateShowTouchesFromSettings() {
1480 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001481 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001482 }
1483
1484 private void registerShowTouchesSettingObserver() {
1485 mContext.getContentResolver().registerContentObserver(
1486 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001487 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001488 @Override
1489 public void onChange(boolean selfChange) {
1490 updateShowTouchesFromSettings();
1491 }
Jeff Brownd4935962012-09-25 13:27:20 -07001492 }, UserHandle.USER_ALL);
Jeff Browndaf4a122011-08-26 17:14:14 -07001493 }
1494
Jun Mukaie4e75da2015-12-15 16:19:20 -08001495 public void updateAccessibilityLargePointerFromSettings() {
1496 final int accessibilityConfig = Settings.Secure.getIntForUser(
1497 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
1498 0, UserHandle.USER_CURRENT);
1499 PointerIcon.sUseLargeIcons = (accessibilityConfig == 1);
1500 nativeReloadPointerIcons(mPtr);
1501 }
1502
Jun Mukai19a56012015-11-24 11:25:52 -08001503 private void registerAccessibilityLargePointerSettingObserver() {
1504 mContext.getContentResolver().registerContentObserver(
1505 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1506 new ContentObserver(mHandler) {
1507 @Override
1508 public void onChange(boolean selfChange) {
Jun Mukaie4e75da2015-12-15 16:19:20 -08001509 updateAccessibilityLargePointerFromSettings();
Jun Mukai19a56012015-11-24 11:25:52 -08001510 }
1511 }, UserHandle.USER_ALL);
1512 }
1513
Jeff Browndaf4a122011-08-26 17:14:14 -07001514 private int getShowTouchesSetting(int defaultValue) {
1515 int result = defaultValue;
1516 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001517 result = Settings.System.getIntForUser(mContext.getContentResolver(),
1518 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
Jeff Browndaf4a122011-08-26 17:14:14 -07001519 } catch (SettingNotFoundException snfe) {
1520 }
1521 return result;
1522 }
1523
Jeff Browna47425a2012-04-13 04:09:27 -07001524 // Binder call
1525 @Override
1526 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1527 if (repeat >= pattern.length) {
1528 throw new ArrayIndexOutOfBoundsException();
1529 }
1530
1531 VibratorToken v;
1532 synchronized (mVibratorLock) {
1533 v = mVibratorTokens.get(token);
1534 if (v == null) {
1535 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1536 try {
1537 token.linkToDeath(v, 0);
1538 } catch (RemoteException ex) {
1539 // give up
1540 throw new RuntimeException(ex);
1541 }
1542 mVibratorTokens.put(token, v);
1543 }
1544 }
1545
1546 synchronized (v) {
1547 v.mVibrating = true;
1548 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1549 }
1550 }
1551
1552 // Binder call
1553 @Override
1554 public void cancelVibrate(int deviceId, IBinder token) {
1555 VibratorToken v;
1556 synchronized (mVibratorLock) {
1557 v = mVibratorTokens.get(token);
1558 if (v == null || v.mDeviceId != deviceId) {
1559 return; // nothing to cancel
1560 }
1561 }
1562
1563 cancelVibrateIfNeeded(v);
1564 }
1565
1566 void onVibratorTokenDied(VibratorToken v) {
1567 synchronized (mVibratorLock) {
1568 mVibratorTokens.remove(v.mToken);
1569 }
1570
1571 cancelVibrateIfNeeded(v);
1572 }
1573
1574 private void cancelVibrateIfNeeded(VibratorToken v) {
1575 synchronized (v) {
1576 if (v.mVibrating) {
1577 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1578 v.mVibrating = false;
1579 }
1580 }
1581 }
1582
Jun Mukai19a56012015-11-24 11:25:52 -08001583 // Binder call
1584 @Override
1585 public void setPointerIconShape(int iconId) {
1586 nativeSetPointerIconShape(mPtr, iconId);
1587 }
Jun Mukai1db53972015-09-11 18:08:31 -07001588
Jun Mukaid4eaef72015-10-30 15:54:33 -07001589 // Binder call
1590 @Override
1591 public void setCustomPointerIcon(PointerIcon icon) {
1592 nativeSetCustomPointerIcon(mPtr, icon);
1593 }
1594
Jeff Brown4532e612012-04-05 14:27:12 -07001595 @Override
1596 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna3bc5652012-04-17 11:42:25 -07001597 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
Jeff Brown4532e612012-04-05 14:27:12 -07001598 != PackageManager.PERMISSION_GRANTED) {
1599 pw.println("Permission Denial: can't dump InputManager from from pid="
1600 + Binder.getCallingPid()
1601 + ", uid=" + Binder.getCallingUid());
1602 return;
1603 }
1604
1605 pw.println("INPUT MANAGER (dumpsys input)\n");
1606 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001607 if (dumpStr != null) {
1608 pw.println(dumpStr);
1609 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001610 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001611
Jeff Brownac143512012-04-05 18:57:33 -07001612 private boolean checkCallingPermission(String permission, String func) {
1613 // Quick check: if the calling permission is me, it's all okay.
1614 if (Binder.getCallingPid() == Process.myPid()) {
1615 return true;
1616 }
1617
1618 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1619 return true;
1620 }
1621 String msg = "Permission Denial: " + func + " from pid="
1622 + Binder.getCallingPid()
1623 + ", uid=" + Binder.getCallingUid()
1624 + " requires " + permission;
1625 Slog.w(TAG, msg);
1626 return false;
1627 }
1628
Jeff Brown4532e612012-04-05 14:27:12 -07001629 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001630 @Override
Jeff Brown89ef0722011-08-10 16:25:21 -07001631 public void monitor() {
1632 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -07001633 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001634 }
1635
Jeff Brown4532e612012-04-05 14:27:12 -07001636 // Native callback.
1637 private void notifyConfigurationChanged(long whenNanos) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001638 mWindowManagerCallbacks.notifyConfigurationChanged();
Jeff Brown4532e612012-04-05 14:27:12 -07001639 }
1640
1641 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001642 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1643 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001644 if (!mInputDevicesChangedPending) {
1645 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001646 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1647 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001648 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001649
1650 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001651 }
1652 }
1653
1654 // Native callback.
Jeff Brownbcc046a2012-09-27 20:46:43 -07001655 private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1656 if (DEBUG) {
1657 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1658 + ", mask=" + Integer.toHexString(switchMask));
1659 }
1660
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001661 if ((switchMask & SW_LID_BIT) != 0) {
1662 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
Jeff Brownbcc046a2012-09-27 20:46:43 -07001663 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
Jeff Brown53384282012-08-20 20:16:01 -07001664 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001665
Michael Wright3818c922014-09-02 13:59:07 -07001666 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
Michael Wright9e10d252014-09-13 19:41:20 -07001667 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
Michael Wright3818c922014-09-02 13:59:07 -07001668 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1669 }
1670
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001671 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1672 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1673 switchMask);
1674 }
Michael Wright39e5e942015-08-19 22:52:47 +01001675
Michael Wright9209c9c2015-09-03 17:57:01 +01001676 if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
Michael Wright39e5e942015-08-19 22:52:47 +01001677 SomeArgs args = SomeArgs.obtain();
1678 args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
1679 args.argi2 = (int) (whenNanos >> 32);
1680 args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
1681 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
1682 args).sendToTarget();
1683 }
Jeff Brown4532e612012-04-05 14:27:12 -07001684 }
1685
1686 // Native callback.
1687 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001688 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
Jeff Brown4532e612012-04-05 14:27:12 -07001689 }
1690
1691 // Native callback.
1692 private long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001693 InputWindowHandle inputWindowHandle, String reason) {
1694 return mWindowManagerCallbacks.notifyANR(
1695 inputApplicationHandle, inputWindowHandle, reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001696 }
1697
1698 // Native callback.
1699 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1700 synchronized (mInputFilterLock) {
1701 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001702 try {
1703 mInputFilter.filterInputEvent(event, policyFlags);
1704 } catch (RemoteException e) {
1705 /* ignore */
1706 }
Jeff Brown4532e612012-04-05 14:27:12 -07001707 return false;
1708 }
1709 }
1710 event.recycle();
1711 return true;
1712 }
1713
1714 // Native callback.
Jeff Brown037c33e2014-04-09 00:31:55 -07001715 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1716 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001717 }
1718
1719 // Native callback.
Michael Wright70af00a2014-09-03 19:30:20 -07001720 private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
1721 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
Jeff Brown26875502014-01-30 21:47:47 -08001722 whenNanos, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001723 }
1724
1725 // Native callback.
1726 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1727 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001728 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001729 }
1730
1731 // Native callback.
1732 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1733 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001734 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001735 }
1736
1737 // Native callback.
1738 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1739 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1740 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1741 }
1742
1743 // Native callback.
1744 private int getVirtualKeyQuietTimeMillis() {
1745 return mContext.getResources().getInteger(
1746 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1747 }
1748
1749 // Native callback.
1750 private String[] getExcludedDeviceNames() {
1751 ArrayList<String> names = new ArrayList<String>();
1752
1753 // Read partner-provided list of excluded input devices
1754 XmlPullParser parser = null;
1755 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1756 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1757 FileReader confreader = null;
1758 try {
1759 confreader = new FileReader(confFile);
1760 parser = Xml.newPullParser();
1761 parser.setInput(confreader);
1762 XmlUtils.beginDocument(parser, "devices");
1763
1764 while (true) {
1765 XmlUtils.nextElement(parser);
1766 if (!"device".equals(parser.getName())) {
1767 break;
1768 }
1769 String name = parser.getAttributeValue(null, "name");
1770 if (name != null) {
1771 names.add(name);
1772 }
1773 }
1774 } catch (FileNotFoundException e) {
1775 // It's ok if the file does not exist.
1776 } catch (Exception e) {
1777 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1778 } finally {
1779 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1780 }
1781
1782 return names.toArray(new String[names.size()]);
1783 }
1784
1785 // Native callback.
1786 private int getKeyRepeatTimeout() {
1787 return ViewConfiguration.getKeyRepeatTimeout();
1788 }
1789
1790 // Native callback.
1791 private int getKeyRepeatDelay() {
1792 return ViewConfiguration.getKeyRepeatDelay();
1793 }
1794
1795 // Native callback.
1796 private int getHoverTapTimeout() {
1797 return ViewConfiguration.getHoverTapTimeout();
1798 }
1799
1800 // Native callback.
1801 private int getHoverTapSlop() {
1802 return ViewConfiguration.getHoverTapSlop();
1803 }
1804
1805 // Native callback.
1806 private int getDoubleTapTimeout() {
1807 return ViewConfiguration.getDoubleTapTimeout();
1808 }
1809
1810 // Native callback.
1811 private int getLongPressTimeout() {
1812 return ViewConfiguration.getLongPressTimeout();
1813 }
1814
1815 // Native callback.
1816 private int getPointerLayer() {
Jeff Browna9d131c2012-09-20 16:48:17 -07001817 return mWindowManagerCallbacks.getPointerLayer();
Jeff Brown4532e612012-04-05 14:27:12 -07001818 }
1819
1820 // Native callback.
1821 private PointerIcon getPointerIcon() {
1822 return PointerIcon.getDefaultIcon(mContext);
1823 }
1824
Jeff Brown6ec6f792012-04-17 16:52:41 -07001825 // Native callback.
RoboErikfb290df2013-12-16 11:27:55 -08001826 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001827 if (!mSystemReady) {
1828 return null;
1829 }
1830
RoboErikfb290df2013-12-16 11:27:55 -08001831 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001832 if (keyboardLayoutDescriptor == null) {
1833 return null;
1834 }
1835
1836 final String[] result = new String[2];
1837 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1838 @Override
Michael Wright07483422015-10-30 16:20:13 +00001839 public void visitKeyboardLayout(Resources resources,
1840 int keyboardLayoutResId, KeyboardLayout layout) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001841 try {
Michael Wright07483422015-10-30 16:20:13 +00001842 result[0] = layout.getDescriptor();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001843 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07001844 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07001845 } catch (IOException ex) {
1846 } catch (NotFoundException ex) {
1847 }
1848 }
1849 });
1850 if (result[0] == null) {
Michael Wright07483422015-10-30 16:20:13 +00001851 Slog.w(TAG, "Could not get keyboard layout with descriptor '"
Jeff Brown6ec6f792012-04-17 16:52:41 -07001852 + keyboardLayoutDescriptor + "'.");
1853 return null;
1854 }
1855 return result;
1856 }
1857
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001858 // Native callback.
1859 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07001860 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
1861 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
1862 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001863 }
1864 return null;
1865 }
1866
Jeff Brown4532e612012-04-05 14:27:12 -07001867 /**
1868 * Callback interface implemented by the Window Manager.
1869 */
Jeff Browna9d131c2012-09-20 16:48:17 -07001870 public interface WindowManagerCallbacks {
Jeff Brown4532e612012-04-05 14:27:12 -07001871 public void notifyConfigurationChanged();
1872
1873 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
1874
Michael Wright3818c922014-09-02 13:59:07 -07001875 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
1876
Jeff Brown4532e612012-04-05 14:27:12 -07001877 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
1878
1879 public long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001880 InputWindowHandle inputWindowHandle, String reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001881
Jeff Brown037c33e2014-04-09 00:31:55 -07001882 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001883
Michael Wright70af00a2014-09-03 19:30:20 -07001884 public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001885
1886 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
1887 KeyEvent event, int policyFlags);
1888
1889 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1890 KeyEvent event, int policyFlags);
1891
1892 public int getPointerLayer();
1893 }
1894
1895 /**
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001896 * Callback interface implemented by WiredAccessoryObserver.
1897 */
1898 public interface WiredAccessoryCallbacks {
1899 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
Eric Laurent4a5eeb92014-05-06 10:49:04 -07001900 public void systemReady();
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001901 }
1902
1903 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001904 * Private handler for the input manager.
1905 */
1906 private final class InputManagerHandler extends Handler {
Jeff Browna9d131c2012-09-20 16:48:17 -07001907 public InputManagerHandler(Looper looper) {
1908 super(looper, null, true /*async*/);
Jeff Browna2910d02012-08-25 12:29:46 -07001909 }
1910
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001911 @Override
1912 public void handleMessage(Message msg) {
1913 switch (msg.what) {
1914 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07001915 deliverInputDevicesChanged((InputDevice[])msg.obj);
1916 break;
1917 case MSG_SWITCH_KEYBOARD_LAYOUT:
1918 handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
1919 break;
1920 case MSG_RELOAD_KEYBOARD_LAYOUTS:
1921 reloadKeyboardLayouts();
1922 break;
1923 case MSG_UPDATE_KEYBOARD_LAYOUTS:
1924 updateKeyboardLayouts();
1925 break;
1926 case MSG_RELOAD_DEVICE_ALIASES:
1927 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001928 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08001929 case MSG_DELIVER_TABLET_MODE_CHANGED: {
Michael Wright39e5e942015-08-19 22:52:47 +01001930 SomeArgs args = (SomeArgs) msg.obj;
1931 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
1932 boolean inTabletMode = (boolean) args.arg1;
1933 deliverTabletModeChanged(whenNanos, inTabletMode);
1934 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08001935 }
1936 case MSG_INPUT_METHOD_SUBTYPE_CHANGED: {
1937 final int userId = msg.arg1;
1938 final SomeArgs args = (SomeArgs) msg.obj;
1939 final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1;
1940 final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2;
1941 args.recycle();
1942 handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype);
1943 break;
1944 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001945 }
1946 }
1947 }
1948
1949 /**
Jeff Brown4532e612012-04-05 14:27:12 -07001950 * Hosting interface for input filters to call back into the input manager.
1951 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001952 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07001953 private boolean mDisconnected;
1954
1955 public void disconnectLocked() {
1956 mDisconnected = true;
1957 }
1958
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001959 @Override
Jeff Brown0029c662011-03-30 02:25:18 -07001960 public void sendInputEvent(InputEvent event, int policyFlags) {
1961 if (event == null) {
1962 throw new IllegalArgumentException("event must not be null");
1963 }
1964
1965 synchronized (mInputFilterLock) {
1966 if (!mDisconnected) {
Jeff Brownca9bc702014-02-11 14:32:56 -08001967 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
Jeff Brownac143512012-04-05 18:57:33 -07001968 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07001969 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
1970 }
1971 }
1972 }
1973 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001974
1975 private static final class KeyboardLayoutDescriptor {
1976 public String packageName;
1977 public String receiverName;
1978 public String keyboardLayoutName;
1979
1980 public static String format(String packageName,
1981 String receiverName, String keyboardName) {
1982 return packageName + "/" + receiverName + "/" + keyboardName;
1983 }
1984
1985 public static KeyboardLayoutDescriptor parse(String descriptor) {
1986 int pos = descriptor.indexOf('/');
1987 if (pos < 0 || pos + 1 == descriptor.length()) {
1988 return null;
1989 }
1990 int pos2 = descriptor.indexOf('/', pos + 1);
1991 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
1992 return null;
1993 }
1994
1995 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
1996 result.packageName = descriptor.substring(0, pos);
1997 result.receiverName = descriptor.substring(pos + 1, pos2);
1998 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
1999 return result;
2000 }
2001 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002002
Jeff Brown6ec6f792012-04-17 16:52:41 -07002003 private interface KeyboardLayoutVisitor {
Michael Wright07483422015-10-30 16:20:13 +00002004 void visitKeyboardLayout(Resources resources,
2005 int keyboardLayoutResId, KeyboardLayout layout);
Jeff Brown6ec6f792012-04-17 16:52:41 -07002006 }
2007
Jeff Brownaf9e8d32012-04-12 17:32:48 -07002008 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
2009 private final int mPid;
2010 private final IInputDevicesChangedListener mListener;
2011
2012 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
2013 mPid = pid;
2014 mListener = listener;
2015 }
2016
2017 @Override
2018 public void binderDied() {
2019 if (DEBUG) {
2020 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
2021 }
2022 onInputDevicesChangedListenerDied(mPid);
2023 }
2024
2025 public void notifyInputDevicesChanged(int[] info) {
2026 try {
2027 mListener.onInputDevicesChanged(info);
2028 } catch (RemoteException ex) {
2029 Slog.w(TAG, "Failed to notify process "
2030 + mPid + " that input devices changed, assuming it died.", ex);
2031 binderDied();
2032 }
2033 }
2034 }
Jeff Browna47425a2012-04-13 04:09:27 -07002035
Michael Wright39e5e942015-08-19 22:52:47 +01002036 private final class TabletModeChangedListenerRecord implements DeathRecipient {
2037 private final int mPid;
2038 private final ITabletModeChangedListener mListener;
2039
2040 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
2041 mPid = pid;
2042 mListener = listener;
2043 }
2044
2045 @Override
2046 public void binderDied() {
2047 if (DEBUG) {
2048 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
2049 }
2050 onTabletModeChangedListenerDied(mPid);
2051 }
2052
2053 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
2054 try {
2055 mListener.onTabletModeChanged(whenNanos, inTabletMode);
2056 } catch (RemoteException ex) {
2057 Slog.w(TAG, "Failed to notify process " + mPid +
2058 " that tablet mode changed, assuming it died.", ex);
2059 binderDied();
2060 }
2061 }
2062 }
2063
Jeff Browna47425a2012-04-13 04:09:27 -07002064 private final class VibratorToken implements DeathRecipient {
2065 public final int mDeviceId;
2066 public final IBinder mToken;
2067 public final int mTokenValue;
2068
2069 public boolean mVibrating;
2070
2071 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
2072 mDeviceId = deviceId;
2073 mToken = token;
2074 mTokenValue = tokenValue;
2075 }
2076
2077 @Override
2078 public void binderDied() {
2079 if (DEBUG) {
2080 Slog.d(TAG, "Vibrator token died.");
2081 }
2082 onVibratorTokenDied(this);
2083 }
2084 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002085
2086 private final class LocalService extends InputManagerInternal {
2087 @Override
2088 public void setDisplayViewports(
2089 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
2090 setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
2091 }
Jeff Brownca9bc702014-02-11 14:32:56 -08002092
2093 @Override
2094 public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
2095 return injectInputEventInternal(event, displayId, mode);
2096 }
Jeff Brown037c33e2014-04-09 00:31:55 -07002097
2098 @Override
2099 public void setInteractive(boolean interactive) {
2100 nativeSetInteractive(mPtr, interactive);
2101 }
Yohei Yukawab097b822015-12-01 10:43:08 -08002102
2103 @Override
2104 public void onInputMethodSubtypeChanged(int userId,
2105 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
2106 final SomeArgs someArgs = SomeArgs.obtain();
2107 someArgs.arg1 = inputMethodInfo;
2108 someArgs.arg2 = subtype;
2109 mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs)
2110 .sendToTarget();
2111 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08002112 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07002113}