blob: 95655a56b661883fa3c2aa81f5eb640cd80912a8 [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 Browncf39bdf2012-05-18 14:41:19 -070019import com.android.internal.R;
Jeff Brown46b9ac02010-04-22 18:58:52 -070020import com.android.internal.util.XmlUtils;
Jeff Brown89ef0722011-08-10 16:25:21 -070021import com.android.server.Watchdog;
Jeff Brownd728bf52012-09-08 18:05:28 -070022import com.android.server.display.DisplayManagerService;
23import com.android.server.display.DisplayViewport;
Jeff Brown46b9ac02010-04-22 18:58:52 -070024
25import org.xmlpull.v1.XmlPullParser;
26
Jeff Browna3bc5652012-04-17 11:42:25 -070027import android.Manifest;
Jeff Browncf39bdf2012-05-18 14:41:19 -070028import android.app.Notification;
29import android.app.NotificationManager;
30import android.app.PendingIntent;
Jeff Brown5bbd4b42012-04-20 19:28:00 -070031import android.bluetooth.BluetoothAdapter;
32import android.bluetooth.BluetoothDevice;
Jeff Brown6ec6f792012-04-17 16:52:41 -070033import android.content.BroadcastReceiver;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070034import android.content.ComponentName;
Jeff Brown46b9ac02010-04-22 18:58:52 -070035import android.content.Context;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070036import android.content.Intent;
Jeff Brown6ec6f792012-04-17 16:52:41 -070037import android.content.IntentFilter;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070038import android.content.pm.ActivityInfo;
Jeff Brown349703e2010-06-22 01:27:15 -070039import android.content.pm.PackageManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070040import android.content.pm.ResolveInfo;
41import android.content.pm.PackageManager.NameNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070042import android.content.res.Resources;
Jeff Brown6ec6f792012-04-17 16:52:41 -070043import android.content.res.Resources.NotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070044import android.content.res.TypedArray;
45import android.content.res.XmlResourceParser;
Jeff Brown1a84fd12011-06-02 01:26:32 -070046import android.database.ContentObserver;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070047import android.hardware.input.IInputDevicesChangedListener;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070048import android.hardware.input.IInputManager;
Jeff Brownac143512012-04-05 18:57:33 -070049import android.hardware.input.InputManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070050import android.hardware.input.KeyboardLayout;
Jeff Brown4532e612012-04-05 14:27:12 -070051import android.os.Binder;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070052import android.os.Bundle;
Jeff Brown46b9ac02010-04-22 18:58:52 -070053import android.os.Environment;
Jeff Brown4532e612012-04-05 14:27:12 -070054import android.os.Handler;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070055import android.os.IBinder;
56import android.os.Message;
Jeff Brown05dc66a2011-03-02 14:41:58 -080057import android.os.MessageQueue;
Jeff Brownac143512012-04-05 18:57:33 -070058import android.os.Process;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070059import android.os.RemoteException;
Jeff Brown1a84fd12011-06-02 01:26:32 -070060import android.provider.Settings;
61import android.provider.Settings.SettingNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070062import android.util.Log;
Jeff Brown46b9ac02010-04-22 18:58:52 -070063import android.util.Slog;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070064import android.util.SparseArray;
Jeff Brown46b9ac02010-04-22 18:58:52 -070065import android.util.Xml;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070066import android.view.IInputFilter;
67import android.view.IInputFilterHost;
Jeff Brown46b9ac02010-04-22 18:58:52 -070068import android.view.InputChannel;
Jeff Brown8d608662010-08-30 03:02:23 -070069import android.view.InputDevice;
Jeff Brown6ec402b2010-07-28 15:48:59 -070070import android.view.InputEvent;
Jeff Brown1f245102010-11-18 20:53:46 -080071import android.view.KeyEvent;
Jeff Brown2352b972011-04-12 22:39:53 -070072import android.view.PointerIcon;
Jeff Brown46b9ac02010-04-22 18:58:52 -070073import android.view.Surface;
Jeff Browna4547672011-03-02 21:38:11 -080074import android.view.ViewConfiguration;
Jeff Brown0029c662011-03-30 02:25:18 -070075import android.view.WindowManagerPolicy;
Jeff Browncf39bdf2012-05-18 14:41:19 -070076import android.widget.Toast;
Jeff Brown46b9ac02010-04-22 18:58:52 -070077
Jeff Brown46b9ac02010-04-22 18:58:52 -070078import java.io.File;
Jeff Brown4532e612012-04-05 14:27:12 -070079import java.io.FileDescriptor;
Jeff Brown46b9ac02010-04-22 18:58:52 -070080import java.io.FileNotFoundException;
81import java.io.FileReader;
82import java.io.IOException;
Jeff Brown6ec6f792012-04-17 16:52:41 -070083import java.io.InputStreamReader;
Jeff Brown46b9ac02010-04-22 18:58:52 -070084import java.io.PrintWriter;
85import java.util.ArrayList;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070086import java.util.HashMap;
Jeff Browncf39bdf2012-05-18 14:41:19 -070087import java.util.HashSet;
Jeff Browna3bc5652012-04-17 11:42:25 -070088
Jeff Brown6ec6f792012-04-17 16:52:41 -070089import libcore.io.Streams;
Jeff Browna3bc5652012-04-17 11:42:25 -070090import libcore.util.Objects;
Jeff Brown46b9ac02010-04-22 18:58:52 -070091
92/*
93 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -070094 */
Jeff Brownd728bf52012-09-08 18:05:28 -070095public class InputManagerService extends IInputManager.Stub
96 implements Watchdog.Monitor, DisplayManagerService.InputManagerFuncs {
Jeff Brown46b9ac02010-04-22 18:58:52 -070097 static final String TAG = "InputManager";
Jeff Brown1b9ba572012-05-21 10:54:18 -070098 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -070099
Jeff Brown4532e612012-04-05 14:27:12 -0700100 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
101
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700102 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700103 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
104 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
105 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
106 private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700107
Jeff Brown4532e612012-04-05 14:27:12 -0700108 // Pointer to native input manager service object.
109 private final int mPtr;
110
Jeff Brown46b9ac02010-04-22 18:58:52 -0700111 private final Context mContext;
Jeff Brown4532e612012-04-05 14:27:12 -0700112 private final Callbacks mCallbacks;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700113 private final InputManagerHandler mHandler;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700114 private boolean mSystemReady;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700115 private NotificationManager mNotificationManager;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700116
Jeff Browna3bc5652012-04-17 11:42:25 -0700117 // Persistent data store. Must be locked each time during use.
118 private final PersistentDataStore mDataStore = new PersistentDataStore();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700119
120 // List of currently registered input devices changed listeners by process id.
121 private Object mInputDevicesLock = new Object();
122 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
123 private InputDevice[] mInputDevices = new InputDevice[0];
124 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
125 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
126 private final ArrayList<InputDevicesChangedListenerRecord>
127 mTempInputDevicesChangedListenersToNotify =
128 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
Jeff Browncf39bdf2012-05-18 14:41:19 -0700129 private final ArrayList<InputDevice>
130 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
131 private boolean mKeyboardLayoutNotificationShown;
132 private PendingIntent mKeyboardLayoutIntent;
133 private Toast mSwitchedKeyboardLayoutToast;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700134
Jeff Browna47425a2012-04-13 04:09:27 -0700135 // State for vibrator tokens.
136 private Object mVibratorLock = new Object();
137 private HashMap<IBinder, VibratorToken> mVibratorTokens =
138 new HashMap<IBinder, VibratorToken>();
139 private int mNextVibratorTokenValue;
140
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700141 // State for the currently installed input filter.
142 final Object mInputFilterLock = new Object();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700143 IInputFilter mInputFilter; // guarded by mInputFilterLock
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700144 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
Jeff Brown1a84fd12011-06-02 01:26:32 -0700145
Jeff Brown4532e612012-04-05 14:27:12 -0700146 private static native int nativeInit(InputManagerService service,
147 Context context, MessageQueue messageQueue);
148 private static native void nativeStart(int ptr);
Jeff Brownd728bf52012-09-08 18:05:28 -0700149 private static native void nativeSetDisplayViewport(int ptr, boolean external,
150 int displayId, int rotation,
151 int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
152 int physicalLeft, int physicalTop, int physicalRight, int physicalBottom);
153
Jeff Brown4532e612012-04-05 14:27:12 -0700154 private static native int nativeGetScanCodeState(int ptr,
155 int deviceId, int sourceMask, int scanCode);
156 private static native int nativeGetKeyCodeState(int ptr,
157 int deviceId, int sourceMask, int keyCode);
158 private static native int nativeGetSwitchState(int ptr,
159 int deviceId, int sourceMask, int sw);
160 private static native boolean nativeHasKeys(int ptr,
161 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
162 private static native void nativeRegisterInputChannel(int ptr, InputChannel inputChannel,
Jeff Brown928e0542011-01-10 11:17:36 -0800163 InputWindowHandle inputWindowHandle, boolean monitor);
Jeff Brown4532e612012-04-05 14:27:12 -0700164 private static native void nativeUnregisterInputChannel(int ptr, InputChannel inputChannel);
165 private static native void nativeSetInputFilterEnabled(int ptr, boolean enable);
166 private static native int nativeInjectInputEvent(int ptr, InputEvent event,
Jeff Brown0029c662011-03-30 02:25:18 -0700167 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
168 int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -0700169 private static native void nativeSetInputWindows(int ptr, InputWindowHandle[] windowHandles);
170 private static native void nativeSetInputDispatchMode(int ptr, boolean enabled, boolean frozen);
171 private static native void nativeSetSystemUiVisibility(int ptr, int visibility);
172 private static native void nativeSetFocusedApplication(int ptr,
173 InputApplicationHandle application);
Jeff Brown4532e612012-04-05 14:27:12 -0700174 private static native boolean nativeTransferTouchFocus(int ptr,
175 InputChannel fromChannel, InputChannel toChannel);
176 private static native void nativeSetPointerSpeed(int ptr, int speed);
177 private static native void nativeSetShowTouches(int ptr, boolean enabled);
Jeff Browna47425a2012-04-13 04:09:27 -0700178 private static native void nativeVibrate(int ptr, int deviceId, long[] pattern,
179 int repeat, int token);
180 private static native void nativeCancelVibrate(int ptr, int deviceId, int token);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700181 private static native void nativeReloadKeyboardLayouts(int ptr);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700182 private static native void nativeReloadDeviceAliases(int ptr);
Jeff Brown4532e612012-04-05 14:27:12 -0700183 private static native String nativeDump(int ptr);
184 private static native void nativeMonitor(int ptr);
Jeff Brown4532e612012-04-05 14:27:12 -0700185
Jeff Brownac143512012-04-05 18:57:33 -0700186 // Input event injection constants defined in InputDispatcher.h.
187 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
188 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
189 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
190 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
191
192 // Maximum number of milliseconds to wait for input event injection.
193 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
194
Jeff Brown6d0fec22010-07-23 21:28:06 -0700195 // Key states (may be returned by queries about the current state of a
196 // particular key code, scan code or switch).
197
198 /** The key state is unknown or the requested key itself is not supported. */
199 public static final int KEY_STATE_UNKNOWN = -1;
200
201 /** The key is up. /*/
202 public static final int KEY_STATE_UP = 0;
203
204 /** The key is down. */
205 public static final int KEY_STATE_DOWN = 1;
206
207 /** The key is down but is a virtual key press that is being emulated by the system. */
208 public static final int KEY_STATE_VIRTUAL = 2;
209
Jeff Brownc458ce92012-04-30 14:58:40 -0700210 /** Scan code: Mouse / trackball button. */
211 public static final int BTN_MOUSE = 0x110;
212
213 /** Switch code: Lid switch. When set, lid is shut. */
214 public static final int SW_LID = 0x00;
215
216 /** Switch code: Keypad slide. When set, keyboard is exposed. */
217 public static final int SW_KEYPAD_SLIDE = 0x0a;
218
Jeff Brown4532e612012-04-05 14:27:12 -0700219 public InputManagerService(Context context, Callbacks callbacks) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700220 this.mContext = context;
Jeff Brown4532e612012-04-05 14:27:12 -0700221 this.mCallbacks = callbacks;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700222 this.mHandler = new InputManagerHandler();
Jeff Brown05dc66a2011-03-02 14:41:58 -0800223
Jeff Brown46b9ac02010-04-22 18:58:52 -0700224 Slog.i(TAG, "Initializing input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700225 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700226 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700227
Jeff Brown46b9ac02010-04-22 18:58:52 -0700228 public void start() {
229 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700230 nativeStart(mPtr);
231
232 // Add ourself to the Watchdog monitors.
233 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700234
235 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700236 registerShowTouchesSettingObserver();
237
Jeff Brown1a84fd12011-06-02 01:26:32 -0700238 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700239 updateShowTouchesFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700240 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700241
Matthew Xie96313142012-06-29 16:57:31 -0700242 // TODO(BT) Pass in paramter for bluetooth system
243 public void systemReady() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700244 if (DEBUG) {
245 Slog.d(TAG, "System ready.");
246 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700247 mNotificationManager = (NotificationManager)mContext.getSystemService(
248 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700249 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700250
251 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
252 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
253 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
254 filter.addDataScheme("package");
255 mContext.registerReceiver(new BroadcastReceiver() {
256 @Override
257 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700258 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700259 }
260 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700261
262 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
263 mContext.registerReceiver(new BroadcastReceiver() {
264 @Override
265 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700266 reloadDeviceAliases();
267 }
268 }, filter, null, mHandler);
269
Jeff Browncf39bdf2012-05-18 14:41:19 -0700270 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
271 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700272 }
273
274 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700275 if (DEBUG) {
276 Slog.d(TAG, "Reloading keyboard layouts.");
277 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700278 nativeReloadKeyboardLayouts(mPtr);
279 }
280
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700281 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700282 if (DEBUG) {
283 Slog.d(TAG, "Reloading device names.");
284 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700285 nativeReloadDeviceAliases(mPtr);
286 }
287
Jeff Brownd728bf52012-09-08 18:05:28 -0700288 @Override
289 public void setDisplayViewports(DisplayViewport defaultViewport,
290 DisplayViewport externalTouchViewport) {
291 if (defaultViewport.valid) {
292 setDisplayViewport(false, defaultViewport);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700293 }
Jeff Brownd728bf52012-09-08 18:05:28 -0700294
295 if (externalTouchViewport.valid) {
296 setDisplayViewport(true, externalTouchViewport);
297 } else if (defaultViewport.valid) {
298 setDisplayViewport(true, defaultViewport);
Jeff Brownb6997262010-10-08 22:31:17 -0700299 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700300 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700301
Jeff Brownd728bf52012-09-08 18:05:28 -0700302 private void setDisplayViewport(boolean external, DisplayViewport viewport) {
303 nativeSetDisplayViewport(mPtr, external,
304 viewport.displayId, viewport.orientation,
305 viewport.logicalFrame.left, viewport.logicalFrame.top,
306 viewport.logicalFrame.right, viewport.logicalFrame.bottom,
307 viewport.physicalFrame.left, viewport.physicalFrame.top,
308 viewport.physicalFrame.right, viewport.physicalFrame.bottom);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700309 }
Jeff Brownac143512012-04-05 18:57:33 -0700310
Jeff Brown6d0fec22010-07-23 21:28:06 -0700311 /**
312 * Gets the current state of a key or button by key code.
313 * @param deviceId The input device id, or -1 to consult all devices.
314 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
315 * consider all input sources. An input device is consulted if at least one of its
316 * non-class input source bits matches the specified source mask.
317 * @param keyCode The key code to check.
318 * @return The key state.
319 */
320 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700321 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700322 }
323
Jeff Brown6d0fec22010-07-23 21:28:06 -0700324 /**
325 * Gets the current state of a key or button by scan code.
326 * @param deviceId The input device id, or -1 to consult all devices.
327 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
328 * consider all input sources. An input device is consulted if at least one of its
329 * non-class input source bits matches the specified source mask.
330 * @param scanCode The scan code to check.
331 * @return The key state.
332 */
333 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700334 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700335 }
336
Jeff Brown6d0fec22010-07-23 21:28:06 -0700337 /**
338 * Gets the current state of a switch by switch code.
339 * @param deviceId The input device id, or -1 to consult all devices.
340 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
341 * consider all input sources. An input device is consulted if at least one of its
342 * non-class input source bits matches the specified source mask.
343 * @param switchCode The switch code to check.
344 * @return The switch state.
345 */
346 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700347 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700348 }
349
Jeff Brown6d0fec22010-07-23 21:28:06 -0700350 /**
351 * Determines whether the specified key codes are supported by a particular device.
352 * @param deviceId The input device id, or -1 to consult all devices.
353 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
354 * consider all input sources. An input device is consulted if at least one of its
355 * non-class input source bits matches the specified source mask.
356 * @param keyCodes The array of key codes to check.
357 * @param keyExists An array at least as large as keyCodes whose entries will be set
358 * to true or false based on the presence or absence of support for the corresponding
359 * key codes.
360 * @return True if the lookup was successful, false otherwise.
361 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700362 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700363 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700364 if (keyCodes == null) {
365 throw new IllegalArgumentException("keyCodes must not be null.");
366 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700367 if (keyExists == null || keyExists.length < keyCodes.length) {
368 throw new IllegalArgumentException("keyExists must not be null and must be at "
369 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700370 }
371
Jeff Brown4532e612012-04-05 14:27:12 -0700372 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700373 }
374
Jeff Browna41ca772010-08-11 14:46:32 -0700375 /**
376 * Creates an input channel that will receive all input from the input dispatcher.
377 * @param inputChannelName The input channel name.
378 * @return The input channel.
379 */
380 public InputChannel monitorInput(String inputChannelName) {
381 if (inputChannelName == null) {
382 throw new IllegalArgumentException("inputChannelName must not be null.");
383 }
384
385 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700386 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700387 inputChannels[0].dispose(); // don't need to retain the Java object reference
388 return inputChannels[1];
389 }
390
391 /**
392 * Registers an input channel so that it can be used as an input event target.
393 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800394 * @param inputWindowHandle The handle of the input window associated with the
395 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700396 */
Jeff Brown928e0542011-01-10 11:17:36 -0800397 public void registerInputChannel(InputChannel inputChannel,
398 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700399 if (inputChannel == null) {
400 throw new IllegalArgumentException("inputChannel must not be null.");
401 }
402
Jeff Brown4532e612012-04-05 14:27:12 -0700403 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700404 }
405
Jeff Browna41ca772010-08-11 14:46:32 -0700406 /**
407 * Unregisters an input channel.
408 * @param inputChannel The input channel to unregister.
409 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700410 public void unregisterInputChannel(InputChannel inputChannel) {
411 if (inputChannel == null) {
412 throw new IllegalArgumentException("inputChannel must not be null.");
413 }
414
Jeff Brown4532e612012-04-05 14:27:12 -0700415 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700416 }
Jeff Brown0029c662011-03-30 02:25:18 -0700417
418 /**
419 * Sets an input filter that will receive all input events before they are dispatched.
420 * The input filter may then reinterpret input events or inject new ones.
421 *
422 * To ensure consistency, the input dispatcher automatically drops all events
423 * in progress whenever an input filter is installed or uninstalled. After an input
424 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
425 * Any events it attempts to send after it has been uninstalled will be dropped.
426 *
427 * @param filter The input filter, or null to remove the current filter.
428 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700429 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700430 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700431 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700432 if (oldFilter == filter) {
433 return; // nothing to do
434 }
435
436 if (oldFilter != null) {
437 mInputFilter = null;
438 mInputFilterHost.disconnectLocked();
439 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700440 try {
441 oldFilter.uninstall();
442 } catch (RemoteException re) {
443 /* ignore */
444 }
Jeff Brown0029c662011-03-30 02:25:18 -0700445 }
446
447 if (filter != null) {
448 mInputFilter = filter;
449 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700450 try {
451 filter.install(mInputFilterHost);
452 } catch (RemoteException re) {
453 /* ignore */
454 }
Jeff Brown0029c662011-03-30 02:25:18 -0700455 }
456
Jeff Brown4532e612012-04-05 14:27:12 -0700457 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700458 }
459 }
460
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700461 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700462 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700463 if (event == null) {
464 throw new IllegalArgumentException("event must not be null");
465 }
Jeff Brownac143512012-04-05 18:57:33 -0700466 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
467 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
468 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
469 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700470 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700471
Jeff Brownac143512012-04-05 18:57:33 -0700472 final int pid = Binder.getCallingPid();
473 final int uid = Binder.getCallingUid();
474 final long ident = Binder.clearCallingIdentity();
475 final int result;
476 try {
477 result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
478 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
479 } finally {
480 Binder.restoreCallingIdentity(ident);
481 }
482 switch (result) {
483 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
484 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
485 throw new SecurityException(
486 "Injecting to another application requires INJECT_EVENTS permission");
487 case INPUT_EVENT_INJECTION_SUCCEEDED:
488 return true;
489 case INPUT_EVENT_INJECTION_TIMED_OUT:
490 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
491 return false;
492 case INPUT_EVENT_INJECTION_FAILED:
493 default:
494 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
495 return false;
496 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700497 }
Jeff Brown0029c662011-03-30 02:25:18 -0700498
Jeff Brown8d608662010-08-30 03:02:23 -0700499 /**
500 * Gets information about the input device with the specified id.
501 * @param id The device id.
502 * @return The input device or null if not found.
503 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700504 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700505 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700506 synchronized (mInputDevicesLock) {
507 final int count = mInputDevices.length;
508 for (int i = 0; i < count; i++) {
509 final InputDevice inputDevice = mInputDevices[i];
510 if (inputDevice.getId() == deviceId) {
511 return inputDevice;
512 }
513 }
514 }
515 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700516 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700517
Jeff Brown8d608662010-08-30 03:02:23 -0700518 /**
519 * Gets the ids of all input devices in the system.
520 * @return The input device ids.
521 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700522 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700523 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700524 synchronized (mInputDevicesLock) {
525 final int count = mInputDevices.length;
526 int[] ids = new int[count];
527 for (int i = 0; i < count; i++) {
528 ids[i] = mInputDevices[i].getId();
529 }
530 return ids;
531 }
532 }
533
Jeff Browndaa37532012-05-01 15:54:03 -0700534 /**
535 * Gets all input devices in the system.
536 * @return The array of input devices.
537 */
538 public InputDevice[] getInputDevices() {
539 synchronized (mInputDevicesLock) {
540 return mInputDevices;
541 }
542 }
543
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700544 @Override // Binder call
545 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
546 if (listener == null) {
547 throw new IllegalArgumentException("listener must not be null");
548 }
549
550 synchronized (mInputDevicesLock) {
551 int callingPid = Binder.getCallingPid();
552 if (mInputDevicesChangedListeners.get(callingPid) != null) {
553 throw new SecurityException("The calling process has already "
554 + "registered an InputDevicesChangedListener.");
555 }
556
557 InputDevicesChangedListenerRecord record =
558 new InputDevicesChangedListenerRecord(callingPid, listener);
559 try {
560 IBinder binder = listener.asBinder();
561 binder.linkToDeath(record, 0);
562 } catch (RemoteException ex) {
563 // give up
564 throw new RuntimeException(ex);
565 }
566
567 mInputDevicesChangedListeners.put(callingPid, record);
568 }
569 }
570
571 private void onInputDevicesChangedListenerDied(int pid) {
572 synchronized (mInputDevicesLock) {
573 mInputDevicesChangedListeners.remove(pid);
574 }
575 }
576
577 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700578 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
579 // Scan for changes.
580 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700581 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700582 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700583 final int numListeners;
584 final int[] deviceIdAndGeneration;
585 synchronized (mInputDevicesLock) {
586 if (!mInputDevicesChangedPending) {
587 return;
588 }
589 mInputDevicesChangedPending = false;
590
591 numListeners = mInputDevicesChangedListeners.size();
592 for (int i = 0; i < numListeners; i++) {
593 mTempInputDevicesChangedListenersToNotify.add(
594 mInputDevicesChangedListeners.valueAt(i));
595 }
596
597 final int numDevices = mInputDevices.length;
598 deviceIdAndGeneration = new int[numDevices * 2];
599 for (int i = 0; i < numDevices; i++) {
600 final InputDevice inputDevice = mInputDevices[i];
601 deviceIdAndGeneration[i * 2] = inputDevice.getId();
602 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700603
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700604 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700605 if (!containsInputDeviceWithDescriptor(oldInputDevices,
606 inputDevice.getDescriptor())) {
607 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
608 } else {
609 mTempFullKeyboards.add(inputDevice);
610 }
611 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700612 }
613 }
614
Jeff Browncf39bdf2012-05-18 14:41:19 -0700615 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700616 for (int i = 0; i < numListeners; i++) {
617 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
618 deviceIdAndGeneration);
619 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700620 mTempInputDevicesChangedListenersToNotify.clear();
621
622 // Check for missing keyboard layouts.
623 if (mNotificationManager != null) {
624 final int numFullKeyboards = mTempFullKeyboards.size();
625 boolean missingLayoutForExternalKeyboard = false;
626 boolean missingLayoutForExternalKeyboardAdded = false;
627 synchronized (mDataStore) {
628 for (int i = 0; i < numFullKeyboards; i++) {
629 final InputDevice inputDevice = mTempFullKeyboards.get(i);
630 if (mDataStore.getCurrentKeyboardLayout(inputDevice.getDescriptor()) == null) {
631 missingLayoutForExternalKeyboard = true;
632 if (i < numFullKeyboardsAdded) {
633 missingLayoutForExternalKeyboardAdded = true;
634 }
635 }
636 }
637 }
638 if (missingLayoutForExternalKeyboard) {
639 if (missingLayoutForExternalKeyboardAdded) {
640 showMissingKeyboardLayoutNotification();
641 }
642 } else if (mKeyboardLayoutNotificationShown) {
643 hideMissingKeyboardLayoutNotification();
644 }
645 }
646 mTempFullKeyboards.clear();
647 }
648
649 // Must be called on handler.
650 private void showMissingKeyboardLayoutNotification() {
651 if (!mKeyboardLayoutNotificationShown) {
652 if (mKeyboardLayoutIntent == null) {
653 final Intent intent = new Intent("android.settings.INPUT_METHOD_SETTINGS");
654 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
655 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
656 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
657 mKeyboardLayoutIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
658 }
659
660 Resources r = mContext.getResources();
661 Notification notification = new Notification.Builder(mContext)
662 .setContentTitle(r.getString(
663 R.string.select_keyboard_layout_notification_title))
664 .setContentText(r.getString(
665 R.string.select_keyboard_layout_notification_message))
666 .setContentIntent(mKeyboardLayoutIntent)
667 .setSmallIcon(R.drawable.ic_settings_language)
668 .setPriority(Notification.PRIORITY_LOW)
669 .build();
670 mNotificationManager.notify(R.string.select_keyboard_layout_notification_title,
671 notification);
672 mKeyboardLayoutNotificationShown = true;
673 }
674 }
675
676 // Must be called on handler.
677 private void hideMissingKeyboardLayoutNotification() {
678 if (mKeyboardLayoutNotificationShown) {
679 mKeyboardLayoutNotificationShown = false;
680 mNotificationManager.cancel(R.string.select_keyboard_layout_notification_title);
681 }
682 }
683
684 // Must be called on handler.
685 private void updateKeyboardLayouts() {
686 // Scan all input devices state for keyboard layouts that have been uninstalled.
687 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
688 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
689 @Override
690 public void visitKeyboardLayout(Resources resources,
691 String descriptor, String label, String collection, int keyboardLayoutResId) {
692 availableKeyboardLayouts.add(descriptor);
693 }
694 });
695 synchronized (mDataStore) {
696 try {
697 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
698 } finally {
699 mDataStore.saveIfNeeded();
700 }
701 }
702
703 // Reload keyboard layouts.
704 reloadKeyboardLayouts();
705 }
706
Jeff Browncf39bdf2012-05-18 14:41:19 -0700707 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
708 String descriptor) {
709 final int numDevices = inputDevices.length;
710 for (int i = 0; i < numDevices; i++) {
711 final InputDevice inputDevice = inputDevices[i];
712 if (inputDevice.getDescriptor().equals(descriptor)) {
713 return true;
714 }
715 }
716 return false;
Jeff Brown8d608662010-08-30 03:02:23 -0700717 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700718
719 @Override // Binder call
720 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700721 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
722 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
723 @Override
724 public void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700725 String descriptor, String label, String collection, int keyboardLayoutResId) {
726 list.add(new KeyboardLayout(descriptor, label, collection));
Jeff Brown6ec6f792012-04-17 16:52:41 -0700727 }
728 });
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700729 return list.toArray(new KeyboardLayout[list.size()]);
730 }
731
732 @Override // Binder call
733 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
734 if (keyboardLayoutDescriptor == null) {
735 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
736 }
737
Jeff Brown6ec6f792012-04-17 16:52:41 -0700738 final KeyboardLayout[] result = new KeyboardLayout[1];
739 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
740 @Override
741 public void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700742 String descriptor, String label, String collection, int keyboardLayoutResId) {
743 result[0] = new KeyboardLayout(descriptor, label, collection);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700744 }
745 });
746 if (result[0] == null) {
747 Log.w(TAG, "Could not get keyboard layout with descriptor '"
748 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700749 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700750 return result[0];
751 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700752
Jeff Brown6ec6f792012-04-17 16:52:41 -0700753 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700754 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700755 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
756 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
757 PackageManager.GET_META_DATA)) {
758 visitKeyboardLayoutsInPackage(pm, resolveInfo.activityInfo, null, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700759 }
760 }
761
Jeff Brown6ec6f792012-04-17 16:52:41 -0700762 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
763 KeyboardLayoutVisitor visitor) {
764 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
765 if (d != null) {
766 final PackageManager pm = mContext.getPackageManager();
767 try {
768 ActivityInfo receiver = pm.getReceiverInfo(
769 new ComponentName(d.packageName, d.receiverName),
770 PackageManager.GET_META_DATA);
771 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, visitor);
772 } catch (NameNotFoundException ex) {
773 }
774 }
775 }
776
777 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
778 String keyboardName, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700779 Bundle metaData = receiver.metaData;
780 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700781 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700782 }
783
784 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
785 if (configResId == 0) {
786 Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
787 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700788 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700789 }
790
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700791 CharSequence receiverLabel = receiver.loadLabel(pm);
792 String collection = receiverLabel != null ? receiverLabel.toString() : "";
793
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700794 try {
795 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
796 XmlResourceParser parser = resources.getXml(configResId);
797 try {
798 XmlUtils.beginDocument(parser, "keyboard-layouts");
799
800 for (;;) {
801 XmlUtils.nextElement(parser);
802 String element = parser.getName();
803 if (element == null) {
804 break;
805 }
806 if (element.equals("keyboard-layout")) {
807 TypedArray a = resources.obtainAttributes(
808 parser, com.android.internal.R.styleable.KeyboardLayout);
809 try {
810 String name = a.getString(
811 com.android.internal.R.styleable.KeyboardLayout_name);
812 String label = a.getString(
813 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -0700814 int keyboardLayoutResId = a.getResourceId(
815 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
816 0);
817 if (name == null || label == null || keyboardLayoutResId == 0) {
818 Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700819 + "attributes in keyboard layout "
820 + "resource from receiver "
821 + receiver.packageName + "/" + receiver.name);
822 } else {
823 String descriptor = KeyboardLayoutDescriptor.format(
824 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700825 if (keyboardName == null || name.equals(keyboardName)) {
826 visitor.visitKeyboardLayout(resources, descriptor,
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700827 label, collection, keyboardLayoutResId);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700828 }
829 }
830 } finally {
831 a.recycle();
832 }
833 } else {
834 Log.w(TAG, "Skipping unrecognized element '" + element
835 + "' in keyboard layout resource from receiver "
836 + receiver.packageName + "/" + receiver.name);
837 }
838 }
839 } finally {
840 parser.close();
841 }
842 } catch (Exception ex) {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700843 Log.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700844 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700845 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700846 }
847
848 @Override // Binder call
Jeff Browncf39bdf2012-05-18 14:41:19 -0700849 public String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700850 if (inputDeviceDescriptor == null) {
851 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
852 }
853
Jeff Browna3bc5652012-04-17 11:42:25 -0700854 synchronized (mDataStore) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700855 return mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
Jeff Browna3bc5652012-04-17 11:42:25 -0700856 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700857 }
858
859 @Override // Binder call
Jeff Browncf39bdf2012-05-18 14:41:19 -0700860 public void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700861 String keyboardLayoutDescriptor) {
862 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -0700863 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700864 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
865 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700866 if (inputDeviceDescriptor == null) {
867 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
868 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700869 if (keyboardLayoutDescriptor == null) {
870 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
871 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700872
Jeff Browna3bc5652012-04-17 11:42:25 -0700873 synchronized (mDataStore) {
874 try {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700875 if (mDataStore.setCurrentKeyboardLayout(
876 inputDeviceDescriptor, keyboardLayoutDescriptor)) {
877 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
878 }
Jeff Browna3bc5652012-04-17 11:42:25 -0700879 } finally {
880 mDataStore.saveIfNeeded();
881 }
882 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700883 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700884
Jeff Browncf39bdf2012-05-18 14:41:19 -0700885 @Override // Binder call
886 public String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor) {
887 if (inputDeviceDescriptor == null) {
888 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
889 }
890
891 synchronized (mDataStore) {
892 return mDataStore.getKeyboardLayouts(inputDeviceDescriptor);
893 }
894 }
895
896 @Override // Binder call
897 public void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
898 String keyboardLayoutDescriptor) {
899 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
900 "addKeyboardLayoutForInputDevice()")) {
901 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
902 }
903 if (inputDeviceDescriptor == null) {
904 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
905 }
906 if (keyboardLayoutDescriptor == null) {
907 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
908 }
909
910 synchronized (mDataStore) {
911 try {
912 String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
913 if (mDataStore.addKeyboardLayout(inputDeviceDescriptor, keyboardLayoutDescriptor)
914 && !Objects.equal(oldLayout,
915 mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) {
916 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
917 }
918 } finally {
919 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700920 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700921 }
922 }
923
924 @Override // Binder call
925 public void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
926 String keyboardLayoutDescriptor) {
927 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
928 "removeKeyboardLayoutForInputDevice()")) {
929 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
930 }
931 if (inputDeviceDescriptor == null) {
932 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
933 }
934 if (keyboardLayoutDescriptor == null) {
935 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
936 }
937
938 synchronized (mDataStore) {
939 try {
940 String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
941 if (mDataStore.removeKeyboardLayout(inputDeviceDescriptor,
942 keyboardLayoutDescriptor)
943 && !Objects.equal(oldLayout,
944 mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) {
945 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
946 }
947 } finally {
948 mDataStore.saveIfNeeded();
949 }
950 }
951 }
952
953 public void switchKeyboardLayout(int deviceId, int direction) {
954 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
955 }
956
957 // Must be called on handler.
958 private void handleSwitchKeyboardLayout(int deviceId, int direction) {
959 final InputDevice device = getInputDevice(deviceId);
960 final String inputDeviceDescriptor = device.getDescriptor();
961 if (device != null) {
962 final boolean changed;
963 final String keyboardLayoutDescriptor;
964 synchronized (mDataStore) {
965 try {
966 changed = mDataStore.switchKeyboardLayout(inputDeviceDescriptor, direction);
967 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
968 inputDeviceDescriptor);
969 } finally {
970 mDataStore.saveIfNeeded();
971 }
972 }
973
974 if (changed) {
975 if (mSwitchedKeyboardLayoutToast != null) {
976 mSwitchedKeyboardLayoutToast.cancel();
977 mSwitchedKeyboardLayoutToast = null;
978 }
979 if (keyboardLayoutDescriptor != null) {
980 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
981 if (keyboardLayout != null) {
982 mSwitchedKeyboardLayoutToast = Toast.makeText(
983 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
984 mSwitchedKeyboardLayoutToast.show();
985 }
986 }
987
988 reloadKeyboardLayouts();
989 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700990 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700991 }
992
Jeff Brown9302c872011-07-13 22:51:29 -0700993 public void setInputWindows(InputWindowHandle[] windowHandles) {
Jeff Brown4532e612012-04-05 14:27:12 -0700994 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -0700995 }
996
Jeff Brown9302c872011-07-13 22:51:29 -0700997 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -0700998 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -0700999 }
1000
Jeff Brown349703e2010-06-22 01:27:15 -07001001 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001002 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001003 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001004
1005 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001006 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001007 }
1008
Jeff Browne6504122010-09-27 14:52:15 -07001009 /**
1010 * Atomically transfers touch focus from one window to another as identified by
1011 * their input channels. It is possible for multiple windows to have
1012 * touch focus if they support split touch dispatch
1013 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1014 * method only transfers touch focus of the specified window without affecting
1015 * other windows that may also have touch focus at the same time.
1016 * @param fromChannel The channel of a window that currently has touch focus.
1017 * @param toChannel The channel of the window that should receive touch focus in
1018 * place of the first.
1019 * @return True if the transfer was successful. False if the window with the
1020 * specified channel did not actually have touch focus at the time of the request.
1021 */
1022 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1023 if (fromChannel == null) {
1024 throw new IllegalArgumentException("fromChannel must not be null.");
1025 }
1026 if (toChannel == null) {
1027 throw new IllegalArgumentException("toChannel must not be null.");
1028 }
Jeff Brown4532e612012-04-05 14:27:12 -07001029 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -07001030 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001031
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001032 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001033 public void tryPointerSpeed(int speed) {
1034 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1035 "tryPointerSpeed()")) {
1036 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1037 }
1038
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001039 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1040 throw new IllegalArgumentException("speed out of range");
1041 }
1042
Jeff Brownac143512012-04-05 18:57:33 -07001043 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001044 }
1045
1046 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001047 int speed = getPointerSpeedSetting();
1048 setPointerSpeedUnchecked(speed);
1049 }
1050
1051 private void setPointerSpeedUnchecked(int speed) {
1052 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1053 InputManager.MAX_POINTER_SPEED);
1054 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001055 }
1056
1057 private void registerPointerSpeedSettingObserver() {
1058 mContext.getContentResolver().registerContentObserver(
1059 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001060 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001061 @Override
1062 public void onChange(boolean selfChange) {
1063 updatePointerSpeedFromSettings();
1064 }
1065 });
1066 }
1067
Jeff Brownac143512012-04-05 18:57:33 -07001068 private int getPointerSpeedSetting() {
1069 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001070 try {
1071 speed = Settings.System.getInt(mContext.getContentResolver(),
1072 Settings.System.POINTER_SPEED);
1073 } catch (SettingNotFoundException snfe) {
1074 }
1075 return speed;
1076 }
1077
Jeff Browndaf4a122011-08-26 17:14:14 -07001078 public void updateShowTouchesFromSettings() {
1079 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001080 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001081 }
1082
1083 private void registerShowTouchesSettingObserver() {
1084 mContext.getContentResolver().registerContentObserver(
1085 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001086 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001087 @Override
1088 public void onChange(boolean selfChange) {
1089 updateShowTouchesFromSettings();
1090 }
1091 });
1092 }
1093
1094 private int getShowTouchesSetting(int defaultValue) {
1095 int result = defaultValue;
1096 try {
1097 result = Settings.System.getInt(mContext.getContentResolver(),
1098 Settings.System.SHOW_TOUCHES);
1099 } catch (SettingNotFoundException snfe) {
1100 }
1101 return result;
1102 }
1103
Jeff Browna47425a2012-04-13 04:09:27 -07001104 // Binder call
1105 @Override
1106 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1107 if (repeat >= pattern.length) {
1108 throw new ArrayIndexOutOfBoundsException();
1109 }
1110
1111 VibratorToken v;
1112 synchronized (mVibratorLock) {
1113 v = mVibratorTokens.get(token);
1114 if (v == null) {
1115 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1116 try {
1117 token.linkToDeath(v, 0);
1118 } catch (RemoteException ex) {
1119 // give up
1120 throw new RuntimeException(ex);
1121 }
1122 mVibratorTokens.put(token, v);
1123 }
1124 }
1125
1126 synchronized (v) {
1127 v.mVibrating = true;
1128 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1129 }
1130 }
1131
1132 // Binder call
1133 @Override
1134 public void cancelVibrate(int deviceId, IBinder token) {
1135 VibratorToken v;
1136 synchronized (mVibratorLock) {
1137 v = mVibratorTokens.get(token);
1138 if (v == null || v.mDeviceId != deviceId) {
1139 return; // nothing to cancel
1140 }
1141 }
1142
1143 cancelVibrateIfNeeded(v);
1144 }
1145
1146 void onVibratorTokenDied(VibratorToken v) {
1147 synchronized (mVibratorLock) {
1148 mVibratorTokens.remove(v.mToken);
1149 }
1150
1151 cancelVibrateIfNeeded(v);
1152 }
1153
1154 private void cancelVibrateIfNeeded(VibratorToken v) {
1155 synchronized (v) {
1156 if (v.mVibrating) {
1157 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1158 v.mVibrating = false;
1159 }
1160 }
1161 }
1162
Jeff Brown4532e612012-04-05 14:27:12 -07001163 @Override
1164 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna3bc5652012-04-17 11:42:25 -07001165 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
Jeff Brown4532e612012-04-05 14:27:12 -07001166 != PackageManager.PERMISSION_GRANTED) {
1167 pw.println("Permission Denial: can't dump InputManager from from pid="
1168 + Binder.getCallingPid()
1169 + ", uid=" + Binder.getCallingUid());
1170 return;
1171 }
1172
1173 pw.println("INPUT MANAGER (dumpsys input)\n");
1174 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001175 if (dumpStr != null) {
1176 pw.println(dumpStr);
1177 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001178 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001179
Jeff Brownac143512012-04-05 18:57:33 -07001180 private boolean checkCallingPermission(String permission, String func) {
1181 // Quick check: if the calling permission is me, it's all okay.
1182 if (Binder.getCallingPid() == Process.myPid()) {
1183 return true;
1184 }
1185
1186 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1187 return true;
1188 }
1189 String msg = "Permission Denial: " + func + " from pid="
1190 + Binder.getCallingPid()
1191 + ", uid=" + Binder.getCallingUid()
1192 + " requires " + permission;
1193 Slog.w(TAG, msg);
1194 return false;
1195 }
1196
Jeff Brown4532e612012-04-05 14:27:12 -07001197 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Jeff Brown89ef0722011-08-10 16:25:21 -07001198 public void monitor() {
1199 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -07001200 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001201 }
1202
Jeff Brown4532e612012-04-05 14:27:12 -07001203 // Native callback.
1204 private void notifyConfigurationChanged(long whenNanos) {
1205 mCallbacks.notifyConfigurationChanged();
1206 }
1207
1208 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001209 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1210 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001211 if (!mInputDevicesChangedPending) {
1212 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001213 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1214 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001215 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001216
1217 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001218 }
1219 }
1220
1221 // Native callback.
Jeff Brown53384282012-08-20 20:16:01 -07001222 private void notifySwitch(long whenNanos, int switchCode, int switchValue) {
1223 switch (switchCode) {
1224 case SW_LID:
1225 mCallbacks.notifyLidSwitchChanged(whenNanos, switchValue == 0);
1226 break;
1227 }
Jeff Brown4532e612012-04-05 14:27:12 -07001228 }
1229
1230 // Native callback.
1231 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
1232 mCallbacks.notifyInputChannelBroken(inputWindowHandle);
1233 }
1234
1235 // Native callback.
1236 private long notifyANR(InputApplicationHandle inputApplicationHandle,
1237 InputWindowHandle inputWindowHandle) {
1238 return mCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle);
1239 }
1240
1241 // Native callback.
1242 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1243 synchronized (mInputFilterLock) {
1244 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001245 try {
1246 mInputFilter.filterInputEvent(event, policyFlags);
1247 } catch (RemoteException e) {
1248 /* ignore */
1249 }
Jeff Brown4532e612012-04-05 14:27:12 -07001250 return false;
1251 }
1252 }
1253 event.recycle();
1254 return true;
1255 }
1256
1257 // Native callback.
1258 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
1259 return mCallbacks.interceptKeyBeforeQueueing(
1260 event, policyFlags, isScreenOn);
1261 }
1262
1263 // Native callback.
1264 private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
1265 return mCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
1266 }
1267
1268 // Native callback.
1269 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1270 KeyEvent event, int policyFlags) {
1271 return mCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
1272 }
1273
1274 // Native callback.
1275 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1276 KeyEvent event, int policyFlags) {
1277 return mCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
1278 }
1279
1280 // Native callback.
1281 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1282 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1283 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1284 }
1285
1286 // Native callback.
1287 private int getVirtualKeyQuietTimeMillis() {
1288 return mContext.getResources().getInteger(
1289 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1290 }
1291
1292 // Native callback.
1293 private String[] getExcludedDeviceNames() {
1294 ArrayList<String> names = new ArrayList<String>();
1295
1296 // Read partner-provided list of excluded input devices
1297 XmlPullParser parser = null;
1298 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1299 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1300 FileReader confreader = null;
1301 try {
1302 confreader = new FileReader(confFile);
1303 parser = Xml.newPullParser();
1304 parser.setInput(confreader);
1305 XmlUtils.beginDocument(parser, "devices");
1306
1307 while (true) {
1308 XmlUtils.nextElement(parser);
1309 if (!"device".equals(parser.getName())) {
1310 break;
1311 }
1312 String name = parser.getAttributeValue(null, "name");
1313 if (name != null) {
1314 names.add(name);
1315 }
1316 }
1317 } catch (FileNotFoundException e) {
1318 // It's ok if the file does not exist.
1319 } catch (Exception e) {
1320 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1321 } finally {
1322 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1323 }
1324
1325 return names.toArray(new String[names.size()]);
1326 }
1327
1328 // Native callback.
1329 private int getKeyRepeatTimeout() {
1330 return ViewConfiguration.getKeyRepeatTimeout();
1331 }
1332
1333 // Native callback.
1334 private int getKeyRepeatDelay() {
1335 return ViewConfiguration.getKeyRepeatDelay();
1336 }
1337
1338 // Native callback.
1339 private int getHoverTapTimeout() {
1340 return ViewConfiguration.getHoverTapTimeout();
1341 }
1342
1343 // Native callback.
1344 private int getHoverTapSlop() {
1345 return ViewConfiguration.getHoverTapSlop();
1346 }
1347
1348 // Native callback.
1349 private int getDoubleTapTimeout() {
1350 return ViewConfiguration.getDoubleTapTimeout();
1351 }
1352
1353 // Native callback.
1354 private int getLongPressTimeout() {
1355 return ViewConfiguration.getLongPressTimeout();
1356 }
1357
1358 // Native callback.
1359 private int getPointerLayer() {
1360 return mCallbacks.getPointerLayer();
1361 }
1362
1363 // Native callback.
1364 private PointerIcon getPointerIcon() {
1365 return PointerIcon.getDefaultIcon(mContext);
1366 }
1367
Jeff Brown6ec6f792012-04-17 16:52:41 -07001368 // Native callback.
1369 private String[] getKeyboardLayoutOverlay(String inputDeviceDescriptor) {
1370 if (!mSystemReady) {
1371 return null;
1372 }
1373
Jeff Browncf39bdf2012-05-18 14:41:19 -07001374 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(
1375 inputDeviceDescriptor);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001376 if (keyboardLayoutDescriptor == null) {
1377 return null;
1378 }
1379
1380 final String[] result = new String[2];
1381 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1382 @Override
1383 public void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001384 String descriptor, String label, String collection, int keyboardLayoutResId) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001385 try {
1386 result[0] = descriptor;
1387 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07001388 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07001389 } catch (IOException ex) {
1390 } catch (NotFoundException ex) {
1391 }
1392 }
1393 });
1394 if (result[0] == null) {
1395 Log.w(TAG, "Could not get keyboard layout with descriptor '"
1396 + keyboardLayoutDescriptor + "'.");
1397 return null;
1398 }
1399 return result;
1400 }
1401
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001402 // Native callback.
1403 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07001404 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
1405 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
1406 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001407 }
1408 return null;
1409 }
1410
Jeff Brown6ec6f792012-04-17 16:52:41 -07001411
Jeff Brown4532e612012-04-05 14:27:12 -07001412 /**
1413 * Callback interface implemented by the Window Manager.
1414 */
1415 public interface Callbacks {
1416 public void notifyConfigurationChanged();
1417
1418 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
1419
1420 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
1421
1422 public long notifyANR(InputApplicationHandle inputApplicationHandle,
1423 InputWindowHandle inputWindowHandle);
1424
1425 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
1426
1427 public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
1428
1429 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
1430 KeyEvent event, int policyFlags);
1431
1432 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1433 KeyEvent event, int policyFlags);
1434
1435 public int getPointerLayer();
1436 }
1437
1438 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001439 * Private handler for the input manager.
1440 */
1441 private final class InputManagerHandler extends Handler {
Jeff Browna2910d02012-08-25 12:29:46 -07001442 public InputManagerHandler() {
1443 super(true /*async*/);
1444 }
1445
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001446 @Override
1447 public void handleMessage(Message msg) {
1448 switch (msg.what) {
1449 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07001450 deliverInputDevicesChanged((InputDevice[])msg.obj);
1451 break;
1452 case MSG_SWITCH_KEYBOARD_LAYOUT:
1453 handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
1454 break;
1455 case MSG_RELOAD_KEYBOARD_LAYOUTS:
1456 reloadKeyboardLayouts();
1457 break;
1458 case MSG_UPDATE_KEYBOARD_LAYOUTS:
1459 updateKeyboardLayouts();
1460 break;
1461 case MSG_RELOAD_DEVICE_ALIASES:
1462 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001463 break;
1464 }
1465 }
1466 }
1467
1468 /**
Jeff Brown4532e612012-04-05 14:27:12 -07001469 * Hosting interface for input filters to call back into the input manager.
1470 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001471 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07001472 private boolean mDisconnected;
1473
1474 public void disconnectLocked() {
1475 mDisconnected = true;
1476 }
1477
1478 public void sendInputEvent(InputEvent event, int policyFlags) {
1479 if (event == null) {
1480 throw new IllegalArgumentException("event must not be null");
1481 }
1482
1483 synchronized (mInputFilterLock) {
1484 if (!mDisconnected) {
Jeff Brownac143512012-04-05 18:57:33 -07001485 nativeInjectInputEvent(mPtr, event, 0, 0,
1486 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07001487 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
1488 }
1489 }
1490 }
1491 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001492
1493 private static final class KeyboardLayoutDescriptor {
1494 public String packageName;
1495 public String receiverName;
1496 public String keyboardLayoutName;
1497
1498 public static String format(String packageName,
1499 String receiverName, String keyboardName) {
1500 return packageName + "/" + receiverName + "/" + keyboardName;
1501 }
1502
1503 public static KeyboardLayoutDescriptor parse(String descriptor) {
1504 int pos = descriptor.indexOf('/');
1505 if (pos < 0 || pos + 1 == descriptor.length()) {
1506 return null;
1507 }
1508 int pos2 = descriptor.indexOf('/', pos + 1);
1509 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
1510 return null;
1511 }
1512
1513 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
1514 result.packageName = descriptor.substring(0, pos);
1515 result.receiverName = descriptor.substring(pos + 1, pos2);
1516 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
1517 return result;
1518 }
1519 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001520
Jeff Brown6ec6f792012-04-17 16:52:41 -07001521 private interface KeyboardLayoutVisitor {
1522 void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001523 String descriptor, String label, String collection, int keyboardLayoutResId);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001524 }
1525
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001526 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
1527 private final int mPid;
1528 private final IInputDevicesChangedListener mListener;
1529
1530 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
1531 mPid = pid;
1532 mListener = listener;
1533 }
1534
1535 @Override
1536 public void binderDied() {
1537 if (DEBUG) {
1538 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
1539 }
1540 onInputDevicesChangedListenerDied(mPid);
1541 }
1542
1543 public void notifyInputDevicesChanged(int[] info) {
1544 try {
1545 mListener.onInputDevicesChanged(info);
1546 } catch (RemoteException ex) {
1547 Slog.w(TAG, "Failed to notify process "
1548 + mPid + " that input devices changed, assuming it died.", ex);
1549 binderDied();
1550 }
1551 }
1552 }
Jeff Browna47425a2012-04-13 04:09:27 -07001553
1554 private final class VibratorToken implements DeathRecipient {
1555 public final int mDeviceId;
1556 public final IBinder mToken;
1557 public final int mTokenValue;
1558
1559 public boolean mVibrating;
1560
1561 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
1562 mDeviceId = deviceId;
1563 mToken = token;
1564 mTokenValue = tokenValue;
1565 }
1566
1567 @Override
1568 public void binderDied() {
1569 if (DEBUG) {
1570 Slog.d(TAG, "Vibrator token died.");
1571 }
1572 onVibratorTokenDied(this);
1573 }
1574 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001575}