blob: 2f25df1e66415ca3ba198fff5f4ebaecd45b9b51 [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
19import com.android.internal.util.XmlUtils;
Jeff Brown89ef0722011-08-10 16:25:21 -070020import com.android.server.Watchdog;
Jeff Brown46b9ac02010-04-22 18:58:52 -070021
22import org.xmlpull.v1.XmlPullParser;
23
Jeff Brown9f25b7f2012-04-10 14:30:49 -070024import android.content.ComponentName;
Jeff Brown46b9ac02010-04-22 18:58:52 -070025import android.content.Context;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070026import android.content.Intent;
27import android.content.pm.ActivityInfo;
Jeff Brown349703e2010-06-22 01:27:15 -070028import android.content.pm.PackageManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070029import android.content.pm.ResolveInfo;
30import android.content.pm.PackageManager.NameNotFoundException;
Jeff Brown46b9ac02010-04-22 18:58:52 -070031import android.content.res.Configuration;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070032import android.content.res.Resources;
33import android.content.res.TypedArray;
34import android.content.res.XmlResourceParser;
Jeff Brown1a84fd12011-06-02 01:26:32 -070035import android.database.ContentObserver;
Jeff Brown4532e612012-04-05 14:27:12 -070036import android.hardware.input.IInputManager;
Jeff Brownac143512012-04-05 18:57:33 -070037import android.hardware.input.InputManager;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070038import android.hardware.input.KeyboardLayout;
Jeff Brown4532e612012-04-05 14:27:12 -070039import android.os.Binder;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070040import android.os.Bundle;
Jeff Brown46b9ac02010-04-22 18:58:52 -070041import android.os.Environment;
Jeff Brown4532e612012-04-05 14:27:12 -070042import android.os.Handler;
Jeff Brown05dc66a2011-03-02 14:41:58 -080043import android.os.MessageQueue;
Jeff Brownac143512012-04-05 18:57:33 -070044import android.os.Process;
Jeff Brown1a84fd12011-06-02 01:26:32 -070045import android.provider.Settings;
46import android.provider.Settings.SettingNotFoundException;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070047import android.util.Log;
Jeff Brown46b9ac02010-04-22 18:58:52 -070048import android.util.Slog;
49import android.util.Xml;
50import android.view.InputChannel;
Jeff Brown8d608662010-08-30 03:02:23 -070051import android.view.InputDevice;
Jeff Brown6ec402b2010-07-28 15:48:59 -070052import android.view.InputEvent;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070053import android.view.KeyCharacterMap;
Jeff Brown1f245102010-11-18 20:53:46 -080054import android.view.KeyEvent;
Jeff Brown2352b972011-04-12 22:39:53 -070055import android.view.PointerIcon;
Jeff Brown46b9ac02010-04-22 18:58:52 -070056import android.view.Surface;
Jeff Browna4547672011-03-02 21:38:11 -080057import android.view.ViewConfiguration;
Jeff Brown0029c662011-03-30 02:25:18 -070058import android.view.WindowManagerPolicy;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070059import android.view.KeyCharacterMap.UnavailableException;
Jeff Brown46b9ac02010-04-22 18:58:52 -070060
Jeff Brown46b9ac02010-04-22 18:58:52 -070061import java.io.File;
Jeff Brown4532e612012-04-05 14:27:12 -070062import java.io.FileDescriptor;
Jeff Brown46b9ac02010-04-22 18:58:52 -070063import java.io.FileNotFoundException;
64import java.io.FileReader;
65import java.io.IOException;
Jeff Brown46b9ac02010-04-22 18:58:52 -070066import java.io.PrintWriter;
67import java.util.ArrayList;
Jeff Brown9f25b7f2012-04-10 14:30:49 -070068import java.util.HashMap;
69import java.util.List;
Jeff Brown46b9ac02010-04-22 18:58:52 -070070
71/*
72 * Wraps the C++ InputManager and provides its callbacks.
Jeff Brown46b9ac02010-04-22 18:58:52 -070073 */
Jeff Brown4532e612012-04-05 14:27:12 -070074public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
Jeff Brown46b9ac02010-04-22 18:58:52 -070075 static final String TAG = "InputManager";
Jeff Brown4532e612012-04-05 14:27:12 -070076 static final boolean DEBUG = false;
Jeff Brownb6997262010-10-08 22:31:17 -070077
Jeff Brown4532e612012-04-05 14:27:12 -070078 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
79
80 // Pointer to native input manager service object.
81 private final int mPtr;
82
Jeff Brown46b9ac02010-04-22 18:58:52 -070083 private final Context mContext;
Jeff Brown4532e612012-04-05 14:27:12 -070084 private final Callbacks mCallbacks;
85 private final Handler mHandler;
Jeff Brown1a84fd12011-06-02 01:26:32 -070086
Jeff Brown4532e612012-04-05 14:27:12 -070087 private static native int nativeInit(InputManagerService service,
88 Context context, MessageQueue messageQueue);
89 private static native void nativeStart(int ptr);
90 private static native void nativeSetDisplaySize(int ptr, int displayId,
91 int width, int height, int externalWidth, int externalHeight);
92 private static native void nativeSetDisplayOrientation(int ptr, int displayId, int rotation);
Jeff Brown46b9ac02010-04-22 18:58:52 -070093
Jeff Brown4532e612012-04-05 14:27:12 -070094 private static native int nativeGetScanCodeState(int ptr,
95 int deviceId, int sourceMask, int scanCode);
96 private static native int nativeGetKeyCodeState(int ptr,
97 int deviceId, int sourceMask, int keyCode);
98 private static native int nativeGetSwitchState(int ptr,
99 int deviceId, int sourceMask, int sw);
100 private static native boolean nativeHasKeys(int ptr,
101 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
102 private static native void nativeRegisterInputChannel(int ptr, InputChannel inputChannel,
Jeff Brown928e0542011-01-10 11:17:36 -0800103 InputWindowHandle inputWindowHandle, boolean monitor);
Jeff Brown4532e612012-04-05 14:27:12 -0700104 private static native void nativeUnregisterInputChannel(int ptr, InputChannel inputChannel);
105 private static native void nativeSetInputFilterEnabled(int ptr, boolean enable);
106 private static native int nativeInjectInputEvent(int ptr, InputEvent event,
Jeff Brown0029c662011-03-30 02:25:18 -0700107 int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
108 int policyFlags);
Jeff Brown4532e612012-04-05 14:27:12 -0700109 private static native void nativeSetInputWindows(int ptr, InputWindowHandle[] windowHandles);
110 private static native void nativeSetInputDispatchMode(int ptr, boolean enabled, boolean frozen);
111 private static native void nativeSetSystemUiVisibility(int ptr, int visibility);
112 private static native void nativeSetFocusedApplication(int ptr,
113 InputApplicationHandle application);
114 private static native InputDevice nativeGetInputDevice(int ptr, int deviceId);
115 private static native void nativeGetInputConfiguration(int ptr, Configuration configuration);
116 private static native int[] nativeGetInputDeviceIds(int ptr);
117 private static native boolean nativeTransferTouchFocus(int ptr,
118 InputChannel fromChannel, InputChannel toChannel);
119 private static native void nativeSetPointerSpeed(int ptr, int speed);
120 private static native void nativeSetShowTouches(int ptr, boolean enabled);
121 private static native String nativeDump(int ptr);
122 private static native void nativeMonitor(int ptr);
Jeff Brown4532e612012-04-05 14:27:12 -0700123
Jeff Brownac143512012-04-05 18:57:33 -0700124 // Input event injection constants defined in InputDispatcher.h.
125 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
126 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
127 private static final int INPUT_EVENT_INJECTION_FAILED = 2;
128 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
129
130 // Maximum number of milliseconds to wait for input event injection.
131 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
132
Jeff Brown6d0fec22010-07-23 21:28:06 -0700133 // Key states (may be returned by queries about the current state of a
134 // particular key code, scan code or switch).
135
136 /** The key state is unknown or the requested key itself is not supported. */
137 public static final int KEY_STATE_UNKNOWN = -1;
138
139 /** The key is up. /*/
140 public static final int KEY_STATE_UP = 0;
141
142 /** The key is down. */
143 public static final int KEY_STATE_DOWN = 1;
144
145 /** The key is down but is a virtual key press that is being emulated by the system. */
146 public static final int KEY_STATE_VIRTUAL = 2;
147
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700148 // Used to simulate a persistent data store for keyboard layouts.
149 // TODO: Replace with the real thing.
150 private final HashMap<String, String> mFakeRegistry = new HashMap<String, String>();
151
Jeff Brown0029c662011-03-30 02:25:18 -0700152 // State for the currently installed input filter.
153 final Object mInputFilterLock = new Object();
154 InputFilter mInputFilter;
155 InputFilterHost mInputFilterHost;
156
Jeff Brown4532e612012-04-05 14:27:12 -0700157 public InputManagerService(Context context, Callbacks callbacks) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700158 this.mContext = context;
Jeff Brown4532e612012-04-05 14:27:12 -0700159 this.mCallbacks = callbacks;
160 this.mHandler = new Handler();
Jeff Brown05dc66a2011-03-02 14:41:58 -0800161
Jeff Brown46b9ac02010-04-22 18:58:52 -0700162 Slog.i(TAG, "Initializing input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700163 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
Jeff Brown46b9ac02010-04-22 18:58:52 -0700164 }
Jeff Brown1a84fd12011-06-02 01:26:32 -0700165
Jeff Brown46b9ac02010-04-22 18:58:52 -0700166 public void start() {
167 Slog.i(TAG, "Starting input manager");
Jeff Brown4532e612012-04-05 14:27:12 -0700168 nativeStart(mPtr);
169
170 // Add ourself to the Watchdog monitors.
171 Watchdog.getInstance().addMonitor(this);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700172
173 registerPointerSpeedSettingObserver();
Jeff Browndaf4a122011-08-26 17:14:14 -0700174 registerShowTouchesSettingObserver();
175
Jeff Brown1a84fd12011-06-02 01:26:32 -0700176 updatePointerSpeedFromSettings();
Jeff Browndaf4a122011-08-26 17:14:14 -0700177 updateShowTouchesFromSettings();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700178 }
179
Jeff Brownbc68a592011-07-25 12:58:12 -0700180 public void setDisplaySize(int displayId, int width, int height,
181 int externalWidth, int externalHeight) {
182 if (width <= 0 || height <= 0 || externalWidth <= 0 || externalHeight <= 0) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700183 throw new IllegalArgumentException("Invalid display id or dimensions.");
184 }
185
Jeff Brownb6997262010-10-08 22:31:17 -0700186 if (DEBUG) {
Jeff Brownbc68a592011-07-25 12:58:12 -0700187 Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height
188 + " external size " + externalWidth + "x" + externalHeight);
Jeff Brownb6997262010-10-08 22:31:17 -0700189 }
Jeff Brown4532e612012-04-05 14:27:12 -0700190 nativeSetDisplaySize(mPtr, displayId, width, height, externalWidth, externalHeight);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700191 }
192
193 public void setDisplayOrientation(int displayId, int rotation) {
194 if (rotation < Surface.ROTATION_0 || rotation > Surface.ROTATION_270) {
195 throw new IllegalArgumentException("Invalid rotation.");
196 }
197
Jeff Brownb6997262010-10-08 22:31:17 -0700198 if (DEBUG) {
199 Slog.d(TAG, "Setting display #" + displayId + " orientation to " + rotation);
200 }
Jeff Brown4532e612012-04-05 14:27:12 -0700201 nativeSetDisplayOrientation(mPtr, displayId, rotation);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700202 }
203
204 public void getInputConfiguration(Configuration config) {
205 if (config == null) {
206 throw new IllegalArgumentException("config must not be null.");
207 }
208
Jeff Brown4532e612012-04-05 14:27:12 -0700209 nativeGetInputConfiguration(mPtr, config);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700210 }
Jeff Brownac143512012-04-05 18:57:33 -0700211
Jeff Brown6d0fec22010-07-23 21:28:06 -0700212 /**
213 * Gets the current state of a key or button by key code.
214 * @param deviceId The input device id, or -1 to consult all devices.
215 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
216 * consider all input sources. An input device is consulted if at least one of its
217 * non-class input source bits matches the specified source mask.
218 * @param keyCode The key code to check.
219 * @return The key state.
220 */
221 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700222 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700223 }
224
Jeff Brown6d0fec22010-07-23 21:28:06 -0700225 /**
226 * Gets the current state of a key or button by scan code.
227 * @param deviceId The input device id, or -1 to consult all devices.
228 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
229 * consider all input sources. An input device is consulted if at least one of its
230 * non-class input source bits matches the specified source mask.
231 * @param scanCode The scan code to check.
232 * @return The key state.
233 */
234 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700235 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700236 }
237
Jeff Brown6d0fec22010-07-23 21:28:06 -0700238 /**
239 * Gets the current state of a switch by switch code.
240 * @param deviceId The input device id, or -1 to consult all devices.
241 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
242 * consider all input sources. An input device is consulted if at least one of its
243 * non-class input source bits matches the specified source mask.
244 * @param switchCode The switch code to check.
245 * @return The switch state.
246 */
247 public int getSwitchState(int deviceId, int sourceMask, int switchCode) {
Jeff Brown4532e612012-04-05 14:27:12 -0700248 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700249 }
250
Jeff Brown6d0fec22010-07-23 21:28:06 -0700251 /**
252 * Determines whether the specified key codes are supported by a particular device.
253 * @param deviceId The input device id, or -1 to consult all devices.
254 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
255 * consider all input sources. An input device is consulted if at least one of its
256 * non-class input source bits matches the specified source mask.
257 * @param keyCodes The array of key codes to check.
258 * @param keyExists An array at least as large as keyCodes whose entries will be set
259 * to true or false based on the presence or absence of support for the corresponding
260 * key codes.
261 * @return True if the lookup was successful, false otherwise.
262 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700263 @Override // Binder call
Jeff Brown6d0fec22010-07-23 21:28:06 -0700264 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700265 if (keyCodes == null) {
266 throw new IllegalArgumentException("keyCodes must not be null.");
267 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700268 if (keyExists == null || keyExists.length < keyCodes.length) {
269 throw new IllegalArgumentException("keyExists must not be null and must be at "
270 + "least as large as keyCodes.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700271 }
272
Jeff Brown4532e612012-04-05 14:27:12 -0700273 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700274 }
275
Jeff Browna41ca772010-08-11 14:46:32 -0700276 /**
277 * Creates an input channel that will receive all input from the input dispatcher.
278 * @param inputChannelName The input channel name.
279 * @return The input channel.
280 */
281 public InputChannel monitorInput(String inputChannelName) {
282 if (inputChannelName == null) {
283 throw new IllegalArgumentException("inputChannelName must not be null.");
284 }
285
286 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
Jeff Brown4532e612012-04-05 14:27:12 -0700287 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
Jeff Browna41ca772010-08-11 14:46:32 -0700288 inputChannels[0].dispose(); // don't need to retain the Java object reference
289 return inputChannels[1];
290 }
291
292 /**
293 * Registers an input channel so that it can be used as an input event target.
294 * @param inputChannel The input channel to register.
Jeff Brown928e0542011-01-10 11:17:36 -0800295 * @param inputWindowHandle The handle of the input window associated with the
296 * input channel, or null if none.
Jeff Browna41ca772010-08-11 14:46:32 -0700297 */
Jeff Brown928e0542011-01-10 11:17:36 -0800298 public void registerInputChannel(InputChannel inputChannel,
299 InputWindowHandle inputWindowHandle) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700300 if (inputChannel == null) {
301 throw new IllegalArgumentException("inputChannel must not be null.");
302 }
303
Jeff Brown4532e612012-04-05 14:27:12 -0700304 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700305 }
306
Jeff Browna41ca772010-08-11 14:46:32 -0700307 /**
308 * Unregisters an input channel.
309 * @param inputChannel The input channel to unregister.
310 */
Jeff Brown46b9ac02010-04-22 18:58:52 -0700311 public void unregisterInputChannel(InputChannel inputChannel) {
312 if (inputChannel == null) {
313 throw new IllegalArgumentException("inputChannel must not be null.");
314 }
315
Jeff Brown4532e612012-04-05 14:27:12 -0700316 nativeUnregisterInputChannel(mPtr, inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700317 }
Jeff Brown0029c662011-03-30 02:25:18 -0700318
319 /**
320 * Sets an input filter that will receive all input events before they are dispatched.
321 * The input filter may then reinterpret input events or inject new ones.
322 *
323 * To ensure consistency, the input dispatcher automatically drops all events
324 * in progress whenever an input filter is installed or uninstalled. After an input
325 * filter is uninstalled, it can no longer send input events unless it is reinstalled.
326 * Any events it attempts to send after it has been uninstalled will be dropped.
327 *
328 * @param filter The input filter, or null to remove the current filter.
329 */
330 public void setInputFilter(InputFilter filter) {
331 synchronized (mInputFilterLock) {
332 final InputFilter oldFilter = mInputFilter;
333 if (oldFilter == filter) {
334 return; // nothing to do
335 }
336
337 if (oldFilter != null) {
338 mInputFilter = null;
339 mInputFilterHost.disconnectLocked();
340 mInputFilterHost = null;
341 oldFilter.uninstall();
342 }
343
344 if (filter != null) {
345 mInputFilter = filter;
346 mInputFilterHost = new InputFilterHost();
347 filter.install(mInputFilterHost);
348 }
349
Jeff Brown4532e612012-04-05 14:27:12 -0700350 nativeSetInputFilterEnabled(mPtr, filter != null);
Jeff Brown0029c662011-03-30 02:25:18 -0700351 }
352 }
353
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700354 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700355 public boolean injectInputEvent(InputEvent event, int mode) {
Jeff Brown7fbdc842010-06-17 20:52:56 -0700356 if (event == null) {
357 throw new IllegalArgumentException("event must not be null");
358 }
Jeff Brownac143512012-04-05 18:57:33 -0700359 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
360 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
361 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
362 throw new IllegalArgumentException("mode is invalid");
Jeff Brown7fbdc842010-06-17 20:52:56 -0700363 }
Jeff Brown6ec402b2010-07-28 15:48:59 -0700364
Jeff Brownac143512012-04-05 18:57:33 -0700365 final int pid = Binder.getCallingPid();
366 final int uid = Binder.getCallingUid();
367 final long ident = Binder.clearCallingIdentity();
368 final int result;
369 try {
370 result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
371 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
372 } finally {
373 Binder.restoreCallingIdentity(ident);
374 }
375 switch (result) {
376 case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
377 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
378 throw new SecurityException(
379 "Injecting to another application requires INJECT_EVENTS permission");
380 case INPUT_EVENT_INJECTION_SUCCEEDED:
381 return true;
382 case INPUT_EVENT_INJECTION_TIMED_OUT:
383 Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
384 return false;
385 case INPUT_EVENT_INJECTION_FAILED:
386 default:
387 Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
388 return false;
389 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700390 }
Jeff Brown0029c662011-03-30 02:25:18 -0700391
Jeff Brown8d608662010-08-30 03:02:23 -0700392 /**
393 * Gets information about the input device with the specified id.
394 * @param id The device id.
395 * @return The input device or null if not found.
396 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700397 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700398 public InputDevice getInputDevice(int deviceId) {
Jeff Brown4532e612012-04-05 14:27:12 -0700399 return nativeGetInputDevice(mPtr, deviceId);
Jeff Brown8d608662010-08-30 03:02:23 -0700400 }
401
402 /**
403 * Gets the ids of all input devices in the system.
404 * @return The input device ids.
405 */
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700406 @Override // Binder call
Jeff Brown8d608662010-08-30 03:02:23 -0700407 public int[] getInputDeviceIds() {
Jeff Brown4532e612012-04-05 14:27:12 -0700408 return nativeGetInputDeviceIds(mPtr);
Jeff Brown8d608662010-08-30 03:02:23 -0700409 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700410
411 @Override // Binder call
412 public KeyboardLayout[] getKeyboardLayouts() {
413 ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
414
415 final PackageManager pm = mContext.getPackageManager();
416 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
417 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
418 PackageManager.GET_META_DATA)) {
419 loadKeyboardLayouts(pm, resolveInfo.activityInfo, list, null);
420 }
421 return list.toArray(new KeyboardLayout[list.size()]);
422 }
423
424 @Override // Binder call
425 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
426 if (keyboardLayoutDescriptor == null) {
427 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
428 }
429
430 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
431 if (d == null) {
432 return null;
433 }
434
435 final PackageManager pm = mContext.getPackageManager();
436 try {
437 ActivityInfo receiver = pm.getReceiverInfo(
438 new ComponentName(d.packageName, d.receiverName),
439 PackageManager.GET_META_DATA);
440 return loadKeyboardLayouts(pm, receiver, null, d.keyboardLayoutName);
441 } catch (NameNotFoundException ex) {
442 Log.w(TAG, "Could not load keyboard layout '" + d.keyboardLayoutName
443 + "' from receiver " + d.packageName + "/" + d.receiverName, ex);
444 return null;
445 }
446 }
447
448 private KeyboardLayout loadKeyboardLayouts(
449 PackageManager pm, ActivityInfo receiver,
450 List<KeyboardLayout> list, String keyboardName) {
451 Bundle metaData = receiver.metaData;
452 if (metaData == null) {
453 return null;
454 }
455
456 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
457 if (configResId == 0) {
458 Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
459 + "' on receiver " + receiver.packageName + "/" + receiver.name);
460 return null;
461 }
462
463 try {
464 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
465 XmlResourceParser parser = resources.getXml(configResId);
466 try {
467 XmlUtils.beginDocument(parser, "keyboard-layouts");
468
469 for (;;) {
470 XmlUtils.nextElement(parser);
471 String element = parser.getName();
472 if (element == null) {
473 break;
474 }
475 if (element.equals("keyboard-layout")) {
476 TypedArray a = resources.obtainAttributes(
477 parser, com.android.internal.R.styleable.KeyboardLayout);
478 try {
479 String name = a.getString(
480 com.android.internal.R.styleable.KeyboardLayout_name);
481 String label = a.getString(
482 com.android.internal.R.styleable.KeyboardLayout_label);
483 int kcmResId = a.getResourceId(
484 com.android.internal.R.styleable.KeyboardLayout_kcm, 0);
485 if (name == null || label == null || kcmResId == 0) {
486 Log.w(TAG, "Missing required 'name', 'label' or 'kcm' "
487 + "attributes in keyboard layout "
488 + "resource from receiver "
489 + receiver.packageName + "/" + receiver.name);
490 } else {
491 String descriptor = KeyboardLayoutDescriptor.format(
492 receiver.packageName, receiver.name, name);
493 KeyboardLayout c = new KeyboardLayout(descriptor, label);
494 if (keyboardName != null && name.equals(keyboardName)) {
495 return c;
496 }
497 if (list != null) {
498 list.add(c);
499 }
500 }
501 } finally {
502 a.recycle();
503 }
504 } else {
505 Log.w(TAG, "Skipping unrecognized element '" + element
506 + "' in keyboard layout resource from receiver "
507 + receiver.packageName + "/" + receiver.name);
508 }
509 }
510 } finally {
511 parser.close();
512 }
513 } catch (Exception ex) {
514 Log.w(TAG, "Could not load keyboard layout resource from receiver "
515 + receiver.packageName + "/" + receiver.name, ex);
516 return null;
517 }
518 if (keyboardName != null) {
519 Log.w(TAG, "Could not load keyboard layout '" + keyboardName
520 + "' from receiver " + receiver.packageName + "/" + receiver.name
521 + " because it was not declared in the keyboard layout resource.");
522 }
523 return null;
524 }
525
526 @Override // Binder call
527 public String getKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
528 if (inputDeviceDescriptor == null) {
529 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
530 }
531
532 return mFakeRegistry.get(inputDeviceDescriptor);
533 }
534
535 @Override // Binder call
536 public void setKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
537 String keyboardLayoutDescriptor) {
538 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
539 "setKeyboardLayoutForInputDevice()")) {
540 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
541 }
542
543 if (inputDeviceDescriptor == null) {
544 throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
545 }
546
547 mFakeRegistry.put(inputDeviceDescriptor, keyboardLayoutDescriptor);
548 }
549
550 /**
551 * Loads the key character map associated with the keyboard layout.
552 *
553 * @param pm The package manager.
554 * @return The key character map, or null if it could not be loaded for any reason.
555 *
556 public KeyCharacterMap loadKeyCharacterMap(PackageManager pm) {
557 if (pm == null) {
558 throw new IllegalArgumentException("pm must not be null");
559 }
560
561 if (mKeyCharacterMap == null) {
562 KeyboardLayoutDescriptor d = InputManager.parseKeyboardLayoutDescriptor(mDescriptor);
563 if (d == null) {
564 Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
565 + "' because the descriptor could not be parsed.");
566 return null;
567 }
568
569 CharSequence cs = pm.getText(d.packageName, mKeyCharacterMapResId, null);
570 if (cs == null) {
571 Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
572 + "' because its associated resource could not be loaded.");
573 return null;
574 }
575
576 try {
577 mKeyCharacterMap = KeyCharacterMap.load(cs);
578 } catch (UnavailableException ex) {
579 Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
580 + "' due to an error while parsing.", ex);
581 return null;
582 }
583 }
584 return mKeyCharacterMap;
585 }*/
586
Jeff Brown9302c872011-07-13 22:51:29 -0700587 public void setInputWindows(InputWindowHandle[] windowHandles) {
Jeff Brown4532e612012-04-05 14:27:12 -0700588 nativeSetInputWindows(mPtr, windowHandles);
Jeff Brown349703e2010-06-22 01:27:15 -0700589 }
590
Jeff Brown9302c872011-07-13 22:51:29 -0700591 public void setFocusedApplication(InputApplicationHandle application) {
Jeff Brown4532e612012-04-05 14:27:12 -0700592 nativeSetFocusedApplication(mPtr, application);
Jeff Brown349703e2010-06-22 01:27:15 -0700593 }
594
Jeff Brown349703e2010-06-22 01:27:15 -0700595 public void setInputDispatchMode(boolean enabled, boolean frozen) {
Jeff Brown4532e612012-04-05 14:27:12 -0700596 nativeSetInputDispatchMode(mPtr, enabled, frozen);
Jeff Brown349703e2010-06-22 01:27:15 -0700597 }
Jeff Brown05dc66a2011-03-02 14:41:58 -0800598
599 public void setSystemUiVisibility(int visibility) {
Jeff Brown4532e612012-04-05 14:27:12 -0700600 nativeSetSystemUiVisibility(mPtr, visibility);
Jeff Brown05dc66a2011-03-02 14:41:58 -0800601 }
602
Jeff Browne6504122010-09-27 14:52:15 -0700603 /**
604 * Atomically transfers touch focus from one window to another as identified by
605 * their input channels. It is possible for multiple windows to have
606 * touch focus if they support split touch dispatch
607 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
608 * method only transfers touch focus of the specified window without affecting
609 * other windows that may also have touch focus at the same time.
610 * @param fromChannel The channel of a window that currently has touch focus.
611 * @param toChannel The channel of the window that should receive touch focus in
612 * place of the first.
613 * @return True if the transfer was successful. False if the window with the
614 * specified channel did not actually have touch focus at the time of the request.
615 */
616 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
617 if (fromChannel == null) {
618 throw new IllegalArgumentException("fromChannel must not be null.");
619 }
620 if (toChannel == null) {
621 throw new IllegalArgumentException("toChannel must not be null.");
622 }
Jeff Brown4532e612012-04-05 14:27:12 -0700623 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
Jeff Browne6504122010-09-27 14:52:15 -0700624 }
Jeff Brown05dc66a2011-03-02 14:41:58 -0800625
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700626 @Override // Binder call
Jeff Brownac143512012-04-05 18:57:33 -0700627 public void tryPointerSpeed(int speed) {
628 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
629 "tryPointerSpeed()")) {
630 throw new SecurityException("Requires SET_POINTER_SPEED permission");
631 }
632
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700633 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) {
634 throw new IllegalArgumentException("speed out of range");
635 }
636
Jeff Brownac143512012-04-05 18:57:33 -0700637 setPointerSpeedUnchecked(speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700638 }
639
640 public void updatePointerSpeedFromSettings() {
Jeff Brownac143512012-04-05 18:57:33 -0700641 int speed = getPointerSpeedSetting();
642 setPointerSpeedUnchecked(speed);
643 }
644
645 private void setPointerSpeedUnchecked(int speed) {
646 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
647 InputManager.MAX_POINTER_SPEED);
648 nativeSetPointerSpeed(mPtr, speed);
Jeff Brown1a84fd12011-06-02 01:26:32 -0700649 }
650
651 private void registerPointerSpeedSettingObserver() {
652 mContext.getContentResolver().registerContentObserver(
653 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
Jeff Brown4532e612012-04-05 14:27:12 -0700654 new ContentObserver(mHandler) {
Jeff Brown1a84fd12011-06-02 01:26:32 -0700655 @Override
656 public void onChange(boolean selfChange) {
657 updatePointerSpeedFromSettings();
658 }
659 });
660 }
661
Jeff Brownac143512012-04-05 18:57:33 -0700662 private int getPointerSpeedSetting() {
663 int speed = InputManager.DEFAULT_POINTER_SPEED;
Jeff Brown1a84fd12011-06-02 01:26:32 -0700664 try {
665 speed = Settings.System.getInt(mContext.getContentResolver(),
666 Settings.System.POINTER_SPEED);
667 } catch (SettingNotFoundException snfe) {
668 }
669 return speed;
670 }
671
Jeff Browndaf4a122011-08-26 17:14:14 -0700672 public void updateShowTouchesFromSettings() {
673 int setting = getShowTouchesSetting(0);
Jeff Brown4532e612012-04-05 14:27:12 -0700674 nativeSetShowTouches(mPtr, setting != 0);
Jeff Browndaf4a122011-08-26 17:14:14 -0700675 }
676
677 private void registerShowTouchesSettingObserver() {
678 mContext.getContentResolver().registerContentObserver(
679 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
Jeff Brown4532e612012-04-05 14:27:12 -0700680 new ContentObserver(mHandler) {
Jeff Browndaf4a122011-08-26 17:14:14 -0700681 @Override
682 public void onChange(boolean selfChange) {
683 updateShowTouchesFromSettings();
684 }
685 });
686 }
687
688 private int getShowTouchesSetting(int defaultValue) {
689 int result = defaultValue;
690 try {
691 result = Settings.System.getInt(mContext.getContentResolver(),
692 Settings.System.SHOW_TOUCHES);
693 } catch (SettingNotFoundException snfe) {
694 }
695 return result;
696 }
697
Jeff Brown4532e612012-04-05 14:27:12 -0700698 @Override
699 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
700 if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
701 != PackageManager.PERMISSION_GRANTED) {
702 pw.println("Permission Denial: can't dump InputManager from from pid="
703 + Binder.getCallingPid()
704 + ", uid=" + Binder.getCallingUid());
705 return;
706 }
707
708 pw.println("INPUT MANAGER (dumpsys input)\n");
709 String dumpStr = nativeDump(mPtr);
Jeff Browne33348b2010-07-15 23:54:05 -0700710 if (dumpStr != null) {
711 pw.println(dumpStr);
712 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700713 }
Jeff Brownb4ff35d2011-01-02 16:37:43 -0800714
Jeff Brownac143512012-04-05 18:57:33 -0700715 private boolean checkCallingPermission(String permission, String func) {
716 // Quick check: if the calling permission is me, it's all okay.
717 if (Binder.getCallingPid() == Process.myPid()) {
718 return true;
719 }
720
721 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
722 return true;
723 }
724 String msg = "Permission Denial: " + func + " from pid="
725 + Binder.getCallingPid()
726 + ", uid=" + Binder.getCallingUid()
727 + " requires " + permission;
728 Slog.w(TAG, msg);
729 return false;
730 }
731
Jeff Brown4532e612012-04-05 14:27:12 -0700732 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
Jeff Brown89ef0722011-08-10 16:25:21 -0700733 public void monitor() {
734 synchronized (mInputFilterLock) { }
Jeff Brown4532e612012-04-05 14:27:12 -0700735 nativeMonitor(mPtr);
Jeff Brown89ef0722011-08-10 16:25:21 -0700736 }
737
Jeff Brown4532e612012-04-05 14:27:12 -0700738 // Native callback.
739 private void notifyConfigurationChanged(long whenNanos) {
740 mCallbacks.notifyConfigurationChanged();
741 }
742
743 // Native callback.
744 private void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
745 mCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
746 }
747
748 // Native callback.
749 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
750 mCallbacks.notifyInputChannelBroken(inputWindowHandle);
751 }
752
753 // Native callback.
754 private long notifyANR(InputApplicationHandle inputApplicationHandle,
755 InputWindowHandle inputWindowHandle) {
756 return mCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle);
757 }
758
759 // Native callback.
760 final boolean filterInputEvent(InputEvent event, int policyFlags) {
761 synchronized (mInputFilterLock) {
762 if (mInputFilter != null) {
763 mInputFilter.filterInputEvent(event, policyFlags);
764 return false;
765 }
766 }
767 event.recycle();
768 return true;
769 }
770
771 // Native callback.
772 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
773 return mCallbacks.interceptKeyBeforeQueueing(
774 event, policyFlags, isScreenOn);
775 }
776
777 // Native callback.
778 private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
779 return mCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
780 }
781
782 // Native callback.
783 private long interceptKeyBeforeDispatching(InputWindowHandle focus,
784 KeyEvent event, int policyFlags) {
785 return mCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
786 }
787
788 // Native callback.
789 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
790 KeyEvent event, int policyFlags) {
791 return mCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
792 }
793
794 // Native callback.
795 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
796 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
797 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
798 }
799
800 // Native callback.
801 private int getVirtualKeyQuietTimeMillis() {
802 return mContext.getResources().getInteger(
803 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
804 }
805
806 // Native callback.
807 private String[] getExcludedDeviceNames() {
808 ArrayList<String> names = new ArrayList<String>();
809
810 // Read partner-provided list of excluded input devices
811 XmlPullParser parser = null;
812 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
813 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
814 FileReader confreader = null;
815 try {
816 confreader = new FileReader(confFile);
817 parser = Xml.newPullParser();
818 parser.setInput(confreader);
819 XmlUtils.beginDocument(parser, "devices");
820
821 while (true) {
822 XmlUtils.nextElement(parser);
823 if (!"device".equals(parser.getName())) {
824 break;
825 }
826 String name = parser.getAttributeValue(null, "name");
827 if (name != null) {
828 names.add(name);
829 }
830 }
831 } catch (FileNotFoundException e) {
832 // It's ok if the file does not exist.
833 } catch (Exception e) {
834 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
835 } finally {
836 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
837 }
838
839 return names.toArray(new String[names.size()]);
840 }
841
842 // Native callback.
843 private int getKeyRepeatTimeout() {
844 return ViewConfiguration.getKeyRepeatTimeout();
845 }
846
847 // Native callback.
848 private int getKeyRepeatDelay() {
849 return ViewConfiguration.getKeyRepeatDelay();
850 }
851
852 // Native callback.
853 private int getHoverTapTimeout() {
854 return ViewConfiguration.getHoverTapTimeout();
855 }
856
857 // Native callback.
858 private int getHoverTapSlop() {
859 return ViewConfiguration.getHoverTapSlop();
860 }
861
862 // Native callback.
863 private int getDoubleTapTimeout() {
864 return ViewConfiguration.getDoubleTapTimeout();
865 }
866
867 // Native callback.
868 private int getLongPressTimeout() {
869 return ViewConfiguration.getLongPressTimeout();
870 }
871
872 // Native callback.
873 private int getPointerLayer() {
874 return mCallbacks.getPointerLayer();
875 }
876
877 // Native callback.
878 private PointerIcon getPointerIcon() {
879 return PointerIcon.getDefaultIcon(mContext);
880 }
881
882 /**
883 * Callback interface implemented by the Window Manager.
884 */
885 public interface Callbacks {
886 public void notifyConfigurationChanged();
887
888 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
889
890 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
891
892 public long notifyANR(InputApplicationHandle inputApplicationHandle,
893 InputWindowHandle inputWindowHandle);
894
895 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
896
897 public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
898
899 public long interceptKeyBeforeDispatching(InputWindowHandle focus,
900 KeyEvent event, int policyFlags);
901
902 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
903 KeyEvent event, int policyFlags);
904
905 public int getPointerLayer();
906 }
907
908 /**
909 * Hosting interface for input filters to call back into the input manager.
910 */
Jeff Brown0029c662011-03-30 02:25:18 -0700911 private final class InputFilterHost implements InputFilter.Host {
912 private boolean mDisconnected;
913
914 public void disconnectLocked() {
915 mDisconnected = true;
916 }
917
918 public void sendInputEvent(InputEvent event, int policyFlags) {
919 if (event == null) {
920 throw new IllegalArgumentException("event must not be null");
921 }
922
923 synchronized (mInputFilterLock) {
924 if (!mDisconnected) {
Jeff Brownac143512012-04-05 18:57:33 -0700925 nativeInjectInputEvent(mPtr, event, 0, 0,
926 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
Jeff Brown0029c662011-03-30 02:25:18 -0700927 policyFlags | WindowManagerPolicy.FLAG_FILTERED);
928 }
929 }
930 }
931 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700932
933 private static final class KeyboardLayoutDescriptor {
934 public String packageName;
935 public String receiverName;
936 public String keyboardLayoutName;
937
938 public static String format(String packageName,
939 String receiverName, String keyboardName) {
940 return packageName + "/" + receiverName + "/" + keyboardName;
941 }
942
943 public static KeyboardLayoutDescriptor parse(String descriptor) {
944 int pos = descriptor.indexOf('/');
945 if (pos < 0 || pos + 1 == descriptor.length()) {
946 return null;
947 }
948 int pos2 = descriptor.indexOf('/', pos + 1);
949 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
950 return null;
951 }
952
953 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
954 result.packageName = descriptor.substring(0, pos);
955 result.receiverName = descriptor.substring(pos + 1, pos2);
956 result.keyboardLayoutName = descriptor.substring(pos2 + 1);
957 return result;
958 }
959 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700960}