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