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