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