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