InputManagerService.java revision 8ebac231966e27364e5d463b63540a0527d40c4b
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 android.view.Display; 20import com.android.internal.R; 21import com.android.internal.util.XmlUtils; 22import com.android.server.DisplayThread; 23import com.android.server.LocalServices; 24import com.android.server.Watchdog; 25 26import org.xmlpull.v1.XmlPullParser; 27 28import android.Manifest; 29import android.app.Notification; 30import android.app.NotificationManager; 31import android.app.PendingIntent; 32import android.bluetooth.BluetoothAdapter; 33import android.bluetooth.BluetoothDevice; 34import android.content.BroadcastReceiver; 35import android.content.ComponentName; 36import android.content.Context; 37import android.content.Intent; 38import android.content.IntentFilter; 39import android.content.pm.ActivityInfo; 40import android.content.pm.ApplicationInfo; 41import android.content.pm.PackageManager; 42import android.content.pm.ResolveInfo; 43import android.content.pm.PackageManager.NameNotFoundException; 44import android.content.res.Resources; 45import android.content.res.Resources.NotFoundException; 46import android.content.res.TypedArray; 47import android.content.res.XmlResourceParser; 48import android.database.ContentObserver; 49import android.hardware.display.DisplayViewport; 50import android.hardware.input.IInputDevicesChangedListener; 51import android.hardware.input.IInputManager; 52import android.hardware.input.InputDeviceIdentifier; 53import android.hardware.input.InputManager; 54import android.hardware.input.InputManagerInternal; 55import android.hardware.input.KeyboardLayout; 56import android.hardware.input.TouchCalibration; 57import android.os.Binder; 58import android.os.Bundle; 59import android.os.Environment; 60import android.os.Handler; 61import android.os.IBinder; 62import android.os.Looper; 63import android.os.Message; 64import android.os.MessageQueue; 65import android.os.Process; 66import android.os.RemoteException; 67import android.os.UserHandle; 68import android.provider.Settings; 69import android.provider.Settings.SettingNotFoundException; 70import android.util.Log; 71import android.util.Slog; 72import android.util.SparseArray; 73import android.util.Xml; 74import android.view.IInputFilter; 75import android.view.IInputFilterHost; 76import android.view.InputChannel; 77import android.view.InputDevice; 78import android.view.InputEvent; 79import android.view.KeyEvent; 80import android.view.PointerIcon; 81import android.view.Surface; 82import android.view.ViewConfiguration; 83import android.view.WindowManagerPolicy; 84import android.widget.Toast; 85 86import java.io.File; 87import java.io.FileDescriptor; 88import java.io.FileNotFoundException; 89import java.io.FileReader; 90import java.io.IOException; 91import java.io.InputStreamReader; 92import java.io.PrintWriter; 93import java.util.ArrayList; 94import java.util.HashMap; 95import java.util.HashSet; 96 97import libcore.io.Streams; 98import libcore.util.Objects; 99 100/* 101 * Wraps the C++ InputManager and provides its callbacks. 102 */ 103public 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 156 private static native long nativeInit(InputManagerService service, 157 Context context, MessageQueue messageQueue); 158 private static native void nativeStart(long ptr); 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 165 private static native int nativeGetScanCodeState(long ptr, 166 int deviceId, int sourceMask, int scanCode); 167 private static native int nativeGetKeyCodeState(long ptr, 168 int deviceId, int sourceMask, int keyCode); 169 private static native int nativeGetSwitchState(long ptr, 170 int deviceId, int sourceMask, int sw); 171 private static native boolean nativeHasKeys(long ptr, 172 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists); 173 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel, 174 InputWindowHandle inputWindowHandle, boolean monitor); 175 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel); 176 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable); 177 private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId, 178 int injectorPid, int injectorUid, int syncMode, int timeoutMillis, 179 int policyFlags); 180 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles); 181 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen); 182 private static native void nativeSetSystemUiVisibility(long ptr, int visibility); 183 private static native void nativeSetFocusedApplication(long ptr, 184 InputApplicationHandle application); 185 private static native boolean nativeTransferTouchFocus(long ptr, 186 InputChannel fromChannel, InputChannel toChannel); 187 private static native void nativeSetPointerSpeed(long ptr, int speed); 188 private static native void nativeSetShowTouches(long ptr, boolean enabled); 189 private static native void nativeSetInteractive(long ptr, boolean interactive); 190 private static native void nativeReloadCalibration(long ptr); 191 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern, 192 int repeat, int token); 193 private static native void nativeCancelVibrate(long ptr, int deviceId, int token); 194 private static native void nativeReloadKeyboardLayouts(long ptr); 195 private static native void nativeReloadDeviceAliases(long ptr); 196 private static native String nativeDump(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 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 274 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) { 275 mWindowManagerCallbacks = callbacks; 276 } 277 278 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) { 279 mWiredAccessoryCallbacks = callbacks; 280 } 281 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 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 341 private void reloadKeyboardLayouts() { 342 if (DEBUG) { 343 Slog.d(TAG, "Reloading keyboard layouts."); 344 } 345 nativeReloadKeyboardLayouts(mPtr); 346 } 347 348 private void reloadDeviceAliases() { 349 if (DEBUG) { 350 Slog.d(TAG, "Reloading device names."); 351 } 352 nativeReloadDeviceAliases(mPtr); 353 } 354 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 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 529 public boolean injectInputEvent(InputEvent event, int mode) { 530 return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode); 531 } 532 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 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 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 */ 609 public InputDevice[] getInputDevices() { 610 synchronized (mInputDevicesLock) { 611 return mInputDevices; 612 } 613 } 614 615 @Override // Binder call 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 642 private void onInputDevicesChangedListenerDied(int pid) { 643 synchronized (mInputDevicesLock) { 644 mInputDevicesChangedListeners.remove(pid); 645 } 646 } 647 648 // Must be called on handler. 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 synchronized (mDataStore) { 699 for (int i = 0; i < numFullKeyboards; i++) { 700 final InputDevice inputDevice = mTempFullKeyboards.get(i); 701 final String layout = 702 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier()); 703 if (layout == null) { 704 missingLayoutForExternalKeyboard = true; 705 if (i < numFullKeyboardsAdded) { 706 missingLayoutForExternalKeyboardAdded = true; 707 } 708 } 709 } 710 } 711 if (missingLayoutForExternalKeyboard) { 712 if (missingLayoutForExternalKeyboardAdded) { 713 showMissingKeyboardLayoutNotification(); 714 } 715 } else if (mKeyboardLayoutNotificationShown) { 716 hideMissingKeyboardLayoutNotification(); 717 } 718 } 719 mTempFullKeyboards.clear(); 720 } 721 722 @Override // Binder call & native callback 723 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor, 724 int surfaceRotation) { 725 if (inputDeviceDescriptor == null) { 726 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 727 } 728 729 synchronized (mDataStore) { 730 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation); 731 } 732 } 733 734 @Override // Binder call 735 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation, 736 TouchCalibration calibration) { 737 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION, 738 "setTouchCalibrationForInputDevice()")) { 739 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission"); 740 } 741 if (inputDeviceDescriptor == null) { 742 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 743 } 744 if (calibration == null) { 745 throw new IllegalArgumentException("calibration must not be null"); 746 } 747 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) { 748 throw new IllegalArgumentException("surfaceRotation value out of bounds"); 749 } 750 751 synchronized (mDataStore) { 752 try { 753 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation, 754 calibration)) { 755 nativeReloadCalibration(mPtr); 756 } 757 } finally { 758 mDataStore.saveIfNeeded(); 759 } 760 } 761 } 762 763 // Must be called on handler. 764 private void showMissingKeyboardLayoutNotification() { 765 if (!mKeyboardLayoutNotificationShown) { 766 if (mKeyboardLayoutIntent == null) { 767 final Intent intent = new Intent("android.settings.INPUT_METHOD_SETTINGS"); 768 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 769 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 770 | Intent.FLAG_ACTIVITY_CLEAR_TOP); 771 mKeyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0, 772 intent, 0, null, UserHandle.CURRENT); 773 } 774 775 Resources r = mContext.getResources(); 776 Notification notification = new Notification.Builder(mContext) 777 .setContentTitle(r.getString( 778 R.string.select_keyboard_layout_notification_title)) 779 .setContentText(r.getString( 780 R.string.select_keyboard_layout_notification_message)) 781 .setContentIntent(mKeyboardLayoutIntent) 782 .setSmallIcon(R.drawable.ic_settings_language) 783 .setPriority(Notification.PRIORITY_LOW) 784 .setColor(mContext.getResources().getColor( 785 com.android.internal.R.color.system_notification_accent_color)) 786 .build(); 787 mNotificationManager.notifyAsUser(null, 788 R.string.select_keyboard_layout_notification_title, 789 notification, UserHandle.ALL); 790 mKeyboardLayoutNotificationShown = true; 791 } 792 } 793 794 // Must be called on handler. 795 private void hideMissingKeyboardLayoutNotification() { 796 if (mKeyboardLayoutNotificationShown) { 797 mKeyboardLayoutNotificationShown = false; 798 mNotificationManager.cancelAsUser(null, 799 R.string.select_keyboard_layout_notification_title, 800 UserHandle.ALL); 801 } 802 } 803 804 // Must be called on handler. 805 private void updateKeyboardLayouts() { 806 // Scan all input devices state for keyboard layouts that have been uninstalled. 807 final HashSet<String> availableKeyboardLayouts = new HashSet<String>(); 808 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 809 @Override 810 public void visitKeyboardLayout(Resources resources, String descriptor, String label, 811 String collection, int keyboardLayoutResId, int priority) { 812 availableKeyboardLayouts.add(descriptor); 813 } 814 }); 815 synchronized (mDataStore) { 816 try { 817 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts); 818 } finally { 819 mDataStore.saveIfNeeded(); 820 } 821 } 822 823 // Reload keyboard layouts. 824 reloadKeyboardLayouts(); 825 } 826 827 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices, 828 String descriptor) { 829 final int numDevices = inputDevices.length; 830 for (int i = 0; i < numDevices; i++) { 831 final InputDevice inputDevice = inputDevices[i]; 832 if (inputDevice.getDescriptor().equals(descriptor)) { 833 return true; 834 } 835 } 836 return false; 837 } 838 839 @Override // Binder call 840 public KeyboardLayout[] getKeyboardLayouts() { 841 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>(); 842 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 843 @Override 844 public void visitKeyboardLayout(Resources resources, String descriptor, String label, 845 String collection, int keyboardLayoutResId, int priority) { 846 list.add(new KeyboardLayout(descriptor, label, collection, priority)); 847 } 848 }); 849 return list.toArray(new KeyboardLayout[list.size()]); 850 } 851 852 @Override // Binder call 853 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) { 854 if (keyboardLayoutDescriptor == null) { 855 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 856 } 857 858 final KeyboardLayout[] result = new KeyboardLayout[1]; 859 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 860 @Override 861 public void visitKeyboardLayout(Resources resources, String descriptor, 862 String label, String collection, int keyboardLayoutResId, int priority) { 863 result[0] = new KeyboardLayout(descriptor, label, collection, priority); 864 } 865 }); 866 if (result[0] == null) { 867 Log.w(TAG, "Could not get keyboard layout with descriptor '" 868 + keyboardLayoutDescriptor + "'."); 869 } 870 return result[0]; 871 } 872 873 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) { 874 final PackageManager pm = mContext.getPackageManager(); 875 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS); 876 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent, 877 PackageManager.GET_META_DATA)) { 878 final ActivityInfo activityInfo = resolveInfo.activityInfo; 879 final int priority = resolveInfo.priority; 880 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor); 881 } 882 } 883 884 private void visitKeyboardLayout(String keyboardLayoutDescriptor, 885 KeyboardLayoutVisitor visitor) { 886 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor); 887 if (d != null) { 888 final PackageManager pm = mContext.getPackageManager(); 889 try { 890 ActivityInfo receiver = pm.getReceiverInfo( 891 new ComponentName(d.packageName, d.receiverName), 892 PackageManager.GET_META_DATA); 893 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor); 894 } catch (NameNotFoundException ex) { 895 } 896 } 897 } 898 899 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, 900 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) { 901 Bundle metaData = receiver.metaData; 902 if (metaData == null) { 903 return; 904 } 905 906 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS); 907 if (configResId == 0) { 908 Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS 909 + "' on receiver " + receiver.packageName + "/" + receiver.name); 910 return; 911 } 912 913 CharSequence receiverLabel = receiver.loadLabel(pm); 914 String collection = receiverLabel != null ? receiverLabel.toString() : ""; 915 int priority; 916 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 917 priority = requestedPriority; 918 } else { 919 priority = 0; 920 } 921 922 try { 923 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo); 924 XmlResourceParser parser = resources.getXml(configResId); 925 try { 926 XmlUtils.beginDocument(parser, "keyboard-layouts"); 927 928 for (;;) { 929 XmlUtils.nextElement(parser); 930 String element = parser.getName(); 931 if (element == null) { 932 break; 933 } 934 if (element.equals("keyboard-layout")) { 935 TypedArray a = resources.obtainAttributes( 936 parser, com.android.internal.R.styleable.KeyboardLayout); 937 try { 938 String name = a.getString( 939 com.android.internal.R.styleable.KeyboardLayout_name); 940 String label = a.getString( 941 com.android.internal.R.styleable.KeyboardLayout_label); 942 int keyboardLayoutResId = a.getResourceId( 943 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout, 944 0); 945 if (name == null || label == null || keyboardLayoutResId == 0) { 946 Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' " 947 + "attributes in keyboard layout " 948 + "resource from receiver " 949 + receiver.packageName + "/" + receiver.name); 950 } else { 951 String descriptor = KeyboardLayoutDescriptor.format( 952 receiver.packageName, receiver.name, name); 953 if (keyboardName == null || name.equals(keyboardName)) { 954 visitor.visitKeyboardLayout(resources, descriptor, 955 label, collection, keyboardLayoutResId, priority); 956 } 957 } 958 } finally { 959 a.recycle(); 960 } 961 } else { 962 Log.w(TAG, "Skipping unrecognized element '" + element 963 + "' in keyboard layout resource from receiver " 964 + receiver.packageName + "/" + receiver.name); 965 } 966 } 967 } finally { 968 parser.close(); 969 } 970 } catch (Exception ex) { 971 Log.w(TAG, "Could not parse keyboard layout resource from receiver " 972 + receiver.packageName + "/" + receiver.name, ex); 973 } 974 } 975 976 /** 977 * Builds a layout descriptor for the vendor/product. This returns the 978 * descriptor for ids that aren't useful (such as the default 0, 0). 979 */ 980 private String getLayoutDescriptor(InputDeviceIdentifier identifier) { 981 if (identifier == null || identifier.getDescriptor() == null) { 982 throw new IllegalArgumentException("identifier and descriptor must not be null"); 983 } 984 985 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) { 986 return identifier.getDescriptor(); 987 } 988 StringBuilder bob = new StringBuilder(); 989 bob.append("vendor:").append(identifier.getVendorId()); 990 bob.append(",product:").append(identifier.getProductId()); 991 return bob.toString(); 992 } 993 994 @Override // Binder call 995 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) { 996 997 String key = getLayoutDescriptor(identifier); 998 synchronized (mDataStore) { 999 String layout = null; 1000 // try loading it using the layout descriptor if we have it 1001 layout = mDataStore.getCurrentKeyboardLayout(key); 1002 if (layout == null && !key.equals(identifier.getDescriptor())) { 1003 // if it doesn't exist fall back to the device descriptor 1004 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1005 } 1006 if (DEBUG) { 1007 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got " 1008 + layout); 1009 } 1010 return layout; 1011 } 1012 } 1013 1014 @Override // Binder call 1015 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1016 String keyboardLayoutDescriptor) { 1017 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1018 "setCurrentKeyboardLayoutForInputDevice()")) { 1019 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1020 } 1021 if (keyboardLayoutDescriptor == null) { 1022 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1023 } 1024 1025 String key = getLayoutDescriptor(identifier); 1026 synchronized (mDataStore) { 1027 try { 1028 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) { 1029 if (DEBUG) { 1030 Slog.d(TAG, "Saved keyboard layout using " + key); 1031 } 1032 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1033 } 1034 } finally { 1035 mDataStore.saveIfNeeded(); 1036 } 1037 } 1038 } 1039 1040 @Override // Binder call 1041 public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { 1042 String key = getLayoutDescriptor(identifier); 1043 synchronized (mDataStore) { 1044 String[] layouts = mDataStore.getKeyboardLayouts(key); 1045 if ((layouts == null || layouts.length == 0) 1046 && !key.equals(identifier.getDescriptor())) { 1047 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor()); 1048 } 1049 return layouts; 1050 } 1051 } 1052 1053 @Override // Binder call 1054 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1055 String keyboardLayoutDescriptor) { 1056 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1057 "addKeyboardLayoutForInputDevice()")) { 1058 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1059 } 1060 if (keyboardLayoutDescriptor == null) { 1061 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1062 } 1063 1064 String key = getLayoutDescriptor(identifier); 1065 synchronized (mDataStore) { 1066 try { 1067 String oldLayout = mDataStore.getCurrentKeyboardLayout(key); 1068 if (oldLayout == null && !key.equals(identifier.getDescriptor())) { 1069 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1070 } 1071 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor) 1072 && !Objects.equal(oldLayout, 1073 mDataStore.getCurrentKeyboardLayout(key))) { 1074 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1075 } 1076 } finally { 1077 mDataStore.saveIfNeeded(); 1078 } 1079 } 1080 } 1081 1082 @Override // Binder call 1083 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1084 String keyboardLayoutDescriptor) { 1085 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1086 "removeKeyboardLayoutForInputDevice()")) { 1087 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1088 } 1089 if (keyboardLayoutDescriptor == null) { 1090 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1091 } 1092 1093 String key = getLayoutDescriptor(identifier); 1094 synchronized (mDataStore) { 1095 try { 1096 String oldLayout = mDataStore.getCurrentKeyboardLayout(key); 1097 if (oldLayout == null && !key.equals(identifier.getDescriptor())) { 1098 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1099 } 1100 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor); 1101 if (!key.equals(identifier.getDescriptor())) { 1102 // We need to remove from both places to ensure it is gone 1103 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(), 1104 keyboardLayoutDescriptor); 1105 } 1106 if (removed && !Objects.equal(oldLayout, 1107 mDataStore.getCurrentKeyboardLayout(key))) { 1108 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1109 } 1110 } finally { 1111 mDataStore.saveIfNeeded(); 1112 } 1113 } 1114 } 1115 1116 public void switchKeyboardLayout(int deviceId, int direction) { 1117 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget(); 1118 } 1119 1120 // Must be called on handler. 1121 private void handleSwitchKeyboardLayout(int deviceId, int direction) { 1122 final InputDevice device = getInputDevice(deviceId); 1123 if (device != null) { 1124 final boolean changed; 1125 final String keyboardLayoutDescriptor; 1126 1127 String key = getLayoutDescriptor(device.getIdentifier()); 1128 synchronized (mDataStore) { 1129 try { 1130 changed = mDataStore.switchKeyboardLayout(key, direction); 1131 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout( 1132 key); 1133 } finally { 1134 mDataStore.saveIfNeeded(); 1135 } 1136 } 1137 1138 if (changed) { 1139 if (mSwitchedKeyboardLayoutToast != null) { 1140 mSwitchedKeyboardLayoutToast.cancel(); 1141 mSwitchedKeyboardLayoutToast = null; 1142 } 1143 if (keyboardLayoutDescriptor != null) { 1144 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor); 1145 if (keyboardLayout != null) { 1146 mSwitchedKeyboardLayoutToast = Toast.makeText( 1147 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT); 1148 mSwitchedKeyboardLayoutToast.show(); 1149 } 1150 } 1151 1152 reloadKeyboardLayouts(); 1153 } 1154 } 1155 } 1156 1157 public void setInputWindows(InputWindowHandle[] windowHandles) { 1158 nativeSetInputWindows(mPtr, windowHandles); 1159 } 1160 1161 public void setFocusedApplication(InputApplicationHandle application) { 1162 nativeSetFocusedApplication(mPtr, application); 1163 } 1164 1165 public void setInputDispatchMode(boolean enabled, boolean frozen) { 1166 nativeSetInputDispatchMode(mPtr, enabled, frozen); 1167 } 1168 1169 public void setSystemUiVisibility(int visibility) { 1170 nativeSetSystemUiVisibility(mPtr, visibility); 1171 } 1172 1173 /** 1174 * Atomically transfers touch focus from one window to another as identified by 1175 * their input channels. It is possible for multiple windows to have 1176 * touch focus if they support split touch dispatch 1177 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this 1178 * method only transfers touch focus of the specified window without affecting 1179 * other windows that may also have touch focus at the same time. 1180 * @param fromChannel The channel of a window that currently has touch focus. 1181 * @param toChannel The channel of the window that should receive touch focus in 1182 * place of the first. 1183 * @return True if the transfer was successful. False if the window with the 1184 * specified channel did not actually have touch focus at the time of the request. 1185 */ 1186 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) { 1187 if (fromChannel == null) { 1188 throw new IllegalArgumentException("fromChannel must not be null."); 1189 } 1190 if (toChannel == null) { 1191 throw new IllegalArgumentException("toChannel must not be null."); 1192 } 1193 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel); 1194 } 1195 1196 @Override // Binder call 1197 public void tryPointerSpeed(int speed) { 1198 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, 1199 "tryPointerSpeed()")) { 1200 throw new SecurityException("Requires SET_POINTER_SPEED permission"); 1201 } 1202 1203 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) { 1204 throw new IllegalArgumentException("speed out of range"); 1205 } 1206 1207 setPointerSpeedUnchecked(speed); 1208 } 1209 1210 public void updatePointerSpeedFromSettings() { 1211 int speed = getPointerSpeedSetting(); 1212 setPointerSpeedUnchecked(speed); 1213 } 1214 1215 private void setPointerSpeedUnchecked(int speed) { 1216 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED), 1217 InputManager.MAX_POINTER_SPEED); 1218 nativeSetPointerSpeed(mPtr, speed); 1219 } 1220 1221 private void registerPointerSpeedSettingObserver() { 1222 mContext.getContentResolver().registerContentObserver( 1223 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true, 1224 new ContentObserver(mHandler) { 1225 @Override 1226 public void onChange(boolean selfChange) { 1227 updatePointerSpeedFromSettings(); 1228 } 1229 }, UserHandle.USER_ALL); 1230 } 1231 1232 private int getPointerSpeedSetting() { 1233 int speed = InputManager.DEFAULT_POINTER_SPEED; 1234 try { 1235 speed = Settings.System.getIntForUser(mContext.getContentResolver(), 1236 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT); 1237 } catch (SettingNotFoundException snfe) { 1238 } 1239 return speed; 1240 } 1241 1242 public void updateShowTouchesFromSettings() { 1243 int setting = getShowTouchesSetting(0); 1244 nativeSetShowTouches(mPtr, setting != 0); 1245 } 1246 1247 private void registerShowTouchesSettingObserver() { 1248 mContext.getContentResolver().registerContentObserver( 1249 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true, 1250 new ContentObserver(mHandler) { 1251 @Override 1252 public void onChange(boolean selfChange) { 1253 updateShowTouchesFromSettings(); 1254 } 1255 }, UserHandle.USER_ALL); 1256 } 1257 1258 private int getShowTouchesSetting(int defaultValue) { 1259 int result = defaultValue; 1260 try { 1261 result = Settings.System.getIntForUser(mContext.getContentResolver(), 1262 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT); 1263 } catch (SettingNotFoundException snfe) { 1264 } 1265 return result; 1266 } 1267 1268 // Binder call 1269 @Override 1270 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) { 1271 if (repeat >= pattern.length) { 1272 throw new ArrayIndexOutOfBoundsException(); 1273 } 1274 1275 VibratorToken v; 1276 synchronized (mVibratorLock) { 1277 v = mVibratorTokens.get(token); 1278 if (v == null) { 1279 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++); 1280 try { 1281 token.linkToDeath(v, 0); 1282 } catch (RemoteException ex) { 1283 // give up 1284 throw new RuntimeException(ex); 1285 } 1286 mVibratorTokens.put(token, v); 1287 } 1288 } 1289 1290 synchronized (v) { 1291 v.mVibrating = true; 1292 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue); 1293 } 1294 } 1295 1296 // Binder call 1297 @Override 1298 public void cancelVibrate(int deviceId, IBinder token) { 1299 VibratorToken v; 1300 synchronized (mVibratorLock) { 1301 v = mVibratorTokens.get(token); 1302 if (v == null || v.mDeviceId != deviceId) { 1303 return; // nothing to cancel 1304 } 1305 } 1306 1307 cancelVibrateIfNeeded(v); 1308 } 1309 1310 void onVibratorTokenDied(VibratorToken v) { 1311 synchronized (mVibratorLock) { 1312 mVibratorTokens.remove(v.mToken); 1313 } 1314 1315 cancelVibrateIfNeeded(v); 1316 } 1317 1318 private void cancelVibrateIfNeeded(VibratorToken v) { 1319 synchronized (v) { 1320 if (v.mVibrating) { 1321 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue); 1322 v.mVibrating = false; 1323 } 1324 } 1325 } 1326 1327 @Override 1328 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1329 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 1330 != PackageManager.PERMISSION_GRANTED) { 1331 pw.println("Permission Denial: can't dump InputManager from from pid=" 1332 + Binder.getCallingPid() 1333 + ", uid=" + Binder.getCallingUid()); 1334 return; 1335 } 1336 1337 pw.println("INPUT MANAGER (dumpsys input)\n"); 1338 String dumpStr = nativeDump(mPtr); 1339 if (dumpStr != null) { 1340 pw.println(dumpStr); 1341 } 1342 } 1343 1344 private boolean checkCallingPermission(String permission, String func) { 1345 // Quick check: if the calling permission is me, it's all okay. 1346 if (Binder.getCallingPid() == Process.myPid()) { 1347 return true; 1348 } 1349 1350 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { 1351 return true; 1352 } 1353 String msg = "Permission Denial: " + func + " from pid=" 1354 + Binder.getCallingPid() 1355 + ", uid=" + Binder.getCallingUid() 1356 + " requires " + permission; 1357 Slog.w(TAG, msg); 1358 return false; 1359 } 1360 1361 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). 1362 @Override 1363 public void monitor() { 1364 synchronized (mInputFilterLock) { } 1365 nativeMonitor(mPtr); 1366 } 1367 1368 // Native callback. 1369 private void notifyConfigurationChanged(long whenNanos) { 1370 mWindowManagerCallbacks.notifyConfigurationChanged(); 1371 } 1372 1373 // Native callback. 1374 private void notifyInputDevicesChanged(InputDevice[] inputDevices) { 1375 synchronized (mInputDevicesLock) { 1376 if (!mInputDevicesChangedPending) { 1377 mInputDevicesChangedPending = true; 1378 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED, 1379 mInputDevices).sendToTarget(); 1380 } 1381 1382 mInputDevices = inputDevices; 1383 } 1384 } 1385 1386 // Native callback. 1387 private void notifySwitch(long whenNanos, int switchValues, int switchMask) { 1388 if (DEBUG) { 1389 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues) 1390 + ", mask=" + Integer.toHexString(switchMask)); 1391 } 1392 1393 if ((switchMask & SW_LID_BIT) != 0) { 1394 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0); 1395 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); 1396 } 1397 1398 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) { 1399 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0); 1400 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered); 1401 } 1402 1403 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) { 1404 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues, 1405 switchMask); 1406 } 1407 } 1408 1409 // Native callback. 1410 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { 1411 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle); 1412 } 1413 1414 // Native callback. 1415 private long notifyANR(InputApplicationHandle inputApplicationHandle, 1416 InputWindowHandle inputWindowHandle, String reason) { 1417 return mWindowManagerCallbacks.notifyANR( 1418 inputApplicationHandle, inputWindowHandle, reason); 1419 } 1420 1421 // Native callback. 1422 final boolean filterInputEvent(InputEvent event, int policyFlags) { 1423 synchronized (mInputFilterLock) { 1424 if (mInputFilter != null) { 1425 try { 1426 mInputFilter.filterInputEvent(event, policyFlags); 1427 } catch (RemoteException e) { 1428 /* ignore */ 1429 } 1430 return false; 1431 } 1432 } 1433 event.recycle(); 1434 return true; 1435 } 1436 1437 // Native callback. 1438 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { 1439 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags); 1440 } 1441 1442 // Native callback. 1443 private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) { 1444 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive( 1445 whenNanos, policyFlags); 1446 } 1447 1448 // Native callback. 1449 private long interceptKeyBeforeDispatching(InputWindowHandle focus, 1450 KeyEvent event, int policyFlags) { 1451 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); 1452 } 1453 1454 // Native callback. 1455 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 1456 KeyEvent event, int policyFlags) { 1457 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags); 1458 } 1459 1460 // Native callback. 1461 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) { 1462 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS, 1463 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED; 1464 } 1465 1466 // Native callback. 1467 private int getVirtualKeyQuietTimeMillis() { 1468 return mContext.getResources().getInteger( 1469 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis); 1470 } 1471 1472 // Native callback. 1473 private String[] getExcludedDeviceNames() { 1474 ArrayList<String> names = new ArrayList<String>(); 1475 1476 // Read partner-provided list of excluded input devices 1477 XmlPullParser parser = null; 1478 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". 1479 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH); 1480 FileReader confreader = null; 1481 try { 1482 confreader = new FileReader(confFile); 1483 parser = Xml.newPullParser(); 1484 parser.setInput(confreader); 1485 XmlUtils.beginDocument(parser, "devices"); 1486 1487 while (true) { 1488 XmlUtils.nextElement(parser); 1489 if (!"device".equals(parser.getName())) { 1490 break; 1491 } 1492 String name = parser.getAttributeValue(null, "name"); 1493 if (name != null) { 1494 names.add(name); 1495 } 1496 } 1497 } catch (FileNotFoundException e) { 1498 // It's ok if the file does not exist. 1499 } catch (Exception e) { 1500 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e); 1501 } finally { 1502 try { if (confreader != null) confreader.close(); } catch (IOException e) { } 1503 } 1504 1505 return names.toArray(new String[names.size()]); 1506 } 1507 1508 // Native callback. 1509 private int getKeyRepeatTimeout() { 1510 return ViewConfiguration.getKeyRepeatTimeout(); 1511 } 1512 1513 // Native callback. 1514 private int getKeyRepeatDelay() { 1515 return ViewConfiguration.getKeyRepeatDelay(); 1516 } 1517 1518 // Native callback. 1519 private int getHoverTapTimeout() { 1520 return ViewConfiguration.getHoverTapTimeout(); 1521 } 1522 1523 // Native callback. 1524 private int getHoverTapSlop() { 1525 return ViewConfiguration.getHoverTapSlop(); 1526 } 1527 1528 // Native callback. 1529 private int getDoubleTapTimeout() { 1530 return ViewConfiguration.getDoubleTapTimeout(); 1531 } 1532 1533 // Native callback. 1534 private int getLongPressTimeout() { 1535 return ViewConfiguration.getLongPressTimeout(); 1536 } 1537 1538 // Native callback. 1539 private int getPointerLayer() { 1540 return mWindowManagerCallbacks.getPointerLayer(); 1541 } 1542 1543 // Native callback. 1544 private PointerIcon getPointerIcon() { 1545 return PointerIcon.getDefaultIcon(mContext); 1546 } 1547 1548 // Native callback. 1549 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) { 1550 if (!mSystemReady) { 1551 return null; 1552 } 1553 1554 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier); 1555 if (keyboardLayoutDescriptor == null) { 1556 return null; 1557 } 1558 1559 final String[] result = new String[2]; 1560 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 1561 @Override 1562 public void visitKeyboardLayout(Resources resources, String descriptor, String label, 1563 String collection, int keyboardLayoutResId, int priority) { 1564 try { 1565 result[0] = descriptor; 1566 result[1] = Streams.readFully(new InputStreamReader( 1567 resources.openRawResource(keyboardLayoutResId))); 1568 } catch (IOException ex) { 1569 } catch (NotFoundException ex) { 1570 } 1571 } 1572 }); 1573 if (result[0] == null) { 1574 Log.w(TAG, "Could not get keyboard layout with descriptor '" 1575 + keyboardLayoutDescriptor + "'."); 1576 return null; 1577 } 1578 return result; 1579 } 1580 1581 // Native callback. 1582 private String getDeviceAlias(String uniqueId) { 1583 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) { 1584 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId) 1585 return null; 1586 } 1587 return null; 1588 } 1589 1590 /** 1591 * Callback interface implemented by the Window Manager. 1592 */ 1593 public interface WindowManagerCallbacks { 1594 public void notifyConfigurationChanged(); 1595 1596 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen); 1597 1598 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered); 1599 1600 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle); 1601 1602 public long notifyANR(InputApplicationHandle inputApplicationHandle, 1603 InputWindowHandle inputWindowHandle, String reason); 1604 1605 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags); 1606 1607 public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags); 1608 1609 public long interceptKeyBeforeDispatching(InputWindowHandle focus, 1610 KeyEvent event, int policyFlags); 1611 1612 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 1613 KeyEvent event, int policyFlags); 1614 1615 public int getPointerLayer(); 1616 } 1617 1618 /** 1619 * Callback interface implemented by WiredAccessoryObserver. 1620 */ 1621 public interface WiredAccessoryCallbacks { 1622 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask); 1623 public void systemReady(); 1624 } 1625 1626 /** 1627 * Private handler for the input manager. 1628 */ 1629 private final class InputManagerHandler extends Handler { 1630 public InputManagerHandler(Looper looper) { 1631 super(looper, null, true /*async*/); 1632 } 1633 1634 @Override 1635 public void handleMessage(Message msg) { 1636 switch (msg.what) { 1637 case MSG_DELIVER_INPUT_DEVICES_CHANGED: 1638 deliverInputDevicesChanged((InputDevice[])msg.obj); 1639 break; 1640 case MSG_SWITCH_KEYBOARD_LAYOUT: 1641 handleSwitchKeyboardLayout(msg.arg1, msg.arg2); 1642 break; 1643 case MSG_RELOAD_KEYBOARD_LAYOUTS: 1644 reloadKeyboardLayouts(); 1645 break; 1646 case MSG_UPDATE_KEYBOARD_LAYOUTS: 1647 updateKeyboardLayouts(); 1648 break; 1649 case MSG_RELOAD_DEVICE_ALIASES: 1650 reloadDeviceAliases(); 1651 break; 1652 } 1653 } 1654 } 1655 1656 /** 1657 * Hosting interface for input filters to call back into the input manager. 1658 */ 1659 private final class InputFilterHost extends IInputFilterHost.Stub { 1660 private boolean mDisconnected; 1661 1662 public void disconnectLocked() { 1663 mDisconnected = true; 1664 } 1665 1666 @Override 1667 public void sendInputEvent(InputEvent event, int policyFlags) { 1668 if (event == null) { 1669 throw new IllegalArgumentException("event must not be null"); 1670 } 1671 1672 synchronized (mInputFilterLock) { 1673 if (!mDisconnected) { 1674 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0, 1675 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0, 1676 policyFlags | WindowManagerPolicy.FLAG_FILTERED); 1677 } 1678 } 1679 } 1680 } 1681 1682 private static final class KeyboardLayoutDescriptor { 1683 public String packageName; 1684 public String receiverName; 1685 public String keyboardLayoutName; 1686 1687 public static String format(String packageName, 1688 String receiverName, String keyboardName) { 1689 return packageName + "/" + receiverName + "/" + keyboardName; 1690 } 1691 1692 public static KeyboardLayoutDescriptor parse(String descriptor) { 1693 int pos = descriptor.indexOf('/'); 1694 if (pos < 0 || pos + 1 == descriptor.length()) { 1695 return null; 1696 } 1697 int pos2 = descriptor.indexOf('/', pos + 1); 1698 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) { 1699 return null; 1700 } 1701 1702 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor(); 1703 result.packageName = descriptor.substring(0, pos); 1704 result.receiverName = descriptor.substring(pos + 1, pos2); 1705 result.keyboardLayoutName = descriptor.substring(pos2 + 1); 1706 return result; 1707 } 1708 } 1709 1710 private interface KeyboardLayoutVisitor { 1711 void visitKeyboardLayout(Resources resources, String descriptor, String label, 1712 String collection, int keyboardLayoutResId, int priority); 1713 } 1714 1715 private final class InputDevicesChangedListenerRecord implements DeathRecipient { 1716 private final int mPid; 1717 private final IInputDevicesChangedListener mListener; 1718 1719 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) { 1720 mPid = pid; 1721 mListener = listener; 1722 } 1723 1724 @Override 1725 public void binderDied() { 1726 if (DEBUG) { 1727 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died."); 1728 } 1729 onInputDevicesChangedListenerDied(mPid); 1730 } 1731 1732 public void notifyInputDevicesChanged(int[] info) { 1733 try { 1734 mListener.onInputDevicesChanged(info); 1735 } catch (RemoteException ex) { 1736 Slog.w(TAG, "Failed to notify process " 1737 + mPid + " that input devices changed, assuming it died.", ex); 1738 binderDied(); 1739 } 1740 } 1741 } 1742 1743 private final class VibratorToken implements DeathRecipient { 1744 public final int mDeviceId; 1745 public final IBinder mToken; 1746 public final int mTokenValue; 1747 1748 public boolean mVibrating; 1749 1750 public VibratorToken(int deviceId, IBinder token, int tokenValue) { 1751 mDeviceId = deviceId; 1752 mToken = token; 1753 mTokenValue = tokenValue; 1754 } 1755 1756 @Override 1757 public void binderDied() { 1758 if (DEBUG) { 1759 Slog.d(TAG, "Vibrator token died."); 1760 } 1761 onVibratorTokenDied(this); 1762 } 1763 } 1764 1765 private final class LocalService extends InputManagerInternal { 1766 @Override 1767 public void setDisplayViewports( 1768 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) { 1769 setDisplayViewportsInternal(defaultViewport, externalTouchViewport); 1770 } 1771 1772 @Override 1773 public boolean injectInputEvent(InputEvent event, int displayId, int mode) { 1774 return injectInputEventInternal(event, displayId, mode); 1775 } 1776 1777 @Override 1778 public void setInteractive(boolean interactive) { 1779 nativeSetInteractive(mPtr, interactive); 1780 } 1781 } 1782} 1783