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