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