InputManagerService.java revision 037c33eae74bee2774897d969d48947f9abe254f
1413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber/* 2413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * Copyright (C) 2010 The Android Open Source Project 3413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * 4413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * you may not use this file except in compliance with the License. 6413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * You may obtain a copy of the License at 7413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * 8413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * 10413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * Unless required by applicable law or agreed to in writing, software 11413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * See the License for the specific language governing permissions and 14413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * limitations under the License. 15413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber */ 16413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 17544ad2be674423238c47650d2c8588ba7dfc9ed2Marco Nelissenpackage com.android.server.input; 18544ad2be674423238c47650d2c8588ba7dfc9ed2Marco Nelissen 19544ad2be674423238c47650d2c8588ba7dfc9ed2Marco Nelissenimport android.view.Display; 20544ad2be674423238c47650d2c8588ba7dfc9ed2Marco Nelissenimport com.android.internal.R; 21413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport com.android.internal.util.XmlUtils; 22413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport com.android.server.DisplayThread; 23544ad2be674423238c47650d2c8588ba7dfc9ed2Marco Nelissenimport com.android.server.LocalServices; 241f7d356fa094b975ad2ebf9217be6abba2c70825Mathias Agopianimport com.android.server.Watchdog; 25413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 26413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport org.xmlpull.v1.XmlPullParser; 27413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 2834581f44cde67960fbac3ba1f191a2c063ea5145Marco Nelissenimport android.Manifest; 29413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.app.Notification; 30413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.app.NotificationManager; 3134581f44cde67960fbac3ba1f191a2c063ea5145Marco Nelissenimport android.app.PendingIntent; 32413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.bluetooth.BluetoothAdapter; 33413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.bluetooth.BluetoothDevice; 34413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.content.BroadcastReceiver; 35413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.content.ComponentName; 36544ad2be674423238c47650d2c8588ba7dfc9ed2Marco Nelissenimport android.content.Context; 37413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.content.Intent; 38413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.content.IntentFilter; 3934581f44cde67960fbac3ba1f191a2c063ea5145Marco Nelissenimport android.content.pm.ActivityInfo; 40413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.content.pm.PackageManager; 41413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.content.pm.ResolveInfo; 427188e55f54a43c55fd6b96454720c447f1dc454eJeff Brownimport android.content.pm.PackageManager.NameNotFoundException; 43413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.content.res.Resources; 4434581f44cde67960fbac3ba1f191a2c063ea5145Marco Nelissenimport android.content.res.Resources.NotFoundException; 45544ad2be674423238c47650d2c8588ba7dfc9ed2Marco Nelissenimport android.content.res.TypedArray; 46413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.content.res.XmlResourceParser; 47413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.database.ContentObserver; 4834581f44cde67960fbac3ba1f191a2c063ea5145Marco Nelissenimport android.hardware.display.DisplayViewport; 49413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.hardware.input.IInputDevicesChangedListener; 50413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.hardware.input.IInputManager; 51413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberimport android.hardware.input.InputDeviceIdentifier; 52import android.hardware.input.InputManager; 53import android.hardware.input.InputManagerInternal; 54import android.hardware.input.KeyboardLayout; 55import android.os.Binder; 56import android.os.Bundle; 57import android.os.Environment; 58import android.os.Handler; 59import android.os.IBinder; 60import android.os.Looper; 61import android.os.Message; 62import android.os.MessageQueue; 63import android.os.Process; 64import android.os.RemoteException; 65import android.os.UserHandle; 66import android.provider.Settings; 67import android.provider.Settings.SettingNotFoundException; 68import android.util.Log; 69import android.util.Slog; 70import android.util.SparseArray; 71import android.util.Xml; 72import android.view.IInputFilter; 73import android.view.IInputFilterHost; 74import android.view.InputChannel; 75import android.view.InputDevice; 76import android.view.InputEvent; 77import android.view.KeyEvent; 78import android.view.PointerIcon; 79import android.view.ViewConfiguration; 80import android.view.WindowManagerPolicy; 81import android.widget.Toast; 82 83import java.io.File; 84import java.io.FileDescriptor; 85import java.io.FileNotFoundException; 86import java.io.FileReader; 87import java.io.IOException; 88import java.io.InputStreamReader; 89import java.io.PrintWriter; 90import java.util.ArrayList; 91import java.util.HashMap; 92import java.util.HashSet; 93 94import libcore.io.Streams; 95import libcore.util.Objects; 96 97/* 98 * Wraps the C++ InputManager and provides its callbacks. 99 */ 100public class InputManagerService extends IInputManager.Stub 101 implements Watchdog.Monitor { 102 static final String TAG = "InputManager"; 103 static final boolean DEBUG = false; 104 105 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; 106 107 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1; 108 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2; 109 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3; 110 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4; 111 private static final int MSG_RELOAD_DEVICE_ALIASES = 5; 112 113 // Pointer to native input manager service object. 114 private final long mPtr; 115 116 private final Context mContext; 117 private final InputManagerHandler mHandler; 118 119 private WindowManagerCallbacks mWindowManagerCallbacks; 120 private WiredAccessoryCallbacks mWiredAccessoryCallbacks; 121 private boolean mSystemReady; 122 private NotificationManager mNotificationManager; 123 124 // Persistent data store. Must be locked each time during use. 125 private final PersistentDataStore mDataStore = new PersistentDataStore(); 126 127 // List of currently registered input devices changed listeners by process id. 128 private Object mInputDevicesLock = new Object(); 129 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock 130 private InputDevice[] mInputDevices = new InputDevice[0]; 131 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners = 132 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock 133 private final ArrayList<InputDevicesChangedListenerRecord> 134 mTempInputDevicesChangedListenersToNotify = 135 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only 136 private final ArrayList<InputDevice> 137 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only 138 private boolean mKeyboardLayoutNotificationShown; 139 private PendingIntent mKeyboardLayoutIntent; 140 private Toast mSwitchedKeyboardLayoutToast; 141 142 // State for vibrator tokens. 143 private Object mVibratorLock = new Object(); 144 private HashMap<IBinder, VibratorToken> mVibratorTokens = 145 new HashMap<IBinder, VibratorToken>(); 146 private int mNextVibratorTokenValue; 147 148 // State for the currently installed input filter. 149 final Object mInputFilterLock = new Object(); 150 IInputFilter mInputFilter; // guarded by mInputFilterLock 151 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock 152 153 private static native long nativeInit(InputManagerService service, 154 Context context, MessageQueue messageQueue); 155 private static native void nativeStart(long ptr); 156 private static native void nativeSetDisplayViewport(long ptr, boolean external, 157 int displayId, int rotation, 158 int logicalLeft, int logicalTop, int logicalRight, int logicalBottom, 159 int physicalLeft, int physicalTop, int physicalRight, int physicalBottom, 160 int deviceWidth, int deviceHeight); 161 162 private static native int nativeGetScanCodeState(long ptr, 163 int deviceId, int sourceMask, int scanCode); 164 private static native int nativeGetKeyCodeState(long ptr, 165 int deviceId, int sourceMask, int keyCode); 166 private static native int nativeGetSwitchState(long ptr, 167 int deviceId, int sourceMask, int sw); 168 private static native boolean nativeHasKeys(long ptr, 169 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists); 170 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel, 171 InputWindowHandle inputWindowHandle, boolean monitor); 172 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel); 173 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable); 174 private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId, 175 int injectorPid, int injectorUid, int syncMode, int timeoutMillis, 176 int policyFlags); 177 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles); 178 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen); 179 private static native void nativeSetSystemUiVisibility(long ptr, int visibility); 180 private static native void nativeSetFocusedApplication(long ptr, 181 InputApplicationHandle application); 182 private static native boolean nativeTransferTouchFocus(long ptr, 183 InputChannel fromChannel, InputChannel toChannel); 184 private static native void nativeSetPointerSpeed(long ptr, int speed); 185 private static native void nativeSetShowTouches(long ptr, boolean enabled); 186 private static native void nativeSetInteractive(long ptr, boolean interactive); 187 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern, 188 int repeat, int token); 189 private static native void nativeCancelVibrate(long ptr, int deviceId, int token); 190 private static native void nativeReloadKeyboardLayouts(long ptr); 191 private static native void nativeReloadDeviceAliases(long ptr); 192 private static native String nativeDump(long ptr); 193 private static native void nativeMonitor(long ptr); 194 195 // Input event injection constants defined in InputDispatcher.h. 196 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0; 197 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1; 198 private static final int INPUT_EVENT_INJECTION_FAILED = 2; 199 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3; 200 201 // Maximum number of milliseconds to wait for input event injection. 202 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000; 203 204 // Key states (may be returned by queries about the current state of a 205 // particular key code, scan code or switch). 206 207 /** The key state is unknown or the requested key itself is not supported. */ 208 public static final int KEY_STATE_UNKNOWN = -1; 209 210 /** The key is up. /*/ 211 public static final int KEY_STATE_UP = 0; 212 213 /** The key is down. */ 214 public static final int KEY_STATE_DOWN = 1; 215 216 /** The key is down but is a virtual key press that is being emulated by the system. */ 217 public static final int KEY_STATE_VIRTUAL = 2; 218 219 /** Scan code: Mouse / trackball button. */ 220 public static final int BTN_MOUSE = 0x110; 221 222 // Switch code values must match bionic/libc/kernel/common/linux/input.h 223 /** Switch code: Lid switch. When set, lid is shut. */ 224 public static final int SW_LID = 0x00; 225 226 /** Switch code: Keypad slide. When set, keyboard is exposed. */ 227 public static final int SW_KEYPAD_SLIDE = 0x0a; 228 229 /** Switch code: Headphone. When set, headphone is inserted. */ 230 public static final int SW_HEADPHONE_INSERT = 0x02; 231 232 /** Switch code: Microphone. When set, microphone is inserted. */ 233 public static final int SW_MICROPHONE_INSERT = 0x04; 234 235 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */ 236 public static final int SW_JACK_PHYSICAL_INSERT = 0x07; 237 238 public static final int SW_LID_BIT = 1 << SW_LID; 239 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE; 240 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT; 241 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT; 242 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT; 243 public static final int SW_JACK_BITS = 244 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT; 245 246 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */ 247 final boolean mUseDevInputEventForAudioJack; 248 249 public InputManagerService(Context context) { 250 this.mContext = context; 251 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper()); 252 253 mUseDevInputEventForAudioJack = 254 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); 255 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack=" 256 + mUseDevInputEventForAudioJack); 257 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); 258 259 LocalServices.addService(InputManagerInternal.class, new LocalService()); 260 } 261 262 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) { 263 mWindowManagerCallbacks = callbacks; 264 } 265 266 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) { 267 mWiredAccessoryCallbacks = callbacks; 268 } 269 270 public void start() { 271 Slog.i(TAG, "Starting input manager"); 272 nativeStart(mPtr); 273 274 // Add ourself to the Watchdog monitors. 275 Watchdog.getInstance().addMonitor(this); 276 277 registerPointerSpeedSettingObserver(); 278 registerShowTouchesSettingObserver(); 279 280 mContext.registerReceiver(new BroadcastReceiver() { 281 @Override 282 public void onReceive(Context context, Intent intent) { 283 updatePointerSpeedFromSettings(); 284 updateShowTouchesFromSettings(); 285 } 286 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler); 287 288 updatePointerSpeedFromSettings(); 289 updateShowTouchesFromSettings(); 290 } 291 292 // TODO(BT) Pass in paramter for bluetooth system 293 public void systemRunning() { 294 if (DEBUG) { 295 Slog.d(TAG, "System ready."); 296 } 297 mNotificationManager = (NotificationManager)mContext.getSystemService( 298 Context.NOTIFICATION_SERVICE); 299 mSystemReady = true; 300 301 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); 302 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 303 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 304 filter.addAction(Intent.ACTION_PACKAGE_REPLACED); 305 filter.addDataScheme("package"); 306 mContext.registerReceiver(new BroadcastReceiver() { 307 @Override 308 public void onReceive(Context context, Intent intent) { 309 updateKeyboardLayouts(); 310 } 311 }, filter, null, mHandler); 312 313 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED); 314 mContext.registerReceiver(new BroadcastReceiver() { 315 @Override 316 public void onReceive(Context context, Intent intent) { 317 reloadDeviceAliases(); 318 } 319 }, filter, null, mHandler); 320 321 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES); 322 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS); 323 } 324 325 private void reloadKeyboardLayouts() { 326 if (DEBUG) { 327 Slog.d(TAG, "Reloading keyboard layouts."); 328 } 329 nativeReloadKeyboardLayouts(mPtr); 330 } 331 332 private void reloadDeviceAliases() { 333 if (DEBUG) { 334 Slog.d(TAG, "Reloading device names."); 335 } 336 nativeReloadDeviceAliases(mPtr); 337 } 338 339 private void setDisplayViewportsInternal(DisplayViewport defaultViewport, 340 DisplayViewport externalTouchViewport) { 341 if (defaultViewport.valid) { 342 setDisplayViewport(false, defaultViewport); 343 } 344 345 if (externalTouchViewport.valid) { 346 setDisplayViewport(true, externalTouchViewport); 347 } else if (defaultViewport.valid) { 348 setDisplayViewport(true, defaultViewport); 349 } 350 } 351 352 private void setDisplayViewport(boolean external, DisplayViewport viewport) { 353 nativeSetDisplayViewport(mPtr, external, 354 viewport.displayId, viewport.orientation, 355 viewport.logicalFrame.left, viewport.logicalFrame.top, 356 viewport.logicalFrame.right, viewport.logicalFrame.bottom, 357 viewport.physicalFrame.left, viewport.physicalFrame.top, 358 viewport.physicalFrame.right, viewport.physicalFrame.bottom, 359 viewport.deviceWidth, viewport.deviceHeight); 360 } 361 362 /** 363 * Gets the current state of a key or button by key code. 364 * @param deviceId The input device id, or -1 to consult all devices. 365 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 366 * consider all input sources. An input device is consulted if at least one of its 367 * non-class input source bits matches the specified source mask. 368 * @param keyCode The key code to check. 369 * @return The key state. 370 */ 371 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) { 372 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode); 373 } 374 375 /** 376 * Gets the current state of a key or button by scan code. 377 * @param deviceId The input device id, or -1 to consult all devices. 378 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 379 * consider all input sources. An input device is consulted if at least one of its 380 * non-class input source bits matches the specified source mask. 381 * @param scanCode The scan code to check. 382 * @return The key state. 383 */ 384 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) { 385 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode); 386 } 387 388 /** 389 * Gets the current state of a switch by switch code. 390 * @param deviceId The input device id, or -1 to consult all devices. 391 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 392 * consider all input sources. An input device is consulted if at least one of its 393 * non-class input source bits matches the specified source mask. 394 * @param switchCode The switch code to check. 395 * @return The switch state. 396 */ 397 public int getSwitchState(int deviceId, int sourceMask, int switchCode) { 398 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode); 399 } 400 401 /** 402 * Determines whether the specified key codes are supported by a particular device. 403 * @param deviceId The input device id, or -1 to consult all devices. 404 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 405 * consider all input sources. An input device is consulted if at least one of its 406 * non-class input source bits matches the specified source mask. 407 * @param keyCodes The array of key codes to check. 408 * @param keyExists An array at least as large as keyCodes whose entries will be set 409 * to true or false based on the presence or absence of support for the corresponding 410 * key codes. 411 * @return True if the lookup was successful, false otherwise. 412 */ 413 @Override // Binder call 414 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) { 415 if (keyCodes == null) { 416 throw new IllegalArgumentException("keyCodes must not be null."); 417 } 418 if (keyExists == null || keyExists.length < keyCodes.length) { 419 throw new IllegalArgumentException("keyExists must not be null and must be at " 420 + "least as large as keyCodes."); 421 } 422 423 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists); 424 } 425 426 /** 427 * Creates an input channel that will receive all input from the input dispatcher. 428 * @param inputChannelName The input channel name. 429 * @return The input channel. 430 */ 431 public InputChannel monitorInput(String inputChannelName) { 432 if (inputChannelName == null) { 433 throw new IllegalArgumentException("inputChannelName must not be null."); 434 } 435 436 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); 437 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true); 438 inputChannels[0].dispose(); // don't need to retain the Java object reference 439 return inputChannels[1]; 440 } 441 442 /** 443 * Registers an input channel so that it can be used as an input event target. 444 * @param inputChannel The input channel to register. 445 * @param inputWindowHandle The handle of the input window associated with the 446 * input channel, or null if none. 447 */ 448 public void registerInputChannel(InputChannel inputChannel, 449 InputWindowHandle inputWindowHandle) { 450 if (inputChannel == null) { 451 throw new IllegalArgumentException("inputChannel must not be null."); 452 } 453 454 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false); 455 } 456 457 /** 458 * Unregisters an input channel. 459 * @param inputChannel The input channel to unregister. 460 */ 461 public void unregisterInputChannel(InputChannel inputChannel) { 462 if (inputChannel == null) { 463 throw new IllegalArgumentException("inputChannel must not be null."); 464 } 465 466 nativeUnregisterInputChannel(mPtr, inputChannel); 467 } 468 469 /** 470 * Sets an input filter that will receive all input events before they are dispatched. 471 * The input filter may then reinterpret input events or inject new ones. 472 * 473 * To ensure consistency, the input dispatcher automatically drops all events 474 * in progress whenever an input filter is installed or uninstalled. After an input 475 * filter is uninstalled, it can no longer send input events unless it is reinstalled. 476 * Any events it attempts to send after it has been uninstalled will be dropped. 477 * 478 * @param filter The input filter, or null to remove the current filter. 479 */ 480 public void setInputFilter(IInputFilter filter) { 481 synchronized (mInputFilterLock) { 482 final IInputFilter oldFilter = mInputFilter; 483 if (oldFilter == filter) { 484 return; // nothing to do 485 } 486 487 if (oldFilter != null) { 488 mInputFilter = null; 489 mInputFilterHost.disconnectLocked(); 490 mInputFilterHost = null; 491 try { 492 oldFilter.uninstall(); 493 } catch (RemoteException re) { 494 /* ignore */ 495 } 496 } 497 498 if (filter != null) { 499 mInputFilter = filter; 500 mInputFilterHost = new InputFilterHost(); 501 try { 502 filter.install(mInputFilterHost); 503 } catch (RemoteException re) { 504 /* ignore */ 505 } 506 } 507 508 nativeSetInputFilterEnabled(mPtr, filter != null); 509 } 510 } 511 512 @Override // Binder call 513 public boolean injectInputEvent(InputEvent event, int mode) { 514 return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode); 515 } 516 517 private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) { 518 if (event == null) { 519 throw new IllegalArgumentException("event must not be null"); 520 } 521 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC 522 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH 523 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) { 524 throw new IllegalArgumentException("mode is invalid"); 525 } 526 527 final int pid = Binder.getCallingPid(); 528 final int uid = Binder.getCallingUid(); 529 final long ident = Binder.clearCallingIdentity(); 530 final int result; 531 try { 532 result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode, 533 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); 534 } finally { 535 Binder.restoreCallingIdentity(ident); 536 } 537 switch (result) { 538 case INPUT_EVENT_INJECTION_PERMISSION_DENIED: 539 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied."); 540 throw new SecurityException( 541 "Injecting to another application requires INJECT_EVENTS permission"); 542 case INPUT_EVENT_INJECTION_SUCCEEDED: 543 return true; 544 case INPUT_EVENT_INJECTION_TIMED_OUT: 545 Slog.w(TAG, "Input event injection from pid " + pid + " timed out."); 546 return false; 547 case INPUT_EVENT_INJECTION_FAILED: 548 default: 549 Slog.w(TAG, "Input event injection from pid " + pid + " failed."); 550 return false; 551 } 552 } 553 554 /** 555 * Gets information about the input device with the specified id. 556 * @param deviceId The device id. 557 * @return The input device or null if not found. 558 */ 559 @Override // Binder call 560 public InputDevice getInputDevice(int deviceId) { 561 synchronized (mInputDevicesLock) { 562 final int count = mInputDevices.length; 563 for (int i = 0; i < count; i++) { 564 final InputDevice inputDevice = mInputDevices[i]; 565 if (inputDevice.getId() == deviceId) { 566 return inputDevice; 567 } 568 } 569 } 570 return null; 571 } 572 573 /** 574 * Gets the ids of all input devices in the system. 575 * @return The input device ids. 576 */ 577 @Override // Binder call 578 public int[] getInputDeviceIds() { 579 synchronized (mInputDevicesLock) { 580 final int count = mInputDevices.length; 581 int[] ids = new int[count]; 582 for (int i = 0; i < count; i++) { 583 ids[i] = mInputDevices[i].getId(); 584 } 585 return ids; 586 } 587 } 588 589 /** 590 * Gets all input devices in the system. 591 * @return The array of input devices. 592 */ 593 public InputDevice[] getInputDevices() { 594 synchronized (mInputDevicesLock) { 595 return mInputDevices; 596 } 597 } 598 599 @Override // Binder call 600 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) { 601 if (listener == null) { 602 throw new IllegalArgumentException("listener must not be null"); 603 } 604 605 synchronized (mInputDevicesLock) { 606 int callingPid = Binder.getCallingPid(); 607 if (mInputDevicesChangedListeners.get(callingPid) != null) { 608 throw new SecurityException("The calling process has already " 609 + "registered an InputDevicesChangedListener."); 610 } 611 612 InputDevicesChangedListenerRecord record = 613 new InputDevicesChangedListenerRecord(callingPid, listener); 614 try { 615 IBinder binder = listener.asBinder(); 616 binder.linkToDeath(record, 0); 617 } catch (RemoteException ex) { 618 // give up 619 throw new RuntimeException(ex); 620 } 621 622 mInputDevicesChangedListeners.put(callingPid, record); 623 } 624 } 625 626 private void onInputDevicesChangedListenerDied(int pid) { 627 synchronized (mInputDevicesLock) { 628 mInputDevicesChangedListeners.remove(pid); 629 } 630 } 631 632 // Must be called on handler. 633 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) { 634 // Scan for changes. 635 int numFullKeyboardsAdded = 0; 636 mTempInputDevicesChangedListenersToNotify.clear(); 637 mTempFullKeyboards.clear(); 638 final int numListeners; 639 final int[] deviceIdAndGeneration; 640 synchronized (mInputDevicesLock) { 641 if (!mInputDevicesChangedPending) { 642 return; 643 } 644 mInputDevicesChangedPending = false; 645 646 numListeners = mInputDevicesChangedListeners.size(); 647 for (int i = 0; i < numListeners; i++) { 648 mTempInputDevicesChangedListenersToNotify.add( 649 mInputDevicesChangedListeners.valueAt(i)); 650 } 651 652 final int numDevices = mInputDevices.length; 653 deviceIdAndGeneration = new int[numDevices * 2]; 654 for (int i = 0; i < numDevices; i++) { 655 final InputDevice inputDevice = mInputDevices[i]; 656 deviceIdAndGeneration[i * 2] = inputDevice.getId(); 657 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration(); 658 659 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) { 660 if (!containsInputDeviceWithDescriptor(oldInputDevices, 661 inputDevice.getDescriptor())) { 662 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice); 663 } else { 664 mTempFullKeyboards.add(inputDevice); 665 } 666 } 667 } 668 } 669 670 // Notify listeners. 671 for (int i = 0; i < numListeners; i++) { 672 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged( 673 deviceIdAndGeneration); 674 } 675 mTempInputDevicesChangedListenersToNotify.clear(); 676 677 // Check for missing keyboard layouts. 678 if (mNotificationManager != null) { 679 final int numFullKeyboards = mTempFullKeyboards.size(); 680 boolean missingLayoutForExternalKeyboard = false; 681 boolean missingLayoutForExternalKeyboardAdded = false; 682 synchronized (mDataStore) { 683 for (int i = 0; i < numFullKeyboards; i++) { 684 final InputDevice inputDevice = mTempFullKeyboards.get(i); 685 if (mDataStore.getCurrentKeyboardLayout(inputDevice.getDescriptor()) == null) { 686 missingLayoutForExternalKeyboard = true; 687 if (i < numFullKeyboardsAdded) { 688 missingLayoutForExternalKeyboardAdded = true; 689 } 690 } 691 } 692 } 693 if (missingLayoutForExternalKeyboard) { 694 if (missingLayoutForExternalKeyboardAdded) { 695 showMissingKeyboardLayoutNotification(); 696 } 697 } else if (mKeyboardLayoutNotificationShown) { 698 hideMissingKeyboardLayoutNotification(); 699 } 700 } 701 mTempFullKeyboards.clear(); 702 } 703 704 // Must be called on handler. 705 private void showMissingKeyboardLayoutNotification() { 706 if (!mKeyboardLayoutNotificationShown) { 707 if (mKeyboardLayoutIntent == null) { 708 final Intent intent = new Intent("android.settings.INPUT_METHOD_SETTINGS"); 709 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 710 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 711 | Intent.FLAG_ACTIVITY_CLEAR_TOP); 712 mKeyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0, 713 intent, 0, null, UserHandle.CURRENT); 714 } 715 716 Resources r = mContext.getResources(); 717 Notification notification = new Notification.Builder(mContext) 718 .setContentTitle(r.getString( 719 R.string.select_keyboard_layout_notification_title)) 720 .setContentText(r.getString( 721 R.string.select_keyboard_layout_notification_message)) 722 .setContentIntent(mKeyboardLayoutIntent) 723 .setSmallIcon(R.drawable.ic_settings_language) 724 .setPriority(Notification.PRIORITY_LOW) 725 .build(); 726 mNotificationManager.notifyAsUser(null, 727 R.string.select_keyboard_layout_notification_title, 728 notification, UserHandle.ALL); 729 mKeyboardLayoutNotificationShown = true; 730 } 731 } 732 733 // Must be called on handler. 734 private void hideMissingKeyboardLayoutNotification() { 735 if (mKeyboardLayoutNotificationShown) { 736 mKeyboardLayoutNotificationShown = false; 737 mNotificationManager.cancelAsUser(null, 738 R.string.select_keyboard_layout_notification_title, 739 UserHandle.ALL); 740 } 741 } 742 743 // Must be called on handler. 744 private void updateKeyboardLayouts() { 745 // Scan all input devices state for keyboard layouts that have been uninstalled. 746 final HashSet<String> availableKeyboardLayouts = new HashSet<String>(); 747 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 748 @Override 749 public void visitKeyboardLayout(Resources resources, 750 String descriptor, String label, String collection, int keyboardLayoutResId) { 751 availableKeyboardLayouts.add(descriptor); 752 } 753 }); 754 synchronized (mDataStore) { 755 try { 756 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts); 757 } finally { 758 mDataStore.saveIfNeeded(); 759 } 760 } 761 762 // Reload keyboard layouts. 763 reloadKeyboardLayouts(); 764 } 765 766 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices, 767 String descriptor) { 768 final int numDevices = inputDevices.length; 769 for (int i = 0; i < numDevices; i++) { 770 final InputDevice inputDevice = inputDevices[i]; 771 if (inputDevice.getDescriptor().equals(descriptor)) { 772 return true; 773 } 774 } 775 return false; 776 } 777 778 @Override // Binder call 779 public KeyboardLayout[] getKeyboardLayouts() { 780 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>(); 781 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 782 @Override 783 public void visitKeyboardLayout(Resources resources, 784 String descriptor, String label, String collection, int keyboardLayoutResId) { 785 list.add(new KeyboardLayout(descriptor, label, collection)); 786 } 787 }); 788 return list.toArray(new KeyboardLayout[list.size()]); 789 } 790 791 @Override // Binder call 792 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) { 793 if (keyboardLayoutDescriptor == null) { 794 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 795 } 796 797 final KeyboardLayout[] result = new KeyboardLayout[1]; 798 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 799 @Override 800 public void visitKeyboardLayout(Resources resources, 801 String descriptor, String label, String collection, int keyboardLayoutResId) { 802 result[0] = new KeyboardLayout(descriptor, label, collection); 803 } 804 }); 805 if (result[0] == null) { 806 Log.w(TAG, "Could not get keyboard layout with descriptor '" 807 + keyboardLayoutDescriptor + "'."); 808 } 809 return result[0]; 810 } 811 812 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) { 813 final PackageManager pm = mContext.getPackageManager(); 814 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS); 815 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent, 816 PackageManager.GET_META_DATA)) { 817 visitKeyboardLayoutsInPackage(pm, resolveInfo.activityInfo, null, visitor); 818 } 819 } 820 821 private void visitKeyboardLayout(String keyboardLayoutDescriptor, 822 KeyboardLayoutVisitor visitor) { 823 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor); 824 if (d != null) { 825 final PackageManager pm = mContext.getPackageManager(); 826 try { 827 ActivityInfo receiver = pm.getReceiverInfo( 828 new ComponentName(d.packageName, d.receiverName), 829 PackageManager.GET_META_DATA); 830 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, visitor); 831 } catch (NameNotFoundException ex) { 832 } 833 } 834 } 835 836 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, 837 String keyboardName, KeyboardLayoutVisitor visitor) { 838 Bundle metaData = receiver.metaData; 839 if (metaData == null) { 840 return; 841 } 842 843 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS); 844 if (configResId == 0) { 845 Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS 846 + "' on receiver " + receiver.packageName + "/" + receiver.name); 847 return; 848 } 849 850 CharSequence receiverLabel = receiver.loadLabel(pm); 851 String collection = receiverLabel != null ? receiverLabel.toString() : ""; 852 853 try { 854 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo); 855 XmlResourceParser parser = resources.getXml(configResId); 856 try { 857 XmlUtils.beginDocument(parser, "keyboard-layouts"); 858 859 for (;;) { 860 XmlUtils.nextElement(parser); 861 String element = parser.getName(); 862 if (element == null) { 863 break; 864 } 865 if (element.equals("keyboard-layout")) { 866 TypedArray a = resources.obtainAttributes( 867 parser, com.android.internal.R.styleable.KeyboardLayout); 868 try { 869 String name = a.getString( 870 com.android.internal.R.styleable.KeyboardLayout_name); 871 String label = a.getString( 872 com.android.internal.R.styleable.KeyboardLayout_label); 873 int keyboardLayoutResId = a.getResourceId( 874 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout, 875 0); 876 if (name == null || label == null || keyboardLayoutResId == 0) { 877 Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' " 878 + "attributes in keyboard layout " 879 + "resource from receiver " 880 + receiver.packageName + "/" + receiver.name); 881 } else { 882 String descriptor = KeyboardLayoutDescriptor.format( 883 receiver.packageName, receiver.name, name); 884 if (keyboardName == null || name.equals(keyboardName)) { 885 visitor.visitKeyboardLayout(resources, descriptor, 886 label, collection, keyboardLayoutResId); 887 } 888 } 889 } finally { 890 a.recycle(); 891 } 892 } else { 893 Log.w(TAG, "Skipping unrecognized element '" + element 894 + "' in keyboard layout resource from receiver " 895 + receiver.packageName + "/" + receiver.name); 896 } 897 } 898 } finally { 899 parser.close(); 900 } 901 } catch (Exception ex) { 902 Log.w(TAG, "Could not parse keyboard layout resource from receiver " 903 + receiver.packageName + "/" + receiver.name, ex); 904 } 905 } 906 907 /** 908 * Builds a layout descriptor for the vendor/product. This returns the 909 * descriptor for ids that aren't useful (such as the default 0, 0). 910 */ 911 private String getLayoutDescriptor(InputDeviceIdentifier identifier) { 912 if (identifier == null || identifier.getDescriptor() == null) { 913 throw new IllegalArgumentException("identifier and descriptor must not be null"); 914 } 915 916 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) { 917 return identifier.getDescriptor(); 918 } 919 StringBuilder bob = new StringBuilder(); 920 bob.append("vendor:").append(identifier.getVendorId()); 921 bob.append(",product:").append(identifier.getProductId()); 922 return bob.toString(); 923 } 924 925 @Override // Binder call 926 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) { 927 928 String key = getLayoutDescriptor(identifier); 929 synchronized (mDataStore) { 930 String layout = null; 931 // try loading it using the layout descriptor if we have it 932 layout = mDataStore.getCurrentKeyboardLayout(key); 933 if (layout == null && !key.equals(identifier.getDescriptor())) { 934 // if it doesn't exist fall back to the device descriptor 935 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 936 } 937 if (DEBUG) { 938 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got " 939 + layout); 940 } 941 return layout; 942 } 943 } 944 945 @Override // Binder call 946 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 947 String keyboardLayoutDescriptor) { 948 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 949 "setCurrentKeyboardLayoutForInputDevice()")) { 950 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 951 } 952 if (keyboardLayoutDescriptor == null) { 953 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 954 } 955 956 String key = getLayoutDescriptor(identifier); 957 synchronized (mDataStore) { 958 try { 959 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) { 960 if (DEBUG) { 961 Slog.d(TAG, "Saved keyboard layout using " + key); 962 } 963 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 964 } 965 } finally { 966 mDataStore.saveIfNeeded(); 967 } 968 } 969 } 970 971 @Override // Binder call 972 public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { 973 String key = getLayoutDescriptor(identifier); 974 synchronized (mDataStore) { 975 String[] layouts = mDataStore.getKeyboardLayouts(key); 976 if ((layouts == null || layouts.length == 0) 977 && !key.equals(identifier.getDescriptor())) { 978 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor()); 979 } 980 return layouts; 981 } 982 } 983 984 @Override // Binder call 985 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 986 String keyboardLayoutDescriptor) { 987 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 988 "addKeyboardLayoutForInputDevice()")) { 989 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 990 } 991 if (keyboardLayoutDescriptor == null) { 992 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 993 } 994 995 String key = getLayoutDescriptor(identifier); 996 synchronized (mDataStore) { 997 try { 998 String oldLayout = mDataStore.getCurrentKeyboardLayout(key); 999 if (oldLayout == null && !key.equals(identifier.getDescriptor())) { 1000 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1001 } 1002 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor) 1003 && !Objects.equal(oldLayout, 1004 mDataStore.getCurrentKeyboardLayout(key))) { 1005 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1006 } 1007 } finally { 1008 mDataStore.saveIfNeeded(); 1009 } 1010 } 1011 } 1012 1013 @Override // Binder call 1014 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1015 String keyboardLayoutDescriptor) { 1016 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1017 "removeKeyboardLayoutForInputDevice()")) { 1018 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1019 } 1020 if (keyboardLayoutDescriptor == null) { 1021 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1022 } 1023 1024 String key = getLayoutDescriptor(identifier); 1025 synchronized (mDataStore) { 1026 try { 1027 String oldLayout = mDataStore.getCurrentKeyboardLayout(key); 1028 if (oldLayout == null && !key.equals(identifier.getDescriptor())) { 1029 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1030 } 1031 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor); 1032 if (!key.equals(identifier.getDescriptor())) { 1033 // We need to remove from both places to ensure it is gone 1034 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(), 1035 keyboardLayoutDescriptor); 1036 } 1037 if (removed && !Objects.equal(oldLayout, 1038 mDataStore.getCurrentKeyboardLayout(key))) { 1039 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1040 } 1041 } finally { 1042 mDataStore.saveIfNeeded(); 1043 } 1044 } 1045 } 1046 1047 public void switchKeyboardLayout(int deviceId, int direction) { 1048 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget(); 1049 } 1050 1051 // Must be called on handler. 1052 private void handleSwitchKeyboardLayout(int deviceId, int direction) { 1053 final InputDevice device = getInputDevice(deviceId); 1054 if (device != null) { 1055 final boolean changed; 1056 final String keyboardLayoutDescriptor; 1057 1058 String key = getLayoutDescriptor(device.getIdentifier()); 1059 synchronized (mDataStore) { 1060 try { 1061 changed = mDataStore.switchKeyboardLayout(key, direction); 1062 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout( 1063 key); 1064 } finally { 1065 mDataStore.saveIfNeeded(); 1066 } 1067 } 1068 1069 if (changed) { 1070 if (mSwitchedKeyboardLayoutToast != null) { 1071 mSwitchedKeyboardLayoutToast.cancel(); 1072 mSwitchedKeyboardLayoutToast = null; 1073 } 1074 if (keyboardLayoutDescriptor != null) { 1075 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor); 1076 if (keyboardLayout != null) { 1077 mSwitchedKeyboardLayoutToast = Toast.makeText( 1078 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT); 1079 mSwitchedKeyboardLayoutToast.show(); 1080 } 1081 } 1082 1083 reloadKeyboardLayouts(); 1084 } 1085 } 1086 } 1087 1088 public void setInputWindows(InputWindowHandle[] windowHandles) { 1089 nativeSetInputWindows(mPtr, windowHandles); 1090 } 1091 1092 public void setFocusedApplication(InputApplicationHandle application) { 1093 nativeSetFocusedApplication(mPtr, application); 1094 } 1095 1096 public void setInputDispatchMode(boolean enabled, boolean frozen) { 1097 nativeSetInputDispatchMode(mPtr, enabled, frozen); 1098 } 1099 1100 public void setSystemUiVisibility(int visibility) { 1101 nativeSetSystemUiVisibility(mPtr, visibility); 1102 } 1103 1104 /** 1105 * Atomically transfers touch focus from one window to another as identified by 1106 * their input channels. It is possible for multiple windows to have 1107 * touch focus if they support split touch dispatch 1108 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this 1109 * method only transfers touch focus of the specified window without affecting 1110 * other windows that may also have touch focus at the same time. 1111 * @param fromChannel The channel of a window that currently has touch focus. 1112 * @param toChannel The channel of the window that should receive touch focus in 1113 * place of the first. 1114 * @return True if the transfer was successful. False if the window with the 1115 * specified channel did not actually have touch focus at the time of the request. 1116 */ 1117 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) { 1118 if (fromChannel == null) { 1119 throw new IllegalArgumentException("fromChannel must not be null."); 1120 } 1121 if (toChannel == null) { 1122 throw new IllegalArgumentException("toChannel must not be null."); 1123 } 1124 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel); 1125 } 1126 1127 @Override // Binder call 1128 public void tryPointerSpeed(int speed) { 1129 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, 1130 "tryPointerSpeed()")) { 1131 throw new SecurityException("Requires SET_POINTER_SPEED permission"); 1132 } 1133 1134 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) { 1135 throw new IllegalArgumentException("speed out of range"); 1136 } 1137 1138 setPointerSpeedUnchecked(speed); 1139 } 1140 1141 public void updatePointerSpeedFromSettings() { 1142 int speed = getPointerSpeedSetting(); 1143 setPointerSpeedUnchecked(speed); 1144 } 1145 1146 private void setPointerSpeedUnchecked(int speed) { 1147 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED), 1148 InputManager.MAX_POINTER_SPEED); 1149 nativeSetPointerSpeed(mPtr, speed); 1150 } 1151 1152 private void registerPointerSpeedSettingObserver() { 1153 mContext.getContentResolver().registerContentObserver( 1154 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true, 1155 new ContentObserver(mHandler) { 1156 @Override 1157 public void onChange(boolean selfChange) { 1158 updatePointerSpeedFromSettings(); 1159 } 1160 }, UserHandle.USER_ALL); 1161 } 1162 1163 private int getPointerSpeedSetting() { 1164 int speed = InputManager.DEFAULT_POINTER_SPEED; 1165 try { 1166 speed = Settings.System.getIntForUser(mContext.getContentResolver(), 1167 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT); 1168 } catch (SettingNotFoundException snfe) { 1169 } 1170 return speed; 1171 } 1172 1173 public void updateShowTouchesFromSettings() { 1174 int setting = getShowTouchesSetting(0); 1175 nativeSetShowTouches(mPtr, setting != 0); 1176 } 1177 1178 private void registerShowTouchesSettingObserver() { 1179 mContext.getContentResolver().registerContentObserver( 1180 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true, 1181 new ContentObserver(mHandler) { 1182 @Override 1183 public void onChange(boolean selfChange) { 1184 updateShowTouchesFromSettings(); 1185 } 1186 }, UserHandle.USER_ALL); 1187 } 1188 1189 private int getShowTouchesSetting(int defaultValue) { 1190 int result = defaultValue; 1191 try { 1192 result = Settings.System.getIntForUser(mContext.getContentResolver(), 1193 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT); 1194 } catch (SettingNotFoundException snfe) { 1195 } 1196 return result; 1197 } 1198 1199 // Binder call 1200 @Override 1201 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) { 1202 if (repeat >= pattern.length) { 1203 throw new ArrayIndexOutOfBoundsException(); 1204 } 1205 1206 VibratorToken v; 1207 synchronized (mVibratorLock) { 1208 v = mVibratorTokens.get(token); 1209 if (v == null) { 1210 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++); 1211 try { 1212 token.linkToDeath(v, 0); 1213 } catch (RemoteException ex) { 1214 // give up 1215 throw new RuntimeException(ex); 1216 } 1217 mVibratorTokens.put(token, v); 1218 } 1219 } 1220 1221 synchronized (v) { 1222 v.mVibrating = true; 1223 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue); 1224 } 1225 } 1226 1227 // Binder call 1228 @Override 1229 public void cancelVibrate(int deviceId, IBinder token) { 1230 VibratorToken v; 1231 synchronized (mVibratorLock) { 1232 v = mVibratorTokens.get(token); 1233 if (v == null || v.mDeviceId != deviceId) { 1234 return; // nothing to cancel 1235 } 1236 } 1237 1238 cancelVibrateIfNeeded(v); 1239 } 1240 1241 void onVibratorTokenDied(VibratorToken v) { 1242 synchronized (mVibratorLock) { 1243 mVibratorTokens.remove(v.mToken); 1244 } 1245 1246 cancelVibrateIfNeeded(v); 1247 } 1248 1249 private void cancelVibrateIfNeeded(VibratorToken v) { 1250 synchronized (v) { 1251 if (v.mVibrating) { 1252 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue); 1253 v.mVibrating = false; 1254 } 1255 } 1256 } 1257 1258 @Override 1259 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1260 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 1261 != PackageManager.PERMISSION_GRANTED) { 1262 pw.println("Permission Denial: can't dump InputManager from from pid=" 1263 + Binder.getCallingPid() 1264 + ", uid=" + Binder.getCallingUid()); 1265 return; 1266 } 1267 1268 pw.println("INPUT MANAGER (dumpsys input)\n"); 1269 String dumpStr = nativeDump(mPtr); 1270 if (dumpStr != null) { 1271 pw.println(dumpStr); 1272 } 1273 } 1274 1275 private boolean checkCallingPermission(String permission, String func) { 1276 // Quick check: if the calling permission is me, it's all okay. 1277 if (Binder.getCallingPid() == Process.myPid()) { 1278 return true; 1279 } 1280 1281 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { 1282 return true; 1283 } 1284 String msg = "Permission Denial: " + func + " from pid=" 1285 + Binder.getCallingPid() 1286 + ", uid=" + Binder.getCallingUid() 1287 + " requires " + permission; 1288 Slog.w(TAG, msg); 1289 return false; 1290 } 1291 1292 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). 1293 @Override 1294 public void monitor() { 1295 synchronized (mInputFilterLock) { } 1296 nativeMonitor(mPtr); 1297 } 1298 1299 // Native callback. 1300 private void notifyConfigurationChanged(long whenNanos) { 1301 mWindowManagerCallbacks.notifyConfigurationChanged(); 1302 } 1303 1304 // Native callback. 1305 private void notifyInputDevicesChanged(InputDevice[] inputDevices) { 1306 synchronized (mInputDevicesLock) { 1307 if (!mInputDevicesChangedPending) { 1308 mInputDevicesChangedPending = true; 1309 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED, 1310 mInputDevices).sendToTarget(); 1311 } 1312 1313 mInputDevices = inputDevices; 1314 } 1315 } 1316 1317 // Native callback. 1318 private void notifySwitch(long whenNanos, int switchValues, int switchMask) { 1319 if (DEBUG) { 1320 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues) 1321 + ", mask=" + Integer.toHexString(switchMask)); 1322 } 1323 1324 if ((switchMask & SW_LID_BIT) != 0) { 1325 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0); 1326 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); 1327 } 1328 1329 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) { 1330 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues, 1331 switchMask); 1332 } 1333 } 1334 1335 // Native callback. 1336 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { 1337 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle); 1338 } 1339 1340 // Native callback. 1341 private long notifyANR(InputApplicationHandle inputApplicationHandle, 1342 InputWindowHandle inputWindowHandle, String reason) { 1343 return mWindowManagerCallbacks.notifyANR( 1344 inputApplicationHandle, inputWindowHandle, reason); 1345 } 1346 1347 // Native callback. 1348 final boolean filterInputEvent(InputEvent event, int policyFlags) { 1349 synchronized (mInputFilterLock) { 1350 if (mInputFilter != null) { 1351 try { 1352 mInputFilter.filterInputEvent(event, policyFlags); 1353 } catch (RemoteException e) { 1354 /* ignore */ 1355 } 1356 return false; 1357 } 1358 } 1359 event.recycle(); 1360 return true; 1361 } 1362 1363 // Native callback. 1364 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { 1365 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags); 1366 } 1367 1368 // Native callback. 1369 private int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) { 1370 return mWindowManagerCallbacks.interceptWakeMotionBeforeQueueing( 1371 whenNanos, policyFlags); 1372 } 1373 1374 // Native callback. 1375 private long interceptKeyBeforeDispatching(InputWindowHandle focus, 1376 KeyEvent event, int policyFlags) { 1377 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); 1378 } 1379 1380 // Native callback. 1381 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 1382 KeyEvent event, int policyFlags) { 1383 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags); 1384 } 1385 1386 // Native callback. 1387 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) { 1388 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS, 1389 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED; 1390 } 1391 1392 // Native callback. 1393 private int getVirtualKeyQuietTimeMillis() { 1394 return mContext.getResources().getInteger( 1395 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis); 1396 } 1397 1398 // Native callback. 1399 private String[] getExcludedDeviceNames() { 1400 ArrayList<String> names = new ArrayList<String>(); 1401 1402 // Read partner-provided list of excluded input devices 1403 XmlPullParser parser = null; 1404 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". 1405 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH); 1406 FileReader confreader = null; 1407 try { 1408 confreader = new FileReader(confFile); 1409 parser = Xml.newPullParser(); 1410 parser.setInput(confreader); 1411 XmlUtils.beginDocument(parser, "devices"); 1412 1413 while (true) { 1414 XmlUtils.nextElement(parser); 1415 if (!"device".equals(parser.getName())) { 1416 break; 1417 } 1418 String name = parser.getAttributeValue(null, "name"); 1419 if (name != null) { 1420 names.add(name); 1421 } 1422 } 1423 } catch (FileNotFoundException e) { 1424 // It's ok if the file does not exist. 1425 } catch (Exception e) { 1426 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e); 1427 } finally { 1428 try { if (confreader != null) confreader.close(); } catch (IOException e) { } 1429 } 1430 1431 return names.toArray(new String[names.size()]); 1432 } 1433 1434 // Native callback. 1435 private int getKeyRepeatTimeout() { 1436 return ViewConfiguration.getKeyRepeatTimeout(); 1437 } 1438 1439 // Native callback. 1440 private int getKeyRepeatDelay() { 1441 return ViewConfiguration.getKeyRepeatDelay(); 1442 } 1443 1444 // Native callback. 1445 private int getHoverTapTimeout() { 1446 return ViewConfiguration.getHoverTapTimeout(); 1447 } 1448 1449 // Native callback. 1450 private int getHoverTapSlop() { 1451 return ViewConfiguration.getHoverTapSlop(); 1452 } 1453 1454 // Native callback. 1455 private int getDoubleTapTimeout() { 1456 return ViewConfiguration.getDoubleTapTimeout(); 1457 } 1458 1459 // Native callback. 1460 private int getLongPressTimeout() { 1461 return ViewConfiguration.getLongPressTimeout(); 1462 } 1463 1464 // Native callback. 1465 private int getPointerLayer() { 1466 return mWindowManagerCallbacks.getPointerLayer(); 1467 } 1468 1469 // Native callback. 1470 private PointerIcon getPointerIcon() { 1471 return PointerIcon.getDefaultIcon(mContext); 1472 } 1473 1474 // Native callback. 1475 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) { 1476 if (!mSystemReady) { 1477 return null; 1478 } 1479 1480 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier); 1481 if (keyboardLayoutDescriptor == null) { 1482 return null; 1483 } 1484 1485 final String[] result = new String[2]; 1486 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 1487 @Override 1488 public void visitKeyboardLayout(Resources resources, 1489 String descriptor, String label, String collection, int keyboardLayoutResId) { 1490 try { 1491 result[0] = descriptor; 1492 result[1] = Streams.readFully(new InputStreamReader( 1493 resources.openRawResource(keyboardLayoutResId))); 1494 } catch (IOException ex) { 1495 } catch (NotFoundException ex) { 1496 } 1497 } 1498 }); 1499 if (result[0] == null) { 1500 Log.w(TAG, "Could not get keyboard layout with descriptor '" 1501 + keyboardLayoutDescriptor + "'."); 1502 return null; 1503 } 1504 return result; 1505 } 1506 1507 // Native callback. 1508 private String getDeviceAlias(String uniqueId) { 1509 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) { 1510 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId) 1511 return null; 1512 } 1513 return null; 1514 } 1515 1516 /** 1517 * Callback interface implemented by the Window Manager. 1518 */ 1519 public interface WindowManagerCallbacks { 1520 public void notifyConfigurationChanged(); 1521 1522 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen); 1523 1524 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle); 1525 1526 public long notifyANR(InputApplicationHandle inputApplicationHandle, 1527 InputWindowHandle inputWindowHandle, String reason); 1528 1529 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags); 1530 1531 public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags); 1532 1533 public long interceptKeyBeforeDispatching(InputWindowHandle focus, 1534 KeyEvent event, int policyFlags); 1535 1536 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 1537 KeyEvent event, int policyFlags); 1538 1539 public int getPointerLayer(); 1540 } 1541 1542 /** 1543 * Callback interface implemented by WiredAccessoryObserver. 1544 */ 1545 public interface WiredAccessoryCallbacks { 1546 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask); 1547 } 1548 1549 /** 1550 * Private handler for the input manager. 1551 */ 1552 private final class InputManagerHandler extends Handler { 1553 public InputManagerHandler(Looper looper) { 1554 super(looper, null, true /*async*/); 1555 } 1556 1557 @Override 1558 public void handleMessage(Message msg) { 1559 switch (msg.what) { 1560 case MSG_DELIVER_INPUT_DEVICES_CHANGED: 1561 deliverInputDevicesChanged((InputDevice[])msg.obj); 1562 break; 1563 case MSG_SWITCH_KEYBOARD_LAYOUT: 1564 handleSwitchKeyboardLayout(msg.arg1, msg.arg2); 1565 break; 1566 case MSG_RELOAD_KEYBOARD_LAYOUTS: 1567 reloadKeyboardLayouts(); 1568 break; 1569 case MSG_UPDATE_KEYBOARD_LAYOUTS: 1570 updateKeyboardLayouts(); 1571 break; 1572 case MSG_RELOAD_DEVICE_ALIASES: 1573 reloadDeviceAliases(); 1574 break; 1575 } 1576 } 1577 } 1578 1579 /** 1580 * Hosting interface for input filters to call back into the input manager. 1581 */ 1582 private final class InputFilterHost extends IInputFilterHost.Stub { 1583 private boolean mDisconnected; 1584 1585 public void disconnectLocked() { 1586 mDisconnected = true; 1587 } 1588 1589 @Override 1590 public void sendInputEvent(InputEvent event, int policyFlags) { 1591 if (event == null) { 1592 throw new IllegalArgumentException("event must not be null"); 1593 } 1594 1595 synchronized (mInputFilterLock) { 1596 if (!mDisconnected) { 1597 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0, 1598 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0, 1599 policyFlags | WindowManagerPolicy.FLAG_FILTERED); 1600 } 1601 } 1602 } 1603 } 1604 1605 private static final class KeyboardLayoutDescriptor { 1606 public String packageName; 1607 public String receiverName; 1608 public String keyboardLayoutName; 1609 1610 public static String format(String packageName, 1611 String receiverName, String keyboardName) { 1612 return packageName + "/" + receiverName + "/" + keyboardName; 1613 } 1614 1615 public static KeyboardLayoutDescriptor parse(String descriptor) { 1616 int pos = descriptor.indexOf('/'); 1617 if (pos < 0 || pos + 1 == descriptor.length()) { 1618 return null; 1619 } 1620 int pos2 = descriptor.indexOf('/', pos + 1); 1621 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) { 1622 return null; 1623 } 1624 1625 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor(); 1626 result.packageName = descriptor.substring(0, pos); 1627 result.receiverName = descriptor.substring(pos + 1, pos2); 1628 result.keyboardLayoutName = descriptor.substring(pos2 + 1); 1629 return result; 1630 } 1631 } 1632 1633 private interface KeyboardLayoutVisitor { 1634 void visitKeyboardLayout(Resources resources, 1635 String descriptor, String label, String collection, int keyboardLayoutResId); 1636 } 1637 1638 private final class InputDevicesChangedListenerRecord implements DeathRecipient { 1639 private final int mPid; 1640 private final IInputDevicesChangedListener mListener; 1641 1642 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) { 1643 mPid = pid; 1644 mListener = listener; 1645 } 1646 1647 @Override 1648 public void binderDied() { 1649 if (DEBUG) { 1650 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died."); 1651 } 1652 onInputDevicesChangedListenerDied(mPid); 1653 } 1654 1655 public void notifyInputDevicesChanged(int[] info) { 1656 try { 1657 mListener.onInputDevicesChanged(info); 1658 } catch (RemoteException ex) { 1659 Slog.w(TAG, "Failed to notify process " 1660 + mPid + " that input devices changed, assuming it died.", ex); 1661 binderDied(); 1662 } 1663 } 1664 } 1665 1666 private final class VibratorToken implements DeathRecipient { 1667 public final int mDeviceId; 1668 public final IBinder mToken; 1669 public final int mTokenValue; 1670 1671 public boolean mVibrating; 1672 1673 public VibratorToken(int deviceId, IBinder token, int tokenValue) { 1674 mDeviceId = deviceId; 1675 mToken = token; 1676 mTokenValue = tokenValue; 1677 } 1678 1679 @Override 1680 public void binderDied() { 1681 if (DEBUG) { 1682 Slog.d(TAG, "Vibrator token died."); 1683 } 1684 onVibratorTokenDied(this); 1685 } 1686 } 1687 1688 private final class LocalService extends InputManagerInternal { 1689 @Override 1690 public void setDisplayViewports( 1691 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) { 1692 setDisplayViewportsInternal(defaultViewport, externalTouchViewport); 1693 } 1694 1695 @Override 1696 public boolean injectInputEvent(InputEvent event, int displayId, int mode) { 1697 return injectInputEventInternal(event, displayId, mode); 1698 } 1699 1700 @Override 1701 public void setInteractive(boolean interactive) { 1702 nativeSetInteractive(mPtr, interactive); 1703 } 1704 } 1705} 1706