blob: 69d8442fa2f10d3ed64750539805a2a91999aeaa [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
Jeff Brownca9bc702014-02-11 14:32:56 -080019import android.view.Display;
Jeff Browncf39bdf2012-05-18 14:41:19 -070020import com.android.internal.R;
Jeff Brown46b9ac02010-04-22 18:58:52 -070021import com.android.internal.util.XmlUtils;
Jeff Brown4ccb8232014-01-16 22:16:42 -080022import com.android.server.DisplayThread;
23import com.android.server.LocalServices;
Jeff Brown89ef0722011-08-10 16:25:21 -070024import com.android.server.Watchdog;
Jeff Brown46b9ac02010-04-22 18:58:52 -070025
26import org.xmlpull.v1.XmlPullParser;
27
Jeff Browna3bc5652012-04-17 11:42:25 -070028import android.Manifest;
Jeff Browncf39bdf2012-05-18 14:41:19 -070029import android.app.Notification;
30import android.app.NotificationManager;
31import android.app.PendingIntent;
Jeff Brown5bbd4b42012-04-20 19:28:00 -070032import android.bluetooth.BluetoothAdapter;
33import android.bluetooth.BluetoothDevice;
Jeff Brown6ec6f792012-04-17 16:52:41 -070034import android.content.BroadcastReceiver;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070035import android.content.ComponentName;
Jeff Brown46b9ac02010-04-22 18:58:52 -070036import android.content.Context;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070037import android.content.Intent;
Jeff Brown6ec6f792012-04-17 16:52:41 -070038import android.content.IntentFilter;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070039import android.content.pm.ActivityInfo;
Jeff Brown349703e2010-06-22 01:27:15 -070040import android.content.pm.PackageManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070041import android.content.pm.ResolveInfo;
42import android.content.pm.PackageManager.NameNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070043import android.content.res.Resources;
Jeff Brown6ec6f792012-04-17 16:52:41 -070044import android.content.res.Resources.NotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070045import android.content.res.TypedArray;
46import android.content.res.XmlResourceParser;
Jeff Brown1a84fd12011-06-02 01:26:32 -070047import android.database.ContentObserver;
Jeff Brown4ccb8232014-01-16 22:16:42 -080048import android.hardware.display.DisplayViewport;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070049import android.hardware.input.IInputDevicesChangedListener;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070050import android.hardware.input.IInputManager;
RoboErikfb290df2013-12-16 11:27:55 -080051import android.hardware.input.InputDeviceIdentifier;
Jeff Brownac143512012-04-05 18:57:33 -070052import android.hardware.input.InputManager;
Jeff Brown4ccb8232014-01-16 22:16:42 -080053import android.hardware.input.InputManagerInternal;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070054import android.hardware.input.KeyboardLayout;
Jason Gerecked6396d62014-01-27 18:30:37 -080055import android.hardware.input.TouchCalibration;
Jeff Brown4532e612012-04-05 14:27:12 -070056import android.os.Binder;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070057import android.os.Bundle;
Jeff Brown46b9ac02010-04-22 18:58:52 -070058import android.os.Environment;
Jeff Brown4532e612012-04-05 14:27:12 -070059import android.os.Handler;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070060import android.os.IBinder;
Jeff Browna9d131c2012-09-20 16:48:17 -070061import android.os.Looper;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070062import android.os.Message;
Jeff Brown05dc66a2011-03-02 14:41:58 -080063import android.os.MessageQueue;
Jeff Brownac143512012-04-05 18:57:33 -070064import android.os.Process;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070065import android.os.RemoteException;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070066import android.os.UserHandle;
Jeff Brown1a84fd12011-06-02 01:26:32 -070067import android.provider.Settings;
68import android.provider.Settings.SettingNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070069import android.util.Log;
Jeff Brown46b9ac02010-04-22 18:58:52 -070070import android.util.Slog;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070071import android.util.SparseArray;
Jeff Brown46b9ac02010-04-22 18:58:52 -070072import android.util.Xml;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070073import android.view.IInputFilter;
74import android.view.IInputFilterHost;
Jeff Brown46b9ac02010-04-22 18:58:52 -070075import android.view.InputChannel;
Jeff Brown8d608662010-08-30 03:02:23 -070076import android.view.InputDevice;
Jeff Brown6ec402b2010-07-28 15:48:59 -070077import android.view.InputEvent;
Jeff Brown1f245102010-11-18 20:53:46 -080078import android.view.KeyEvent;
Jeff Brown2352b972011-04-12 22:39:53 -070079import android.view.PointerIcon;
Jeff Browna4547672011-03-02 21:38:11 -080080import android.view.ViewConfiguration;
Jeff Brown0029c662011-03-30 02:25:18 -070081import android.view.WindowManagerPolicy;
Jeff Browncf39bdf2012-05-18 14:41:19 -070082import android.widget.Toast;
Jeff Brown46b9ac02010-04-22 18:58:52 -070083
Jeff Brown46b9ac02010-04-22 18:58:52 -070084import java.io.File;
Jeff Brown4532e612012-04-05 14:27:12 -070085import java.io.FileDescriptor;
Jeff Brown46b9ac02010-04-22 18:58:52 -070086import java.io.FileNotFoundException;
87import java.io.FileReader;
88import java.io.IOException;
Jeff Brown6ec6f792012-04-17 16:52:41 -070089import java.io.InputStreamReader;
Jeff Brown46b9ac02010-04-22 18:58:52 -070090import java.io.PrintWriter;
91import java.util.ArrayList;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070092import java.util.HashMap;
Jeff Browncf39bdf2012-05-18 14:41:19 -070093import java.util.HashSet;
Jeff Browna3bc5652012-04-17 11:42:25 -070094
Jeff Brown6ec6f792012-04-17 16:52:41 -070095import libcore.io.Streams;
Jeff Browna3bc5652012-04-17 11:42:25 -070096import libcore.util.Objects;
Jeff Brown46b9ac02010-04-22 18:58:52 -070097
98/*
99 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -0700100 */
Jeff Brownd728bf52012-09-08 18:05:28 -0700101public class InputManagerService extends IInputManager.Stub
Jeff Brown4ccb8232014-01-16 22:16:42 -0800102 implements Watchdog.Monitor {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700103 static final String TAG = "InputManager";
Jeff Brown1b9ba572012-05-21 10:54:18 -0700104 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -0700105
Jeff Brown4532e612012-04-05 14:27:12 -0700106 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
107
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700108 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700109 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
110 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
111 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
112 private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700113
Jeff Brown4532e612012-04-05 14:27:12 -0700114 // Pointer to native input manager service object.
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000115 private final long mPtr;
Jeff Brown4532e612012-04-05 14:27:12 -0700116
Jeff Brown46b9ac02010-04-22 18:58:52 -0700117 private final Context mContext;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700118 private final InputManagerHandler mHandler;
Jeff Browna9d131c2012-09-20 16:48:17 -0700119
120 private WindowManagerCallbacks mWindowManagerCallbacks;
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700121 private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700122 private boolean mSystemReady;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700123 private NotificationManager mNotificationManager;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700124
Jeff Browna3bc5652012-04-17 11:42:25 -0700125 // Persistent data store. Must be locked each time during use.
126 private final PersistentDataStore mDataStore = new PersistentDataStore();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700127
128 // List of currently registered input devices changed listeners by process id.
129 private Object mInputDevicesLock = new Object();
130 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
131 private InputDevice[] mInputDevices = new InputDevice[0];
132 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
133 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
134 private final ArrayList<InputDevicesChangedListenerRecord>
135 mTempInputDevicesChangedListenersToNotify =
136 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
Jeff Browncf39bdf2012-05-18 14:41:19 -0700137 private final ArrayList<InputDevice>
138 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
139 private boolean mKeyboardLayoutNotificationShown;
140 private PendingIntent mKeyboardLayoutIntent;
141 private Toast mSwitchedKeyboardLayoutToast;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700142
Jeff Browna47425a2012-04-13 04:09:27 -0700143 // State for vibrator tokens.
144 private Object mVibratorLock = new Object();
145 private HashMap<IBinder, VibratorToken> mVibratorTokens =
146 new HashMap<IBinder, VibratorToken>();
147 private int mNextVibratorTokenValue;
148
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700149 // State for the currently installed input filter.
150 final Object mInputFilterLock = new Object();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700151 IInputFilter mInputFilter; // guarded by mInputFilterLock
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700152 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
Jeff Brown1a84fd12011-06-02 01:26:32 -0700153
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000154 private static native long nativeInit(InputManagerService service,
Jeff Brown4532e612012-04-05 14:27:12 -0700155 Context context, MessageQueue messageQueue);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000156 private static native void nativeStart(long ptr);
157 private static native void nativeSetDisplayViewport(long ptr, boolean external,
Jeff Brownd728bf52012-09-08 18:05:28 -0700158 int displayId, int rotation,
159 int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
Jeff Brown83d616a2012-09-09 20:33:43 -0700160 int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
161 int deviceWidth, int deviceHeight);
Jeff Brownd728bf52012-09-08 18:05:28 -0700162
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000163 private static native int nativeGetScanCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700164 int deviceId, int sourceMask, int scanCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000165 private static native int nativeGetKeyCodeState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700166 int deviceId, int sourceMask, int keyCode);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000167 private static native int nativeGetSwitchState(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700168 int deviceId, int sourceMask, int sw);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000169 private static native boolean nativeHasKeys(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700170 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000171 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
Jeff Brown928e0542011-01-10 11:17:36 -0800172 InputWindowHandle inputWindowHandle, boolean monitor);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000173 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
174 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
Jeff Brownca9bc702014-02-11 14:32:56 -0800175 private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId,
Jeff Brown0029c662011-03-30 02:25:18 -0700176 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
177 int policyFlags);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000178 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
179 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
180 private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
181 private static native void nativeSetFocusedApplication(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700182 InputApplicationHandle application);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000183 private static native boolean nativeTransferTouchFocus(long ptr,
Jeff Brown4532e612012-04-05 14:27:12 -0700184 InputChannel fromChannel, InputChannel toChannel);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000185 private static native void nativeSetPointerSpeed(long ptr, int speed);
186 private static native void nativeSetShowTouches(long ptr, boolean enabled);
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800187 private static native void nativeReloadCalibration(long ptr);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000188 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
Jeff Browna47425a2012-04-13 04:09:27 -0700189 int repeat, int token);
Ashok Bhat7e2a9dc2014-01-02 19:43:30 +0000190 private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
191 private static native void nativeReloadKeyboardLayouts(long ptr);
192 private static native void nativeReloadDeviceAliases(long ptr);
193 private static native String nativeDump(long ptr);
194 private static native void nativeMonitor(long ptr);
Jeff Brown4532e612012-04-05 14:27:12 -0700195
Jeff Brownac143512012-04-05 18:57:33 -0700196 // Input event injection constants defined in InputDispatcher.h.
197 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
198 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
199 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
200 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
201
202 // Maximum number of milliseconds to wait for input event injection.
203 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
204
Jeff Brown6d0fec22010-07-23 21:28:06 -0700205 // Key states (may be returned by queries about the current state of a
206 // particular key code, scan code or switch).
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700207
Jeff Brown6d0fec22010-07-23 21:28:06 -0700208 /** The key state is unknown or the requested key itself is not supported. */
209 public static final int KEY_STATE_UNKNOWN = -1;
210
211 /** The key is up. /*/
212 public static final int KEY_STATE_UP = 0;
213
214 /** The key is down. */
215 public static final int KEY_STATE_DOWN = 1;
216
217 /** The key is down but is a virtual key press that is being emulated by the system. */
218 public static final int KEY_STATE_VIRTUAL = 2;
219
Jeff Brownc458ce92012-04-30 14:58:40 -0700220 /** Scan code: Mouse / trackball button. */
221 public static final int BTN_MOUSE = 0x110;
222
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700223 // Switch code values must match bionic/libc/kernel/common/linux/input.h
Jeff Brownc458ce92012-04-30 14:58:40 -0700224 /** Switch code: Lid switch. When set, lid is shut. */
225 public static final int SW_LID = 0x00;
226
227 /** Switch code: Keypad slide. When set, keyboard is exposed. */
228 public static final int SW_KEYPAD_SLIDE = 0x0a;
229
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700230 /** Switch code: Headphone. When set, headphone is inserted. */
231 public static final int SW_HEADPHONE_INSERT = 0x02;
232
233 /** Switch code: Microphone. When set, microphone is inserted. */
234 public static final int SW_MICROPHONE_INSERT = 0x04;
235
236 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */
237 public static final int SW_JACK_PHYSICAL_INSERT = 0x07;
238
239 public static final int SW_LID_BIT = 1 << SW_LID;
240 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
241 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
242 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
243 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT;
244 public static final int SW_JACK_BITS =
245 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT;
246
247 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
248 final boolean mUseDevInputEventForAudioJack;
249
Jeff Brown4ccb8232014-01-16 22:16:42 -0800250 public InputManagerService(Context context) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700251 this.mContext = context;
Jeff Brown4ccb8232014-01-16 22:16:42 -0800252 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
Jeff Brown05dc66a2011-03-02 14:41:58 -0800253
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700254 mUseDevInputEventForAudioJack =
255 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
256 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
257 + mUseDevInputEventForAudioJack);
Jeff Brown4532e612012-04-05 14:27:12 -0700258 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown4ccb8232014-01-16 22:16:42 -0800259
260 LocalServices.addService(InputManagerInternal.class, new LocalService());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700261 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700262
Jeff Browna9d131c2012-09-20 16:48:17 -0700263 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
264 mWindowManagerCallbacks = callbacks;
265 }
266
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700267 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
268 mWiredAccessoryCallbacks = callbacks;
269 }
270
Jeff Brown46b9ac02010-04-22 18:58:52 -0700271 public void start() {
272 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700273 nativeStart(mPtr);
274
275 // Add ourself to the Watchdog monitors.
276 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700277
278 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700279 registerShowTouchesSettingObserver();
280
Jeff Brownd4935962012-09-25 13:27:20 -0700281 mContext.registerReceiver(new BroadcastReceiver() {
282 @Override
283 public void onReceive(Context context, Intent intent) {
284 updatePointerSpeedFromSettings();
285 updateShowTouchesFromSettings();
286 }
287 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
288
Jeff Brown1a84fd12011-06-02 01:26:32 -0700289 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700290 updateShowTouchesFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700291 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700292
Matthew Xie96313142012-06-29 16:57:31 -0700293 // TODO(BT) Pass in paramter for bluetooth system
Svetoslav Ganova0027152013-06-25 14:59:53 -0700294 public void systemRunning() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700295 if (DEBUG) {
296 Slog.d(TAG, "System ready.");
297 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700298 mNotificationManager = (NotificationManager)mContext.getSystemService(
299 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700300 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700301
302 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
303 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
304 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Jeff Brown69b07162013-11-07 00:30:16 -0800305 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700306 filter.addDataScheme("package");
307 mContext.registerReceiver(new BroadcastReceiver() {
308 @Override
309 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700310 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700311 }
312 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700313
314 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
315 mContext.registerReceiver(new BroadcastReceiver() {
316 @Override
317 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700318 reloadDeviceAliases();
319 }
320 }, filter, null, mHandler);
321
Jeff Browncf39bdf2012-05-18 14:41:19 -0700322 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
323 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700324 }
325
326 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700327 if (DEBUG) {
328 Slog.d(TAG, "Reloading keyboard layouts.");
329 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700330 nativeReloadKeyboardLayouts(mPtr);
331 }
332
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700333 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700334 if (DEBUG) {
335 Slog.d(TAG, "Reloading device names.");
336 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700337 nativeReloadDeviceAliases(mPtr);
338 }
339
Jeff Brown4ccb8232014-01-16 22:16:42 -0800340 private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
Jeff Brownd728bf52012-09-08 18:05:28 -0700341 DisplayViewport externalTouchViewport) {
342 if (defaultViewport.valid) {
343 setDisplayViewport(false, defaultViewport);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700344 }
Jeff Brownd728bf52012-09-08 18:05:28 -0700345
346 if (externalTouchViewport.valid) {
347 setDisplayViewport(true, externalTouchViewport);
348 } else if (defaultViewport.valid) {
349 setDisplayViewport(true, defaultViewport);
Jeff Brownb6997262010-10-08 22:31:17 -0700350 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700351 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700352
Jeff Brownd728bf52012-09-08 18:05:28 -0700353 private void setDisplayViewport(boolean external, DisplayViewport viewport) {
354 nativeSetDisplayViewport(mPtr, external,
355 viewport.displayId, viewport.orientation,
356 viewport.logicalFrame.left, viewport.logicalFrame.top,
357 viewport.logicalFrame.right, viewport.logicalFrame.bottom,
358 viewport.physicalFrame.left, viewport.physicalFrame.top,
Jeff Brown83d616a2012-09-09 20:33:43 -0700359 viewport.physicalFrame.right, viewport.physicalFrame.bottom,
360 viewport.deviceWidth, viewport.deviceHeight);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700361 }
Jeff Brownac143512012-04-05 18:57:33 -0700362
Jeff Brown6d0fec22010-07-23 21:28:06 -0700363 /**
364 * Gets the current state of a key or button by key code.
365 * @param deviceId The input device id, or -1 to consult all devices.
366 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
367 * consider all input sources. An input device is consulted if at least one of its
368 * non-class input source bits matches the specified source mask.
369 * @param keyCode The key code to check.
370 * @return The key state.
371 */
372 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700373 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700374 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700375
Jeff Brown6d0fec22010-07-23 21:28:06 -0700376 /**
377 * Gets the current state of a key or button by scan code.
378 * @param deviceId The input device id, or -1 to consult all devices.
379 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
380 * consider all input sources. An input device is consulted if at least one of its
381 * non-class input source bits matches the specified source mask.
382 * @param scanCode The scan code to check.
383 * @return The key state.
384 */
385 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700386 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700387 }
RoboErikfb290df2013-12-16 11:27:55 -0800388
Jeff Brown6d0fec22010-07-23 21:28:06 -0700389 /**
390 * Gets the current state of a switch by switch code.
391 * @param deviceId The input device id, or -1 to consult all devices.
392 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
393 * consider all input sources. An input device is consulted if at least one of its
394 * non-class input source bits matches the specified source mask.
395 * @param switchCode The switch code to check.
396 * @return The switch state.
397 */
398 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700399 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700400 }
401
Jeff Brown6d0fec22010-07-23 21:28:06 -0700402 /**
403 * Determines whether the specified key codes are supported by a particular device.
404 * @param deviceId The input device id, or -1 to consult all devices.
405 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
406 * consider all input sources. An input device is consulted if at least one of its
407 * non-class input source bits matches the specified source mask.
408 * @param keyCodes The array of key codes to check.
409 * @param keyExists An array at least as large as keyCodes whose entries will be set
410 * to true or false based on the presence or absence of support for the corresponding
411 * key codes.
412 * @return True if the lookup was successful, false otherwise.
413 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700414 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700415 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700416 if (keyCodes == null) {
417 throw new IllegalArgumentException("keyCodes must not be null.");
418 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700419 if (keyExists == null || keyExists.length < keyCodes.length) {
420 throw new IllegalArgumentException("keyExists must not be null and must be at "
421 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700422 }
RoboErikfb290df2013-12-16 11:27:55 -0800423
Jeff Brown4532e612012-04-05 14:27:12 -0700424 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700425 }
RoboErikfb290df2013-12-16 11:27:55 -0800426
Jeff Browna41ca772010-08-11 14:46:32 -0700427 /**
428 * Creates an input channel that will receive all input from the input dispatcher.
429 * @param inputChannelName The input channel name.
430 * @return The input channel.
431 */
432 public InputChannel monitorInput(String inputChannelName) {
433 if (inputChannelName == null) {
434 throw new IllegalArgumentException("inputChannelName must not be null.");
435 }
RoboErikfb290df2013-12-16 11:27:55 -0800436
Jeff Browna41ca772010-08-11 14:46:32 -0700437 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700438 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700439 inputChannels[0].dispose(); // don't need to retain the Java object reference
440 return inputChannels[1];
441 }
442
443 /**
444 * Registers an input channel so that it can be used as an input event target.
445 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800446 * @param inputWindowHandle The handle of the input window associated with the
447 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700448 */
Jeff Brown928e0542011-01-10 11:17:36 -0800449 public void registerInputChannel(InputChannel inputChannel,
450 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700451 if (inputChannel == null) {
452 throw new IllegalArgumentException("inputChannel must not be null.");
453 }
RoboErikfb290df2013-12-16 11:27:55 -0800454
Jeff Brown4532e612012-04-05 14:27:12 -0700455 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700456 }
RoboErikfb290df2013-12-16 11:27:55 -0800457
Jeff Browna41ca772010-08-11 14:46:32 -0700458 /**
459 * Unregisters an input channel.
460 * @param inputChannel The input channel to unregister.
461 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700462 public void unregisterInputChannel(InputChannel inputChannel) {
463 if (inputChannel == null) {
464 throw new IllegalArgumentException("inputChannel must not be null.");
465 }
RoboErikfb290df2013-12-16 11:27:55 -0800466
Jeff Brown4532e612012-04-05 14:27:12 -0700467 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700468 }
Jeff Brown0029c662011-03-30 02:25:18 -0700469
470 /**
471 * Sets an input filter that will receive all input events before they are dispatched.
472 * The input filter may then reinterpret input events or inject new ones.
473 *
474 * To ensure consistency, the input dispatcher automatically drops all events
475 * in progress whenever an input filter is installed or uninstalled. After an input
476 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
477 * Any events it attempts to send after it has been uninstalled will be dropped.
478 *
479 * @param filter The input filter, or null to remove the current filter.
480 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700481 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700482 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700483 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700484 if (oldFilter == filter) {
485 return; // nothing to do
486 }
487
488 if (oldFilter != null) {
489 mInputFilter = null;
490 mInputFilterHost.disconnectLocked();
491 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700492 try {
493 oldFilter.uninstall();
494 } catch (RemoteException re) {
495 /* ignore */
496 }
Jeff Brown0029c662011-03-30 02:25:18 -0700497 }
498
499 if (filter != null) {
500 mInputFilter = filter;
501 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700502 try {
503 filter.install(mInputFilterHost);
504 } catch (RemoteException re) {
505 /* ignore */
506 }
Jeff Brown0029c662011-03-30 02:25:18 -0700507 }
508
Jeff Brown4532e612012-04-05 14:27:12 -0700509 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700510 }
511 }
512
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700513 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700514 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brownca9bc702014-02-11 14:32:56 -0800515 return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
516 }
517
518 private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700519 if (event == null) {
520 throw new IllegalArgumentException("event must not be null");
521 }
Jeff Brownac143512012-04-05 18:57:33 -0700522 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
523 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
524 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
525 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700526 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700527
Jeff Brownac143512012-04-05 18:57:33 -0700528 final int pid = Binder.getCallingPid();
529 final int uid = Binder.getCallingUid();
530 final long ident = Binder.clearCallingIdentity();
531 final int result;
532 try {
Jeff Brownca9bc702014-02-11 14:32:56 -0800533 result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
Jeff Brownac143512012-04-05 18:57:33 -0700534 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
535 } finally {
536 Binder.restoreCallingIdentity(ident);
537 }
538 switch (result) {
539 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
540 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
541 throw new SecurityException(
542 "Injecting to another application requires INJECT_EVENTS permission");
543 case INPUT_EVENT_INJECTION_SUCCEEDED:
544 return true;
545 case INPUT_EVENT_INJECTION_TIMED_OUT:
546 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
547 return false;
548 case INPUT_EVENT_INJECTION_FAILED:
549 default:
550 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
551 return false;
552 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700553 }
Jeff Brown0029c662011-03-30 02:25:18 -0700554
Jeff Brown8d608662010-08-30 03:02:23 -0700555 /**
556 * Gets information about the input device with the specified id.
Craig Mautner2f39e9f2012-09-21 11:39:54 -0700557 * @param deviceId The device id.
Jeff Brown8d608662010-08-30 03:02:23 -0700558 * @return The input device or null if not found.
559 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700560 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700561 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700562 synchronized (mInputDevicesLock) {
563 final int count = mInputDevices.length;
564 for (int i = 0; i < count; i++) {
565 final InputDevice inputDevice = mInputDevices[i];
566 if (inputDevice.getId() == deviceId) {
567 return inputDevice;
568 }
569 }
570 }
571 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700572 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700573
Jeff Brown8d608662010-08-30 03:02:23 -0700574 /**
575 * Gets the ids of all input devices in the system.
576 * @return The input device ids.
577 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700578 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700579 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700580 synchronized (mInputDevicesLock) {
581 final int count = mInputDevices.length;
582 int[] ids = new int[count];
583 for (int i = 0; i < count; i++) {
584 ids[i] = mInputDevices[i].getId();
585 }
586 return ids;
587 }
588 }
589
Jeff Browndaa37532012-05-01 15:54:03 -0700590 /**
591 * Gets all input devices in the system.
592 * @return The array of input devices.
593 */
594 public InputDevice[] getInputDevices() {
595 synchronized (mInputDevicesLock) {
596 return mInputDevices;
597 }
598 }
599
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700600 @Override // Binder call
601 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
602 if (listener == null) {
603 throw new IllegalArgumentException("listener must not be null");
604 }
605
606 synchronized (mInputDevicesLock) {
607 int callingPid = Binder.getCallingPid();
608 if (mInputDevicesChangedListeners.get(callingPid) != null) {
609 throw new SecurityException("The calling process has already "
610 + "registered an InputDevicesChangedListener.");
611 }
612
613 InputDevicesChangedListenerRecord record =
614 new InputDevicesChangedListenerRecord(callingPid, listener);
615 try {
616 IBinder binder = listener.asBinder();
617 binder.linkToDeath(record, 0);
618 } catch (RemoteException ex) {
619 // give up
620 throw new RuntimeException(ex);
621 }
622
623 mInputDevicesChangedListeners.put(callingPid, record);
624 }
625 }
626
627 private void onInputDevicesChangedListenerDied(int pid) {
628 synchronized (mInputDevicesLock) {
629 mInputDevicesChangedListeners.remove(pid);
630 }
631 }
632
633 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700634 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
635 // Scan for changes.
636 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700637 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700638 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700639 final int numListeners;
640 final int[] deviceIdAndGeneration;
641 synchronized (mInputDevicesLock) {
642 if (!mInputDevicesChangedPending) {
643 return;
644 }
645 mInputDevicesChangedPending = false;
646
647 numListeners = mInputDevicesChangedListeners.size();
648 for (int i = 0; i < numListeners; i++) {
649 mTempInputDevicesChangedListenersToNotify.add(
650 mInputDevicesChangedListeners.valueAt(i));
651 }
652
653 final int numDevices = mInputDevices.length;
654 deviceIdAndGeneration = new int[numDevices * 2];
655 for (int i = 0; i < numDevices; i++) {
656 final InputDevice inputDevice = mInputDevices[i];
657 deviceIdAndGeneration[i * 2] = inputDevice.getId();
658 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700659
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700660 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700661 if (!containsInputDeviceWithDescriptor(oldInputDevices,
662 inputDevice.getDescriptor())) {
663 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
664 } else {
665 mTempFullKeyboards.add(inputDevice);
666 }
667 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700668 }
669 }
670
Jeff Browncf39bdf2012-05-18 14:41:19 -0700671 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700672 for (int i = 0; i < numListeners; i++) {
673 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
674 deviceIdAndGeneration);
675 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700676 mTempInputDevicesChangedListenersToNotify.clear();
677
678 // Check for missing keyboard layouts.
679 if (mNotificationManager != null) {
680 final int numFullKeyboards = mTempFullKeyboards.size();
681 boolean missingLayoutForExternalKeyboard = false;
682 boolean missingLayoutForExternalKeyboardAdded = false;
683 synchronized (mDataStore) {
684 for (int i = 0; i < numFullKeyboards; i++) {
685 final InputDevice inputDevice = mTempFullKeyboards.get(i);
686 if (mDataStore.getCurrentKeyboardLayout(inputDevice.getDescriptor()) == null) {
687 missingLayoutForExternalKeyboard = true;
688 if (i < numFullKeyboardsAdded) {
689 missingLayoutForExternalKeyboardAdded = true;
690 }
691 }
692 }
693 }
694 if (missingLayoutForExternalKeyboard) {
695 if (missingLayoutForExternalKeyboardAdded) {
696 showMissingKeyboardLayoutNotification();
697 }
698 } else if (mKeyboardLayoutNotificationShown) {
699 hideMissingKeyboardLayoutNotification();
700 }
701 }
702 mTempFullKeyboards.clear();
703 }
704
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800705 @Override // Binder call & native callback
Jason Gerecked6396d62014-01-27 18:30:37 -0800706 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor) {
707 if (inputDeviceDescriptor == null) {
708 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
709 }
710
711 synchronized (mDataStore) {
712 return mDataStore.getTouchCalibration(inputDeviceDescriptor);
713 }
714 }
715
716 @Override // Binder call
717 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor,
718 TouchCalibration calibration) {
719 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION,
720 "setTouchCalibrationForInputDevice()")) {
721 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission");
722 }
723 if (inputDeviceDescriptor == null) {
724 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
725 }
726 if (calibration == null) {
727 throw new IllegalArgumentException("calibration must not be null");
728 }
729
730 synchronized (mDataStore) {
731 try {
Jason Gerecke857aa7b2014-01-27 18:34:20 -0800732 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, calibration)) {
733 nativeReloadCalibration(mPtr);
734 }
Jason Gerecked6396d62014-01-27 18:30:37 -0800735 } finally {
736 mDataStore.saveIfNeeded();
737 }
738 }
739 }
740
Jeff Browncf39bdf2012-05-18 14:41:19 -0700741 // Must be called on handler.
742 private void showMissingKeyboardLayoutNotification() {
743 if (!mKeyboardLayoutNotificationShown) {
744 if (mKeyboardLayoutIntent == null) {
745 final Intent intent = new Intent("android.settings.INPUT_METHOD_SETTINGS");
746 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
747 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
748 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700749 mKeyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
750 intent, 0, null, UserHandle.CURRENT);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700751 }
752
753 Resources r = mContext.getResources();
754 Notification notification = new Notification.Builder(mContext)
755 .setContentTitle(r.getString(
756 R.string.select_keyboard_layout_notification_title))
757 .setContentText(r.getString(
758 R.string.select_keyboard_layout_notification_message))
759 .setContentIntent(mKeyboardLayoutIntent)
760 .setSmallIcon(R.drawable.ic_settings_language)
761 .setPriority(Notification.PRIORITY_LOW)
762 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700763 mNotificationManager.notifyAsUser(null,
764 R.string.select_keyboard_layout_notification_title,
765 notification, UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700766 mKeyboardLayoutNotificationShown = true;
767 }
768 }
769
770 // Must be called on handler.
771 private void hideMissingKeyboardLayoutNotification() {
772 if (mKeyboardLayoutNotificationShown) {
773 mKeyboardLayoutNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700774 mNotificationManager.cancelAsUser(null,
775 R.string.select_keyboard_layout_notification_title,
776 UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700777 }
778 }
779
780 // Must be called on handler.
781 private void updateKeyboardLayouts() {
782 // Scan all input devices state for keyboard layouts that have been uninstalled.
783 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
784 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
785 @Override
786 public void visitKeyboardLayout(Resources resources,
787 String descriptor, String label, String collection, int keyboardLayoutResId) {
788 availableKeyboardLayouts.add(descriptor);
789 }
790 });
791 synchronized (mDataStore) {
792 try {
793 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
794 } finally {
795 mDataStore.saveIfNeeded();
796 }
797 }
798
799 // Reload keyboard layouts.
800 reloadKeyboardLayouts();
801 }
802
Jeff Browncf39bdf2012-05-18 14:41:19 -0700803 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
804 String descriptor) {
805 final int numDevices = inputDevices.length;
806 for (int i = 0; i < numDevices; i++) {
807 final InputDevice inputDevice = inputDevices[i];
808 if (inputDevice.getDescriptor().equals(descriptor)) {
809 return true;
810 }
811 }
812 return false;
Jeff Brown8d608662010-08-30 03:02:23 -0700813 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700814
815 @Override // Binder call
816 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700817 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
818 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
819 @Override
820 public void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700821 String descriptor, String label, String collection, int keyboardLayoutResId) {
822 list.add(new KeyboardLayout(descriptor, label, collection));
Jeff Brown6ec6f792012-04-17 16:52:41 -0700823 }
824 });
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700825 return list.toArray(new KeyboardLayout[list.size()]);
826 }
827
828 @Override // Binder call
829 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
830 if (keyboardLayoutDescriptor == null) {
831 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
832 }
833
Jeff Brown6ec6f792012-04-17 16:52:41 -0700834 final KeyboardLayout[] result = new KeyboardLayout[1];
835 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
836 @Override
837 public void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700838 String descriptor, String label, String collection, int keyboardLayoutResId) {
839 result[0] = new KeyboardLayout(descriptor, label, collection);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700840 }
841 });
842 if (result[0] == null) {
843 Log.w(TAG, "Could not get keyboard layout with descriptor '"
844 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700845 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700846 return result[0];
847 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700848
Jeff Brown6ec6f792012-04-17 16:52:41 -0700849 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700850 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700851 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
852 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
853 PackageManager.GET_META_DATA)) {
854 visitKeyboardLayoutsInPackage(pm, resolveInfo.activityInfo, null, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700855 }
856 }
857
Jeff Brown6ec6f792012-04-17 16:52:41 -0700858 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
859 KeyboardLayoutVisitor visitor) {
860 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
861 if (d != null) {
862 final PackageManager pm = mContext.getPackageManager();
863 try {
864 ActivityInfo receiver = pm.getReceiverInfo(
865 new ComponentName(d.packageName, d.receiverName),
866 PackageManager.GET_META_DATA);
867 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, visitor);
868 } catch (NameNotFoundException ex) {
869 }
870 }
871 }
872
873 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
874 String keyboardName, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700875 Bundle metaData = receiver.metaData;
876 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700877 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700878 }
879
880 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
881 if (configResId == 0) {
882 Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
883 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700884 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700885 }
886
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700887 CharSequence receiverLabel = receiver.loadLabel(pm);
888 String collection = receiverLabel != null ? receiverLabel.toString() : "";
889
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700890 try {
891 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
892 XmlResourceParser parser = resources.getXml(configResId);
893 try {
894 XmlUtils.beginDocument(parser, "keyboard-layouts");
895
896 for (;;) {
897 XmlUtils.nextElement(parser);
898 String element = parser.getName();
899 if (element == null) {
900 break;
901 }
902 if (element.equals("keyboard-layout")) {
903 TypedArray a = resources.obtainAttributes(
904 parser, com.android.internal.R.styleable.KeyboardLayout);
905 try {
906 String name = a.getString(
907 com.android.internal.R.styleable.KeyboardLayout_name);
908 String label = a.getString(
909 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -0700910 int keyboardLayoutResId = a.getResourceId(
911 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
912 0);
913 if (name == null || label == null || keyboardLayoutResId == 0) {
914 Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700915 + "attributes in keyboard layout "
916 + "resource from receiver "
917 + receiver.packageName + "/" + receiver.name);
918 } else {
919 String descriptor = KeyboardLayoutDescriptor.format(
920 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700921 if (keyboardName == null || name.equals(keyboardName)) {
922 visitor.visitKeyboardLayout(resources, descriptor,
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700923 label, collection, keyboardLayoutResId);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700924 }
925 }
926 } finally {
927 a.recycle();
928 }
929 } else {
930 Log.w(TAG, "Skipping unrecognized element '" + element
931 + "' in keyboard layout resource from receiver "
932 + receiver.packageName + "/" + receiver.name);
933 }
934 }
935 } finally {
936 parser.close();
937 }
938 } catch (Exception ex) {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700939 Log.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700940 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700941 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700942 }
943
RoboErikfb290df2013-12-16 11:27:55 -0800944 /**
945 * Builds a layout descriptor for the vendor/product. This returns the
946 * descriptor for ids that aren't useful (such as the default 0, 0).
947 */
948 private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
949 if (identifier == null || identifier.getDescriptor() == null) {
950 throw new IllegalArgumentException("identifier and descriptor must not be null");
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700951 }
952
RoboErikfb290df2013-12-16 11:27:55 -0800953 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
954 return identifier.getDescriptor();
955 }
956 StringBuilder bob = new StringBuilder();
957 bob.append("vendor:").append(identifier.getVendorId());
958 bob.append(",product:").append(identifier.getProductId());
959 return bob.toString();
960 }
961
962 @Override // Binder call
963 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
964
965 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -0700966 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -0800967 String layout = null;
968 // try loading it using the layout descriptor if we have it
969 layout = mDataStore.getCurrentKeyboardLayout(key);
970 if (layout == null && !key.equals(identifier.getDescriptor())) {
971 // if it doesn't exist fall back to the device descriptor
972 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
973 }
974 if (DEBUG) {
975 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
976 + layout);
977 }
978 return layout;
Jeff Browna3bc5652012-04-17 11:42:25 -0700979 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700980 }
981
982 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -0800983 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700984 String keyboardLayoutDescriptor) {
985 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -0700986 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700987 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
988 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700989 if (keyboardLayoutDescriptor == null) {
990 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
991 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700992
RoboErikfb290df2013-12-16 11:27:55 -0800993 String key = getLayoutDescriptor(identifier);
Jeff Browna3bc5652012-04-17 11:42:25 -0700994 synchronized (mDataStore) {
995 try {
RoboErikfb290df2013-12-16 11:27:55 -0800996 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
997 if (DEBUG) {
998 Slog.d(TAG, "Saved keyboard layout using " + key);
999 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001000 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1001 }
Jeff Browna3bc5652012-04-17 11:42:25 -07001002 } finally {
1003 mDataStore.saveIfNeeded();
1004 }
1005 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001006 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001007
Jeff Browncf39bdf2012-05-18 14:41:19 -07001008 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001009 public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
1010 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001011 synchronized (mDataStore) {
RoboErikfb290df2013-12-16 11:27:55 -08001012 String[] layouts = mDataStore.getKeyboardLayouts(key);
1013 if ((layouts == null || layouts.length == 0)
1014 && !key.equals(identifier.getDescriptor())) {
1015 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
1016 }
1017 return layouts;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001018 }
1019 }
1020
1021 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001022 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001023 String keyboardLayoutDescriptor) {
1024 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1025 "addKeyboardLayoutForInputDevice()")) {
1026 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1027 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001028 if (keyboardLayoutDescriptor == null) {
1029 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1030 }
1031
RoboErikfb290df2013-12-16 11:27:55 -08001032 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001033 synchronized (mDataStore) {
1034 try {
RoboErikfb290df2013-12-16 11:27:55 -08001035 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1036 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1037 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1038 }
1039 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
Jeff Browncf39bdf2012-05-18 14:41:19 -07001040 && !Objects.equal(oldLayout,
RoboErikfb290df2013-12-16 11:27:55 -08001041 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001042 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1043 }
1044 } finally {
1045 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -07001046 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001047 }
1048 }
1049
1050 @Override // Binder call
RoboErikfb290df2013-12-16 11:27:55 -08001051 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
Jeff Browncf39bdf2012-05-18 14:41:19 -07001052 String keyboardLayoutDescriptor) {
1053 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
1054 "removeKeyboardLayoutForInputDevice()")) {
1055 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
1056 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001057 if (keyboardLayoutDescriptor == null) {
1058 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
1059 }
1060
RoboErikfb290df2013-12-16 11:27:55 -08001061 String key = getLayoutDescriptor(identifier);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001062 synchronized (mDataStore) {
1063 try {
RoboErikfb290df2013-12-16 11:27:55 -08001064 String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
1065 if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
1066 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
1067 }
1068 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
1069 if (!key.equals(identifier.getDescriptor())) {
1070 // We need to remove from both places to ensure it is gone
1071 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
1072 keyboardLayoutDescriptor);
1073 }
1074 if (removed && !Objects.equal(oldLayout,
1075 mDataStore.getCurrentKeyboardLayout(key))) {
Jeff Browncf39bdf2012-05-18 14:41:19 -07001076 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
1077 }
1078 } finally {
1079 mDataStore.saveIfNeeded();
1080 }
1081 }
1082 }
1083
1084 public void switchKeyboardLayout(int deviceId, int direction) {
1085 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
1086 }
1087
1088 // Must be called on handler.
1089 private void handleSwitchKeyboardLayout(int deviceId, int direction) {
1090 final InputDevice device = getInputDevice(deviceId);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001091 if (device != null) {
1092 final boolean changed;
1093 final String keyboardLayoutDescriptor;
RoboErikfb290df2013-12-16 11:27:55 -08001094
1095 String key = getLayoutDescriptor(device.getIdentifier());
Jeff Browncf39bdf2012-05-18 14:41:19 -07001096 synchronized (mDataStore) {
1097 try {
RoboErikfb290df2013-12-16 11:27:55 -08001098 changed = mDataStore.switchKeyboardLayout(key, direction);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001099 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
RoboErikfb290df2013-12-16 11:27:55 -08001100 key);
Jeff Browncf39bdf2012-05-18 14:41:19 -07001101 } finally {
1102 mDataStore.saveIfNeeded();
1103 }
1104 }
1105
1106 if (changed) {
1107 if (mSwitchedKeyboardLayoutToast != null) {
1108 mSwitchedKeyboardLayoutToast.cancel();
1109 mSwitchedKeyboardLayoutToast = null;
1110 }
1111 if (keyboardLayoutDescriptor != null) {
1112 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
1113 if (keyboardLayout != null) {
1114 mSwitchedKeyboardLayoutToast = Toast.makeText(
1115 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
1116 mSwitchedKeyboardLayoutToast.show();
1117 }
1118 }
1119
1120 reloadKeyboardLayouts();
1121 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001122 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001123 }
1124
Jeff Brown9302c872011-07-13 22:51:29 -07001125 public void setInputWindows(InputWindowHandle[] windowHandles) {
Jeff Brown4532e612012-04-05 14:27:12 -07001126 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -07001127 }
RoboErikfb290df2013-12-16 11:27:55 -08001128
Jeff Brown9302c872011-07-13 22:51:29 -07001129 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -07001130 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -07001131 }
RoboErikfb290df2013-12-16 11:27:55 -08001132
Jeff Brown349703e2010-06-22 01:27:15 -07001133 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001134 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001135 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001136
1137 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001138 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001139 }
1140
Jeff Browne6504122010-09-27 14:52:15 -07001141 /**
1142 * Atomically transfers touch focus from one window to another as identified by
1143 * their input channels. It is possible for multiple windows to have
1144 * touch focus if they support split touch dispatch
1145 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1146 * method only transfers touch focus of the specified window without affecting
1147 * other windows that may also have touch focus at the same time.
1148 * @param fromChannel The channel of a window that currently has touch focus.
1149 * @param toChannel The channel of the window that should receive touch focus in
1150 * place of the first.
1151 * @return True if the transfer was successful. False if the window with the
1152 * specified channel did not actually have touch focus at the time of the request.
1153 */
1154 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1155 if (fromChannel == null) {
1156 throw new IllegalArgumentException("fromChannel must not be null.");
1157 }
1158 if (toChannel == null) {
1159 throw new IllegalArgumentException("toChannel must not be null.");
1160 }
Jeff Brown4532e612012-04-05 14:27:12 -07001161 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -07001162 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001163
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001164 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001165 public void tryPointerSpeed(int speed) {
1166 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1167 "tryPointerSpeed()")) {
1168 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1169 }
1170
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001171 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1172 throw new IllegalArgumentException("speed out of range");
1173 }
1174
Jeff Brownac143512012-04-05 18:57:33 -07001175 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001176 }
1177
1178 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001179 int speed = getPointerSpeedSetting();
1180 setPointerSpeedUnchecked(speed);
1181 }
1182
1183 private void setPointerSpeedUnchecked(int speed) {
1184 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1185 InputManager.MAX_POINTER_SPEED);
1186 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001187 }
1188
1189 private void registerPointerSpeedSettingObserver() {
1190 mContext.getContentResolver().registerContentObserver(
1191 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001192 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001193 @Override
1194 public void onChange(boolean selfChange) {
1195 updatePointerSpeedFromSettings();
1196 }
Jeff Brownd4935962012-09-25 13:27:20 -07001197 }, UserHandle.USER_ALL);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001198 }
1199
Jeff Brownac143512012-04-05 18:57:33 -07001200 private int getPointerSpeedSetting() {
1201 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001202 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001203 speed = Settings.System.getIntForUser(mContext.getContentResolver(),
1204 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001205 } catch (SettingNotFoundException snfe) {
1206 }
1207 return speed;
1208 }
1209
Jeff Browndaf4a122011-08-26 17:14:14 -07001210 public void updateShowTouchesFromSettings() {
1211 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001212 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001213 }
1214
1215 private void registerShowTouchesSettingObserver() {
1216 mContext.getContentResolver().registerContentObserver(
1217 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001218 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001219 @Override
1220 public void onChange(boolean selfChange) {
1221 updateShowTouchesFromSettings();
1222 }
Jeff Brownd4935962012-09-25 13:27:20 -07001223 }, UserHandle.USER_ALL);
Jeff Browndaf4a122011-08-26 17:14:14 -07001224 }
1225
1226 private int getShowTouchesSetting(int defaultValue) {
1227 int result = defaultValue;
1228 try {
Jeff Brownd4935962012-09-25 13:27:20 -07001229 result = Settings.System.getIntForUser(mContext.getContentResolver(),
1230 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT);
Jeff Browndaf4a122011-08-26 17:14:14 -07001231 } catch (SettingNotFoundException snfe) {
1232 }
1233 return result;
1234 }
1235
Jeff Browna47425a2012-04-13 04:09:27 -07001236 // Binder call
1237 @Override
1238 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1239 if (repeat >= pattern.length) {
1240 throw new ArrayIndexOutOfBoundsException();
1241 }
1242
1243 VibratorToken v;
1244 synchronized (mVibratorLock) {
1245 v = mVibratorTokens.get(token);
1246 if (v == null) {
1247 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1248 try {
1249 token.linkToDeath(v, 0);
1250 } catch (RemoteException ex) {
1251 // give up
1252 throw new RuntimeException(ex);
1253 }
1254 mVibratorTokens.put(token, v);
1255 }
1256 }
1257
1258 synchronized (v) {
1259 v.mVibrating = true;
1260 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1261 }
1262 }
1263
1264 // Binder call
1265 @Override
1266 public void cancelVibrate(int deviceId, IBinder token) {
1267 VibratorToken v;
1268 synchronized (mVibratorLock) {
1269 v = mVibratorTokens.get(token);
1270 if (v == null || v.mDeviceId != deviceId) {
1271 return; // nothing to cancel
1272 }
1273 }
1274
1275 cancelVibrateIfNeeded(v);
1276 }
1277
1278 void onVibratorTokenDied(VibratorToken v) {
1279 synchronized (mVibratorLock) {
1280 mVibratorTokens.remove(v.mToken);
1281 }
1282
1283 cancelVibrateIfNeeded(v);
1284 }
1285
1286 private void cancelVibrateIfNeeded(VibratorToken v) {
1287 synchronized (v) {
1288 if (v.mVibrating) {
1289 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1290 v.mVibrating = false;
1291 }
1292 }
1293 }
1294
Jeff Brown4532e612012-04-05 14:27:12 -07001295 @Override
1296 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna3bc5652012-04-17 11:42:25 -07001297 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
Jeff Brown4532e612012-04-05 14:27:12 -07001298 != PackageManager.PERMISSION_GRANTED) {
1299 pw.println("Permission Denial: can't dump InputManager from from pid="
1300 + Binder.getCallingPid()
1301 + ", uid=" + Binder.getCallingUid());
1302 return;
1303 }
1304
1305 pw.println("INPUT MANAGER (dumpsys input)\n");
1306 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001307 if (dumpStr != null) {
1308 pw.println(dumpStr);
1309 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001310 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001311
Jeff Brownac143512012-04-05 18:57:33 -07001312 private boolean checkCallingPermission(String permission, String func) {
1313 // Quick check: if the calling permission is me, it's all okay.
1314 if (Binder.getCallingPid() == Process.myPid()) {
1315 return true;
1316 }
1317
1318 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1319 return true;
1320 }
1321 String msg = "Permission Denial: " + func + " from pid="
1322 + Binder.getCallingPid()
1323 + ", uid=" + Binder.getCallingUid()
1324 + " requires " + permission;
1325 Slog.w(TAG, msg);
1326 return false;
1327 }
1328
Jeff Brown4532e612012-04-05 14:27:12 -07001329 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001330 @Override
Jeff Brown89ef0722011-08-10 16:25:21 -07001331 public void monitor() {
1332 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -07001333 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001334 }
1335
Jeff Brown4532e612012-04-05 14:27:12 -07001336 // Native callback.
1337 private void notifyConfigurationChanged(long whenNanos) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001338 mWindowManagerCallbacks.notifyConfigurationChanged();
Jeff Brown4532e612012-04-05 14:27:12 -07001339 }
1340
1341 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001342 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1343 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001344 if (!mInputDevicesChangedPending) {
1345 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001346 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1347 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001348 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001349
1350 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001351 }
1352 }
1353
1354 // Native callback.
Jeff Brownbcc046a2012-09-27 20:46:43 -07001355 private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
1356 if (DEBUG) {
1357 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
1358 + ", mask=" + Integer.toHexString(switchMask));
1359 }
1360
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001361 if ((switchMask & SW_LID_BIT) != 0) {
1362 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
Jeff Brownbcc046a2012-09-27 20:46:43 -07001363 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
Jeff Brown53384282012-08-20 20:16:01 -07001364 }
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001365
1366 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
1367 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
1368 switchMask);
1369 }
Jeff Brown4532e612012-04-05 14:27:12 -07001370 }
1371
1372 // Native callback.
1373 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001374 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
Jeff Brown4532e612012-04-05 14:27:12 -07001375 }
1376
1377 // Native callback.
1378 private long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001379 InputWindowHandle inputWindowHandle, String reason) {
1380 return mWindowManagerCallbacks.notifyANR(
1381 inputApplicationHandle, inputWindowHandle, reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001382 }
1383
1384 // Native callback.
1385 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1386 synchronized (mInputFilterLock) {
1387 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001388 try {
1389 mInputFilter.filterInputEvent(event, policyFlags);
1390 } catch (RemoteException e) {
1391 /* ignore */
1392 }
Jeff Brown4532e612012-04-05 14:27:12 -07001393 return false;
1394 }
1395 }
1396 event.recycle();
1397 return true;
1398 }
1399
1400 // Native callback.
1401 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001402 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(
Jeff Brown4532e612012-04-05 14:27:12 -07001403 event, policyFlags, isScreenOn);
1404 }
1405
1406 // Native callback.
Jeff Brown26875502014-01-30 21:47:47 -08001407 private int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
1408 return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(
1409 whenNanos, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001410 }
1411
1412 // Native callback.
1413 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1414 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001415 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001416 }
1417
1418 // Native callback.
1419 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1420 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001421 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001422 }
1423
1424 // Native callback.
1425 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1426 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1427 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1428 }
1429
1430 // Native callback.
1431 private int getVirtualKeyQuietTimeMillis() {
1432 return mContext.getResources().getInteger(
1433 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1434 }
1435
1436 // Native callback.
1437 private String[] getExcludedDeviceNames() {
1438 ArrayList<String> names = new ArrayList<String>();
1439
1440 // Read partner-provided list of excluded input devices
1441 XmlPullParser parser = null;
1442 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1443 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1444 FileReader confreader = null;
1445 try {
1446 confreader = new FileReader(confFile);
1447 parser = Xml.newPullParser();
1448 parser.setInput(confreader);
1449 XmlUtils.beginDocument(parser, "devices");
1450
1451 while (true) {
1452 XmlUtils.nextElement(parser);
1453 if (!"device".equals(parser.getName())) {
1454 break;
1455 }
1456 String name = parser.getAttributeValue(null, "name");
1457 if (name != null) {
1458 names.add(name);
1459 }
1460 }
1461 } catch (FileNotFoundException e) {
1462 // It's ok if the file does not exist.
1463 } catch (Exception e) {
1464 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1465 } finally {
1466 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1467 }
1468
1469 return names.toArray(new String[names.size()]);
1470 }
1471
1472 // Native callback.
1473 private int getKeyRepeatTimeout() {
1474 return ViewConfiguration.getKeyRepeatTimeout();
1475 }
1476
1477 // Native callback.
1478 private int getKeyRepeatDelay() {
1479 return ViewConfiguration.getKeyRepeatDelay();
1480 }
1481
1482 // Native callback.
1483 private int getHoverTapTimeout() {
1484 return ViewConfiguration.getHoverTapTimeout();
1485 }
1486
1487 // Native callback.
1488 private int getHoverTapSlop() {
1489 return ViewConfiguration.getHoverTapSlop();
1490 }
1491
1492 // Native callback.
1493 private int getDoubleTapTimeout() {
1494 return ViewConfiguration.getDoubleTapTimeout();
1495 }
1496
1497 // Native callback.
1498 private int getLongPressTimeout() {
1499 return ViewConfiguration.getLongPressTimeout();
1500 }
1501
1502 // Native callback.
1503 private int getPointerLayer() {
Jeff Browna9d131c2012-09-20 16:48:17 -07001504 return mWindowManagerCallbacks.getPointerLayer();
Jeff Brown4532e612012-04-05 14:27:12 -07001505 }
1506
1507 // Native callback.
1508 private PointerIcon getPointerIcon() {
1509 return PointerIcon.getDefaultIcon(mContext);
1510 }
1511
Jeff Brown6ec6f792012-04-17 16:52:41 -07001512 // Native callback.
RoboErikfb290df2013-12-16 11:27:55 -08001513 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001514 if (!mSystemReady) {
1515 return null;
1516 }
1517
RoboErikfb290df2013-12-16 11:27:55 -08001518 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001519 if (keyboardLayoutDescriptor == null) {
1520 return null;
1521 }
1522
1523 final String[] result = new String[2];
1524 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1525 @Override
1526 public void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001527 String descriptor, String label, String collection, int keyboardLayoutResId) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001528 try {
1529 result[0] = descriptor;
1530 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07001531 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07001532 } catch (IOException ex) {
1533 } catch (NotFoundException ex) {
1534 }
1535 }
1536 });
1537 if (result[0] == null) {
1538 Log.w(TAG, "Could not get keyboard layout with descriptor '"
1539 + keyboardLayoutDescriptor + "'.");
1540 return null;
1541 }
1542 return result;
1543 }
1544
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001545 // Native callback.
1546 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07001547 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
1548 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
1549 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001550 }
1551 return null;
1552 }
1553
Jeff Brown4532e612012-04-05 14:27:12 -07001554 /**
1555 * Callback interface implemented by the Window Manager.
1556 */
Jeff Browna9d131c2012-09-20 16:48:17 -07001557 public interface WindowManagerCallbacks {
Jeff Brown4532e612012-04-05 14:27:12 -07001558 public void notifyConfigurationChanged();
1559
1560 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
1561
1562 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
1563
1564 public long notifyANR(InputApplicationHandle inputApplicationHandle,
Jeff Brownbd181bb2013-09-10 16:44:24 -07001565 InputWindowHandle inputWindowHandle, String reason);
Jeff Brown4532e612012-04-05 14:27:12 -07001566
1567 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
1568
Jeff Brown26875502014-01-30 21:47:47 -08001569 public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001570
1571 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
1572 KeyEvent event, int policyFlags);
1573
1574 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1575 KeyEvent event, int policyFlags);
1576
1577 public int getPointerLayer();
1578 }
1579
1580 /**
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001581 * Callback interface implemented by WiredAccessoryObserver.
1582 */
1583 public interface WiredAccessoryCallbacks {
1584 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
1585 }
1586
1587 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001588 * Private handler for the input manager.
1589 */
1590 private final class InputManagerHandler extends Handler {
Jeff Browna9d131c2012-09-20 16:48:17 -07001591 public InputManagerHandler(Looper looper) {
1592 super(looper, null, true /*async*/);
Jeff Browna2910d02012-08-25 12:29:46 -07001593 }
1594
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001595 @Override
1596 public void handleMessage(Message msg) {
1597 switch (msg.what) {
1598 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07001599 deliverInputDevicesChanged((InputDevice[])msg.obj);
1600 break;
1601 case MSG_SWITCH_KEYBOARD_LAYOUT:
1602 handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
1603 break;
1604 case MSG_RELOAD_KEYBOARD_LAYOUTS:
1605 reloadKeyboardLayouts();
1606 break;
1607 case MSG_UPDATE_KEYBOARD_LAYOUTS:
1608 updateKeyboardLayouts();
1609 break;
1610 case MSG_RELOAD_DEVICE_ALIASES:
1611 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001612 break;
1613 }
1614 }
1615 }
1616
1617 /**
Jeff Brown4532e612012-04-05 14:27:12 -07001618 * Hosting interface for input filters to call back into the input manager.
1619 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001620 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07001621 private boolean mDisconnected;
1622
1623 public void disconnectLocked() {
1624 mDisconnected = true;
1625 }
1626
Craig Mautner2f39e9f2012-09-21 11:39:54 -07001627 @Override
Jeff Brown0029c662011-03-30 02:25:18 -07001628 public void sendInputEvent(InputEvent event, int policyFlags) {
1629 if (event == null) {
1630 throw new IllegalArgumentException("event must not be null");
1631 }
1632
1633 synchronized (mInputFilterLock) {
1634 if (!mDisconnected) {
Jeff Brownca9bc702014-02-11 14:32:56 -08001635 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
Jeff Brownac143512012-04-05 18:57:33 -07001636 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07001637 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
1638 }
1639 }
1640 }
1641 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001642
1643 private static final class KeyboardLayoutDescriptor {
1644 public String packageName;
1645 public String receiverName;
1646 public String keyboardLayoutName;
1647
1648 public static String format(String packageName,
1649 String receiverName, String keyboardName) {
1650 return packageName + "/" + receiverName + "/" + keyboardName;
1651 }
1652
1653 public static KeyboardLayoutDescriptor parse(String descriptor) {
1654 int pos = descriptor.indexOf('/');
1655 if (pos < 0 || pos + 1 == descriptor.length()) {
1656 return null;
1657 }
1658 int pos2 = descriptor.indexOf('/', pos + 1);
1659 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
1660 return null;
1661 }
1662
1663 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
1664 result.packageName = descriptor.substring(0, pos);
1665 result.receiverName = descriptor.substring(pos + 1, pos2);
1666 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
1667 return result;
1668 }
1669 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001670
Jeff Brown6ec6f792012-04-17 16:52:41 -07001671 private interface KeyboardLayoutVisitor {
1672 void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001673 String descriptor, String label, String collection, int keyboardLayoutResId);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001674 }
1675
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001676 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
1677 private final int mPid;
1678 private final IInputDevicesChangedListener mListener;
1679
1680 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
1681 mPid = pid;
1682 mListener = listener;
1683 }
1684
1685 @Override
1686 public void binderDied() {
1687 if (DEBUG) {
1688 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
1689 }
1690 onInputDevicesChangedListenerDied(mPid);
1691 }
1692
1693 public void notifyInputDevicesChanged(int[] info) {
1694 try {
1695 mListener.onInputDevicesChanged(info);
1696 } catch (RemoteException ex) {
1697 Slog.w(TAG, "Failed to notify process "
1698 + mPid + " that input devices changed, assuming it died.", ex);
1699 binderDied();
1700 }
1701 }
1702 }
Jeff Browna47425a2012-04-13 04:09:27 -07001703
1704 private final class VibratorToken implements DeathRecipient {
1705 public final int mDeviceId;
1706 public final IBinder mToken;
1707 public final int mTokenValue;
1708
1709 public boolean mVibrating;
1710
1711 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
1712 mDeviceId = deviceId;
1713 mToken = token;
1714 mTokenValue = tokenValue;
1715 }
1716
1717 @Override
1718 public void binderDied() {
1719 if (DEBUG) {
1720 Slog.d(TAG, "Vibrator token died.");
1721 }
1722 onVibratorTokenDied(this);
1723 }
1724 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08001725
1726 private final class LocalService extends InputManagerInternal {
1727 @Override
1728 public void setDisplayViewports(
1729 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
1730 setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
1731 }
Jeff Brownca9bc702014-02-11 14:32:56 -08001732
1733 @Override
1734 public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
1735 return injectInputEventInternal(event, displayId, mode);
1736 }
Jeff Brown4ccb8232014-01-16 22:16:42 -08001737 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001738}