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