blob: 8b373834a6b36eb5d7e1712110b1fe9966854cd3 [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;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070073import android.util.Log;
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;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700100import java.util.HashMap;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700101import java.util.HashSet;
Michael Wright39e5e942015-08-19 22:52:47 +0100102import java.util.List;
Jeff Browna3bc5652012-04-17 11:42:25 -0700103
Jeff Brown6ec6f792012-04-17 16:52:41 -0700104import libcore.io.Streams;
Jeff Browna3bc5652012-04-17 11:42:25 -0700105import libcore.util.Objects;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700106
107/*
108 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -0700109 */
Jeff Brownd728bf52012-09-08 18:05:28 -0700110public class InputManagerService extends IInputManager.Stub
Jeff Brown4ccb8232014-01-16 22:16:42 -0800111 implements Watchdog.Monitor {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700112 static final String TAG = "InputManager";
Jeff Brown1b9ba572012-05-21 10:54:18 -0700113 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -0700114
Jeff Brown4532e612012-04-05 14:27:12 -0700115 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
116
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700117 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700118 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
119 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
120 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
121 private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
Michael Wright39e5e942015-08-19 22:52:47 +0100122 private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
Yohei Yukawab097b822015-12-01 10:43:08 -0800123 private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700124
Jeff Brown4532e612012-04-05 14:27:12 -0700125 // Pointer to native input manager service object.
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000126 private final long mPtr;
Jeff Brown4532e612012-04-05 14:27:12 -0700127
Jeff Brown46b9ac02010-04-22 18:58:52 -0700128 private final Context mContext;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700129 private final InputManagerHandler mHandler;
Jeff Browna9d131c2012-09-20 16:48:17 -0700130
131 private WindowManagerCallbacks mWindowManagerCallbacks;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700132 private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700133 private boolean mSystemReady;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700134 private NotificationManager mNotificationManager;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700135
Michael Wright39e5e942015-08-19 22:52:47 +0100136 private final Object mTabletModeLock = new Object();
137 // List of currently registered tablet mode changed listeners by process id
138 private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
139 new SparseArray<>(); // guarded by mTabletModeLock
140 private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
141 new ArrayList<>();
142
Jeff Browna3bc5652012-04-17 11:42:25 -0700143 // Persistent data store. Must be locked each time during use.
144 private final PersistentDataStore mDataStore = new PersistentDataStore();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700145
146 // List of currently registered input devices changed listeners by process id.
147 private Object mInputDevicesLock = new Object();
148 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
149 private InputDevice[] mInputDevices = new InputDevice[0];
150 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
151 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
152 private final ArrayList<InputDevicesChangedListenerRecord>
153 mTempInputDevicesChangedListenersToNotify =
154 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
Jeff Browncf39bdf2012-05-18 14:41:19 -0700155 private final ArrayList<InputDevice>
156 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
157 private boolean mKeyboardLayoutNotificationShown;
158 private PendingIntent mKeyboardLayoutIntent;
159 private Toast mSwitchedKeyboardLayoutToast;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700160
Jeff Browna47425a2012-04-13 04:09:27 -0700161 // State for vibrator tokens.
162 private Object mVibratorLock = new Object();
163 private HashMap<IBinder, VibratorToken> mVibratorTokens =
164 new HashMap<IBinder, VibratorToken>();
165 private int mNextVibratorTokenValue;
166
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700167 // State for the currently installed input filter.
168 final Object mInputFilterLock = new Object();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700169 IInputFilter mInputFilter; // guarded by mInputFilterLock
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700170 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
Jeff Brown1a84fd12011-06-02 01:26:32 -0700171
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000172 private static native long nativeInit(InputManagerService service,
Jeff Brown4532e612012-04-05 14:27:12 -0700173 Context context, MessageQueue messageQueue);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000174 private static native void nativeStart(long ptr);
175 private static native void nativeSetDisplayViewport(long ptr, boolean external,
Jeff Brownd728bf52012-09-08 18:05:28 -0700176 int displayId, int rotation,
177 int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
Jeff Brown83d616a2012-09-09 20:33:43 -0700178 int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
179 int deviceWidth, int deviceHeight);
Jeff Brownd728bf52012-09-08 18:05:28 -0700180
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000181 private static native int nativeGetScanCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700182 int deviceId, int sourceMask, int scanCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000183 private static native int nativeGetKeyCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700184 int deviceId, int sourceMask, int keyCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000185 private static native int nativeGetSwitchState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700186 int deviceId, int sourceMask, int sw);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000187 private static native boolean nativeHasKeys(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700188 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000189 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
Jeff Brown928e0542011-01-10 11:17:36 -0800190 InputWindowHandle inputWindowHandle, boolean monitor);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000191 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
192 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
Jeff Brownca9bc702014-02-11 14:32:56 -0800193 private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId,
Jeff Brown0029c662011-03-30 02:25:18 -0700194 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
195 int policyFlags);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000196 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
197 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
198 private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
199 private static native void nativeSetFocusedApplication(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700200 InputApplicationHandle application);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000201 private static native boolean nativeTransferTouchFocus(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700202 InputChannel fromChannel, InputChannel toChannel);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000203 private static native void nativeSetPointerSpeed(long ptr, int speed);
204 private static native void nativeSetShowTouches(long ptr, boolean enabled);
Jeff Brown037c33e2014-04-09 00:31:55 -0700205 private static native void nativeSetInteractive(long ptr, boolean interactive);
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800206 private static native void nativeReloadCalibration(long ptr);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000207 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
Jeff Browna47425a2012-04-13 04:09:27 -0700208 int repeat, int token);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000209 private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
210 private static native void nativeReloadKeyboardLayouts(long ptr);
211 private static native void nativeReloadDeviceAliases(long ptr);
212 private static native String nativeDump(long ptr);
213 private static native void nativeMonitor(long ptr);
Jun Mukai1db53972015-09-11 18:08:31 -0700214 private static native void nativeSetPointerIconShape(long ptr, int iconId);
Jun Mukai19a56012015-11-24 11:25:52 -0800215 private static native void nativeReloadPointerIcons(long ptr);
Jun Mukaid4eaef72015-10-30 15:54:33 -0700216 private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
Jeff Brown4532e612012-04-05 14:27:12 -0700217
Jeff Brownac143512012-04-05 18:57:33 -0700218 // Input event injection constants defined in InputDispatcher.h.
219 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
220 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
221 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
222 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
223
224 // Maximum number of milliseconds to wait for input event injection.
225 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
226
Jeff Brown6d0fec22010-07-23 21:28:06 -0700227 // Key states (may be returned by queries about the current state of a
228 // particular key code, scan code or switch).
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700229
Jeff Brown6d0fec22010-07-23 21:28:06 -0700230 /** The key state is unknown or the requested key itself is not supported. */
231 public static final int KEY_STATE_UNKNOWN = -1;
232
233 /** The key is up. /*/
234 public static final int KEY_STATE_UP = 0;
235
236 /** The key is down. */
237 public static final int KEY_STATE_DOWN = 1;
238
239 /** The key is down but is a virtual key press that is being emulated by the system. */
240 public static final int KEY_STATE_VIRTUAL = 2;
241
Jeff Brownc458ce92012-04-30 14:58:40 -0700242 /** Scan code: Mouse / trackball button. */
243 public static final int BTN_MOUSE = 0x110;
244
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700245 // Switch code values must match bionic/libc/kernel/common/linux/input.h
Jeff Brownc458ce92012-04-30 14:58:40 -0700246 /** Switch code: Lid switch. When set, lid is shut. */
247 public static final int SW_LID = 0x00;
248
Michael Wright39e5e942015-08-19 22:52:47 +0100249 /** Switch code: Tablet mode switch.
250 * When set, the device is in tablet mode (i.e. no keyboard is connected).
251 */
252 public static final int SW_TABLET_MODE = 0x01;
253
Jeff Brownc458ce92012-04-30 14:58:40 -0700254 /** Switch code: Keypad slide. When set, keyboard is exposed. */
255 public static final int SW_KEYPAD_SLIDE = 0x0a;
256
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700257 /** Switch code: Headphone. When set, headphone is inserted. */
258 public static final int SW_HEADPHONE_INSERT = 0x02;
259
260 /** Switch code: Microphone. When set, microphone is inserted. */
261 public static final int SW_MICROPHONE_INSERT = 0x04;
262
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500263 /** Switch code: Line out. When set, Line out (hi-Z) is inserted. */
264 public static final int SW_LINEOUT_INSERT = 0x06;
265
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700266 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */
267 public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
268
Michael Wright3818c922014-09-02 13:59:07 -0700269 /** Switch code: Camera lens cover. When set the lens is covered. */
270 public static final int SW_CAMERA_LENS_COVER = 0x09;
271
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700272 public static final int SW_LID_BIT = 1 << SW_LID;
Michael Wright39e5e942015-08-19 22:52:47 +0100273 public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700274 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
275 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
276 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500277 public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700278 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
279 public static final int SW_JACK_BITS =
Jon Eklund43cc8bb2014-07-28 16:07:24 -0500280 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
Michael Wright3818c922014-09-02 13:59:07 -0700281 public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700282
283 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
284 final boolean mUseDevInputEventForAudioJack;
285
Jeff Brown4ccb8232014-01-16 22:16:42 -0800286 public InputManagerService(Context context) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700287 this.mContext = context;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800288 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
Jeff Brown05dc66a2011-03-02 14:41:58 -0800289
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700290 mUseDevInputEventForAudioJack =
291 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
292 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
293 + mUseDevInputEventForAudioJack);
Jeff Brown4532e612012-04-05 14:27:12 -0700294 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown4ccb8232014-01-16 22:16:42 -0800295
296 LocalServices.addService(InputManagerInternal.class, new LocalService());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700297 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700298
Jeff Browna9d131c2012-09-20 16:48:17 -0700299 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
300 mWindowManagerCallbacks = callbacks;
301 }
302
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700303 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
304 mWiredAccessoryCallbacks = callbacks;
305 }
306
Jeff Brown46b9ac02010-04-22 18:58:52 -0700307 public void start() {
308 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700309 nativeStart(mPtr);
310
311 // Add ourself to the Watchdog monitors.
312 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700313
314 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700315 registerShowTouchesSettingObserver();
Jun Mukai19a56012015-11-24 11:25:52 -0800316 registerAccessibilityLargePointerSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700317
Jeff Brownd4935962012-09-25 13:27:20 -0700318 mContext.registerReceiver(new BroadcastReceiver() {
319 @Override
320 public void onReceive(Context context, Intent intent) {
321 updatePointerSpeedFromSettings();
322 updateShowTouchesFromSettings();
Jun Mukai19a56012015-11-24 11:25:52 -0800323 nativeReloadPointerIcons(mPtr);
Jeff Brownd4935962012-09-25 13:27:20 -0700324 }
325 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
326
Jeff Brown1a84fd12011-06-02 01:26:32 -0700327 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700328 updateShowTouchesFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700329 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700330
Matthew Xie96313142012-06-29 16:57:31 -0700331 // TODO(BT) Pass in paramter for bluetooth system
Svetoslav Ganova0027152013-06-25 14:59:53 -0700332 public void systemRunning() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700333 if (DEBUG) {
334 Slog.d(TAG, "System ready.");
335 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700336 mNotificationManager = (NotificationManager)mContext.getSystemService(
337 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700338 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700339
340 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
341 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
342 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Jeff Brown69b07162013-11-07 00:30:16 -0800343 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700344 filter.addDataScheme("package");
345 mContext.registerReceiver(new BroadcastReceiver() {
346 @Override
347 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700348 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700349 }
350 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700351
352 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
353 mContext.registerReceiver(new BroadcastReceiver() {
354 @Override
355 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700356 reloadDeviceAliases();
357 }
358 }, filter, null, mHandler);
359
Jeff Browncf39bdf2012-05-18 14:41:19 -0700360 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
361 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700362
363 if (mWiredAccessoryCallbacks != null) {
364 mWiredAccessoryCallbacks.systemReady();
365 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700366 }
367
368 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700369 if (DEBUG) {
370 Slog.d(TAG, "Reloading keyboard layouts.");
371 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700372 nativeReloadKeyboardLayouts(mPtr);
373 }
374
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700375 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700376 if (DEBUG) {
377 Slog.d(TAG, "Reloading device names.");
378 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700379 nativeReloadDeviceAliases(mPtr);
380 }
381
Jeff Brown4ccb8232014-01-16 22:16:42 -0800382 private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
Jeff Brownd728bf52012-09-08 18:05:28 -0700383 DisplayViewport externalTouchViewport) {
384 if (defaultViewport.valid) {
385 setDisplayViewport(false, defaultViewport);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700386 }
Jeff Brownd728bf52012-09-08 18:05:28 -0700387
388 if (externalTouchViewport.valid) {
389 setDisplayViewport(true, externalTouchViewport);
390 } else if (defaultViewport.valid) {
391 setDisplayViewport(true, defaultViewport);
Jeff Brownb6997262010-10-08 22:31:17 -0700392 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700393 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700394
Jeff Brownd728bf52012-09-08 18:05:28 -0700395 private void setDisplayViewport(boolean external, DisplayViewport viewport) {
396 nativeSetDisplayViewport(mPtr, external,
397 viewport.displayId, viewport.orientation,
398 viewport.logicalFrame.left, viewport.logicalFrame.top,
399 viewport.logicalFrame.right, viewport.logicalFrame.bottom,
400 viewport.physicalFrame.left, viewport.physicalFrame.top,
Jeff Brown83d616a2012-09-09 20:33:43 -0700401 viewport.physicalFrame.right, viewport.physicalFrame.bottom,
402 viewport.deviceWidth, viewport.deviceHeight);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700403 }
Jeff Brownac143512012-04-05 18:57:33 -0700404
Jeff Brown6d0fec22010-07-23 21:28:06 -0700405 /**
406 * Gets the current state of a key or button by key code.
407 * @param deviceId The input device id, or -1 to consult all devices.
408 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
409 * consider all input sources. An input device is consulted if at least one of its
410 * non-class input source bits matches the specified source mask.
411 * @param keyCode The key code to check.
412 * @return The key state.
413 */
414 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700415 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700416 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700417
Jeff Brown6d0fec22010-07-23 21:28:06 -0700418 /**
419 * Gets the current state of a key or button by scan code.
420 * @param deviceId The input device id, or -1 to consult all devices.
421 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
422 * consider all input sources. An input device is consulted if at least one of its
423 * non-class input source bits matches the specified source mask.
424 * @param scanCode The scan code to check.
425 * @return The key state.
426 */
427 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700428 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700429 }
RoboErikfb290df2013-12-16 11:27:55 -0800430
Jeff Brown6d0fec22010-07-23 21:28:06 -0700431 /**
432 * Gets the current state of a switch by switch code.
433 * @param deviceId The input device id, or -1 to consult all devices.
434 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
435 * consider all input sources. An input device is consulted if at least one of its
436 * non-class input source bits matches the specified source mask.
437 * @param switchCode The switch code to check.
438 * @return The switch state.
439 */
440 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700441 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700442 }
443
Jeff Brown6d0fec22010-07-23 21:28:06 -0700444 /**
445 * Determines whether the specified key codes are supported by a particular device.
446 * @param deviceId The input device id, or -1 to consult all devices.
447 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
448 * consider all input sources. An input device is consulted if at least one of its
449 * non-class input source bits matches the specified source mask.
450 * @param keyCodes The array of key codes to check.
451 * @param keyExists An array at least as large as keyCodes whose entries will be set
452 * to true or false based on the presence or absence of support for the corresponding
453 * key codes.
454 * @return True if the lookup was successful, false otherwise.
455 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700456 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700457 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700458 if (keyCodes == null) {
459 throw new IllegalArgumentException("keyCodes must not be null.");
460 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700461 if (keyExists == null || keyExists.length < keyCodes.length) {
462 throw new IllegalArgumentException("keyExists must not be null and must be at "
463 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700464 }
RoboErikfb290df2013-12-16 11:27:55 -0800465
Jeff Brown4532e612012-04-05 14:27:12 -0700466 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700467 }
RoboErikfb290df2013-12-16 11:27:55 -0800468
Jeff Browna41ca772010-08-11 14:46:32 -0700469 /**
470 * Creates an input channel that will receive all input from the input dispatcher.
471 * @param inputChannelName The input channel name.
472 * @return The input channel.
473 */
474 public InputChannel monitorInput(String inputChannelName) {
475 if (inputChannelName == null) {
476 throw new IllegalArgumentException("inputChannelName must not be null.");
477 }
RoboErikfb290df2013-12-16 11:27:55 -0800478
Jeff Browna41ca772010-08-11 14:46:32 -0700479 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700480 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700481 inputChannels[0].dispose(); // don't need to retain the Java object reference
482 return inputChannels[1];
483 }
484
485 /**
486 * Registers an input channel so that it can be used as an input event target.
487 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800488 * @param inputWindowHandle The handle of the input window associated with the
489 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700490 */
Jeff Brown928e0542011-01-10 11:17:36 -0800491 public void registerInputChannel(InputChannel inputChannel,
492 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700493 if (inputChannel == null) {
494 throw new IllegalArgumentException("inputChannel must not be null.");
495 }
RoboErikfb290df2013-12-16 11:27:55 -0800496
Jeff Brown4532e612012-04-05 14:27:12 -0700497 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700498 }
RoboErikfb290df2013-12-16 11:27:55 -0800499
Jeff Browna41ca772010-08-11 14:46:32 -0700500 /**
501 * Unregisters an input channel.
502 * @param inputChannel The input channel to unregister.
503 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700504 public void unregisterInputChannel(InputChannel inputChannel) {
505 if (inputChannel == null) {
506 throw new IllegalArgumentException("inputChannel must not be null.");
507 }
RoboErikfb290df2013-12-16 11:27:55 -0800508
Jeff Brown4532e612012-04-05 14:27:12 -0700509 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700510 }
Jeff Brown0029c662011-03-30 02:25:18 -0700511
512 /**
513 * Sets an input filter that will receive all input events before they are dispatched.
514 * The input filter may then reinterpret input events or inject new ones.
515 *
516 * To ensure consistency, the input dispatcher automatically drops all events
517 * in progress whenever an input filter is installed or uninstalled. After an input
518 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
519 * Any events it attempts to send after it has been uninstalled will be dropped.
520 *
521 * @param filter The input filter, or null to remove the current filter.
522 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700523 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700524 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700525 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700526 if (oldFilter == filter) {
527 return; // nothing to do
528 }
529
530 if (oldFilter != null) {
531 mInputFilter = null;
532 mInputFilterHost.disconnectLocked();
533 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700534 try {
535 oldFilter.uninstall();
536 } catch (RemoteException re) {
537 /* ignore */
538 }
Jeff Brown0029c662011-03-30 02:25:18 -0700539 }
540
541 if (filter != null) {
542 mInputFilter = filter;
543 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700544 try {
545 filter.install(mInputFilterHost);
546 } catch (RemoteException re) {
547 /* ignore */
548 }
Jeff Brown0029c662011-03-30 02:25:18 -0700549 }
550
Jeff Brown4532e612012-04-05 14:27:12 -0700551 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700552 }
553 }
554
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700555 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700556 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brownca9bc702014-02-11 14:32:56 -0800557 return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
558 }
559
560 private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700561 if (event == null) {
562 throw new IllegalArgumentException("event must not be null");
563 }
Jeff Brownac143512012-04-05 18:57:33 -0700564 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
565 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
566 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
567 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700568 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700569
Jeff Brownac143512012-04-05 18:57:33 -0700570 final int pid = Binder.getCallingPid();
571 final int uid = Binder.getCallingUid();
572 final long ident = Binder.clearCallingIdentity();
573 final int result;
574 try {
Jeff Brownca9bc702014-02-11 14:32:56 -0800575 result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
Jeff Brownac143512012-04-05 18:57:33 -0700576 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
577 } finally {
578 Binder.restoreCallingIdentity(ident);
579 }
580 switch (result) {
581 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
582 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
583 throw new SecurityException(
584 "Injecting to another application requires INJECT_EVENTS permission");
585 case INPUT_EVENT_INJECTION_SUCCEEDED:
586 return true;
587 case INPUT_EVENT_INJECTION_TIMED_OUT:
588 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
589 return false;
590 case INPUT_EVENT_INJECTION_FAILED:
591 default:
592 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
593 return false;
594 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700595 }
Jeff Brown0029c662011-03-30 02:25:18 -0700596
Jeff Brown8d608662010-08-30 03:02:23 -0700597 /**
598 * Gets information about the input device with the specified id.
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700599 * @param deviceId The device id.
Jeff Brown8d608662010-08-30 03:02:23 -0700600 * @return The input device or null if not found.
601 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700602 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700603 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700604 synchronized (mInputDevicesLock) {
605 final int count = mInputDevices.length;
606 for (int i = 0; i < count; i++) {
607 final InputDevice inputDevice = mInputDevices[i];
608 if (inputDevice.getId() == deviceId) {
609 return inputDevice;
610 }
611 }
612 }
613 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700614 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700615
Jeff Brown8d608662010-08-30 03:02:23 -0700616 /**
617 * Gets the ids of all input devices in the system.
618 * @return The input device ids.
619 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700620 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700621 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700622 synchronized (mInputDevicesLock) {
623 final int count = mInputDevices.length;
624 int[] ids = new int[count];
625 for (int i = 0; i < count; i++) {
626 ids[i] = mInputDevices[i].getId();
627 }
628 return ids;
629 }
630 }
631
Jeff Browndaa37532012-05-01 15:54:03 -0700632 /**
633 * Gets all input devices in the system.
634 * @return The array of input devices.
635 */
636 public InputDevice[] getInputDevices() {
637 synchronized (mInputDevicesLock) {
638 return mInputDevices;
639 }
640 }
641
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700642 @Override // Binder call
643 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
644 if (listener == null) {
645 throw new IllegalArgumentException("listener must not be null");
646 }
647
648 synchronized (mInputDevicesLock) {
649 int callingPid = Binder.getCallingPid();
650 if (mInputDevicesChangedListeners.get(callingPid) != null) {
651 throw new SecurityException("The calling process has already "
652 + "registered an InputDevicesChangedListener.");
653 }
654
655 InputDevicesChangedListenerRecord record =
656 new InputDevicesChangedListenerRecord(callingPid, listener);
657 try {
658 IBinder binder = listener.asBinder();
659 binder.linkToDeath(record, 0);
660 } catch (RemoteException ex) {
661 // give up
662 throw new RuntimeException(ex);
663 }
664
665 mInputDevicesChangedListeners.put(callingPid, record);
666 }
667 }
668
669 private void onInputDevicesChangedListenerDied(int pid) {
670 synchronized (mInputDevicesLock) {
671 mInputDevicesChangedListeners.remove(pid);
672 }
673 }
674
675 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700676 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
677 // Scan for changes.
678 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700679 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700680 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700681 final int numListeners;
682 final int[] deviceIdAndGeneration;
683 synchronized (mInputDevicesLock) {
684 if (!mInputDevicesChangedPending) {
685 return;
686 }
687 mInputDevicesChangedPending = false;
688
689 numListeners = mInputDevicesChangedListeners.size();
690 for (int i = 0; i < numListeners; i++) {
691 mTempInputDevicesChangedListenersToNotify.add(
692 mInputDevicesChangedListeners.valueAt(i));
693 }
694
695 final int numDevices = mInputDevices.length;
696 deviceIdAndGeneration = new int[numDevices * 2];
697 for (int i = 0; i < numDevices; i++) {
698 final InputDevice inputDevice = mInputDevices[i];
699 deviceIdAndGeneration[i * 2] = inputDevice.getId();
700 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700701
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700702 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700703 if (!containsInputDeviceWithDescriptor(oldInputDevices,
704 inputDevice.getDescriptor())) {
705 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
706 } else {
707 mTempFullKeyboards.add(inputDevice);
708 }
709 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700710 }
711 }
712
Jeff Browncf39bdf2012-05-18 14:41:19 -0700713 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700714 for (int i = 0; i < numListeners; i++) {
715 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
716 deviceIdAndGeneration);
717 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700718 mTempInputDevicesChangedListenersToNotify.clear();
719
720 // Check for missing keyboard layouts.
721 if (mNotificationManager != null) {
722 final int numFullKeyboards = mTempFullKeyboards.size();
723 boolean missingLayoutForExternalKeyboard = false;
724 boolean missingLayoutForExternalKeyboardAdded = false;
Michael Wrightc93fbd12014-09-22 20:07:59 -0700725 boolean multipleMissingLayoutsForExternalKeyboardsAdded = false;
726 InputDevice keyboardMissingLayout = null;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700727 synchronized (mDataStore) {
728 for (int i = 0; i < numFullKeyboards; i++) {
729 final InputDevice inputDevice = mTempFullKeyboards.get(i);
Michael Wright86aaca62014-09-08 18:54:45 -0700730 final String layout =
731 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
732 if (layout == null) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700733 missingLayoutForExternalKeyboard = true;
734 if (i < numFullKeyboardsAdded) {
735 missingLayoutForExternalKeyboardAdded = true;
Michael Wrightc93fbd12014-09-22 20:07:59 -0700736 if (keyboardMissingLayout == null) {
737 keyboardMissingLayout = inputDevice;
738 } else {
739 multipleMissingLayoutsForExternalKeyboardsAdded = true;
740 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700741 }
742 }
743 }
744 }
745 if (missingLayoutForExternalKeyboard) {
746 if (missingLayoutForExternalKeyboardAdded) {
Michael Wrightc93fbd12014-09-22 20:07:59 -0700747 if (multipleMissingLayoutsForExternalKeyboardsAdded) {
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(keyboardMissingLayout);
754 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700755 }
756 } else if (mKeyboardLayoutNotificationShown) {
757 hideMissingKeyboardLayoutNotification();
758 }
759 }
760 mTempFullKeyboards.clear();
761 }
762
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800763 @Override // Binder call & native callback
Jason Gerecked5220742014-03-10 09:47:59 -0700764 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
765 int surfaceRotation) {
Jason Gerecked6396d62014-01-27 18:30:37 -0800766 if (inputDeviceDescriptor == null) {
767 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
768 }
769
770 synchronized (mDataStore) {
Jason Gerecked5220742014-03-10 09:47:59 -0700771 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation);
Jason Gerecked6396d62014-01-27 18:30:37 -0800772 }
773 }
774
775 @Override // Binder call
Jason Gerecked5220742014-03-10 09:47:59 -0700776 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation,
Jason Gerecked6396d62014-01-27 18:30:37 -0800777 TouchCalibration calibration) {
778 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
779 "setTouchCalibrationForInputDevice()")) {
780 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
781 }
782 if (inputDeviceDescriptor == null) {
783 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
784 }
785 if (calibration == null) {
786 throw new IllegalArgumentException("calibration must not be null");
787 }
Jason Gerecked5220742014-03-10 09:47:59 -0700788 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) {
789 throw new IllegalArgumentException("surfaceRotation value out of bounds");
790 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800791
792 synchronized (mDataStore) {
793 try {
Jason Gerecked5220742014-03-10 09:47:59 -0700794 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation,
795 calibration)) {
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800796 nativeReloadCalibration(mPtr);
797 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800798 } finally {
799 mDataStore.saveIfNeeded();
800 }
801 }
802 }
803
Michael Wright39e5e942015-08-19 22:52:47 +0100804 @Override // Binder call
Michael Wright9209c9c2015-09-03 17:57:01 +0100805 public int isInTabletMode() {
806 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
807 "isInTabletMode()")) {
808 throw new SecurityException("Requires TABLET_MODE permission");
809 }
810 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
811 }
812
813 @Override // Binder call
Michael Wright39e5e942015-08-19 22:52:47 +0100814 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
Michael Wright9209c9c2015-09-03 17:57:01 +0100815 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
Michael Wright39e5e942015-08-19 22:52:47 +0100816 "registerTabletModeChangedListener()")) {
817 throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
818 }
819 if (listener == null) {
820 throw new IllegalArgumentException("listener must not be null");
821 }
822
823 synchronized (mTabletModeLock) {
824 final int callingPid = Binder.getCallingPid();
825 if (mTabletModeChangedListeners.get(callingPid) != null) {
826 throw new IllegalStateException("The calling process has already registered "
827 + "a TabletModeChangedListener.");
828 }
829 TabletModeChangedListenerRecord record =
830 new TabletModeChangedListenerRecord(callingPid, listener);
831 try {
832 IBinder binder = listener.asBinder();
833 binder.linkToDeath(record, 0);
834 } catch (RemoteException ex) {
835 throw new RuntimeException(ex);
836 }
837 mTabletModeChangedListeners.put(callingPid, record);
838 }
839 }
840
841 private void onTabletModeChangedListenerDied(int pid) {
842 synchronized (mTabletModeLock) {
843 mTabletModeChangedListeners.remove(pid);
844 }
845 }
846
847 // Must be called on handler
848 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
849 mTempTabletModeChangedListenersToNotify.clear();
850 final int numListeners;
851 synchronized (mTabletModeLock) {
852 numListeners = mTabletModeChangedListeners.size();
853 for (int i = 0; i < numListeners; i++) {
854 mTempTabletModeChangedListenersToNotify.add(
855 mTabletModeChangedListeners.valueAt(i));
856 }
857 }
858 for (int i = 0; i < numListeners; i++) {
859 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
860 whenNanos, inTabletMode);
861 }
862 }
863
Jeff Browncf39bdf2012-05-18 14:41:19 -0700864 // Must be called on handler.
Michael Wrightc93fbd12014-09-22 20:07:59 -0700865 private void showMissingKeyboardLayoutNotification(InputDevice device) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700866 if (!mKeyboardLayoutNotificationShown) {
Michael Wrightc93fbd12014-09-22 20:07:59 -0700867 final Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
868 if (device != null) {
869 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -0700870 }
Michael Wrightc93fbd12014-09-22 20:07:59 -0700871 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
872 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
873 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
874 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
875 intent, 0, null, UserHandle.CURRENT);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700876
877 Resources r = mContext.getResources();
878 Notification notification = new Notification.Builder(mContext)
879 .setContentTitle(r.getString(
880 R.string.select_keyboard_layout_notification_title))
881 .setContentText(r.getString(
882 R.string.select_keyboard_layout_notification_message))
Michael Wrightc93fbd12014-09-22 20:07:59 -0700883 .setContentIntent(keyboardLayoutIntent)
Jeff Browncf39bdf2012-05-18 14:41:19 -0700884 .setSmallIcon(R.drawable.ic_settings_language)
885 .setPriority(Notification.PRIORITY_LOW)
Alan Viverette4a357cd2015-03-18 18:37:18 -0700886 .setColor(mContext.getColor(
Selim Cinek255dd042014-08-19 22:29:02 +0200887 com.android.internal.R.color.system_notification_accent_color))
Jeff Browncf39bdf2012-05-18 14:41:19 -0700888 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700889 mNotificationManager.notifyAsUser(null,
890 R.string.select_keyboard_layout_notification_title,
891 notification, UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700892 mKeyboardLayoutNotificationShown = true;
893 }
894 }
895
896 // Must be called on handler.
897 private void hideMissingKeyboardLayoutNotification() {
898 if (mKeyboardLayoutNotificationShown) {
899 mKeyboardLayoutNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700900 mNotificationManager.cancelAsUser(null,
901 R.string.select_keyboard_layout_notification_title,
902 UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700903 }
904 }
905
906 // Must be called on handler.
907 private void updateKeyboardLayouts() {
908 // Scan all input devices state for keyboard layouts that have been uninstalled.
909 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
910 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
911 @Override
Michael Wright8ebac232014-09-18 18:29:49 -0700912 public void visitKeyboardLayout(Resources resources, String descriptor, String label,
913 String collection, int keyboardLayoutResId, int priority) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700914 availableKeyboardLayouts.add(descriptor);
915 }
916 });
917 synchronized (mDataStore) {
918 try {
919 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
920 } finally {
921 mDataStore.saveIfNeeded();
922 }
923 }
924
925 // Reload keyboard layouts.
926 reloadKeyboardLayouts();
927 }
928
Jeff Browncf39bdf2012-05-18 14:41:19 -0700929 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
930 String descriptor) {
931 final int numDevices = inputDevices.length;
932 for (int i = 0; i < numDevices; i++) {
933 final InputDevice inputDevice = inputDevices[i];
934 if (inputDevice.getDescriptor().equals(descriptor)) {
935 return true;
936 }
937 }
938 return false;
Jeff Brown8d608662010-08-30 03:02:23 -0700939 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700940
941 @Override // Binder call
942 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700943 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
944 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
945 @Override
Michael Wright8ebac232014-09-18 18:29:49 -0700946 public void visitKeyboardLayout(Resources resources, String descriptor, String label,
947 String collection, int keyboardLayoutResId, int priority) {
948 list.add(new KeyboardLayout(descriptor, label, collection, priority));
Jeff Brown6ec6f792012-04-17 16:52:41 -0700949 }
950 });
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700951 return list.toArray(new KeyboardLayout[list.size()]);
952 }
953
954 @Override // Binder call
955 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
956 if (keyboardLayoutDescriptor == null) {
957 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
958 }
959
Jeff Brown6ec6f792012-04-17 16:52:41 -0700960 final KeyboardLayout[] result = new KeyboardLayout[1];
961 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
962 @Override
Michael Wright8ebac232014-09-18 18:29:49 -0700963 public void visitKeyboardLayout(Resources resources, String descriptor,
964 String label, String collection, int keyboardLayoutResId, int priority) {
965 result[0] = new KeyboardLayout(descriptor, label, collection, priority);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700966 }
967 });
968 if (result[0] == null) {
969 Log.w(TAG, "Could not get keyboard layout with descriptor '"
970 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700971 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700972 return result[0];
973 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700974
Jeff Brown6ec6f792012-04-17 16:52:41 -0700975 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700976 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700977 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
978 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
979 PackageManager.GET_META_DATA)) {
Michael Wright8ebac232014-09-18 18:29:49 -0700980 final ActivityInfo activityInfo = resolveInfo.activityInfo;
981 final int priority = resolveInfo.priority;
982 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700983 }
984 }
985
Jeff Brown6ec6f792012-04-17 16:52:41 -0700986 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
987 KeyboardLayoutVisitor visitor) {
988 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
989 if (d != null) {
990 final PackageManager pm = mContext.getPackageManager();
991 try {
992 ActivityInfo receiver = pm.getReceiverInfo(
993 new ComponentName(d.packageName, d.receiverName),
994 PackageManager.GET_META_DATA);
Michael Wright8ebac232014-09-18 18:29:49 -0700995 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700996 } catch (NameNotFoundException ex) {
997 }
998 }
999 }
1000
1001 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
Michael Wright8ebac232014-09-18 18:29:49 -07001002 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001003 Bundle metaData = receiver.metaData;
1004 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001005 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001006 }
1007
1008 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
1009 if (configResId == 0) {
1010 Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
1011 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001012 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001013 }
1014
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001015 CharSequence receiverLabel = receiver.loadLabel(pm);
1016 String collection = receiverLabel != null ? receiverLabel.toString() : "";
Michael Wright8ebac232014-09-18 18:29:49 -07001017 int priority;
1018 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1019 priority = requestedPriority;
1020 } else {
1021 priority = 0;
1022 }
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001023
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001024 try {
1025 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
1026 XmlResourceParser parser = resources.getXml(configResId);
1027 try {
1028 XmlUtils.beginDocument(parser, "keyboard-layouts");
1029
1030 for (;;) {
1031 XmlUtils.nextElement(parser);
1032 String element = parser.getName();
1033 if (element == null) {
1034 break;
1035 }
1036 if (element.equals("keyboard-layout")) {
1037 TypedArray a = resources.obtainAttributes(
1038 parser, com.android.internal.R.styleable.KeyboardLayout);
1039 try {
1040 String name = a.getString(
1041 com.android.internal.R.styleable.KeyboardLayout_name);
1042 String label = a.getString(
1043 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -07001044 int keyboardLayoutResId = a.getResourceId(
1045 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
1046 0);
1047 if (name == null || label == null || keyboardLayoutResId == 0) {
1048 Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001049 + "attributes in keyboard layout "
1050 + "resource from receiver "
1051 + receiver.packageName + "/" + receiver.name);
1052 } else {
1053 String descriptor = KeyboardLayoutDescriptor.format(
1054 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001055 if (keyboardName == null || name.equals(keyboardName)) {
1056 visitor.visitKeyboardLayout(resources, descriptor,
Michael Wright8ebac232014-09-18 18:29:49 -07001057 label, collection, keyboardLayoutResId, priority);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001058 }
1059 }
1060 } finally {
1061 a.recycle();
1062 }
1063 } else {
1064 Log.w(TAG, "Skipping unrecognized element '" + element
1065 + "' in keyboard layout resource from receiver "
1066 + receiver.packageName + "/" + receiver.name);
1067 }
1068 }
1069 } finally {
1070 parser.close();
1071 }
1072 } catch (Exception ex) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001073 Log.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001074 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001075 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001076 }
1077
RoboErikfb290df2013-12-16 11:27:55 -08001078 /**
1079 * Builds a layout descriptor for the vendor/product. This returns the
1080 * descriptor for ids that aren't useful (such as the default 0, 0).
1081 */
1082 private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
1083 if (identifier == null || identifier.getDescriptor() == null) {
1084 throw new IllegalArgumentException("identifier and descriptor must not be null");
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001085 }
1086
RoboErikfb290df2013-12-16 11:27:55 -08001087 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
1088 return identifier.getDescriptor();
1089 }
1090 StringBuilder bob = new StringBuilder();
1091 bob.append("vendor:").append(identifier.getVendorId());
1092 bob.append(",product:").append(identifier.getProductId());
1093 return bob.toString();
1094 }
1095
1096 @Override // Binder call
1097 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
1098
1099 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001100 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001101 String layout = null;
1102 // try loading it using the layout descriptor if we have it
1103 layout = mDataStore.getCurrentKeyboardLayout(key);
1104 if (layout == null && !key.equals(identifier.getDescriptor())) {
1105 // if it doesn't exist fall back to the device descriptor
1106 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1107 }
1108 if (DEBUG) {
1109 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
1110 + layout);
1111 }
1112 return layout;
Jeff Browna3bc5652012-04-17 11:42:25 -07001113 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001114 }
1115
1116 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001117 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001118 String keyboardLayoutDescriptor) {
1119 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001120 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001121 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1122 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001123 if (keyboardLayoutDescriptor == null) {
1124 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1125 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001126
RoboErikfb290df2013-12-16 11:27:55 -08001127 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -07001128 synchronized (mDataStore) {
1129 try {
RoboErikfb290df2013-12-16 11:27:55 -08001130 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
1131 if (DEBUG) {
1132 Slog.d(TAG, "Saved keyboard layout using " + key);
1133 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001134 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1135 }
Jeff Browna3bc5652012-04-17 11:42:25 -07001136 } finally {
1137 mDataStore.saveIfNeeded();
1138 }
1139 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001140 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001141
Jeff Browncf39bdf2012-05-18 14:41:19 -07001142 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001143 public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
1144 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001145 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001146 String[] layouts = mDataStore.getKeyboardLayouts(key);
1147 if ((layouts == null || layouts.length == 0)
1148 && !key.equals(identifier.getDescriptor())) {
1149 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1150 }
1151 return layouts;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001152 }
1153 }
1154
1155 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001156 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001157 String keyboardLayoutDescriptor) {
1158 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1159 "addKeyboardLayoutForInputDevice()")) {
1160 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1161 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001162 if (keyboardLayoutDescriptor == null) {
1163 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1164 }
1165
RoboErikfb290df2013-12-16 11:27:55 -08001166 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001167 synchronized (mDataStore) {
1168 try {
RoboErikfb290df2013-12-16 11:27:55 -08001169 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1170 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1171 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1172 }
1173 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
Jeff Browncf39bdf2012-05-18 14:41:19 -07001174 && !Objects.equal(oldLayout,
RoboErikfb290df2013-12-16 11:27:55 -08001175 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001176 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1177 }
1178 } finally {
1179 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001180 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001181 }
1182 }
1183
1184 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001185 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001186 String keyboardLayoutDescriptor) {
1187 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1188 "removeKeyboardLayoutForInputDevice()")) {
1189 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1190 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001191 if (keyboardLayoutDescriptor == null) {
1192 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1193 }
1194
RoboErikfb290df2013-12-16 11:27:55 -08001195 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001196 synchronized (mDataStore) {
1197 try {
RoboErikfb290df2013-12-16 11:27:55 -08001198 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1199 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1200 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1201 }
1202 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1203 if (!key.equals(identifier.getDescriptor())) {
1204 // We need to remove from both places to ensure it is gone
1205 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1206 keyboardLayoutDescriptor);
1207 }
1208 if (removed && !Objects.equal(oldLayout,
1209 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001210 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1211 }
1212 } finally {
1213 mDataStore.saveIfNeeded();
1214 }
1215 }
1216 }
1217
Yohei Yukawab097b822015-12-01 10:43:08 -08001218 // Must be called on handler.
1219 private void handleSwitchInputMethodSubtype(int userId,
1220 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
1221 if (DEBUG) {
1222 Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
1223 + " ime=" + inputMethodInfo + " subtype=" + subtype);
1224 }
1225 }
1226
Jeff Browncf39bdf2012-05-18 14:41:19 -07001227 public void switchKeyboardLayout(int deviceId, int direction) {
1228 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
1229 }
1230
1231 // Must be called on handler.
1232 private void handleSwitchKeyboardLayout(int deviceId, int direction) {
1233 final InputDevice device = getInputDevice(deviceId);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001234 if (device != null) {
1235 final boolean changed;
1236 final String keyboardLayoutDescriptor;
RoboErikfb290df2013-12-16 11:27:55 -08001237
1238 String key = getLayoutDescriptor(device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001239 synchronized (mDataStore) {
1240 try {
RoboErikfb290df2013-12-16 11:27:55 -08001241 changed = mDataStore.switchKeyboardLayout(key, direction);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001242 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
RoboErikfb290df2013-12-16 11:27:55 -08001243 key);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001244 } finally {
1245 mDataStore.saveIfNeeded();
1246 }
1247 }
1248
1249 if (changed) {
1250 if (mSwitchedKeyboardLayoutToast != null) {
1251 mSwitchedKeyboardLayoutToast.cancel();
1252 mSwitchedKeyboardLayoutToast = null;
1253 }
1254 if (keyboardLayoutDescriptor != null) {
1255 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
1256 if (keyboardLayout != null) {
1257 mSwitchedKeyboardLayoutToast = Toast.makeText(
1258 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
1259 mSwitchedKeyboardLayoutToast.show();
1260 }
1261 }
1262
1263 reloadKeyboardLayouts();
1264 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001265 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001266 }
1267
Jeff Brown9302c872011-07-13 22:51:29 -07001268 public void setInputWindows(InputWindowHandle[] windowHandles) {
Jeff Brown4532e612012-04-05 14:27:12 -07001269 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -07001270 }
RoboErikfb290df2013-12-16 11:27:55 -08001271
Jeff Brown9302c872011-07-13 22:51:29 -07001272 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -07001273 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -07001274 }
RoboErikfb290df2013-12-16 11:27:55 -08001275
Jeff Brown349703e2010-06-22 01:27:15 -07001276 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001277 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001278 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001279
1280 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001281 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001282 }
1283
Jeff Browne6504122010-09-27 14:52:15 -07001284 /**
1285 * Atomically transfers touch focus from one window to another as identified by
1286 * their input channels. It is possible for multiple windows to have
1287 * touch focus if they support split touch dispatch
1288 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1289 * method only transfers touch focus of the specified window without affecting
1290 * other windows that may also have touch focus at the same time.
1291 * @param fromChannel The channel of a window that currently has touch focus.
1292 * @param toChannel The channel of the window that should receive touch focus in
1293 * place of the first.
1294 * @return True if the transfer was successful. False if the window with the
1295 * specified channel did not actually have touch focus at the time of the request.
1296 */
1297 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1298 if (fromChannel == null) {
1299 throw new IllegalArgumentException("fromChannel must not be null.");
1300 }
1301 if (toChannel == null) {
1302 throw new IllegalArgumentException("toChannel must not be null.");
1303 }
Jeff Brown4532e612012-04-05 14:27:12 -07001304 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -07001305 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001306
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001307 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001308 public void tryPointerSpeed(int speed) {
1309 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1310 "tryPointerSpeed()")) {
1311 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1312 }
1313
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001314 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1315 throw new IllegalArgumentException("speed out of range");
1316 }
1317
Jeff Brownac143512012-04-05 18:57:33 -07001318 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001319 }
1320
1321 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001322 int speed = getPointerSpeedSetting();
1323 setPointerSpeedUnchecked(speed);
1324 }
1325
1326 private void setPointerSpeedUnchecked(int speed) {
1327 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1328 InputManager.MAX_POINTER_SPEED);
1329 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001330 }
1331
1332 private void registerPointerSpeedSettingObserver() {
1333 mContext.getContentResolver().registerContentObserver(
1334 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001335 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001336 @Override
1337 public void onChange(boolean selfChange) {
1338 updatePointerSpeedFromSettings();
1339 }
Jeff Brownd4935962012-09-25 13:27:20 -07001340 }, UserHandle.USER_ALL);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001341 }
1342
Jeff Brownac143512012-04-05 18:57:33 -07001343 private int getPointerSpeedSetting() {
1344 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001345 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001346 speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1347 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001348 } catch (SettingNotFoundException snfe) {
1349 }
1350 return speed;
1351 }
1352
Jeff Browndaf4a122011-08-26 17:14:14 -07001353 public void updateShowTouchesFromSettings() {
1354 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001355 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001356 }
1357
1358 private void registerShowTouchesSettingObserver() {
1359 mContext.getContentResolver().registerContentObserver(
1360 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001361 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001362 @Override
1363 public void onChange(boolean selfChange) {
1364 updateShowTouchesFromSettings();
1365 }
Jeff Brownd4935962012-09-25 13:27:20 -07001366 }, UserHandle.USER_ALL);
Jeff Browndaf4a122011-08-26 17:14:14 -07001367 }
1368
Jun Mukai19a56012015-11-24 11:25:52 -08001369 private void registerAccessibilityLargePointerSettingObserver() {
1370 mContext.getContentResolver().registerContentObserver(
1371 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
1372 new ContentObserver(mHandler) {
1373 @Override
1374 public void onChange(boolean selfChange) {
1375 nativeReloadPointerIcons(mPtr);
1376 }
1377 }, UserHandle.USER_ALL);
1378 }
1379
Jeff Browndaf4a122011-08-26 17:14:14 -07001380 private int getShowTouchesSetting(int defaultValue) {
1381 int result = defaultValue;
1382 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001383 result = Settings.System.getIntForUser(mContext.getContentResolver(),
1384 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
Jeff Browndaf4a122011-08-26 17:14:14 -07001385 } catch (SettingNotFoundException snfe) {
1386 }
1387 return result;
1388 }
1389
Jeff Browna47425a2012-04-13 04:09:27 -07001390 // Binder call
1391 @Override
1392 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1393 if (repeat >= pattern.length) {
1394 throw new ArrayIndexOutOfBoundsException();
1395 }
1396
1397 VibratorToken v;
1398 synchronized (mVibratorLock) {
1399 v = mVibratorTokens.get(token);
1400 if (v == null) {
1401 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1402 try {
1403 token.linkToDeath(v, 0);
1404 } catch (RemoteException ex) {
1405 // give up
1406 throw new RuntimeException(ex);
1407 }
1408 mVibratorTokens.put(token, v);
1409 }
1410 }
1411
1412 synchronized (v) {
1413 v.mVibrating = true;
1414 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1415 }
1416 }
1417
1418 // Binder call
1419 @Override
1420 public void cancelVibrate(int deviceId, IBinder token) {
1421 VibratorToken v;
1422 synchronized (mVibratorLock) {
1423 v = mVibratorTokens.get(token);
1424 if (v == null || v.mDeviceId != deviceId) {
1425 return; // nothing to cancel
1426 }
1427 }
1428
1429 cancelVibrateIfNeeded(v);
1430 }
1431
1432 void onVibratorTokenDied(VibratorToken v) {
1433 synchronized (mVibratorLock) {
1434 mVibratorTokens.remove(v.mToken);
1435 }
1436
1437 cancelVibrateIfNeeded(v);
1438 }
1439
1440 private void cancelVibrateIfNeeded(VibratorToken v) {
1441 synchronized (v) {
1442 if (v.mVibrating) {
1443 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1444 v.mVibrating = false;
1445 }
1446 }
1447 }
1448
Jun Mukai19a56012015-11-24 11:25:52 -08001449 // Binder call
1450 @Override
1451 public void setPointerIconShape(int iconId) {
1452 nativeSetPointerIconShape(mPtr, iconId);
1453 }
Jun Mukai1db53972015-09-11 18:08:31 -07001454
Jun Mukaid4eaef72015-10-30 15:54:33 -07001455 // Binder call
1456 @Override
1457 public void setCustomPointerIcon(PointerIcon icon) {
1458 nativeSetCustomPointerIcon(mPtr, icon);
1459 }
1460
Jeff Brown4532e612012-04-05 14:27:12 -07001461 @Override
1462 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna3bc5652012-04-17 11:42:25 -07001463 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
Jeff Brown4532e612012-04-05 14:27:12 -07001464 != PackageManager.PERMISSION_GRANTED) {
1465 pw.println("Permission Denial: can't dump InputManager from from pid="
1466 + Binder.getCallingPid()
1467 + ", uid=" + Binder.getCallingUid());
1468 return;
1469 }
1470
1471 pw.println("INPUT MANAGER (dumpsys input)\n");
1472 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001473 if (dumpStr != null) {
1474 pw.println(dumpStr);
1475 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001476 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001477
Jeff Brownac143512012-04-05 18:57:33 -07001478 private boolean checkCallingPermission(String permission, String func) {
1479 // Quick check: if the calling permission is me, it's all okay.
1480 if (Binder.getCallingPid() == Process.myPid()) {
1481 return true;
1482 }
1483
1484 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1485 return true;
1486 }
1487 String msg = "Permission Denial: " + func + " from pid="
1488 + Binder.getCallingPid()
1489 + ", uid=" + Binder.getCallingUid()
1490 + " requires " + permission;
1491 Slog.w(TAG, msg);
1492 return false;
1493 }
1494
Jeff Brown4532e612012-04-05 14:27:12 -07001495 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001496 @Override
Jeff Brown89ef0722011-08-10 16:25:21 -07001497 public void monitor() {
1498 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -07001499 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001500 }
1501
Jeff Brown4532e612012-04-05 14:27:12 -07001502 // Native callback.
1503 private void notifyConfigurationChanged(long whenNanos) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001504 mWindowManagerCallbacks.notifyConfigurationChanged();
Jeff Brown4532e612012-04-05 14:27:12 -07001505 }
1506
1507 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001508 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1509 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001510 if (!mInputDevicesChangedPending) {
1511 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001512 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1513 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001514 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001515
1516 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001517 }
1518 }
1519
1520 // Native callback.
Jeff Brownbcc046a2012-09-27 20:46:43 -07001521 private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1522 if (DEBUG) {
1523 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1524 + ", mask=" + Integer.toHexString(switchMask));
1525 }
1526
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001527 if ((switchMask & SW_LID_BIT) != 0) {
1528 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
Jeff Brownbcc046a2012-09-27 20:46:43 -07001529 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
Jeff Brown53384282012-08-20 20:16:01 -07001530 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001531
Michael Wright3818c922014-09-02 13:59:07 -07001532 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
Michael Wright9e10d252014-09-13 19:41:20 -07001533 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
Michael Wright3818c922014-09-02 13:59:07 -07001534 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
1535 }
1536
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001537 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1538 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1539 switchMask);
1540 }
Michael Wright39e5e942015-08-19 22:52:47 +01001541
Michael Wright9209c9c2015-09-03 17:57:01 +01001542 if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
Michael Wright39e5e942015-08-19 22:52:47 +01001543 SomeArgs args = SomeArgs.obtain();
1544 args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
1545 args.argi2 = (int) (whenNanos >> 32);
1546 args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
1547 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
1548 args).sendToTarget();
1549 }
Jeff Brown4532e612012-04-05 14:27:12 -07001550 }
1551
1552 // Native callback.
1553 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001554 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
Jeff Brown4532e612012-04-05 14:27:12 -07001555 }
1556
1557 // Native callback.
1558 private long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001559 InputWindowHandle inputWindowHandle, String reason) {
1560 return mWindowManagerCallbacks.notifyANR(
1561 inputApplicationHandle, inputWindowHandle, reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001562 }
1563
1564 // Native callback.
1565 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1566 synchronized (mInputFilterLock) {
1567 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001568 try {
1569 mInputFilter.filterInputEvent(event, policyFlags);
1570 } catch (RemoteException e) {
1571 /* ignore */
1572 }
Jeff Brown4532e612012-04-05 14:27:12 -07001573 return false;
1574 }
1575 }
1576 event.recycle();
1577 return true;
1578 }
1579
1580 // Native callback.
Jeff Brown037c33e2014-04-09 00:31:55 -07001581 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1582 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001583 }
1584
1585 // Native callback.
Michael Wright70af00a2014-09-03 19:30:20 -07001586 private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
1587 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
Jeff Brown26875502014-01-30 21:47:47 -08001588 whenNanos, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001589 }
1590
1591 // Native callback.
1592 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1593 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001594 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001595 }
1596
1597 // Native callback.
1598 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1599 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001600 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001601 }
1602
1603 // Native callback.
1604 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1605 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1606 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1607 }
1608
1609 // Native callback.
1610 private int getVirtualKeyQuietTimeMillis() {
1611 return mContext.getResources().getInteger(
1612 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1613 }
1614
1615 // Native callback.
1616 private String[] getExcludedDeviceNames() {
1617 ArrayList<String> names = new ArrayList<String>();
1618
1619 // Read partner-provided list of excluded input devices
1620 XmlPullParser parser = null;
1621 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1622 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1623 FileReader confreader = null;
1624 try {
1625 confreader = new FileReader(confFile);
1626 parser = Xml.newPullParser();
1627 parser.setInput(confreader);
1628 XmlUtils.beginDocument(parser, "devices");
1629
1630 while (true) {
1631 XmlUtils.nextElement(parser);
1632 if (!"device".equals(parser.getName())) {
1633 break;
1634 }
1635 String name = parser.getAttributeValue(null, "name");
1636 if (name != null) {
1637 names.add(name);
1638 }
1639 }
1640 } catch (FileNotFoundException e) {
1641 // It's ok if the file does not exist.
1642 } catch (Exception e) {
1643 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1644 } finally {
1645 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1646 }
1647
1648 return names.toArray(new String[names.size()]);
1649 }
1650
1651 // Native callback.
1652 private int getKeyRepeatTimeout() {
1653 return ViewConfiguration.getKeyRepeatTimeout();
1654 }
1655
1656 // Native callback.
1657 private int getKeyRepeatDelay() {
1658 return ViewConfiguration.getKeyRepeatDelay();
1659 }
1660
1661 // Native callback.
1662 private int getHoverTapTimeout() {
1663 return ViewConfiguration.getHoverTapTimeout();
1664 }
1665
1666 // Native callback.
1667 private int getHoverTapSlop() {
1668 return ViewConfiguration.getHoverTapSlop();
1669 }
1670
1671 // Native callback.
1672 private int getDoubleTapTimeout() {
1673 return ViewConfiguration.getDoubleTapTimeout();
1674 }
1675
1676 // Native callback.
1677 private int getLongPressTimeout() {
1678 return ViewConfiguration.getLongPressTimeout();
1679 }
1680
1681 // Native callback.
1682 private int getPointerLayer() {
Jeff Browna9d131c2012-09-20 16:48:17 -07001683 return mWindowManagerCallbacks.getPointerLayer();
Jeff Brown4532e612012-04-05 14:27:12 -07001684 }
1685
1686 // Native callback.
1687 private PointerIcon getPointerIcon() {
1688 return PointerIcon.getDefaultIcon(mContext);
1689 }
1690
Jeff Brown6ec6f792012-04-17 16:52:41 -07001691 // Native callback.
RoboErikfb290df2013-12-16 11:27:55 -08001692 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001693 if (!mSystemReady) {
1694 return null;
1695 }
1696
RoboErikfb290df2013-12-16 11:27:55 -08001697 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001698 if (keyboardLayoutDescriptor == null) {
1699 return null;
1700 }
1701
1702 final String[] result = new String[2];
1703 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1704 @Override
Michael Wright8ebac232014-09-18 18:29:49 -07001705 public void visitKeyboardLayout(Resources resources, String descriptor, String label,
1706 String collection, int keyboardLayoutResId, int priority) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001707 try {
1708 result[0] = descriptor;
1709 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07001710 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07001711 } catch (IOException ex) {
1712 } catch (NotFoundException ex) {
1713 }
1714 }
1715 });
1716 if (result[0] == null) {
1717 Log.w(TAG, "Could not get keyboard layout with descriptor '"
1718 + keyboardLayoutDescriptor + "'.");
1719 return null;
1720 }
1721 return result;
1722 }
1723
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001724 // Native callback.
1725 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07001726 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
1727 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
1728 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001729 }
1730 return null;
1731 }
1732
Jeff Brown4532e612012-04-05 14:27:12 -07001733 /**
1734 * Callback interface implemented by the Window Manager.
1735 */
Jeff Browna9d131c2012-09-20 16:48:17 -07001736 public interface WindowManagerCallbacks {
Jeff Brown4532e612012-04-05 14:27:12 -07001737 public void notifyConfigurationChanged();
1738
1739 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
1740
Michael Wright3818c922014-09-02 13:59:07 -07001741 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
1742
Jeff Brown4532e612012-04-05 14:27:12 -07001743 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
1744
1745 public long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001746 InputWindowHandle inputWindowHandle, String reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001747
Jeff Brown037c33e2014-04-09 00:31:55 -07001748 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001749
Michael Wright70af00a2014-09-03 19:30:20 -07001750 public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001751
1752 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
1753 KeyEvent event, int policyFlags);
1754
1755 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1756 KeyEvent event, int policyFlags);
1757
1758 public int getPointerLayer();
1759 }
1760
1761 /**
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001762 * Callback interface implemented by WiredAccessoryObserver.
1763 */
1764 public interface WiredAccessoryCallbacks {
1765 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
Eric Laurent4a5eeb92014-05-06 10:49:04 -07001766 public void systemReady();
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001767 }
1768
1769 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001770 * Private handler for the input manager.
1771 */
1772 private final class InputManagerHandler extends Handler {
Jeff Browna9d131c2012-09-20 16:48:17 -07001773 public InputManagerHandler(Looper looper) {
1774 super(looper, null, true /*async*/);
Jeff Browna2910d02012-08-25 12:29:46 -07001775 }
1776
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001777 @Override
1778 public void handleMessage(Message msg) {
1779 switch (msg.what) {
1780 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07001781 deliverInputDevicesChanged((InputDevice[])msg.obj);
1782 break;
1783 case MSG_SWITCH_KEYBOARD_LAYOUT:
1784 handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
1785 break;
1786 case MSG_RELOAD_KEYBOARD_LAYOUTS:
1787 reloadKeyboardLayouts();
1788 break;
1789 case MSG_UPDATE_KEYBOARD_LAYOUTS:
1790 updateKeyboardLayouts();
1791 break;
1792 case MSG_RELOAD_DEVICE_ALIASES:
1793 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001794 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08001795 case MSG_DELIVER_TABLET_MODE_CHANGED: {
Michael Wright39e5e942015-08-19 22:52:47 +01001796 SomeArgs args = (SomeArgs) msg.obj;
1797 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
1798 boolean inTabletMode = (boolean) args.arg1;
1799 deliverTabletModeChanged(whenNanos, inTabletMode);
1800 break;
Yohei Yukawab097b822015-12-01 10:43:08 -08001801 }
1802 case MSG_INPUT_METHOD_SUBTYPE_CHANGED: {
1803 final int userId = msg.arg1;
1804 final SomeArgs args = (SomeArgs) msg.obj;
1805 final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1;
1806 final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2;
1807 args.recycle();
1808 handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype);
1809 break;
1810 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001811 }
1812 }
1813 }
1814
1815 /**
Jeff Brown4532e612012-04-05 14:27:12 -07001816 * Hosting interface for input filters to call back into the input manager.
1817 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001818 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07001819 private boolean mDisconnected;
1820
1821 public void disconnectLocked() {
1822 mDisconnected = true;
1823 }
1824
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001825 @Override
Jeff Brown0029c662011-03-30 02:25:18 -07001826 public void sendInputEvent(InputEvent event, int policyFlags) {
1827 if (event == null) {
1828 throw new IllegalArgumentException("event must not be null");
1829 }
1830
1831 synchronized (mInputFilterLock) {
1832 if (!mDisconnected) {
Jeff Brownca9bc702014-02-11 14:32:56 -08001833 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
Jeff Brownac143512012-04-05 18:57:33 -07001834 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07001835 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
1836 }
1837 }
1838 }
1839 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001840
1841 private static final class KeyboardLayoutDescriptor {
1842 public String packageName;
1843 public String receiverName;
1844 public String keyboardLayoutName;
1845
1846 public static String format(String packageName,
1847 String receiverName, String keyboardName) {
1848 return packageName + "/" + receiverName + "/" + keyboardName;
1849 }
1850
1851 public static KeyboardLayoutDescriptor parse(String descriptor) {
1852 int pos = descriptor.indexOf('/');
1853 if (pos < 0 || pos + 1 == descriptor.length()) {
1854 return null;
1855 }
1856 int pos2 = descriptor.indexOf('/', pos + 1);
1857 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
1858 return null;
1859 }
1860
1861 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
1862 result.packageName = descriptor.substring(0, pos);
1863 result.receiverName = descriptor.substring(pos + 1, pos2);
1864 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
1865 return result;
1866 }
1867 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001868
Jeff Brown6ec6f792012-04-17 16:52:41 -07001869 private interface KeyboardLayoutVisitor {
Michael Wright8ebac232014-09-18 18:29:49 -07001870 void visitKeyboardLayout(Resources resources, String descriptor, String label,
1871 String collection, int keyboardLayoutResId, int priority);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001872 }
1873
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001874 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
1875 private final int mPid;
1876 private final IInputDevicesChangedListener mListener;
1877
1878 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
1879 mPid = pid;
1880 mListener = listener;
1881 }
1882
1883 @Override
1884 public void binderDied() {
1885 if (DEBUG) {
1886 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
1887 }
1888 onInputDevicesChangedListenerDied(mPid);
1889 }
1890
1891 public void notifyInputDevicesChanged(int[] info) {
1892 try {
1893 mListener.onInputDevicesChanged(info);
1894 } catch (RemoteException ex) {
1895 Slog.w(TAG, "Failed to notify process "
1896 + mPid + " that input devices changed, assuming it died.", ex);
1897 binderDied();
1898 }
1899 }
1900 }
Jeff Browna47425a2012-04-13 04:09:27 -07001901
Michael Wright39e5e942015-08-19 22:52:47 +01001902 private final class TabletModeChangedListenerRecord implements DeathRecipient {
1903 private final int mPid;
1904 private final ITabletModeChangedListener mListener;
1905
1906 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
1907 mPid = pid;
1908 mListener = listener;
1909 }
1910
1911 @Override
1912 public void binderDied() {
1913 if (DEBUG) {
1914 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
1915 }
1916 onTabletModeChangedListenerDied(mPid);
1917 }
1918
1919 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
1920 try {
1921 mListener.onTabletModeChanged(whenNanos, inTabletMode);
1922 } catch (RemoteException ex) {
1923 Slog.w(TAG, "Failed to notify process " + mPid +
1924 " that tablet mode changed, assuming it died.", ex);
1925 binderDied();
1926 }
1927 }
1928 }
1929
Jeff Browna47425a2012-04-13 04:09:27 -07001930 private final class VibratorToken implements DeathRecipient {
1931 public final int mDeviceId;
1932 public final IBinder mToken;
1933 public final int mTokenValue;
1934
1935 public boolean mVibrating;
1936
1937 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
1938 mDeviceId = deviceId;
1939 mToken = token;
1940 mTokenValue = tokenValue;
1941 }
1942
1943 @Override
1944 public void binderDied() {
1945 if (DEBUG) {
1946 Slog.d(TAG, "Vibrator token died.");
1947 }
1948 onVibratorTokenDied(this);
1949 }
1950 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08001951
1952 private final class LocalService extends InputManagerInternal {
1953 @Override
1954 public void setDisplayViewports(
1955 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
1956 setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
1957 }
Jeff Brownca9bc702014-02-11 14:32:56 -08001958
1959 @Override
1960 public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
1961 return injectInputEventInternal(event, displayId, mode);
1962 }
Jeff Brown037c33e2014-04-09 00:31:55 -07001963
1964 @Override
1965 public void setInteractive(boolean interactive) {
1966 nativeSetInteractive(mPtr, interactive);
1967 }
Yohei Yukawab097b822015-12-01 10:43:08 -08001968
1969 @Override
1970 public void onInputMethodSubtypeChanged(int userId,
1971 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) {
1972 final SomeArgs someArgs = SomeArgs.obtain();
1973 someArgs.arg1 = inputMethodInfo;
1974 someArgs.arg2 = subtype;
1975 mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs)
1976 .sendToTarget();
1977 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08001978 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001979}