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