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