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