blob: 7640eff381ce47dd71b0f750df53508ad0bd9800 [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 Browna3bc5652012-04-17 11:42:25 -070019import com.android.internal.os.AtomicFile;
20import com.android.internal.util.FastXmlSerializer;
Jeff Brown46b9ac02010-04-22 18:58:52 -070021import com.android.internal.util.XmlUtils;
Jeff Brown89ef0722011-08-10 16:25:21 -070022import com.android.server.Watchdog;
Jeff Brown46b9ac02010-04-22 18:58:52 -070023
24import org.xmlpull.v1.XmlPullParser;
Jeff Browna3bc5652012-04-17 11:42:25 -070025import org.xmlpull.v1.XmlPullParserException;
26import org.xmlpull.v1.XmlSerializer;
Jeff Brown46b9ac02010-04-22 18:58:52 -070027
Jeff Browna3bc5652012-04-17 11:42:25 -070028import android.Manifest;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070029import android.content.ComponentName;
Jeff Brown46b9ac02010-04-22 18:58:52 -070030import android.content.Context;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070031import android.content.Intent;
32import android.content.pm.ActivityInfo;
Jeff Brown349703e2010-06-22 01:27:15 -070033import android.content.pm.PackageManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070034import android.content.pm.ResolveInfo;
35import android.content.pm.PackageManager.NameNotFoundException;
Jeff Brown46b9ac02010-04-22 18:58:52 -070036import android.content.res.Configuration;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070037import android.content.res.Resources;
38import android.content.res.TypedArray;
39import android.content.res.XmlResourceParser;
Jeff Brown1a84fd12011-06-02 01:26:32 -070040import android.database.ContentObserver;
Jeff Brown4532e612012-04-05 14:27:12 -070041import android.hardware.input.IInputManager;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070042import android.hardware.input.IInputDevicesChangedListener;
Jeff Brownac143512012-04-05 18:57:33 -070043import android.hardware.input.InputManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070044import android.hardware.input.KeyboardLayout;
Jeff Brown4532e612012-04-05 14:27:12 -070045import android.os.Binder;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070046import android.os.Bundle;
Jeff Brown46b9ac02010-04-22 18:58:52 -070047import android.os.Environment;
Jeff Brown4532e612012-04-05 14:27:12 -070048import android.os.Handler;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070049import android.os.IBinder;
50import android.os.Message;
Jeff Brown05dc66a2011-03-02 14:41:58 -080051import android.os.MessageQueue;
Jeff Brownac143512012-04-05 18:57:33 -070052import android.os.Process;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070053import android.os.RemoteException;
Jeff Brown1a84fd12011-06-02 01:26:32 -070054import android.provider.Settings;
55import android.provider.Settings.SettingNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070056import android.util.Log;
Jeff Brown46b9ac02010-04-22 18:58:52 -070057import android.util.Slog;
Jeff Brownaf9e8d32012-04-12 17:32:48 -070058import android.util.SparseArray;
Jeff Brown46b9ac02010-04-22 18:58:52 -070059import android.util.Xml;
60import android.view.InputChannel;
Jeff Brown8d608662010-08-30 03:02:23 -070061import android.view.InputDevice;
Jeff Brown6ec402b2010-07-28 15:48:59 -070062import android.view.InputEvent;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070063import android.view.KeyCharacterMap;
Jeff Brown1f245102010-11-18 20:53:46 -080064import android.view.KeyEvent;
Jeff Brown2352b972011-04-12 22:39:53 -070065import android.view.PointerIcon;
Jeff Brown46b9ac02010-04-22 18:58:52 -070066import android.view.Surface;
Jeff Browna4547672011-03-02 21:38:11 -080067import android.view.ViewConfiguration;
Jeff Brown0029c662011-03-30 02:25:18 -070068import android.view.WindowManagerPolicy;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070069import android.view.KeyCharacterMap.UnavailableException;
Jeff Brown46b9ac02010-04-22 18:58:52 -070070
Jeff Browna3bc5652012-04-17 11:42:25 -070071import java.io.BufferedInputStream;
72import java.io.BufferedOutputStream;
Jeff Brown46b9ac02010-04-22 18:58:52 -070073import java.io.File;
Jeff Brown4532e612012-04-05 14:27:12 -070074import java.io.FileDescriptor;
Jeff Brown46b9ac02010-04-22 18:58:52 -070075import java.io.FileNotFoundException;
Jeff Browna3bc5652012-04-17 11:42:25 -070076import java.io.FileOutputStream;
Jeff Brown46b9ac02010-04-22 18:58:52 -070077import java.io.FileReader;
78import java.io.IOException;
Jeff Browna3bc5652012-04-17 11:42:25 -070079import java.io.InputStream;
Jeff Brown46b9ac02010-04-22 18:58:52 -070080import java.io.PrintWriter;
81import java.util.ArrayList;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070082import java.util.HashMap;
83import java.util.List;
Jeff Browna3bc5652012-04-17 11:42:25 -070084import java.util.Map;
85
86import libcore.io.IoUtils;
87import libcore.util.Objects;
Jeff Brown46b9ac02010-04-22 18:58:52 -070088
89/*
90 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -070091 */
Jeff Brown4532e612012-04-05 14:27:12 -070092public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
Jeff Brown46b9ac02010-04-22 18:58:52 -070093 static final String TAG = "InputManager";
Jeff Brown4532e612012-04-05 14:27:12 -070094 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -070095
Jeff Brown4532e612012-04-05 14:27:12 -070096 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
97
Jeff Brownaf9e8d32012-04-12 17:32:48 -070098 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
99
Jeff Brown4532e612012-04-05 14:27:12 -0700100 // Pointer to native input manager service object.
101 private final int mPtr;
102
Jeff Brown46b9ac02010-04-22 18:58:52 -0700103 private final Context mContext;
Jeff Brown4532e612012-04-05 14:27:12 -0700104 private final Callbacks mCallbacks;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700105 private final InputManagerHandler mHandler;
106
Jeff Browna3bc5652012-04-17 11:42:25 -0700107 // Persistent data store. Must be locked each time during use.
108 private final PersistentDataStore mDataStore = new PersistentDataStore();
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700109
110 // List of currently registered input devices changed listeners by process id.
111 private Object mInputDevicesLock = new Object();
112 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
113 private InputDevice[] mInputDevices = new InputDevice[0];
114 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
115 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
116 private final ArrayList<InputDevicesChangedListenerRecord>
117 mTempInputDevicesChangedListenersToNotify =
118 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
119
Jeff Browna47425a2012-04-13 04:09:27 -0700120 // State for vibrator tokens.
121 private Object mVibratorLock = new Object();
122 private HashMap<IBinder, VibratorToken> mVibratorTokens =
123 new HashMap<IBinder, VibratorToken>();
124 private int mNextVibratorTokenValue;
125
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700126 // State for the currently installed input filter.
127 final Object mInputFilterLock = new Object();
128 InputFilter mInputFilter; // guarded by mInputFilterLock
129 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
Jeff Brown1a84fd12011-06-02 01:26:32 -0700130
Jeff Brown4532e612012-04-05 14:27:12 -0700131 private static native int nativeInit(InputManagerService service,
132 Context context, MessageQueue messageQueue);
133 private static native void nativeStart(int ptr);
134 private static native void nativeSetDisplaySize(int ptr, int displayId,
135 int width, int height, int externalWidth, int externalHeight);
136 private static native void nativeSetDisplayOrientation(int ptr, int displayId, int rotation);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700137
Jeff Brown4532e612012-04-05 14:27:12 -0700138 private static native int nativeGetScanCodeState(int ptr,
139 int deviceId, int sourceMask, int scanCode);
140 private static native int nativeGetKeyCodeState(int ptr,
141 int deviceId, int sourceMask, int keyCode);
142 private static native int nativeGetSwitchState(int ptr,
143 int deviceId, int sourceMask, int sw);
144 private static native boolean nativeHasKeys(int ptr,
145 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
146 private static native void nativeRegisterInputChannel(int ptr, InputChannel inputChannel,
Jeff Brown928e0542011-01-10 11:17:36 -0800147 InputWindowHandle inputWindowHandle, boolean monitor);
Jeff Brown4532e612012-04-05 14:27:12 -0700148 private static native void nativeUnregisterInputChannel(int ptr, InputChannel inputChannel);
149 private static native void nativeSetInputFilterEnabled(int ptr, boolean enable);
150 private static native int nativeInjectInputEvent(int ptr, InputEvent event,
Jeff Brown0029c662011-03-30 02:25:18 -0700151 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
152 int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -0700153 private static native void nativeSetInputWindows(int ptr, InputWindowHandle[] windowHandles);
154 private static native void nativeSetInputDispatchMode(int ptr, boolean enabled, boolean frozen);
155 private static native void nativeSetSystemUiVisibility(int ptr, int visibility);
156 private static native void nativeSetFocusedApplication(int ptr,
157 InputApplicationHandle application);
Jeff Brown4532e612012-04-05 14:27:12 -0700158 private static native void nativeGetInputConfiguration(int ptr, Configuration configuration);
Jeff Brown4532e612012-04-05 14:27:12 -0700159 private static native boolean nativeTransferTouchFocus(int ptr,
160 InputChannel fromChannel, InputChannel toChannel);
161 private static native void nativeSetPointerSpeed(int ptr, int speed);
162 private static native void nativeSetShowTouches(int ptr, boolean enabled);
Jeff Browna47425a2012-04-13 04:09:27 -0700163 private static native void nativeVibrate(int ptr, int deviceId, long[] pattern,
164 int repeat, int token);
165 private static native void nativeCancelVibrate(int ptr, int deviceId, int token);
Jeff Brown4532e612012-04-05 14:27:12 -0700166 private static native String nativeDump(int ptr);
167 private static native void nativeMonitor(int ptr);
Jeff Brown4532e612012-04-05 14:27:12 -0700168
Jeff Brownac143512012-04-05 18:57:33 -0700169 // Input event injection constants defined in InputDispatcher.h.
170 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
171 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
172 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
173 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
174
175 // Maximum number of milliseconds to wait for input event injection.
176 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
177
Jeff Brown6d0fec22010-07-23 21:28:06 -0700178 // Key states (may be returned by queries about the current state of a
179 // particular key code, scan code or switch).
180
181 /** The key state is unknown or the requested key itself is not supported. */
182 public static final int KEY_STATE_UNKNOWN = -1;
183
184 /** The key is up. /*/
185 public static final int KEY_STATE_UP = 0;
186
187 /** The key is down. */
188 public static final int KEY_STATE_DOWN = 1;
189
190 /** The key is down but is a virtual key press that is being emulated by the system. */
191 public static final int KEY_STATE_VIRTUAL = 2;
192
Jeff Brown4532e612012-04-05 14:27:12 -0700193 public InputManagerService(Context context, Callbacks callbacks) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700194 this.mContext = context;
Jeff Brown4532e612012-04-05 14:27:12 -0700195 this.mCallbacks = callbacks;
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700196 this.mHandler = new InputManagerHandler();
Jeff Brown05dc66a2011-03-02 14:41:58 -0800197
Jeff Brown46b9ac02010-04-22 18:58:52 -0700198 Slog.i(TAG, "Initializing input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700199 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700200 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700201
Jeff Brown46b9ac02010-04-22 18:58:52 -0700202 public void start() {
203 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700204 nativeStart(mPtr);
205
206 // Add ourself to the Watchdog monitors.
207 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700208
209 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700210 registerShowTouchesSettingObserver();
211
Jeff Brown1a84fd12011-06-02 01:26:32 -0700212 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700213 updateShowTouchesFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700214 }
215
Jeff Brownbc68a592011-07-25 12:58:12 -0700216 public void setDisplaySize(int displayId, int width, int height,
217 int externalWidth, int externalHeight) {
218 if (width <= 0 || height <= 0 || externalWidth <= 0 || externalHeight <= 0) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700219 throw new IllegalArgumentException("Invalid display id or dimensions.");
220 }
221
Jeff Brownb6997262010-10-08 22:31:17 -0700222 if (DEBUG) {
Jeff Brownbc68a592011-07-25 12:58:12 -0700223 Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height
224 + " external size " + externalWidth + "x" + externalHeight);
Jeff Brownb6997262010-10-08 22:31:17 -0700225 }
Jeff Brown4532e612012-04-05 14:27:12 -0700226 nativeSetDisplaySize(mPtr, displayId, width, height, externalWidth, externalHeight);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700227 }
228
229 public void setDisplayOrientation(int displayId, int rotation) {
230 if (rotation < Surface.ROTATION_0 || rotation > Surface.ROTATION_270) {
231 throw new IllegalArgumentException("Invalid rotation.");
232 }
233
Jeff Brownb6997262010-10-08 22:31:17 -0700234 if (DEBUG) {
235 Slog.d(TAG, "Setting display #" + displayId + " orientation to " + rotation);
236 }
Jeff Brown4532e612012-04-05 14:27:12 -0700237 nativeSetDisplayOrientation(mPtr, displayId, rotation);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700238 }
239
240 public void getInputConfiguration(Configuration config) {
241 if (config == null) {
242 throw new IllegalArgumentException("config must not be null.");
243 }
244
Jeff Brown4532e612012-04-05 14:27:12 -0700245 nativeGetInputConfiguration(mPtr, config);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700246 }
Jeff Brownac143512012-04-05 18:57:33 -0700247
Jeff Brown6d0fec22010-07-23 21:28:06 -0700248 /**
249 * Gets the current state of a key or button by key code.
250 * @param deviceId The input device id, or -1 to consult all devices.
251 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
252 * consider all input sources. An input device is consulted if at least one of its
253 * non-class input source bits matches the specified source mask.
254 * @param keyCode The key code to check.
255 * @return The key state.
256 */
257 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700258 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700259 }
260
Jeff Brown6d0fec22010-07-23 21:28:06 -0700261 /**
262 * Gets the current state of a key or button by scan code.
263 * @param deviceId The input device id, or -1 to consult all devices.
264 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
265 * consider all input sources. An input device is consulted if at least one of its
266 * non-class input source bits matches the specified source mask.
267 * @param scanCode The scan code to check.
268 * @return The key state.
269 */
270 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700271 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700272 }
273
Jeff Brown6d0fec22010-07-23 21:28:06 -0700274 /**
275 * Gets the current state of a switch by switch code.
276 * @param deviceId The input device id, or -1 to consult all devices.
277 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
278 * consider all input sources. An input device is consulted if at least one of its
279 * non-class input source bits matches the specified source mask.
280 * @param switchCode The switch code to check.
281 * @return The switch state.
282 */
283 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700284 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700285 }
286
Jeff Brown6d0fec22010-07-23 21:28:06 -0700287 /**
288 * Determines whether the specified key codes are supported by a particular device.
289 * @param deviceId The input device id, or -1 to consult all devices.
290 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
291 * consider all input sources. An input device is consulted if at least one of its
292 * non-class input source bits matches the specified source mask.
293 * @param keyCodes The array of key codes to check.
294 * @param keyExists An array at least as large as keyCodes whose entries will be set
295 * to true or false based on the presence or absence of support for the corresponding
296 * key codes.
297 * @return True if the lookup was successful, false otherwise.
298 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700299 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700300 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700301 if (keyCodes == null) {
302 throw new IllegalArgumentException("keyCodes must not be null.");
303 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700304 if (keyExists == null || keyExists.length < keyCodes.length) {
305 throw new IllegalArgumentException("keyExists must not be null and must be at "
306 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700307 }
308
Jeff Brown4532e612012-04-05 14:27:12 -0700309 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700310 }
311
Jeff Browna41ca772010-08-11 14:46:32 -0700312 /**
313 * Creates an input channel that will receive all input from the input dispatcher.
314 * @param inputChannelName The input channel name.
315 * @return The input channel.
316 */
317 public InputChannel monitorInput(String inputChannelName) {
318 if (inputChannelName == null) {
319 throw new IllegalArgumentException("inputChannelName must not be null.");
320 }
321
322 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700323 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700324 inputChannels[0].dispose(); // don't need to retain the Java object reference
325 return inputChannels[1];
326 }
327
328 /**
329 * Registers an input channel so that it can be used as an input event target.
330 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800331 * @param inputWindowHandle The handle of the input window associated with the
332 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700333 */
Jeff Brown928e0542011-01-10 11:17:36 -0800334 public void registerInputChannel(InputChannel inputChannel,
335 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700336 if (inputChannel == null) {
337 throw new IllegalArgumentException("inputChannel must not be null.");
338 }
339
Jeff Brown4532e612012-04-05 14:27:12 -0700340 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700341 }
342
Jeff Browna41ca772010-08-11 14:46:32 -0700343 /**
344 * Unregisters an input channel.
345 * @param inputChannel The input channel to unregister.
346 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700347 public void unregisterInputChannel(InputChannel inputChannel) {
348 if (inputChannel == null) {
349 throw new IllegalArgumentException("inputChannel must not be null.");
350 }
351
Jeff Brown4532e612012-04-05 14:27:12 -0700352 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700353 }
Jeff Brown0029c662011-03-30 02:25:18 -0700354
355 /**
356 * Sets an input filter that will receive all input events before they are dispatched.
357 * The input filter may then reinterpret input events or inject new ones.
358 *
359 * To ensure consistency, the input dispatcher automatically drops all events
360 * in progress whenever an input filter is installed or uninstalled. After an input
361 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
362 * Any events it attempts to send after it has been uninstalled will be dropped.
363 *
364 * @param filter The input filter, or null to remove the current filter.
365 */
366 public void setInputFilter(InputFilter filter) {
367 synchronized (mInputFilterLock) {
368 final InputFilter oldFilter = mInputFilter;
369 if (oldFilter == filter) {
370 return; // nothing to do
371 }
372
373 if (oldFilter != null) {
374 mInputFilter = null;
375 mInputFilterHost.disconnectLocked();
376 mInputFilterHost = null;
377 oldFilter.uninstall();
378 }
379
380 if (filter != null) {
381 mInputFilter = filter;
382 mInputFilterHost = new InputFilterHost();
383 filter.install(mInputFilterHost);
384 }
385
Jeff Brown4532e612012-04-05 14:27:12 -0700386 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700387 }
388 }
389
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700390 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700391 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700392 if (event == null) {
393 throw new IllegalArgumentException("event must not be null");
394 }
Jeff Brownac143512012-04-05 18:57:33 -0700395 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
396 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
397 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
398 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700399 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700400
Jeff Brownac143512012-04-05 18:57:33 -0700401 final int pid = Binder.getCallingPid();
402 final int uid = Binder.getCallingUid();
403 final long ident = Binder.clearCallingIdentity();
404 final int result;
405 try {
406 result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
407 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
408 } finally {
409 Binder.restoreCallingIdentity(ident);
410 }
411 switch (result) {
412 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
413 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
414 throw new SecurityException(
415 "Injecting to another application requires INJECT_EVENTS permission");
416 case INPUT_EVENT_INJECTION_SUCCEEDED:
417 return true;
418 case INPUT_EVENT_INJECTION_TIMED_OUT:
419 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
420 return false;
421 case INPUT_EVENT_INJECTION_FAILED:
422 default:
423 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
424 return false;
425 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700426 }
Jeff Brown0029c662011-03-30 02:25:18 -0700427
Jeff Brown8d608662010-08-30 03:02:23 -0700428 /**
429 * Gets information about the input device with the specified id.
430 * @param id The device id.
431 * @return The input device or null if not found.
432 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700433 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700434 public InputDevice getInputDevice(int deviceId) {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700435 synchronized (mInputDevicesLock) {
436 final int count = mInputDevices.length;
437 for (int i = 0; i < count; i++) {
438 final InputDevice inputDevice = mInputDevices[i];
439 if (inputDevice.getId() == deviceId) {
440 return inputDevice;
441 }
442 }
443 }
444 return null;
Jeff Brown8d608662010-08-30 03:02:23 -0700445 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700446
Jeff Brown8d608662010-08-30 03:02:23 -0700447 /**
448 * Gets the ids of all input devices in the system.
449 * @return The input device ids.
450 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700451 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700452 public int[] getInputDeviceIds() {
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700453 synchronized (mInputDevicesLock) {
454 final int count = mInputDevices.length;
455 int[] ids = new int[count];
456 for (int i = 0; i < count; i++) {
457 ids[i] = mInputDevices[i].getId();
458 }
459 return ids;
460 }
461 }
462
463 @Override // Binder call
464 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) {
465 if (listener == null) {
466 throw new IllegalArgumentException("listener must not be null");
467 }
468
469 synchronized (mInputDevicesLock) {
470 int callingPid = Binder.getCallingPid();
471 if (mInputDevicesChangedListeners.get(callingPid) != null) {
472 throw new SecurityException("The calling process has already "
473 + "registered an InputDevicesChangedListener.");
474 }
475
476 InputDevicesChangedListenerRecord record =
477 new InputDevicesChangedListenerRecord(callingPid, listener);
478 try {
479 IBinder binder = listener.asBinder();
480 binder.linkToDeath(record, 0);
481 } catch (RemoteException ex) {
482 // give up
483 throw new RuntimeException(ex);
484 }
485
486 mInputDevicesChangedListeners.put(callingPid, record);
487 }
488 }
489
490 private void onInputDevicesChangedListenerDied(int pid) {
491 synchronized (mInputDevicesLock) {
492 mInputDevicesChangedListeners.remove(pid);
493 }
494 }
495
496 // Must be called on handler.
497 private void deliverInputDevicesChanged() {
498 mTempInputDevicesChangedListenersToNotify.clear();
499
500 final int numListeners;
501 final int[] deviceIdAndGeneration;
502 synchronized (mInputDevicesLock) {
503 if (!mInputDevicesChangedPending) {
504 return;
505 }
506 mInputDevicesChangedPending = false;
507
508 numListeners = mInputDevicesChangedListeners.size();
509 for (int i = 0; i < numListeners; i++) {
510 mTempInputDevicesChangedListenersToNotify.add(
511 mInputDevicesChangedListeners.valueAt(i));
512 }
513
514 final int numDevices = mInputDevices.length;
515 deviceIdAndGeneration = new int[numDevices * 2];
516 for (int i = 0; i < numDevices; i++) {
517 final InputDevice inputDevice = mInputDevices[i];
518 deviceIdAndGeneration[i * 2] = inputDevice.getId();
519 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration();
520 }
521 }
522
523 for (int i = 0; i < numListeners; i++) {
524 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged(
525 deviceIdAndGeneration);
526 }
Jeff Brown8d608662010-08-30 03:02:23 -0700527 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700528
529 @Override // Binder call
530 public KeyboardLayout[] getKeyboardLayouts() {
531 ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
532
533 final PackageManager pm = mContext.getPackageManager();
534 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
535 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
536 PackageManager.GET_META_DATA)) {
537 loadKeyboardLayouts(pm, resolveInfo.activityInfo, list, null);
538 }
539 return list.toArray(new KeyboardLayout[list.size()]);
540 }
541
542 @Override // Binder call
543 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
544 if (keyboardLayoutDescriptor == null) {
545 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
546 }
547
548 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
549 if (d == null) {
550 return null;
551 }
552
553 final PackageManager pm = mContext.getPackageManager();
554 try {
555 ActivityInfo receiver = pm.getReceiverInfo(
556 new ComponentName(d.packageName, d.receiverName),
557 PackageManager.GET_META_DATA);
558 return loadKeyboardLayouts(pm, receiver, null, d.keyboardLayoutName);
559 } catch (NameNotFoundException ex) {
560 Log.w(TAG, "Could not load keyboard layout '" + d.keyboardLayoutName
561 + "' from receiver " + d.packageName + "/" + d.receiverName, ex);
562 return null;
563 }
564 }
565
566 private KeyboardLayout loadKeyboardLayouts(
567 PackageManager pm, ActivityInfo receiver,
568 List<KeyboardLayout> list, String keyboardName) {
569 Bundle metaData = receiver.metaData;
570 if (metaData == null) {
571 return null;
572 }
573
574 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
575 if (configResId == 0) {
576 Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
577 + "' on receiver " + receiver.packageName + "/" + receiver.name);
578 return null;
579 }
580
581 try {
582 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
583 XmlResourceParser parser = resources.getXml(configResId);
584 try {
585 XmlUtils.beginDocument(parser, "keyboard-layouts");
586
587 for (;;) {
588 XmlUtils.nextElement(parser);
589 String element = parser.getName();
590 if (element == null) {
591 break;
592 }
593 if (element.equals("keyboard-layout")) {
594 TypedArray a = resources.obtainAttributes(
595 parser, com.android.internal.R.styleable.KeyboardLayout);
596 try {
597 String name = a.getString(
598 com.android.internal.R.styleable.KeyboardLayout_name);
599 String label = a.getString(
600 com.android.internal.R.styleable.KeyboardLayout_label);
601 int kcmResId = a.getResourceId(
602 com.android.internal.R.styleable.KeyboardLayout_kcm, 0);
603 if (name == null || label == null || kcmResId == 0) {
604 Log.w(TAG, "Missing required 'name', 'label' or 'kcm' "
605 + "attributes in keyboard layout "
606 + "resource from receiver "
607 + receiver.packageName + "/" + receiver.name);
608 } else {
609 String descriptor = KeyboardLayoutDescriptor.format(
610 receiver.packageName, receiver.name, name);
611 KeyboardLayout c = new KeyboardLayout(descriptor, label);
612 if (keyboardName != null && name.equals(keyboardName)) {
613 return c;
614 }
615 if (list != null) {
616 list.add(c);
617 }
618 }
619 } finally {
620 a.recycle();
621 }
622 } else {
623 Log.w(TAG, "Skipping unrecognized element '" + element
624 + "' in keyboard layout resource from receiver "
625 + receiver.packageName + "/" + receiver.name);
626 }
627 }
628 } finally {
629 parser.close();
630 }
631 } catch (Exception ex) {
632 Log.w(TAG, "Could not load keyboard layout resource from receiver "
633 + receiver.packageName + "/" + receiver.name, ex);
634 return null;
635 }
636 if (keyboardName != null) {
637 Log.w(TAG, "Could not load keyboard layout '" + keyboardName
638 + "' from receiver " + receiver.packageName + "/" + receiver.name
639 + " because it was not declared in the keyboard layout resource.");
640 }
641 return null;
642 }
643
644 @Override // Binder call
645 public String getKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
646 if (inputDeviceDescriptor == null) {
647 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
648 }
649
Jeff Browna3bc5652012-04-17 11:42:25 -0700650 synchronized (mDataStore) {
651 return mDataStore.getKeyboardLayout(inputDeviceDescriptor);
652 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700653 }
654
655 @Override // Binder call
656 public void setKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
657 String keyboardLayoutDescriptor) {
658 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
659 "setKeyboardLayoutForInputDevice()")) {
660 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
661 }
662
663 if (inputDeviceDescriptor == null) {
664 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
665 }
666
Jeff Browna3bc5652012-04-17 11:42:25 -0700667 synchronized (mDataStore) {
668 try {
669 mDataStore.setKeyboardLayout(inputDeviceDescriptor, keyboardLayoutDescriptor);
670 } finally {
671 mDataStore.saveIfNeeded();
672 }
673 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700674 }
675
676 /**
677 * Loads the key character map associated with the keyboard layout.
678 *
679 * @param pm The package manager.
680 * @return The key character map, or null if it could not be loaded for any reason.
681 *
682 public KeyCharacterMap loadKeyCharacterMap(PackageManager pm) {
683 if (pm == null) {
684 throw new IllegalArgumentException("pm must not be null");
685 }
686
687 if (mKeyCharacterMap == null) {
688 KeyboardLayoutDescriptor d = InputManager.parseKeyboardLayoutDescriptor(mDescriptor);
689 if (d == null) {
690 Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
691 + "' because the descriptor could not be parsed.");
692 return null;
693 }
694
695 CharSequence cs = pm.getText(d.packageName, mKeyCharacterMapResId, null);
696 if (cs == null) {
697 Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
698 + "' because its associated resource could not be loaded.");
699 return null;
700 }
701
702 try {
703 mKeyCharacterMap = KeyCharacterMap.load(cs);
704 } catch (UnavailableException ex) {
705 Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
706 + "' due to an error while parsing.", ex);
707 return null;
708 }
709 }
710 return mKeyCharacterMap;
711 }*/
712
Jeff Brown9302c872011-07-13 22:51:29 -0700713 public void setInputWindows(InputWindowHandle[] windowHandles) {
Jeff Brown4532e612012-04-05 14:27:12 -0700714 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -0700715 }
716
Jeff Brown9302c872011-07-13 22:51:29 -0700717 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -0700718 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -0700719 }
720
Jeff Brown349703e2010-06-22 01:27:15 -0700721 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -0700722 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -0700723 }
Jeff Brown05dc66a2011-03-02 14:41:58 -0800724
725 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -0700726 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -0800727 }
728
Jeff Browne6504122010-09-27 14:52:15 -0700729 /**
730 * Atomically transfers touch focus from one window to another as identified by
731 * their input channels. It is possible for multiple windows to have
732 * touch focus if they support split touch dispatch
733 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
734 * method only transfers touch focus of the specified window without affecting
735 * other windows that may also have touch focus at the same time.
736 * @param fromChannel The channel of a window that currently has touch focus.
737 * @param toChannel The channel of the window that should receive touch focus in
738 * place of the first.
739 * @return True if the transfer was successful. False if the window with the
740 * specified channel did not actually have touch focus at the time of the request.
741 */
742 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
743 if (fromChannel == null) {
744 throw new IllegalArgumentException("fromChannel must not be null.");
745 }
746 if (toChannel == null) {
747 throw new IllegalArgumentException("toChannel must not be null.");
748 }
Jeff Brown4532e612012-04-05 14:27:12 -0700749 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -0700750 }
Jeff Brown05dc66a2011-03-02 14:41:58 -0800751
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700752 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700753 public void tryPointerSpeed(int speed) {
754 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
755 "tryPointerSpeed()")) {
756 throw new SecurityException("Requires SET_POINTER_SPEED permission");
757 }
758
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700759 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
760 throw new IllegalArgumentException("speed out of range");
761 }
762
Jeff Brownac143512012-04-05 18:57:33 -0700763 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700764 }
765
766 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -0700767 int speed = getPointerSpeedSetting();
768 setPointerSpeedUnchecked(speed);
769 }
770
771 private void setPointerSpeedUnchecked(int speed) {
772 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
773 InputManager.MAX_POINTER_SPEED);
774 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700775 }
776
777 private void registerPointerSpeedSettingObserver() {
778 mContext.getContentResolver().registerContentObserver(
779 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -0700780 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -0700781 @Override
782 public void onChange(boolean selfChange) {
783 updatePointerSpeedFromSettings();
784 }
785 });
786 }
787
Jeff Brownac143512012-04-05 18:57:33 -0700788 private int getPointerSpeedSetting() {
789 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -0700790 try {
791 speed = Settings.System.getInt(mContext.getContentResolver(),
792 Settings.System.POINTER_SPEED);
793 } catch (SettingNotFoundException snfe) {
794 }
795 return speed;
796 }
797
Jeff Browndaf4a122011-08-26 17:14:14 -0700798 public void updateShowTouchesFromSettings() {
799 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -0700800 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -0700801 }
802
803 private void registerShowTouchesSettingObserver() {
804 mContext.getContentResolver().registerContentObserver(
805 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -0700806 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -0700807 @Override
808 public void onChange(boolean selfChange) {
809 updateShowTouchesFromSettings();
810 }
811 });
812 }
813
814 private int getShowTouchesSetting(int defaultValue) {
815 int result = defaultValue;
816 try {
817 result = Settings.System.getInt(mContext.getContentResolver(),
818 Settings.System.SHOW_TOUCHES);
819 } catch (SettingNotFoundException snfe) {
820 }
821 return result;
822 }
823
Jeff Browna47425a2012-04-13 04:09:27 -0700824 // Binder call
825 @Override
826 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) {
827 if (repeat >= pattern.length) {
828 throw new ArrayIndexOutOfBoundsException();
829 }
830
831 VibratorToken v;
832 synchronized (mVibratorLock) {
833 v = mVibratorTokens.get(token);
834 if (v == null) {
835 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++);
836 try {
837 token.linkToDeath(v, 0);
838 } catch (RemoteException ex) {
839 // give up
840 throw new RuntimeException(ex);
841 }
842 mVibratorTokens.put(token, v);
843 }
844 }
845
846 synchronized (v) {
847 v.mVibrating = true;
848 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue);
849 }
850 }
851
852 // Binder call
853 @Override
854 public void cancelVibrate(int deviceId, IBinder token) {
855 VibratorToken v;
856 synchronized (mVibratorLock) {
857 v = mVibratorTokens.get(token);
858 if (v == null || v.mDeviceId != deviceId) {
859 return; // nothing to cancel
860 }
861 }
862
863 cancelVibrateIfNeeded(v);
864 }
865
866 void onVibratorTokenDied(VibratorToken v) {
867 synchronized (mVibratorLock) {
868 mVibratorTokens.remove(v.mToken);
869 }
870
871 cancelVibrateIfNeeded(v);
872 }
873
874 private void cancelVibrateIfNeeded(VibratorToken v) {
875 synchronized (v) {
876 if (v.mVibrating) {
877 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue);
878 v.mVibrating = false;
879 }
880 }
881 }
882
Jeff Brown4532e612012-04-05 14:27:12 -0700883 @Override
884 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna3bc5652012-04-17 11:42:25 -0700885 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
Jeff Brown4532e612012-04-05 14:27:12 -0700886 != PackageManager.PERMISSION_GRANTED) {
887 pw.println("Permission Denial: can't dump InputManager from from pid="
888 + Binder.getCallingPid()
889 + ", uid=" + Binder.getCallingUid());
890 return;
891 }
892
893 pw.println("INPUT MANAGER (dumpsys input)\n");
894 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -0700895 if (dumpStr != null) {
896 pw.println(dumpStr);
897 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700898 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -0800899
Jeff Brownac143512012-04-05 18:57:33 -0700900 private boolean checkCallingPermission(String permission, String func) {
901 // Quick check: if the calling permission is me, it's all okay.
902 if (Binder.getCallingPid() == Process.myPid()) {
903 return true;
904 }
905
906 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
907 return true;
908 }
909 String msg = "Permission Denial: " + func + " from pid="
910 + Binder.getCallingPid()
911 + ", uid=" + Binder.getCallingUid()
912 + " requires " + permission;
913 Slog.w(TAG, msg);
914 return false;
915 }
916
Jeff Brown4532e612012-04-05 14:27:12 -0700917 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Jeff Brown89ef0722011-08-10 16:25:21 -0700918 public void monitor() {
919 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -0700920 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -0700921 }
922
Jeff Brown4532e612012-04-05 14:27:12 -0700923 // Native callback.
924 private void notifyConfigurationChanged(long whenNanos) {
925 mCallbacks.notifyConfigurationChanged();
926 }
927
928 // Native callback.
Jeff Brownaf9e8d32012-04-12 17:32:48 -0700929 private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
930 synchronized (mInputDevicesLock) {
931 mInputDevices = inputDevices;
932
933 if (!mInputDevicesChangedPending) {
934 mInputDevicesChangedPending = true;
935 mHandler.sendEmptyMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED);
936 }
937 }
938 }
939
940 // Native callback.
Jeff Brown4532e612012-04-05 14:27:12 -0700941 private void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
942 mCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
943 }
944
945 // Native callback.
946 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
947 mCallbacks.notifyInputChannelBroken(inputWindowHandle);
948 }
949
950 // Native callback.
951 private long notifyANR(InputApplicationHandle inputApplicationHandle,
952 InputWindowHandle inputWindowHandle) {
953 return mCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle);
954 }
955
956 // Native callback.
957 final boolean filterInputEvent(InputEvent event, int policyFlags) {
958 synchronized (mInputFilterLock) {
959 if (mInputFilter != null) {
960 mInputFilter.filterInputEvent(event, policyFlags);
961 return false;
962 }
963 }
964 event.recycle();
965 return true;
966 }
967
968 // Native callback.
969 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
970 return mCallbacks.interceptKeyBeforeQueueing(
971 event, policyFlags, isScreenOn);
972 }
973
974 // Native callback.
975 private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
976 return mCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
977 }
978
979 // Native callback.
980 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
981 KeyEvent event, int policyFlags) {
982 return mCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
983 }
984
985 // Native callback.
986 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
987 KeyEvent event, int policyFlags) {
988 return mCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
989 }
990
991 // Native callback.
992 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
993 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
994 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
995 }
996
997 // Native callback.
998 private int getVirtualKeyQuietTimeMillis() {
999 return mContext.getResources().getInteger(
1000 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
1001 }
1002
1003 // Native callback.
1004 private String[] getExcludedDeviceNames() {
1005 ArrayList<String> names = new ArrayList<String>();
1006
1007 // Read partner-provided list of excluded input devices
1008 XmlPullParser parser = null;
1009 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
1010 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
1011 FileReader confreader = null;
1012 try {
1013 confreader = new FileReader(confFile);
1014 parser = Xml.newPullParser();
1015 parser.setInput(confreader);
1016 XmlUtils.beginDocument(parser, "devices");
1017
1018 while (true) {
1019 XmlUtils.nextElement(parser);
1020 if (!"device".equals(parser.getName())) {
1021 break;
1022 }
1023 String name = parser.getAttributeValue(null, "name");
1024 if (name != null) {
1025 names.add(name);
1026 }
1027 }
1028 } catch (FileNotFoundException e) {
1029 // It's ok if the file does not exist.
1030 } catch (Exception e) {
1031 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
1032 } finally {
1033 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
1034 }
1035
1036 return names.toArray(new String[names.size()]);
1037 }
1038
1039 // Native callback.
1040 private int getKeyRepeatTimeout() {
1041 return ViewConfiguration.getKeyRepeatTimeout();
1042 }
1043
1044 // Native callback.
1045 private int getKeyRepeatDelay() {
1046 return ViewConfiguration.getKeyRepeatDelay();
1047 }
1048
1049 // Native callback.
1050 private int getHoverTapTimeout() {
1051 return ViewConfiguration.getHoverTapTimeout();
1052 }
1053
1054 // Native callback.
1055 private int getHoverTapSlop() {
1056 return ViewConfiguration.getHoverTapSlop();
1057 }
1058
1059 // Native callback.
1060 private int getDoubleTapTimeout() {
1061 return ViewConfiguration.getDoubleTapTimeout();
1062 }
1063
1064 // Native callback.
1065 private int getLongPressTimeout() {
1066 return ViewConfiguration.getLongPressTimeout();
1067 }
1068
1069 // Native callback.
1070 private int getPointerLayer() {
1071 return mCallbacks.getPointerLayer();
1072 }
1073
1074 // Native callback.
1075 private PointerIcon getPointerIcon() {
1076 return PointerIcon.getDefaultIcon(mContext);
1077 }
1078
1079 /**
1080 * Callback interface implemented by the Window Manager.
1081 */
1082 public interface Callbacks {
1083 public void notifyConfigurationChanged();
1084
1085 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
1086
1087 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
1088
1089 public long notifyANR(InputApplicationHandle inputApplicationHandle,
1090 InputWindowHandle inputWindowHandle);
1091
1092 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
1093
1094 public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
1095
1096 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
1097 KeyEvent event, int policyFlags);
1098
1099 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
1100 KeyEvent event, int policyFlags);
1101
1102 public int getPointerLayer();
1103 }
1104
1105 /**
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001106 * Private handler for the input manager.
1107 */
1108 private final class InputManagerHandler extends Handler {
1109 @Override
1110 public void handleMessage(Message msg) {
1111 switch (msg.what) {
1112 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
1113 deliverInputDevicesChanged();
1114 break;
1115 }
1116 }
1117 }
1118
1119 /**
Jeff Brown4532e612012-04-05 14:27:12 -07001120 * Hosting interface for input filters to call back into the input manager.
1121 */
Jeff Brown0029c662011-03-30 02:25:18 -07001122 private final class InputFilterHost implements InputFilter.Host {
1123 private boolean mDisconnected;
1124
1125 public void disconnectLocked() {
1126 mDisconnected = true;
1127 }
1128
1129 public void sendInputEvent(InputEvent event, int policyFlags) {
1130 if (event == null) {
1131 throw new IllegalArgumentException("event must not be null");
1132 }
1133
1134 synchronized (mInputFilterLock) {
1135 if (!mDisconnected) {
Jeff Brownac143512012-04-05 18:57:33 -07001136 nativeInjectInputEvent(mPtr, event, 0, 0,
1137 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -07001138 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
1139 }
1140 }
1141 }
1142 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -07001143
1144 private static final class KeyboardLayoutDescriptor {
1145 public String packageName;
1146 public String receiverName;
1147 public String keyboardLayoutName;
1148
1149 public static String format(String packageName,
1150 String receiverName, String keyboardName) {
1151 return packageName + "/" + receiverName + "/" + keyboardName;
1152 }
1153
1154 public static KeyboardLayoutDescriptor parse(String descriptor) {
1155 int pos = descriptor.indexOf('/');
1156 if (pos < 0 || pos + 1 == descriptor.length()) {
1157 return null;
1158 }
1159 int pos2 = descriptor.indexOf('/', pos + 1);
1160 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
1161 return null;
1162 }
1163
1164 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
1165 result.packageName = descriptor.substring(0, pos);
1166 result.receiverName = descriptor.substring(pos + 1, pos2);
1167 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
1168 return result;
1169 }
1170 }
Jeff Brownaf9e8d32012-04-12 17:32:48 -07001171
1172 private final class InputDevicesChangedListenerRecord implements DeathRecipient {
1173 private final int mPid;
1174 private final IInputDevicesChangedListener mListener;
1175
1176 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) {
1177 mPid = pid;
1178 mListener = listener;
1179 }
1180
1181 @Override
1182 public void binderDied() {
1183 if (DEBUG) {
1184 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died.");
1185 }
1186 onInputDevicesChangedListenerDied(mPid);
1187 }
1188
1189 public void notifyInputDevicesChanged(int[] info) {
1190 try {
1191 mListener.onInputDevicesChanged(info);
1192 } catch (RemoteException ex) {
1193 Slog.w(TAG, "Failed to notify process "
1194 + mPid + " that input devices changed, assuming it died.", ex);
1195 binderDied();
1196 }
1197 }
1198 }
Jeff Browna47425a2012-04-13 04:09:27 -07001199
1200 private final class VibratorToken implements DeathRecipient {
1201 public final int mDeviceId;
1202 public final IBinder mToken;
1203 public final int mTokenValue;
1204
1205 public boolean mVibrating;
1206
1207 public VibratorToken(int deviceId, IBinder token, int tokenValue) {
1208 mDeviceId = deviceId;
1209 mToken = token;
1210 mTokenValue = tokenValue;
1211 }
1212
1213 @Override
1214 public void binderDied() {
1215 if (DEBUG) {
1216 Slog.d(TAG, "Vibrator token died.");
1217 }
1218 onVibratorTokenDied(this);
1219 }
1220 }
Jeff Browna3bc5652012-04-17 11:42:25 -07001221
1222 /**
1223 * Manages persistent state recorded by the input manager service as an XML file.
1224 * Caller must acquire lock on the data store before accessing it.
1225 *
1226 * File format:
1227 * <code>
1228 * &lt;input-mananger-state>
1229 * &lt;input-devices>
1230 * &lt;input-device descriptor="xxxxx" keyboard-layout="yyyyy" />
1231 * &gt;input-devices>
1232 * &gt;/input-manager-state>
1233 * </code>
1234 */
1235 private static final class PersistentDataStore {
1236 // Input device state by descriptor.
1237 private final HashMap<String, InputDeviceState> mInputDevices =
1238 new HashMap<String, InputDeviceState>();
1239 private final AtomicFile mAtomicFile;
1240
1241 // True if the data has been loaded.
1242 private boolean mLoaded;
1243
1244 // True if there are changes to be saved.
1245 private boolean mDirty;
1246
1247 public PersistentDataStore() {
1248 mAtomicFile = new AtomicFile(new File("/data/system/input-manager-state.xml"));
1249 }
1250
1251 public void saveIfNeeded() {
1252 if (mDirty) {
1253 save();
1254 mDirty = false;
1255 }
1256 }
1257
1258 public String getKeyboardLayout(String inputDeviceDescriptor) {
1259 InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
1260 return state != null ? state.keyboardLayoutDescriptor : null;
1261 }
1262
1263 public boolean setKeyboardLayout(String inputDeviceDescriptor,
1264 String keyboardLayoutDescriptor) {
1265 InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
1266 if (!Objects.equal(state.keyboardLayoutDescriptor, keyboardLayoutDescriptor)) {
1267 state.keyboardLayoutDescriptor = keyboardLayoutDescriptor;
1268 setDirty();
1269 return true;
1270 }
1271 return false;
1272 }
1273
1274 private InputDeviceState getInputDeviceState(String inputDeviceDescriptor,
1275 boolean createIfAbsent) {
1276 loadIfNeeded();
1277 InputDeviceState state = mInputDevices.get(inputDeviceDescriptor);
1278 if (state == null && createIfAbsent) {
1279 state = new InputDeviceState();
1280 mInputDevices.put(inputDeviceDescriptor, state);
1281 setDirty();
1282 }
1283 return state;
1284 }
1285
1286 private void loadIfNeeded() {
1287 if (!mLoaded) {
1288 load();
1289 mLoaded = true;
1290 }
1291 }
1292
1293 private void setDirty() {
1294 mDirty = true;
1295 }
1296
1297 private void clearState() {
1298 mInputDevices.clear();
1299 }
1300
1301 private void load() {
1302 clearState();
1303
1304 final InputStream is;
1305 try {
1306 is = mAtomicFile.openRead();
1307 } catch (FileNotFoundException ex) {
1308 return;
1309 }
1310
1311 XmlPullParser parser;
1312 try {
1313 parser = Xml.newPullParser();
1314 parser.setInput(new BufferedInputStream(is), null);
1315 loadFromXml(parser);
1316 } catch (IOException ex) {
1317 Slog.w(TAG, "Failed to load input manager persistent store data.", ex);
1318 clearState();
1319 } catch (XmlPullParserException ex) {
1320 Slog.w(TAG, "Failed to load input manager persistent store data.", ex);
1321 clearState();
1322 } finally {
1323 IoUtils.closeQuietly(is);
1324 }
1325 }
1326
1327 private void save() {
1328 final FileOutputStream os;
1329 try {
1330 os = mAtomicFile.startWrite();
1331 boolean success = false;
1332 try {
1333 XmlSerializer serializer = new FastXmlSerializer();
1334 serializer.setOutput(new BufferedOutputStream(os), "utf-8");
1335 saveToXml(serializer);
1336 serializer.flush();
1337 success = true;
1338 } finally {
1339 if (success) {
1340 mAtomicFile.finishWrite(os);
1341 } else {
1342 mAtomicFile.failWrite(os);
1343 }
1344 }
1345 } catch (IOException ex) {
1346 Slog.w(TAG, "Failed to save input manager persistent store data.", ex);
1347 }
1348 }
1349
1350 private void loadFromXml(XmlPullParser parser)
1351 throws IOException, XmlPullParserException {
1352 XmlUtils.beginDocument(parser, "input-manager-state");
1353 final int outerDepth = parser.getDepth();
1354 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
1355 if (parser.getName().equals("input-devices")) {
1356 loadInputDevicesFromXml(parser);
1357 }
1358 }
1359 }
1360
1361 private void loadInputDevicesFromXml(XmlPullParser parser)
1362 throws IOException, XmlPullParserException {
1363 final int outerDepth = parser.getDepth();
1364 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
1365 if (parser.getName().equals("input-device")) {
1366 String descriptor = parser.getAttributeValue(null, "descriptor");
1367 if (descriptor == null) {
1368 throw new XmlPullParserException(
1369 "Missing descriptor attribute on input-device");
1370 }
1371 InputDeviceState state = new InputDeviceState();
1372 state.keyboardLayoutDescriptor =
1373 parser.getAttributeValue(null, "keyboard-layout");
1374 mInputDevices.put(descriptor, state);
1375 }
1376 }
1377 }
1378
1379 private void saveToXml(XmlSerializer serializer) throws IOException {
1380 serializer.startDocument(null, true);
1381 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
1382 serializer.startTag(null, "input-manager-state");
1383 serializer.startTag(null, "input-devices");
1384 for (Map.Entry<String, InputDeviceState> entry : mInputDevices.entrySet()) {
1385 final String descriptor = entry.getKey();
1386 final InputDeviceState state = entry.getValue();
1387 serializer.startTag(null, "input-device");
1388 serializer.attribute(null, "descriptor", descriptor);
1389 if (state.keyboardLayoutDescriptor != null) {
1390 serializer.attribute(null, "keyboard-layout", state.keyboardLayoutDescriptor);
1391 }
1392 serializer.endTag(null, "input-device");
1393 }
1394 serializer.endTag(null, "input-devices");
1395 serializer.endTag(null, "input-manager-state");
1396 serializer.endDocument();
1397 }
1398 }
1399
1400 private static final class InputDeviceState {
1401 public String keyboardLayoutDescriptor;
1402 }
Jeff Brown46b9ac02010-04-22 18:58:52 -07001403}