blob: 948c0e0383089393803e4fda9df34c19507a3292 [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;
Jeff Browna9d131c2012-09-20 16:48:17 -070056import android.os.Looper;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070057import android.os.Message;
Jeff Brown05dc66a2011-03-02 14:41:58 -080058import android.os.MessageQueue;
Jeff Brownac143512012-04-05 18:57:33 -070059import android.os.Process;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070060import android.os.RemoteException;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070061import android.os.UserHandle;
Jeff Brown1a84fd12011-06-02 01:26:32 -070062import android.provider.Settings;
63import android.provider.Settings.SettingNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070064import android.util.Log;
Jeff Brown46b9ac02010-04-22 18:58:52 -070065import android.util.Slog;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070066import android.util.SparseArray;
Jeff Brown46b9ac02010-04-22 18:58:52 -070067import android.util.Xml;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070068import android.view.IInputFilter;
69import android.view.IInputFilterHost;
Jeff Brown46b9ac02010-04-22 18:58:52 -070070import android.view.InputChannel;
Jeff Brown8d608662010-08-30 03:02:23 -070071import android.view.InputDevice;
Jeff Brown6ec402b2010-07-28 15:48:59 -070072import android.view.InputEvent;
Jeff Brown1f245102010-11-18 20:53:46 -080073import android.view.KeyEvent;
Jeff Brown2352b972011-04-12 22:39:53 -070074import android.view.PointerIcon;
Jeff Browna4547672011-03-02 21:38:11 -080075import android.view.ViewConfiguration;
Jeff Brown0029c662011-03-30 02:25:18 -070076import android.view.WindowManagerPolicy;
Jeff Browncf39bdf2012-05-18 14:41:19 -070077import android.widget.Toast;
Jeff Brown46b9ac02010-04-22 18:58:52 -070078
Jeff Brown46b9ac02010-04-22 18:58:52 -070079import java.io.File;
Jeff Brown4532e612012-04-05 14:27:12 -070080import java.io.FileDescriptor;
Jeff Brown46b9ac02010-04-22 18:58:52 -070081import java.io.FileNotFoundException;
82import java.io.FileReader;
83import java.io.IOException;
Jeff Brown6ec6f792012-04-17 16:52:41 -070084import java.io.InputStreamReader;
Jeff Brown46b9ac02010-04-22 18:58:52 -070085import java.io.PrintWriter;
86import java.util.ArrayList;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070087import java.util.HashMap;
Jeff Browncf39bdf2012-05-18 14:41:19 -070088import java.util.HashSet;
Jeff Browna3bc5652012-04-17 11:42:25 -070089
Jeff Brown6ec6f792012-04-17 16:52:41 -070090import libcore.io.Streams;
Jeff Browna3bc5652012-04-17 11:42:25 -070091import libcore.util.Objects;
Jeff Brown46b9ac02010-04-22 18:58:52 -070092
93/*
94 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -070095 */
Jeff Brownd728bf52012-09-08 18:05:28 -070096public class InputManagerService extends IInputManager.Stub
97 implements Watchdog.Monitor, DisplayManagerService.InputManagerFuncs {
Jeff Brown46b9ac02010-04-22 18:58:52 -070098 static final String TAG = "InputManager";
Jeff Brown1b9ba572012-05-21 10:54:18 -070099 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -0700100
Jeff Brown4532e612012-04-05 14:27:12 -0700101 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
102
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700103 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700104 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
105 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
106 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
107 private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700108
Jeff Brown4532e612012-04-05 14:27:12 -0700109 // Pointer to native input manager service object.
110 private final int mPtr;
111
Jeff Brown46b9ac02010-04-22 18:58:52 -0700112 private final Context mContext;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700113 private final InputManagerHandler mHandler;
Jeff Browna9d131c2012-09-20 16:48:17 -0700114
115 private WindowManagerCallbacks mWindowManagerCallbacks;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700116 private boolean mSystemReady;
Jeff Browncf39bdf2012-05-18 14:41:19 -0700117 private NotificationManager mNotificationManager;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700118
Jeff Browna3bc5652012-04-17 11:42:25 -0700119 // Persistent data store. Must be locked each time during use.
120 private final PersistentDataStore mDataStore = new PersistentDataStore();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700121
122 // List of currently registered input devices changed listeners by process id.
123 private Object mInputDevicesLock = new Object();
124 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
125 private InputDevice[] mInputDevices = new InputDevice[0];
126 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
127 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
128 private final ArrayList<InputDevicesChangedListenerRecord>
129 mTempInputDevicesChangedListenersToNotify =
130 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
Jeff Browncf39bdf2012-05-18 14:41:19 -0700131 private final ArrayList<InputDevice>
132 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
133 private boolean mKeyboardLayoutNotificationShown;
134 private PendingIntent mKeyboardLayoutIntent;
135 private Toast mSwitchedKeyboardLayoutToast;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700136
Jeff Browna47425a2012-04-13 04:09:27 -0700137 // State for vibrator tokens.
138 private Object mVibratorLock = new Object();
139 private HashMap<IBinder, VibratorToken> mVibratorTokens =
140 new HashMap<IBinder, VibratorToken>();
141 private int mNextVibratorTokenValue;
142
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700143 // State for the currently installed input filter.
144 final Object mInputFilterLock = new Object();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700145 IInputFilter mInputFilter; // guarded by mInputFilterLock
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700146 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
Jeff Brown1a84fd12011-06-02 01:26:32 -0700147
Jeff Brown4532e612012-04-05 14:27:12 -0700148 private static native int nativeInit(InputManagerService service,
149 Context context, MessageQueue messageQueue);
150 private static native void nativeStart(int ptr);
Jeff Brownd728bf52012-09-08 18:05:28 -0700151 private static native void nativeSetDisplayViewport(int ptr, boolean external,
152 int displayId, int rotation,
153 int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
Jeff Brown83d616a2012-09-09 20:33:43 -0700154 int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
155 int deviceWidth, int deviceHeight);
Jeff Brownd728bf52012-09-08 18:05:28 -0700156
Jeff Brown4532e612012-04-05 14:27:12 -0700157 private static native int nativeGetScanCodeState(int ptr,
158 int deviceId, int sourceMask, int scanCode);
159 private static native int nativeGetKeyCodeState(int ptr,
160 int deviceId, int sourceMask, int keyCode);
161 private static native int nativeGetSwitchState(int ptr,
162 int deviceId, int sourceMask, int sw);
163 private static native boolean nativeHasKeys(int ptr,
164 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
165 private static native void nativeRegisterInputChannel(int ptr, InputChannel inputChannel,
Jeff Brown928e0542011-01-10 11:17:36 -0800166 InputWindowHandle inputWindowHandle, boolean monitor);
Jeff Brown4532e612012-04-05 14:27:12 -0700167 private static native void nativeUnregisterInputChannel(int ptr, InputChannel inputChannel);
168 private static native void nativeSetInputFilterEnabled(int ptr, boolean enable);
169 private static native int nativeInjectInputEvent(int ptr, InputEvent event,
Jeff Brown0029c662011-03-30 02:25:18 -0700170 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
171 int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -0700172 private static native void nativeSetInputWindows(int ptr, InputWindowHandle[] windowHandles);
173 private static native void nativeSetInputDispatchMode(int ptr, boolean enabled, boolean frozen);
174 private static native void nativeSetSystemUiVisibility(int ptr, int visibility);
175 private static native void nativeSetFocusedApplication(int ptr,
176 InputApplicationHandle application);
Jeff Brown4532e612012-04-05 14:27:12 -0700177 private static native boolean nativeTransferTouchFocus(int ptr,
178 InputChannel fromChannel, InputChannel toChannel);
179 private static native void nativeSetPointerSpeed(int ptr, int speed);
180 private static native void nativeSetShowTouches(int ptr, boolean enabled);
Jeff Browna47425a2012-04-13 04:09:27 -0700181 private static native void nativeVibrate(int ptr, int deviceId, long[] pattern,
182 int repeat, int token);
183 private static native void nativeCancelVibrate(int ptr, int deviceId, int token);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700184 private static native void nativeReloadKeyboardLayouts(int ptr);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700185 private static native void nativeReloadDeviceAliases(int ptr);
Jeff Brown4532e612012-04-05 14:27:12 -0700186 private static native String nativeDump(int ptr);
187 private static native void nativeMonitor(int ptr);
Jeff Brown4532e612012-04-05 14:27:12 -0700188
Jeff Brownac143512012-04-05 18:57:33 -0700189 // Input event injection constants defined in InputDispatcher.h.
190 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
191 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
192 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
193 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
194
195 // Maximum number of milliseconds to wait for input event injection.
196 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
197
Jeff Brown6d0fec22010-07-23 21:28:06 -0700198 // Key states (may be returned by queries about the current state of a
199 // particular key code, scan code or switch).
200
201 /** The key state is unknown or the requested key itself is not supported. */
202 public static final int KEY_STATE_UNKNOWN = -1;
203
204 /** The key is up. /*/
205 public static final int KEY_STATE_UP = 0;
206
207 /** The key is down. */
208 public static final int KEY_STATE_DOWN = 1;
209
210 /** The key is down but is a virtual key press that is being emulated by the system. */
211 public static final int KEY_STATE_VIRTUAL = 2;
212
Jeff Brownc458ce92012-04-30 14:58:40 -0700213 /** Scan code: Mouse / trackball button. */
214 public static final int BTN_MOUSE = 0x110;
215
216 /** Switch code: Lid switch. When set, lid is shut. */
217 public static final int SW_LID = 0x00;
218
219 /** Switch code: Keypad slide. When set, keyboard is exposed. */
220 public static final int SW_KEYPAD_SLIDE = 0x0a;
221
Jeff Browna9d131c2012-09-20 16:48:17 -0700222 public InputManagerService(Context context, Handler handler) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700223 this.mContext = context;
Jeff Browna9d131c2012-09-20 16:48:17 -0700224 this.mHandler = new InputManagerHandler(handler.getLooper());
Jeff Brown05dc66a2011-03-02 14:41:58 -0800225
Jeff Brown46b9ac02010-04-22 18:58:52 -0700226 Slog.i(TAG, "Initializing input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700227 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700228 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700229
Jeff Browna9d131c2012-09-20 16:48:17 -0700230 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
231 mWindowManagerCallbacks = callbacks;
232 }
233
Jeff Brown46b9ac02010-04-22 18:58:52 -0700234 public void start() {
235 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700236 nativeStart(mPtr);
237
238 // Add ourself to the Watchdog monitors.
239 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700240
241 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700242 registerShowTouchesSettingObserver();
243
Jeff Brown1a84fd12011-06-02 01:26:32 -0700244 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700245 updateShowTouchesFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700246 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700247
Matthew Xie96313142012-06-29 16:57:31 -0700248 // TODO(BT) Pass in paramter for bluetooth system
249 public void systemReady() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700250 if (DEBUG) {
251 Slog.d(TAG, "System ready.");
252 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700253 mNotificationManager = (NotificationManager)mContext.getSystemService(
254 Context.NOTIFICATION_SERVICE);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700255 mSystemReady = true;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700256
257 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
258 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
259 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
260 filter.addDataScheme("package");
261 mContext.registerReceiver(new BroadcastReceiver() {
262 @Override
263 public void onReceive(Context context, Intent intent) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700264 updateKeyboardLayouts();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700265 }
266 }, filter, null, mHandler);
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700267
268 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
269 mContext.registerReceiver(new BroadcastReceiver() {
270 @Override
271 public void onReceive(Context context, Intent intent) {
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700272 reloadDeviceAliases();
273 }
274 }, filter, null, mHandler);
275
Jeff Browncf39bdf2012-05-18 14:41:19 -0700276 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
277 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700278 }
279
280 private void reloadKeyboardLayouts() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700281 if (DEBUG) {
282 Slog.d(TAG, "Reloading keyboard layouts.");
283 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700284 nativeReloadKeyboardLayouts(mPtr);
285 }
286
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700287 private void reloadDeviceAliases() {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700288 if (DEBUG) {
289 Slog.d(TAG, "Reloading device names.");
290 }
Jeff Brown5bbd4b42012-04-20 19:28:00 -0700291 nativeReloadDeviceAliases(mPtr);
292 }
293
Jeff Brownd728bf52012-09-08 18:05:28 -0700294 @Override
295 public void setDisplayViewports(DisplayViewport defaultViewport,
296 DisplayViewport externalTouchViewport) {
297 if (defaultViewport.valid) {
298 setDisplayViewport(false, defaultViewport);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700299 }
Jeff Brownd728bf52012-09-08 18:05:28 -0700300
301 if (externalTouchViewport.valid) {
302 setDisplayViewport(true, externalTouchViewport);
303 } else if (defaultViewport.valid) {
304 setDisplayViewport(true, defaultViewport);
Jeff Brownb6997262010-10-08 22:31:17 -0700305 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700306 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700307
Jeff Brownd728bf52012-09-08 18:05:28 -0700308 private void setDisplayViewport(boolean external, DisplayViewport viewport) {
309 nativeSetDisplayViewport(mPtr, external,
310 viewport.displayId, viewport.orientation,
311 viewport.logicalFrame.left, viewport.logicalFrame.top,
312 viewport.logicalFrame.right, viewport.logicalFrame.bottom,
313 viewport.physicalFrame.left, viewport.physicalFrame.top,
Jeff Brown83d616a2012-09-09 20:33:43 -0700314 viewport.physicalFrame.right, viewport.physicalFrame.bottom,
315 viewport.deviceWidth, viewport.deviceHeight);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700316 }
Jeff Brownac143512012-04-05 18:57:33 -0700317
Jeff Brown6d0fec22010-07-23 21:28:06 -0700318 /**
319 * Gets the current state of a key or button by key code.
320 * @param deviceId The input device id, or -1 to consult all devices.
321 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
322 * consider all input sources. An input device is consulted if at least one of its
323 * non-class input source bits matches the specified source mask.
324 * @param keyCode The key code to check.
325 * @return The key state.
326 */
327 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700328 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700329 }
330
Jeff Brown6d0fec22010-07-23 21:28:06 -0700331 /**
332 * Gets the current state of a key or button by scan code.
333 * @param deviceId The input device id, or -1 to consult all devices.
334 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
335 * consider all input sources. An input device is consulted if at least one of its
336 * non-class input source bits matches the specified source mask.
337 * @param scanCode The scan code to check.
338 * @return The key state.
339 */
340 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700341 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700342 }
343
Jeff Brown6d0fec22010-07-23 21:28:06 -0700344 /**
345 * Gets the current state of a switch by switch code.
346 * @param deviceId The input device id, or -1 to consult all devices.
347 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
348 * consider all input sources. An input device is consulted if at least one of its
349 * non-class input source bits matches the specified source mask.
350 * @param switchCode The switch code to check.
351 * @return The switch state.
352 */
353 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700354 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700355 }
356
Jeff Brown6d0fec22010-07-23 21:28:06 -0700357 /**
358 * Determines whether the specified key codes are supported by a particular device.
359 * @param deviceId The input device id, or -1 to consult all devices.
360 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
361 * consider all input sources. An input device is consulted if at least one of its
362 * non-class input source bits matches the specified source mask.
363 * @param keyCodes The array of key codes to check.
364 * @param keyExists An array at least as large as keyCodes whose entries will be set
365 * to true or false based on the presence or absence of support for the corresponding
366 * key codes.
367 * @return True if the lookup was successful, false otherwise.
368 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700369 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700370 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700371 if (keyCodes == null) {
372 throw new IllegalArgumentException("keyCodes must not be null.");
373 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700374 if (keyExists == null || keyExists.length < keyCodes.length) {
375 throw new IllegalArgumentException("keyExists must not be null and must be at "
376 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700377 }
378
Jeff Brown4532e612012-04-05 14:27:12 -0700379 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700380 }
381
Jeff Browna41ca772010-08-11 14:46:32 -0700382 /**
383 * Creates an input channel that will receive all input from the input dispatcher.
384 * @param inputChannelName The input channel name.
385 * @return The input channel.
386 */
387 public InputChannel monitorInput(String inputChannelName) {
388 if (inputChannelName == null) {
389 throw new IllegalArgumentException("inputChannelName must not be null.");
390 }
391
392 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700393 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700394 inputChannels[0].dispose(); // don't need to retain the Java object reference
395 return inputChannels[1];
396 }
397
398 /**
399 * Registers an input channel so that it can be used as an input event target.
400 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800401 * @param inputWindowHandle The handle of the input window associated with the
402 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700403 */
Jeff Brown928e0542011-01-10 11:17:36 -0800404 public void registerInputChannel(InputChannel inputChannel,
405 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700406 if (inputChannel == null) {
407 throw new IllegalArgumentException("inputChannel must not be null.");
408 }
409
Jeff Brown4532e612012-04-05 14:27:12 -0700410 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700411 }
412
Jeff Browna41ca772010-08-11 14:46:32 -0700413 /**
414 * Unregisters an input channel.
415 * @param inputChannel The input channel to unregister.
416 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700417 public void unregisterInputChannel(InputChannel inputChannel) {
418 if (inputChannel == null) {
419 throw new IllegalArgumentException("inputChannel must not be null.");
420 }
421
Jeff Brown4532e612012-04-05 14:27:12 -0700422 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700423 }
Jeff Brown0029c662011-03-30 02:25:18 -0700424
425 /**
426 * Sets an input filter that will receive all input events before they are dispatched.
427 * The input filter may then reinterpret input events or inject new ones.
428 *
429 * To ensure consistency, the input dispatcher automatically drops all events
430 * in progress whenever an input filter is installed or uninstalled. After an input
431 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
432 * Any events it attempts to send after it has been uninstalled will be dropped.
433 *
434 * @param filter The input filter, or null to remove the current filter.
435 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700436 public void setInputFilter(IInputFilter filter) {
Jeff Brown0029c662011-03-30 02:25:18 -0700437 synchronized (mInputFilterLock) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700438 final IInputFilter oldFilter = mInputFilter;
Jeff Brown0029c662011-03-30 02:25:18 -0700439 if (oldFilter == filter) {
440 return; // nothing to do
441 }
442
443 if (oldFilter != null) {
444 mInputFilter = null;
445 mInputFilterHost.disconnectLocked();
446 mInputFilterHost = null;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700447 try {
448 oldFilter.uninstall();
449 } catch (RemoteException re) {
450 /* ignore */
451 }
Jeff Brown0029c662011-03-30 02:25:18 -0700452 }
453
454 if (filter != null) {
455 mInputFilter = filter;
456 mInputFilterHost = new InputFilterHost();
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700457 try {
458 filter.install(mInputFilterHost);
459 } catch (RemoteException re) {
460 /* ignore */
461 }
Jeff Brown0029c662011-03-30 02:25:18 -0700462 }
463
Jeff Brown4532e612012-04-05 14:27:12 -0700464 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700465 }
466 }
467
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700468 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700469 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700470 if (event == null) {
471 throw new IllegalArgumentException("event must not be null");
472 }
Jeff Brownac143512012-04-05 18:57:33 -0700473 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
474 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
475 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
476 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700477 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700478
Jeff Brownac143512012-04-05 18:57:33 -0700479 final int pid = Binder.getCallingPid();
480 final int uid = Binder.getCallingUid();
481 final long ident = Binder.clearCallingIdentity();
482 final int result;
483 try {
484 result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
485 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
486 } finally {
487 Binder.restoreCallingIdentity(ident);
488 }
489 switch (result) {
490 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
491 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
492 throw new SecurityException(
493 "Injecting to another application requires INJECT_EVENTS permission");
494 case INPUT_EVENT_INJECTION_SUCCEEDED:
495 return true;
496 case INPUT_EVENT_INJECTION_TIMED_OUT:
497 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
498 return false;
499 case INPUT_EVENT_INJECTION_FAILED:
500 default:
501 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
502 return false;
503 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700504 }
Jeff Brown0029c662011-03-30 02:25:18 -0700505
Jeff Brown8d608662010-08-30 03:02:23 -0700506 /**
507 * Gets information about the input device with the specified id.
508 * @param id The device id.
509 * @return The input device or null if not found.
510 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700511 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700512 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700513 synchronized (mInputDevicesLock) {
514 final int count = mInputDevices.length;
515 for (int i = 0; i < count; i++) {
516 final InputDevice inputDevice = mInputDevices[i];
517 if (inputDevice.getId() == deviceId) {
518 return inputDevice;
519 }
520 }
521 }
522 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700523 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700524
Jeff Brown8d608662010-08-30 03:02:23 -0700525 /**
526 * Gets the ids of all input devices in the system.
527 * @return The input device ids.
528 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700529 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700530 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700531 synchronized (mInputDevicesLock) {
532 final int count = mInputDevices.length;
533 int[] ids = new int[count];
534 for (int i = 0; i < count; i++) {
535 ids[i] = mInputDevices[i].getId();
536 }
537 return ids;
538 }
539 }
540
Jeff Browndaa37532012-05-01 15:54:03 -0700541 /**
542 * Gets all input devices in the system.
543 * @return The array of input devices.
544 */
545 public InputDevice[] getInputDevices() {
546 synchronized (mInputDevicesLock) {
547 return mInputDevices;
548 }
549 }
550
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700551 @Override // Binder call
552 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
553 if (listener == null) {
554 throw new IllegalArgumentException("listener must not be null");
555 }
556
557 synchronized (mInputDevicesLock) {
558 int callingPid = Binder.getCallingPid();
559 if (mInputDevicesChangedListeners.get(callingPid) != null) {
560 throw new SecurityException("The calling process has already "
561 + "registered an InputDevicesChangedListener.");
562 }
563
564 InputDevicesChangedListenerRecord record =
565 new InputDevicesChangedListenerRecord(callingPid, listener);
566 try {
567 IBinder binder = listener.asBinder();
568 binder.linkToDeath(record, 0);
569 } catch (RemoteException ex) {
570 // give up
571 throw new RuntimeException(ex);
572 }
573
574 mInputDevicesChangedListeners.put(callingPid, record);
575 }
576 }
577
578 private void onInputDevicesChangedListenerDied(int pid) {
579 synchronized (mInputDevicesLock) {
580 mInputDevicesChangedListeners.remove(pid);
581 }
582 }
583
584 // Must be called on handler.
Jeff Browncf39bdf2012-05-18 14:41:19 -0700585 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
586 // Scan for changes.
587 int numFullKeyboardsAdded = 0;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700588 mTempInputDevicesChangedListenersToNotify.clear();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700589 mTempFullKeyboards.clear();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700590 final int numListeners;
591 final int[] deviceIdAndGeneration;
592 synchronized (mInputDevicesLock) {
593 if (!mInputDevicesChangedPending) {
594 return;
595 }
596 mInputDevicesChangedPending = false;
597
598 numListeners = mInputDevicesChangedListeners.size();
599 for (int i = 0; i < numListeners; i++) {
600 mTempInputDevicesChangedListenersToNotify.add(
601 mInputDevicesChangedListeners.valueAt(i));
602 }
603
604 final int numDevices = mInputDevices.length;
605 deviceIdAndGeneration = new int[numDevices * 2];
606 for (int i = 0; i < numDevices; i++) {
607 final InputDevice inputDevice = mInputDevices[i];
608 deviceIdAndGeneration[i * 2] = inputDevice.getId();
609 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
Jeff Browncf39bdf2012-05-18 14:41:19 -0700610
Jeff Brown7e4ff4b2012-05-30 14:32:16 -0700611 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700612 if (!containsInputDeviceWithDescriptor(oldInputDevices,
613 inputDevice.getDescriptor())) {
614 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
615 } else {
616 mTempFullKeyboards.add(inputDevice);
617 }
618 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700619 }
620 }
621
Jeff Browncf39bdf2012-05-18 14:41:19 -0700622 // Notify listeners.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700623 for (int i = 0; i < numListeners; i++) {
624 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
625 deviceIdAndGeneration);
626 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700627 mTempInputDevicesChangedListenersToNotify.clear();
628
629 // Check for missing keyboard layouts.
630 if (mNotificationManager != null) {
631 final int numFullKeyboards = mTempFullKeyboards.size();
632 boolean missingLayoutForExternalKeyboard = false;
633 boolean missingLayoutForExternalKeyboardAdded = false;
634 synchronized (mDataStore) {
635 for (int i = 0; i < numFullKeyboards; i++) {
636 final InputDevice inputDevice = mTempFullKeyboards.get(i);
637 if (mDataStore.getCurrentKeyboardLayout(inputDevice.getDescriptor()) == null) {
638 missingLayoutForExternalKeyboard = true;
639 if (i < numFullKeyboardsAdded) {
640 missingLayoutForExternalKeyboardAdded = true;
641 }
642 }
643 }
644 }
645 if (missingLayoutForExternalKeyboard) {
646 if (missingLayoutForExternalKeyboardAdded) {
647 showMissingKeyboardLayoutNotification();
648 }
649 } else if (mKeyboardLayoutNotificationShown) {
650 hideMissingKeyboardLayoutNotification();
651 }
652 }
653 mTempFullKeyboards.clear();
654 }
655
656 // Must be called on handler.
657 private void showMissingKeyboardLayoutNotification() {
658 if (!mKeyboardLayoutNotificationShown) {
659 if (mKeyboardLayoutIntent == null) {
660 final Intent intent = new Intent("android.settings.INPUT_METHOD_SETTINGS");
661 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
662 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
663 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700664 mKeyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
665 intent, 0, null, UserHandle.CURRENT);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700666 }
667
668 Resources r = mContext.getResources();
669 Notification notification = new Notification.Builder(mContext)
670 .setContentTitle(r.getString(
671 R.string.select_keyboard_layout_notification_title))
672 .setContentText(r.getString(
673 R.string.select_keyboard_layout_notification_message))
674 .setContentIntent(mKeyboardLayoutIntent)
675 .setSmallIcon(R.drawable.ic_settings_language)
676 .setPriority(Notification.PRIORITY_LOW)
677 .build();
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700678 mNotificationManager.notifyAsUser(null,
679 R.string.select_keyboard_layout_notification_title,
680 notification, UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700681 mKeyboardLayoutNotificationShown = true;
682 }
683 }
684
685 // Must be called on handler.
686 private void hideMissingKeyboardLayoutNotification() {
687 if (mKeyboardLayoutNotificationShown) {
688 mKeyboardLayoutNotificationShown = false;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -0700689 mNotificationManager.cancelAsUser(null,
690 R.string.select_keyboard_layout_notification_title,
691 UserHandle.ALL);
Jeff Browncf39bdf2012-05-18 14:41:19 -0700692 }
693 }
694
695 // Must be called on handler.
696 private void updateKeyboardLayouts() {
697 // Scan all input devices state for keyboard layouts that have been uninstalled.
698 final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
699 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
700 @Override
701 public void visitKeyboardLayout(Resources resources,
702 String descriptor, String label, String collection, int keyboardLayoutResId) {
703 availableKeyboardLayouts.add(descriptor);
704 }
705 });
706 synchronized (mDataStore) {
707 try {
708 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
709 } finally {
710 mDataStore.saveIfNeeded();
711 }
712 }
713
714 // Reload keyboard layouts.
715 reloadKeyboardLayouts();
716 }
717
Jeff Browncf39bdf2012-05-18 14:41:19 -0700718 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
719 String descriptor) {
720 final int numDevices = inputDevices.length;
721 for (int i = 0; i < numDevices; i++) {
722 final InputDevice inputDevice = inputDevices[i];
723 if (inputDevice.getDescriptor().equals(descriptor)) {
724 return true;
725 }
726 }
727 return false;
Jeff Brown8d608662010-08-30 03:02:23 -0700728 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700729
730 @Override // Binder call
731 public KeyboardLayout[] getKeyboardLayouts() {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700732 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
733 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
734 @Override
735 public void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700736 String descriptor, String label, String collection, int keyboardLayoutResId) {
737 list.add(new KeyboardLayout(descriptor, label, collection));
Jeff Brown6ec6f792012-04-17 16:52:41 -0700738 }
739 });
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700740 return list.toArray(new KeyboardLayout[list.size()]);
741 }
742
743 @Override // Binder call
744 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
745 if (keyboardLayoutDescriptor == null) {
746 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
747 }
748
Jeff Brown6ec6f792012-04-17 16:52:41 -0700749 final KeyboardLayout[] result = new KeyboardLayout[1];
750 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
751 @Override
752 public void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700753 String descriptor, String label, String collection, int keyboardLayoutResId) {
754 result[0] = new KeyboardLayout(descriptor, label, collection);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700755 }
756 });
757 if (result[0] == null) {
758 Log.w(TAG, "Could not get keyboard layout with descriptor '"
759 + keyboardLayoutDescriptor + "'.");
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700760 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700761 return result[0];
762 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700763
Jeff Brown6ec6f792012-04-17 16:52:41 -0700764 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700765 final PackageManager pm = mContext.getPackageManager();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700766 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
767 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
768 PackageManager.GET_META_DATA)) {
769 visitKeyboardLayoutsInPackage(pm, resolveInfo.activityInfo, null, visitor);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700770 }
771 }
772
Jeff Brown6ec6f792012-04-17 16:52:41 -0700773 private void visitKeyboardLayout(String keyboardLayoutDescriptor,
774 KeyboardLayoutVisitor visitor) {
775 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
776 if (d != null) {
777 final PackageManager pm = mContext.getPackageManager();
778 try {
779 ActivityInfo receiver = pm.getReceiverInfo(
780 new ComponentName(d.packageName, d.receiverName),
781 PackageManager.GET_META_DATA);
782 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, visitor);
783 } catch (NameNotFoundException ex) {
784 }
785 }
786 }
787
788 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
789 String keyboardName, KeyboardLayoutVisitor visitor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700790 Bundle metaData = receiver.metaData;
791 if (metaData == null) {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700792 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700793 }
794
795 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
796 if (configResId == 0) {
797 Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
798 + "' on receiver " + receiver.packageName + "/" + receiver.name);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700799 return;
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700800 }
801
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700802 CharSequence receiverLabel = receiver.loadLabel(pm);
803 String collection = receiverLabel != null ? receiverLabel.toString() : "";
804
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700805 try {
806 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
807 XmlResourceParser parser = resources.getXml(configResId);
808 try {
809 XmlUtils.beginDocument(parser, "keyboard-layouts");
810
811 for (;;) {
812 XmlUtils.nextElement(parser);
813 String element = parser.getName();
814 if (element == null) {
815 break;
816 }
817 if (element.equals("keyboard-layout")) {
818 TypedArray a = resources.obtainAttributes(
819 parser, com.android.internal.R.styleable.KeyboardLayout);
820 try {
821 String name = a.getString(
822 com.android.internal.R.styleable.KeyboardLayout_name);
823 String label = a.getString(
824 com.android.internal.R.styleable.KeyboardLayout_label);
Jeff Brown2f095762012-05-10 21:29:33 -0700825 int keyboardLayoutResId = a.getResourceId(
826 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
827 0);
828 if (name == null || label == null || keyboardLayoutResId == 0) {
829 Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700830 + "attributes in keyboard layout "
831 + "resource from receiver "
832 + receiver.packageName + "/" + receiver.name);
833 } else {
834 String descriptor = KeyboardLayoutDescriptor.format(
835 receiver.packageName, receiver.name, name);
Jeff Brown6ec6f792012-04-17 16:52:41 -0700836 if (keyboardName == null || name.equals(keyboardName)) {
837 visitor.visitKeyboardLayout(resources, descriptor,
Jeff Brownd9fec5d2012-05-17 16:01:54 -0700838 label, collection, keyboardLayoutResId);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700839 }
840 }
841 } finally {
842 a.recycle();
843 }
844 } else {
845 Log.w(TAG, "Skipping unrecognized element '" + element
846 + "' in keyboard layout resource from receiver "
847 + receiver.packageName + "/" + receiver.name);
848 }
849 }
850 } finally {
851 parser.close();
852 }
853 } catch (Exception ex) {
Jeff Brown6ec6f792012-04-17 16:52:41 -0700854 Log.w(TAG, "Could not parse keyboard layout resource from receiver "
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700855 + receiver.packageName + "/" + receiver.name, ex);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700856 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700857 }
858
859 @Override // Binder call
Jeff Browncf39bdf2012-05-18 14:41:19 -0700860 public String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700861 if (inputDeviceDescriptor == null) {
862 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
863 }
864
Jeff Browna3bc5652012-04-17 11:42:25 -0700865 synchronized (mDataStore) {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700866 return mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
Jeff Browna3bc5652012-04-17 11:42:25 -0700867 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700868 }
869
870 @Override // Binder call
Jeff Browncf39bdf2012-05-18 14:41:19 -0700871 public void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700872 String keyboardLayoutDescriptor) {
873 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
Jeff Browncf39bdf2012-05-18 14:41:19 -0700874 "setCurrentKeyboardLayoutForInputDevice()")) {
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700875 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
876 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700877 if (inputDeviceDescriptor == null) {
878 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
879 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700880 if (keyboardLayoutDescriptor == null) {
881 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
882 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700883
Jeff Browna3bc5652012-04-17 11:42:25 -0700884 synchronized (mDataStore) {
885 try {
Jeff Browncf39bdf2012-05-18 14:41:19 -0700886 if (mDataStore.setCurrentKeyboardLayout(
887 inputDeviceDescriptor, keyboardLayoutDescriptor)) {
888 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
889 }
Jeff Browna3bc5652012-04-17 11:42:25 -0700890 } finally {
891 mDataStore.saveIfNeeded();
892 }
893 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700894 }
Jeff Brown6ec6f792012-04-17 16:52:41 -0700895
Jeff Browncf39bdf2012-05-18 14:41:19 -0700896 @Override // Binder call
897 public String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor) {
898 if (inputDeviceDescriptor == null) {
899 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
900 }
901
902 synchronized (mDataStore) {
903 return mDataStore.getKeyboardLayouts(inputDeviceDescriptor);
904 }
905 }
906
907 @Override // Binder call
908 public void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
909 String keyboardLayoutDescriptor) {
910 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
911 "addKeyboardLayoutForInputDevice()")) {
912 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
913 }
914 if (inputDeviceDescriptor == null) {
915 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
916 }
917 if (keyboardLayoutDescriptor == null) {
918 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
919 }
920
921 synchronized (mDataStore) {
922 try {
923 String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
924 if (mDataStore.addKeyboardLayout(inputDeviceDescriptor, keyboardLayoutDescriptor)
925 && !Objects.equal(oldLayout,
926 mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) {
927 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
928 }
929 } finally {
930 mDataStore.saveIfNeeded();
Jeff Brown6ec6f792012-04-17 16:52:41 -0700931 }
Jeff Browncf39bdf2012-05-18 14:41:19 -0700932 }
933 }
934
935 @Override // Binder call
936 public void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
937 String keyboardLayoutDescriptor) {
938 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
939 "removeKeyboardLayoutForInputDevice()")) {
940 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
941 }
942 if (inputDeviceDescriptor == null) {
943 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
944 }
945 if (keyboardLayoutDescriptor == null) {
946 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
947 }
948
949 synchronized (mDataStore) {
950 try {
951 String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
952 if (mDataStore.removeKeyboardLayout(inputDeviceDescriptor,
953 keyboardLayoutDescriptor)
954 && !Objects.equal(oldLayout,
955 mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) {
956 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
957 }
958 } finally {
959 mDataStore.saveIfNeeded();
960 }
961 }
962 }
963
964 public void switchKeyboardLayout(int deviceId, int direction) {
965 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
966 }
967
968 // Must be called on handler.
969 private void handleSwitchKeyboardLayout(int deviceId, int direction) {
970 final InputDevice device = getInputDevice(deviceId);
971 final String inputDeviceDescriptor = device.getDescriptor();
972 if (device != null) {
973 final boolean changed;
974 final String keyboardLayoutDescriptor;
975 synchronized (mDataStore) {
976 try {
977 changed = mDataStore.switchKeyboardLayout(inputDeviceDescriptor, direction);
978 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
979 inputDeviceDescriptor);
980 } finally {
981 mDataStore.saveIfNeeded();
982 }
983 }
984
985 if (changed) {
986 if (mSwitchedKeyboardLayoutToast != null) {
987 mSwitchedKeyboardLayoutToast.cancel();
988 mSwitchedKeyboardLayoutToast = null;
989 }
990 if (keyboardLayoutDescriptor != null) {
991 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
992 if (keyboardLayout != null) {
993 mSwitchedKeyboardLayoutToast = Toast.makeText(
994 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
995 mSwitchedKeyboardLayoutToast.show();
996 }
997 }
998
999 reloadKeyboardLayouts();
1000 }
Jeff Brown6ec6f792012-04-17 16:52:41 -07001001 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001002 }
1003
Jeff Brown9302c872011-07-13 22:51:29 -07001004 public void setInputWindows(InputWindowHandle[] windowHandles) {
Jeff Brown4532e612012-04-05 14:27:12 -07001005 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -07001006 }
1007
Jeff Brown9302c872011-07-13 22:51:29 -07001008 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -07001009 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -07001010 }
1011
Jeff Brown349703e2010-06-22 01:27:15 -07001012 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -07001013 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -07001014 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001015
1016 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -07001017 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -08001018 }
1019
Jeff Browne6504122010-09-27 14:52:15 -07001020 /**
1021 * Atomically transfers touch focus from one window to another as identified by
1022 * their input channels. It is possible for multiple windows to have
1023 * touch focus if they support split touch dispatch
1024 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
1025 * method only transfers touch focus of the specified window without affecting
1026 * other windows that may also have touch focus at the same time.
1027 * @param fromChannel The channel of a window that currently has touch focus.
1028 * @param toChannel The channel of the window that should receive touch focus in
1029 * place of the first.
1030 * @return True if the transfer was successful. False if the window with the
1031 * specified channel did not actually have touch focus at the time of the request.
1032 */
1033 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
1034 if (fromChannel == null) {
1035 throw new IllegalArgumentException("fromChannel must not be null.");
1036 }
1037 if (toChannel == null) {
1038 throw new IllegalArgumentException("toChannel must not be null.");
1039 }
Jeff Brown4532e612012-04-05 14:27:12 -07001040 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -07001041 }
Jeff Brown05dc66a2011-03-02 14:41:58 -08001042
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001043 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -07001044 public void tryPointerSpeed(int speed) {
1045 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
1046 "tryPointerSpeed()")) {
1047 throw new SecurityException("Requires SET_POINTER_SPEED permission");
1048 }
1049
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001050 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
1051 throw new IllegalArgumentException("speed out of range");
1052 }
1053
Jeff Brownac143512012-04-05 18:57:33 -07001054 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001055 }
1056
1057 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -07001058 int speed = getPointerSpeedSetting();
1059 setPointerSpeedUnchecked(speed);
1060 }
1061
1062 private void setPointerSpeedUnchecked(int speed) {
1063 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
1064 InputManager.MAX_POINTER_SPEED);
1065 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -07001066 }
1067
1068 private void registerPointerSpeedSettingObserver() {
1069 mContext.getContentResolver().registerContentObserver(
1070 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001071 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -07001072 @Override
1073 public void onChange(boolean selfChange) {
1074 updatePointerSpeedFromSettings();
1075 }
1076 });
1077 }
1078
Jeff Brownac143512012-04-05 18:57:33 -07001079 private int getPointerSpeedSetting() {
1080 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -07001081 try {
1082 speed = Settings.System.getInt(mContext.getContentResolver(),
1083 Settings.System.POINTER_SPEED);
1084 } catch (SettingNotFoundException snfe) {
1085 }
1086 return speed;
1087 }
1088
Jeff Browndaf4a122011-08-26 17:14:14 -07001089 public void updateShowTouchesFromSettings() {
1090 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -07001091 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -07001092 }
1093
1094 private void registerShowTouchesSettingObserver() {
1095 mContext.getContentResolver().registerContentObserver(
1096 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -07001097 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -07001098 @Override
1099 public void onChange(boolean selfChange) {
1100 updateShowTouchesFromSettings();
1101 }
1102 });
1103 }
1104
1105 private int getShowTouchesSetting(int defaultValue) {
1106 int result = defaultValue;
1107 try {
1108 result = Settings.System.getInt(mContext.getContentResolver(),
1109 Settings.System.SHOW_TOUCHES);
1110 } catch (SettingNotFoundException snfe) {
1111 }
1112 return result;
1113 }
1114
Jeff Browna47425a2012-04-13 04:09:27 -07001115 // Binder call
1116 @Override
1117 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
1118 if (repeat >= pattern.length) {
1119 throw new ArrayIndexOutOfBoundsException();
1120 }
1121
1122 VibratorToken v;
1123 synchronized (mVibratorLock) {
1124 v = mVibratorTokens.get(token);
1125 if (v == null) {
1126 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
1127 try {
1128 token.linkToDeath(v, 0);
1129 } catch (RemoteException ex) {
1130 // give up
1131 throw new RuntimeException(ex);
1132 }
1133 mVibratorTokens.put(token, v);
1134 }
1135 }
1136
1137 synchronized (v) {
1138 v.mVibrating = true;
1139 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
1140 }
1141 }
1142
1143 // Binder call
1144 @Override
1145 public void cancelVibrate(int deviceId, IBinder token) {
1146 VibratorToken v;
1147 synchronized (mVibratorLock) {
1148 v = mVibratorTokens.get(token);
1149 if (v == null || v.mDeviceId != deviceId) {
1150 return; // nothing to cancel
1151 }
1152 }
1153
1154 cancelVibrateIfNeeded(v);
1155 }
1156
1157 void onVibratorTokenDied(VibratorToken v) {
1158 synchronized (mVibratorLock) {
1159 mVibratorTokens.remove(v.mToken);
1160 }
1161
1162 cancelVibrateIfNeeded(v);
1163 }
1164
1165 private void cancelVibrateIfNeeded(VibratorToken v) {
1166 synchronized (v) {
1167 if (v.mVibrating) {
1168 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
1169 v.mVibrating = false;
1170 }
1171 }
1172 }
1173
Jeff Brown4532e612012-04-05 14:27:12 -07001174 @Override
1175 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna3bc5652012-04-17 11:42:25 -07001176 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
Jeff Brown4532e612012-04-05 14:27:12 -07001177 != PackageManager.PERMISSION_GRANTED) {
1178 pw.println("Permission Denial: can't dump InputManager from from pid="
1179 + Binder.getCallingPid()
1180 + ", uid=" + Binder.getCallingUid());
1181 return;
1182 }
1183
1184 pw.println("INPUT MANAGER (dumpsys input)\n");
1185 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -07001186 if (dumpStr != null) {
1187 pw.println(dumpStr);
1188 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001189 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001190
Jeff Brownac143512012-04-05 18:57:33 -07001191 private boolean checkCallingPermission(String permission, String func) {
1192 // Quick check: if the calling permission is me, it's all okay.
1193 if (Binder.getCallingPid() == Process.myPid()) {
1194 return true;
1195 }
1196
1197 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1198 return true;
1199 }
1200 String msg = "Permission Denial: " + func + " from pid="
1201 + Binder.getCallingPid()
1202 + ", uid=" + Binder.getCallingUid()
1203 + " requires " + permission;
1204 Slog.w(TAG, msg);
1205 return false;
1206 }
1207
Jeff Brown4532e612012-04-05 14:27:12 -07001208 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Jeff Brown89ef0722011-08-10 16:25:21 -07001209 public void monitor() {
1210 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -07001211 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -07001212 }
1213
Jeff Brown4532e612012-04-05 14:27:12 -07001214 // Native callback.
1215 private void notifyConfigurationChanged(long whenNanos) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001216 mWindowManagerCallbacks.notifyConfigurationChanged();
Jeff Brown4532e612012-04-05 14:27:12 -07001217 }
1218
1219 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001220 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
1221 synchronized (mInputDevicesLock) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001222 if (!mInputDevicesChangedPending) {
1223 mInputDevicesChangedPending = true;
Jeff Browncf39bdf2012-05-18 14:41:19 -07001224 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
1225 mInputDevices).sendToTarget();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001226 }
Jeff Browncf39bdf2012-05-18 14:41:19 -07001227
1228 mInputDevices = inputDevices;
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001229 }
1230 }
1231
1232 // Native callback.
Jeff Brown53384282012-08-20 20:16:01 -07001233 private void notifySwitch(long whenNanos, int switchCode, int switchValue) {
1234 switch (switchCode) {
1235 case SW_LID:
Jeff Browna9d131c2012-09-20 16:48:17 -07001236 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, switchValue == 0);
Jeff Brown53384282012-08-20 20:16:01 -07001237 break;
1238 }
Jeff Brown4532e612012-04-05 14:27:12 -07001239 }
1240
1241 // Native callback.
1242 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001243 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle);
Jeff Brown4532e612012-04-05 14:27:12 -07001244 }
1245
1246 // Native callback.
1247 private long notifyANR(InputApplicationHandle inputApplicationHandle,
1248 InputWindowHandle inputWindowHandle) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001249 return mWindowManagerCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle);
Jeff Brown4532e612012-04-05 14:27:12 -07001250 }
1251
1252 // Native callback.
1253 final boolean filterInputEvent(InputEvent event, int policyFlags) {
1254 synchronized (mInputFilterLock) {
1255 if (mInputFilter != null) {
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001256 try {
1257 mInputFilter.filterInputEvent(event, policyFlags);
1258 } catch (RemoteException e) {
1259 /* ignore */
1260 }
Jeff Brown4532e612012-04-05 14:27:12 -07001261 return false;
1262 }
1263 }
1264 event.recycle();
1265 return true;
1266 }
1267
1268 // Native callback.
1269 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001270 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(
Jeff Brown4532e612012-04-05 14:27:12 -07001271 event, policyFlags, isScreenOn);
1272 }
1273
1274 // Native callback.
1275 private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001276 return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001277 }
1278
1279 // Native callback.
1280 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
1281 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001282 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001283 }
1284
1285 // Native callback.
1286 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1287 KeyEvent event, int policyFlags) {
Jeff Browna9d131c2012-09-20 16:48:17 -07001288 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -07001289 }
1290
1291 // Native callback.
1292 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
1293 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
1294 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
1295 }
1296
1297 // Native callback.
1298 private int getVirtualKeyQuietTimeMillis() {
1299 return mContext.getResources().getInteger(
1300 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1301 }
1302
1303 // Native callback.
1304 private String[] getExcludedDeviceNames() {
1305 ArrayList<String> names = new ArrayList<String>();
1306
1307 // Read partner-provided list of excluded input devices
1308 XmlPullParser parser = null;
1309 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1310 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1311 FileReader confreader = null;
1312 try {
1313 confreader = new FileReader(confFile);
1314 parser = Xml.newPullParser();
1315 parser.setInput(confreader);
1316 XmlUtils.beginDocument(parser, "devices");
1317
1318 while (true) {
1319 XmlUtils.nextElement(parser);
1320 if (!"device".equals(parser.getName())) {
1321 break;
1322 }
1323 String name = parser.getAttributeValue(null, "name");
1324 if (name != null) {
1325 names.add(name);
1326 }
1327 }
1328 } catch (FileNotFoundException e) {
1329 // It's ok if the file does not exist.
1330 } catch (Exception e) {
1331 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1332 } finally {
1333 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1334 }
1335
1336 return names.toArray(new String[names.size()]);
1337 }
1338
1339 // Native callback.
1340 private int getKeyRepeatTimeout() {
1341 return ViewConfiguration.getKeyRepeatTimeout();
1342 }
1343
1344 // Native callback.
1345 private int getKeyRepeatDelay() {
1346 return ViewConfiguration.getKeyRepeatDelay();
1347 }
1348
1349 // Native callback.
1350 private int getHoverTapTimeout() {
1351 return ViewConfiguration.getHoverTapTimeout();
1352 }
1353
1354 // Native callback.
1355 private int getHoverTapSlop() {
1356 return ViewConfiguration.getHoverTapSlop();
1357 }
1358
1359 // Native callback.
1360 private int getDoubleTapTimeout() {
1361 return ViewConfiguration.getDoubleTapTimeout();
1362 }
1363
1364 // Native callback.
1365 private int getLongPressTimeout() {
1366 return ViewConfiguration.getLongPressTimeout();
1367 }
1368
1369 // Native callback.
1370 private int getPointerLayer() {
Jeff Browna9d131c2012-09-20 16:48:17 -07001371 return mWindowManagerCallbacks.getPointerLayer();
Jeff Brown4532e612012-04-05 14:27:12 -07001372 }
1373
1374 // Native callback.
1375 private PointerIcon getPointerIcon() {
1376 return PointerIcon.getDefaultIcon(mContext);
1377 }
1378
Jeff Brown6ec6f792012-04-17 16:52:41 -07001379 // Native callback.
1380 private String[] getKeyboardLayoutOverlay(String inputDeviceDescriptor) {
1381 if (!mSystemReady) {
1382 return null;
1383 }
1384
Jeff Browncf39bdf2012-05-18 14:41:19 -07001385 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(
1386 inputDeviceDescriptor);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001387 if (keyboardLayoutDescriptor == null) {
1388 return null;
1389 }
1390
1391 final String[] result = new String[2];
1392 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
1393 @Override
1394 public void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001395 String descriptor, String label, String collection, int keyboardLayoutResId) {
Jeff Brown6ec6f792012-04-17 16:52:41 -07001396 try {
1397 result[0] = descriptor;
1398 result[1] = Streams.readFully(new InputStreamReader(
Jeff Brown2f095762012-05-10 21:29:33 -07001399 resources.openRawResource(keyboardLayoutResId)));
Jeff Brown6ec6f792012-04-17 16:52:41 -07001400 } catch (IOException ex) {
1401 } catch (NotFoundException ex) {
1402 }
1403 }
1404 });
1405 if (result[0] == null) {
1406 Log.w(TAG, "Could not get keyboard layout with descriptor '"
1407 + keyboardLayoutDescriptor + "'.");
1408 return null;
1409 }
1410 return result;
1411 }
1412
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001413 // Native callback.
1414 private String getDeviceAlias(String uniqueId) {
Matthew Xie96313142012-06-29 16:57:31 -07001415 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
1416 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
1417 return null;
Jeff Brown5bbd4b42012-04-20 19:28:00 -07001418 }
1419 return null;
1420 }
1421
Jeff Brown6ec6f792012-04-17 16:52:41 -07001422
Jeff Brown4532e612012-04-05 14:27:12 -07001423 /**
1424 * Callback interface implemented by the Window Manager.
1425 */
Jeff Browna9d131c2012-09-20 16:48:17 -07001426 public interface WindowManagerCallbacks {
Jeff Brown4532e612012-04-05 14:27:12 -07001427 public void notifyConfigurationChanged();
1428
1429 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
1430
1431 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
1432
1433 public long notifyANR(InputApplicationHandle inputApplicationHandle,
1434 InputWindowHandle inputWindowHandle);
1435
1436 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
1437
1438 public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
1439
1440 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
1441 KeyEvent event, int policyFlags);
1442
1443 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1444 KeyEvent event, int policyFlags);
1445
1446 public int getPointerLayer();
1447 }
1448
1449 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001450 * Private handler for the input manager.
1451 */
1452 private final class InputManagerHandler extends Handler {
Jeff Browna9d131c2012-09-20 16:48:17 -07001453 public InputManagerHandler(Looper looper) {
1454 super(looper, null, true /*async*/);
Jeff Browna2910d02012-08-25 12:29:46 -07001455 }
1456
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001457 @Override
1458 public void handleMessage(Message msg) {
1459 switch (msg.what) {
1460 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
Jeff Browncf39bdf2012-05-18 14:41:19 -07001461 deliverInputDevicesChanged((InputDevice[])msg.obj);
1462 break;
1463 case MSG_SWITCH_KEYBOARD_LAYOUT:
1464 handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
1465 break;
1466 case MSG_RELOAD_KEYBOARD_LAYOUTS:
1467 reloadKeyboardLayouts();
1468 break;
1469 case MSG_UPDATE_KEYBOARD_LAYOUTS:
1470 updateKeyboardLayouts();
1471 break;
1472 case MSG_RELOAD_DEVICE_ALIASES:
1473 reloadDeviceAliases();
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001474 break;
1475 }
1476 }
1477 }
1478
1479 /**
Jeff Brown4532e612012-04-05 14:27:12 -07001480 * Hosting interface for input filters to call back into the input manager.
1481 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -07001482 private final class InputFilterHost extends IInputFilterHost.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -07001483 private boolean mDisconnected;
1484
1485 public void disconnectLocked() {
1486 mDisconnected = true;
1487 }
1488
1489 public void sendInputEvent(InputEvent event, int policyFlags) {
1490 if (event == null) {
1491 throw new IllegalArgumentException("event must not be null");
1492 }
1493
1494 synchronized (mInputFilterLock) {
1495 if (!mDisconnected) {
Jeff Brownac143512012-04-05 18:57:33 -07001496 nativeInjectInputEvent(mPtr, event, 0, 0,
1497 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07001498 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
1499 }
1500 }
1501 }
1502 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001503
1504 private static final class KeyboardLayoutDescriptor {
1505 public String packageName;
1506 public String receiverName;
1507 public String keyboardLayoutName;
1508
1509 public static String format(String packageName,
1510 String receiverName, String keyboardName) {
1511 return packageName + "/" + receiverName + "/" + keyboardName;
1512 }
1513
1514 public static KeyboardLayoutDescriptor parse(String descriptor) {
1515 int pos = descriptor.indexOf('/');
1516 if (pos < 0 || pos + 1 == descriptor.length()) {
1517 return null;
1518 }
1519 int pos2 = descriptor.indexOf('/', pos + 1);
1520 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
1521 return null;
1522 }
1523
1524 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
1525 result.packageName = descriptor.substring(0, pos);
1526 result.receiverName = descriptor.substring(pos + 1, pos2);
1527 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
1528 return result;
1529 }
1530 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001531
Jeff Brown6ec6f792012-04-17 16:52:41 -07001532 private interface KeyboardLayoutVisitor {
1533 void visitKeyboardLayout(Resources resources,
Jeff Brownd9fec5d2012-05-17 16:01:54 -07001534 String descriptor, String label, String collection, int keyboardLayoutResId);
Jeff Brown6ec6f792012-04-17 16:52:41 -07001535 }
1536
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001537 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
1538 private final int mPid;
1539 private final IInputDevicesChangedListener mListener;
1540
1541 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
1542 mPid = pid;
1543 mListener = listener;
1544 }
1545
1546 @Override
1547 public void binderDied() {
1548 if (DEBUG) {
1549 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
1550 }
1551 onInputDevicesChangedListenerDied(mPid);
1552 }
1553
1554 public void notifyInputDevicesChanged(int[] info) {
1555 try {
1556 mListener.onInputDevicesChanged(info);
1557 } catch (RemoteException ex) {
1558 Slog.w(TAG, "Failed to notify process "
1559 + mPid + " that input devices changed, assuming it died.", ex);
1560 binderDied();
1561 }
1562 }
1563 }
Jeff Browna47425a2012-04-13 04:09:27 -07001564
1565 private final class VibratorToken implements DeathRecipient {
1566 public final int mDeviceId;
1567 public final IBinder mToken;
1568 public final int mTokenValue;
1569
1570 public boolean mVibrating;
1571
1572 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
1573 mDeviceId = deviceId;
1574 mToken = token;
1575 mTokenValue = tokenValue;
1576 }
1577
1578 @Override
1579 public void binderDied() {
1580 if (DEBUG) {
1581 Slog.d(TAG, "Vibrator token died.");
1582 }
1583 onVibratorTokenDied(this);
1584 }
1585 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001586}