InputManagerService.java revision 23cbe85610f780134cc77dd4a54732a22ed6e86e
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.input; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.os.LocaleList; 22import android.view.Display; 23import com.android.internal.inputmethod.InputMethodSubtypeHandle; 24import com.android.internal.os.SomeArgs; 25import com.android.internal.R; 26import com.android.internal.util.XmlUtils; 27import com.android.server.DisplayThread; 28import com.android.server.LocalServices; 29import com.android.server.Watchdog; 30 31import org.xmlpull.v1.XmlPullParser; 32 33import android.Manifest; 34import android.app.Notification; 35import android.app.NotificationManager; 36import android.app.PendingIntent; 37import android.bluetooth.BluetoothAdapter; 38import android.bluetooth.BluetoothDevice; 39import android.content.BroadcastReceiver; 40import android.content.ComponentName; 41import android.content.Context; 42import android.content.Intent; 43import android.content.IntentFilter; 44import android.content.pm.ActivityInfo; 45import android.content.pm.ApplicationInfo; 46import android.content.pm.PackageManager; 47import android.content.pm.ResolveInfo; 48import android.content.pm.PackageManager.NameNotFoundException; 49import android.content.res.Resources; 50import android.content.res.Resources.NotFoundException; 51import android.content.res.TypedArray; 52import android.content.res.XmlResourceParser; 53import android.database.ContentObserver; 54import android.hardware.display.DisplayViewport; 55import android.hardware.input.IInputDevicesChangedListener; 56import android.hardware.input.IInputManager; 57import android.hardware.input.InputDeviceIdentifier; 58import android.hardware.input.InputManager; 59import android.hardware.input.InputManagerInternal; 60import android.hardware.input.ITabletModeChangedListener; 61import android.hardware.input.KeyboardLayout; 62import android.hardware.input.TouchCalibration; 63import android.os.Binder; 64import android.os.Bundle; 65import android.os.Environment; 66import android.os.Handler; 67import android.os.IBinder; 68import android.os.Looper; 69import android.os.Message; 70import android.os.MessageQueue; 71import android.os.Process; 72import android.os.RemoteException; 73import android.os.ResultReceiver; 74import android.os.ShellCommand; 75import android.os.UserHandle; 76import android.provider.Settings; 77import android.provider.Settings.SettingNotFoundException; 78import android.text.TextUtils; 79import android.util.Slog; 80import android.util.SparseArray; 81import android.util.Xml; 82import android.view.IInputFilter; 83import android.view.IInputFilterHost; 84import android.view.InputChannel; 85import android.view.InputDevice; 86import android.view.InputEvent; 87import android.view.KeyEvent; 88import android.view.PointerIcon; 89import android.view.Surface; 90import android.view.ViewConfiguration; 91import android.view.WindowManagerPolicy; 92import android.view.inputmethod.InputMethod; 93import android.view.inputmethod.InputMethodInfo; 94import android.view.inputmethod.InputMethodSubtype; 95import android.widget.Toast; 96 97import java.io.File; 98import java.io.FileDescriptor; 99import java.io.FileNotFoundException; 100import java.io.FileReader; 101import java.io.IOException; 102import java.io.InputStreamReader; 103import java.io.PrintWriter; 104import java.util.ArrayList; 105import java.util.Arrays; 106import java.util.Collections; 107import java.util.HashMap; 108import java.util.HashSet; 109import java.util.List; 110import java.util.Locale; 111 112import libcore.io.Streams; 113import libcore.util.Objects; 114 115/* 116 * Wraps the C++ InputManager and provides its callbacks. 117 */ 118public class InputManagerService extends IInputManager.Stub 119 implements Watchdog.Monitor { 120 static final String TAG = "InputManager"; 121 static final boolean DEBUG = false; 122 123 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; 124 125 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1; 126 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2; 127 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3; 128 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4; 129 private static final int MSG_RELOAD_DEVICE_ALIASES = 5; 130 private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6; 131 private static final int MSG_INPUT_METHOD_SUBTYPE_CHANGED = 7; 132 133 // Pointer to native input manager service object. 134 private final long mPtr; 135 136 private final Context mContext; 137 private final InputManagerHandler mHandler; 138 139 private WindowManagerCallbacks mWindowManagerCallbacks; 140 private WiredAccessoryCallbacks mWiredAccessoryCallbacks; 141 private boolean mSystemReady; 142 private NotificationManager mNotificationManager; 143 144 private final Object mTabletModeLock = new Object(); 145 // List of currently registered tablet mode changed listeners by process id 146 private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners = 147 new SparseArray<>(); // guarded by mTabletModeLock 148 private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify = 149 new ArrayList<>(); 150 151 // Persistent data store. Must be locked each time during use. 152 private final PersistentDataStore mDataStore = new PersistentDataStore(); 153 154 // List of currently registered input devices changed listeners by process id. 155 private Object mInputDevicesLock = new Object(); 156 private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock 157 private InputDevice[] mInputDevices = new InputDevice[0]; 158 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners = 159 new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock 160 private final ArrayList<InputDevicesChangedListenerRecord> 161 mTempInputDevicesChangedListenersToNotify = 162 new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only 163 private final ArrayList<InputDevice> 164 mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only 165 private boolean mKeyboardLayoutNotificationShown; 166 private InputMethodSubtypeHandle mCurrentImeHandle; 167 168 // State for vibrator tokens. 169 private Object mVibratorLock = new Object(); 170 private HashMap<IBinder, VibratorToken> mVibratorTokens = 171 new HashMap<IBinder, VibratorToken>(); 172 private int mNextVibratorTokenValue; 173 174 // State for the currently installed input filter. 175 final Object mInputFilterLock = new Object(); 176 IInputFilter mInputFilter; // guarded by mInputFilterLock 177 InputFilterHost mInputFilterHost; // guarded by mInputFilterLock 178 179 private static native long nativeInit(InputManagerService service, 180 Context context, MessageQueue messageQueue); 181 private static native void nativeStart(long ptr); 182 private static native void nativeSetDisplayViewport(long ptr, boolean external, 183 int displayId, int rotation, 184 int logicalLeft, int logicalTop, int logicalRight, int logicalBottom, 185 int physicalLeft, int physicalTop, int physicalRight, int physicalBottom, 186 int deviceWidth, int deviceHeight); 187 188 private static native int nativeGetScanCodeState(long ptr, 189 int deviceId, int sourceMask, int scanCode); 190 private static native int nativeGetKeyCodeState(long ptr, 191 int deviceId, int sourceMask, int keyCode); 192 private static native int nativeGetSwitchState(long ptr, 193 int deviceId, int sourceMask, int sw); 194 private static native boolean nativeHasKeys(long ptr, 195 int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists); 196 private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel, 197 InputWindowHandle inputWindowHandle, boolean monitor); 198 private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel); 199 private static native void nativeSetInputFilterEnabled(long ptr, boolean enable); 200 private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId, 201 int injectorPid, int injectorUid, int syncMode, int timeoutMillis, 202 int policyFlags); 203 private static native void nativeToggleCapsLock(long ptr, int deviceId); 204 private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles); 205 private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen); 206 private static native void nativeSetSystemUiVisibility(long ptr, int visibility); 207 private static native void nativeSetFocusedApplication(long ptr, 208 InputApplicationHandle application); 209 private static native boolean nativeTransferTouchFocus(long ptr, 210 InputChannel fromChannel, InputChannel toChannel); 211 private static native void nativeSetPointerSpeed(long ptr, int speed); 212 private static native void nativeSetShowTouches(long ptr, boolean enabled); 213 private static native void nativeSetInteractive(long ptr, boolean interactive); 214 private static native void nativeReloadCalibration(long ptr); 215 private static native void nativeVibrate(long ptr, int deviceId, long[] pattern, 216 int repeat, int token); 217 private static native void nativeCancelVibrate(long ptr, int deviceId, int token); 218 private static native void nativeReloadKeyboardLayouts(long ptr); 219 private static native void nativeReloadDeviceAliases(long ptr); 220 private static native String nativeDump(long ptr); 221 private static native void nativeMonitor(long ptr); 222 private static native void nativeSetPointerIconShape(long ptr, int iconId); 223 private static native void nativeReloadPointerIcons(long ptr); 224 private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon); 225 private static native void nativeSetPointerIconDetached(long ptr, boolean detached); 226 227 // Input event injection constants defined in InputDispatcher.h. 228 private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0; 229 private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1; 230 private static final int INPUT_EVENT_INJECTION_FAILED = 2; 231 private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3; 232 233 // Maximum number of milliseconds to wait for input event injection. 234 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000; 235 236 // Key states (may be returned by queries about the current state of a 237 // particular key code, scan code or switch). 238 239 /** The key state is unknown or the requested key itself is not supported. */ 240 public static final int KEY_STATE_UNKNOWN = -1; 241 242 /** The key is up. /*/ 243 public static final int KEY_STATE_UP = 0; 244 245 /** The key is down. */ 246 public static final int KEY_STATE_DOWN = 1; 247 248 /** The key is down but is a virtual key press that is being emulated by the system. */ 249 public static final int KEY_STATE_VIRTUAL = 2; 250 251 /** Scan code: Mouse / trackball button. */ 252 public static final int BTN_MOUSE = 0x110; 253 254 // Switch code values must match bionic/libc/kernel/common/linux/input.h 255 /** Switch code: Lid switch. When set, lid is shut. */ 256 public static final int SW_LID = 0x00; 257 258 /** Switch code: Tablet mode switch. 259 * When set, the device is in tablet mode (i.e. no keyboard is connected). 260 */ 261 public static final int SW_TABLET_MODE = 0x01; 262 263 /** Switch code: Keypad slide. When set, keyboard is exposed. */ 264 public static final int SW_KEYPAD_SLIDE = 0x0a; 265 266 /** Switch code: Headphone. When set, headphone is inserted. */ 267 public static final int SW_HEADPHONE_INSERT = 0x02; 268 269 /** Switch code: Microphone. When set, microphone is inserted. */ 270 public static final int SW_MICROPHONE_INSERT = 0x04; 271 272 /** Switch code: Line out. When set, Line out (hi-Z) is inserted. */ 273 public static final int SW_LINEOUT_INSERT = 0x06; 274 275 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */ 276 public static final int SW_JACK_PHYSICAL_INSERT = 0x07; 277 278 /** Switch code: Camera lens cover. When set the lens is covered. */ 279 public static final int SW_CAMERA_LENS_COVER = 0x09; 280 281 public static final int SW_LID_BIT = 1 << SW_LID; 282 public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE; 283 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE; 284 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT; 285 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT; 286 public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT; 287 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT; 288 public static final int SW_JACK_BITS = 289 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT; 290 public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER; 291 292 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */ 293 final boolean mUseDevInputEventForAudioJack; 294 295 public InputManagerService(Context context) { 296 this.mContext = context; 297 this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper()); 298 299 mUseDevInputEventForAudioJack = 300 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); 301 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack=" 302 + mUseDevInputEventForAudioJack); 303 mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); 304 305 LocalServices.addService(InputManagerInternal.class, new LocalService()); 306 } 307 308 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) { 309 mWindowManagerCallbacks = callbacks; 310 } 311 312 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) { 313 mWiredAccessoryCallbacks = callbacks; 314 } 315 316 public void start() { 317 Slog.i(TAG, "Starting input manager"); 318 nativeStart(mPtr); 319 320 // Add ourself to the Watchdog monitors. 321 Watchdog.getInstance().addMonitor(this); 322 323 registerPointerSpeedSettingObserver(); 324 registerShowTouchesSettingObserver(); 325 registerAccessibilityLargePointerSettingObserver(); 326 327 mContext.registerReceiver(new BroadcastReceiver() { 328 @Override 329 public void onReceive(Context context, Intent intent) { 330 updatePointerSpeedFromSettings(); 331 updateShowTouchesFromSettings(); 332 updateAccessibilityLargePointerFromSettings(); 333 } 334 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler); 335 336 updatePointerSpeedFromSettings(); 337 updateShowTouchesFromSettings(); 338 updateAccessibilityLargePointerFromSettings(); 339 } 340 341 // TODO(BT) Pass in paramter for bluetooth system 342 public void systemRunning() { 343 if (DEBUG) { 344 Slog.d(TAG, "System ready."); 345 } 346 mNotificationManager = (NotificationManager)mContext.getSystemService( 347 Context.NOTIFICATION_SERVICE); 348 mSystemReady = true; 349 350 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); 351 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 352 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 353 filter.addAction(Intent.ACTION_PACKAGE_REPLACED); 354 filter.addDataScheme("package"); 355 mContext.registerReceiver(new BroadcastReceiver() { 356 @Override 357 public void onReceive(Context context, Intent intent) { 358 updateKeyboardLayouts(); 359 } 360 }, filter, null, mHandler); 361 362 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED); 363 mContext.registerReceiver(new BroadcastReceiver() { 364 @Override 365 public void onReceive(Context context, Intent intent) { 366 reloadDeviceAliases(); 367 } 368 }, filter, null, mHandler); 369 370 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES); 371 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS); 372 373 if (mWiredAccessoryCallbacks != null) { 374 mWiredAccessoryCallbacks.systemReady(); 375 } 376 } 377 378 private void reloadKeyboardLayouts() { 379 if (DEBUG) { 380 Slog.d(TAG, "Reloading keyboard layouts."); 381 } 382 nativeReloadKeyboardLayouts(mPtr); 383 } 384 385 private void reloadDeviceAliases() { 386 if (DEBUG) { 387 Slog.d(TAG, "Reloading device names."); 388 } 389 nativeReloadDeviceAliases(mPtr); 390 } 391 392 private void setDisplayViewportsInternal(DisplayViewport defaultViewport, 393 DisplayViewport externalTouchViewport) { 394 if (defaultViewport.valid) { 395 setDisplayViewport(false, defaultViewport); 396 } 397 398 if (externalTouchViewport.valid) { 399 setDisplayViewport(true, externalTouchViewport); 400 } else if (defaultViewport.valid) { 401 setDisplayViewport(true, defaultViewport); 402 } 403 } 404 405 private void setDisplayViewport(boolean external, DisplayViewport viewport) { 406 nativeSetDisplayViewport(mPtr, external, 407 viewport.displayId, viewport.orientation, 408 viewport.logicalFrame.left, viewport.logicalFrame.top, 409 viewport.logicalFrame.right, viewport.logicalFrame.bottom, 410 viewport.physicalFrame.left, viewport.physicalFrame.top, 411 viewport.physicalFrame.right, viewport.physicalFrame.bottom, 412 viewport.deviceWidth, viewport.deviceHeight); 413 } 414 415 /** 416 * Gets the current state of a key or button by key code. 417 * @param deviceId The input device id, or -1 to consult all devices. 418 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 419 * consider all input sources. An input device is consulted if at least one of its 420 * non-class input source bits matches the specified source mask. 421 * @param keyCode The key code to check. 422 * @return The key state. 423 */ 424 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) { 425 return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode); 426 } 427 428 /** 429 * Gets the current state of a key or button by scan code. 430 * @param deviceId The input device id, or -1 to consult all devices. 431 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 432 * consider all input sources. An input device is consulted if at least one of its 433 * non-class input source bits matches the specified source mask. 434 * @param scanCode The scan code to check. 435 * @return The key state. 436 */ 437 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) { 438 return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode); 439 } 440 441 /** 442 * Gets the current state of a switch by switch code. 443 * @param deviceId The input device id, or -1 to consult all devices. 444 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 445 * consider all input sources. An input device is consulted if at least one of its 446 * non-class input source bits matches the specified source mask. 447 * @param switchCode The switch code to check. 448 * @return The switch state. 449 */ 450 public int getSwitchState(int deviceId, int sourceMask, int switchCode) { 451 return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode); 452 } 453 454 /** 455 * Determines whether the specified key codes are supported by a particular device. 456 * @param deviceId The input device id, or -1 to consult all devices. 457 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 458 * consider all input sources. An input device is consulted if at least one of its 459 * non-class input source bits matches the specified source mask. 460 * @param keyCodes The array of key codes to check. 461 * @param keyExists An array at least as large as keyCodes whose entries will be set 462 * to true or false based on the presence or absence of support for the corresponding 463 * key codes. 464 * @return True if the lookup was successful, false otherwise. 465 */ 466 @Override // Binder call 467 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) { 468 if (keyCodes == null) { 469 throw new IllegalArgumentException("keyCodes must not be null."); 470 } 471 if (keyExists == null || keyExists.length < keyCodes.length) { 472 throw new IllegalArgumentException("keyExists must not be null and must be at " 473 + "least as large as keyCodes."); 474 } 475 476 return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists); 477 } 478 479 /** 480 * Creates an input channel that will receive all input from the input dispatcher. 481 * @param inputChannelName The input channel name. 482 * @return The input channel. 483 */ 484 public InputChannel monitorInput(String inputChannelName) { 485 if (inputChannelName == null) { 486 throw new IllegalArgumentException("inputChannelName must not be null."); 487 } 488 489 InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); 490 nativeRegisterInputChannel(mPtr, inputChannels[0], null, true); 491 inputChannels[0].dispose(); // don't need to retain the Java object reference 492 return inputChannels[1]; 493 } 494 495 /** 496 * Registers an input channel so that it can be used as an input event target. 497 * @param inputChannel The input channel to register. 498 * @param inputWindowHandle The handle of the input window associated with the 499 * input channel, or null if none. 500 */ 501 public void registerInputChannel(InputChannel inputChannel, 502 InputWindowHandle inputWindowHandle) { 503 if (inputChannel == null) { 504 throw new IllegalArgumentException("inputChannel must not be null."); 505 } 506 507 nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false); 508 } 509 510 /** 511 * Unregisters an input channel. 512 * @param inputChannel The input channel to unregister. 513 */ 514 public void unregisterInputChannel(InputChannel inputChannel) { 515 if (inputChannel == null) { 516 throw new IllegalArgumentException("inputChannel must not be null."); 517 } 518 519 nativeUnregisterInputChannel(mPtr, inputChannel); 520 } 521 522 /** 523 * Sets an input filter that will receive all input events before they are dispatched. 524 * The input filter may then reinterpret input events or inject new ones. 525 * 526 * To ensure consistency, the input dispatcher automatically drops all events 527 * in progress whenever an input filter is installed or uninstalled. After an input 528 * filter is uninstalled, it can no longer send input events unless it is reinstalled. 529 * Any events it attempts to send after it has been uninstalled will be dropped. 530 * 531 * @param filter The input filter, or null to remove the current filter. 532 */ 533 public void setInputFilter(IInputFilter filter) { 534 synchronized (mInputFilterLock) { 535 final IInputFilter oldFilter = mInputFilter; 536 if (oldFilter == filter) { 537 return; // nothing to do 538 } 539 540 if (oldFilter != null) { 541 mInputFilter = null; 542 mInputFilterHost.disconnectLocked(); 543 mInputFilterHost = null; 544 try { 545 oldFilter.uninstall(); 546 } catch (RemoteException re) { 547 /* ignore */ 548 } 549 } 550 551 if (filter != null) { 552 mInputFilter = filter; 553 mInputFilterHost = new InputFilterHost(); 554 try { 555 filter.install(mInputFilterHost); 556 } catch (RemoteException re) { 557 /* ignore */ 558 } 559 } 560 561 nativeSetInputFilterEnabled(mPtr, filter != null); 562 } 563 } 564 565 @Override // Binder call 566 public boolean injectInputEvent(InputEvent event, int mode) { 567 return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode); 568 } 569 570 private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) { 571 if (event == null) { 572 throw new IllegalArgumentException("event must not be null"); 573 } 574 if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC 575 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH 576 && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) { 577 throw new IllegalArgumentException("mode is invalid"); 578 } 579 580 final int pid = Binder.getCallingPid(); 581 final int uid = Binder.getCallingUid(); 582 final long ident = Binder.clearCallingIdentity(); 583 final int result; 584 try { 585 result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode, 586 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); 587 } finally { 588 Binder.restoreCallingIdentity(ident); 589 } 590 switch (result) { 591 case INPUT_EVENT_INJECTION_PERMISSION_DENIED: 592 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied."); 593 throw new SecurityException( 594 "Injecting to another application requires INJECT_EVENTS permission"); 595 case INPUT_EVENT_INJECTION_SUCCEEDED: 596 return true; 597 case INPUT_EVENT_INJECTION_TIMED_OUT: 598 Slog.w(TAG, "Input event injection from pid " + pid + " timed out."); 599 return false; 600 case INPUT_EVENT_INJECTION_FAILED: 601 default: 602 Slog.w(TAG, "Input event injection from pid " + pid + " failed."); 603 return false; 604 } 605 } 606 607 /** 608 * Gets information about the input device with the specified id. 609 * @param deviceId The device id. 610 * @return The input device or null if not found. 611 */ 612 @Override // Binder call 613 public InputDevice getInputDevice(int deviceId) { 614 synchronized (mInputDevicesLock) { 615 final int count = mInputDevices.length; 616 for (int i = 0; i < count; i++) { 617 final InputDevice inputDevice = mInputDevices[i]; 618 if (inputDevice.getId() == deviceId) { 619 return inputDevice; 620 } 621 } 622 } 623 return null; 624 } 625 626 /** 627 * Gets the ids of all input devices in the system. 628 * @return The input device ids. 629 */ 630 @Override // Binder call 631 public int[] getInputDeviceIds() { 632 synchronized (mInputDevicesLock) { 633 final int count = mInputDevices.length; 634 int[] ids = new int[count]; 635 for (int i = 0; i < count; i++) { 636 ids[i] = mInputDevices[i].getId(); 637 } 638 return ids; 639 } 640 } 641 642 /** 643 * Gets all input devices in the system. 644 * @return The array of input devices. 645 */ 646 public InputDevice[] getInputDevices() { 647 synchronized (mInputDevicesLock) { 648 return mInputDevices; 649 } 650 } 651 652 @Override // Binder call 653 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) { 654 if (listener == null) { 655 throw new IllegalArgumentException("listener must not be null"); 656 } 657 658 synchronized (mInputDevicesLock) { 659 int callingPid = Binder.getCallingPid(); 660 if (mInputDevicesChangedListeners.get(callingPid) != null) { 661 throw new SecurityException("The calling process has already " 662 + "registered an InputDevicesChangedListener."); 663 } 664 665 InputDevicesChangedListenerRecord record = 666 new InputDevicesChangedListenerRecord(callingPid, listener); 667 try { 668 IBinder binder = listener.asBinder(); 669 binder.linkToDeath(record, 0); 670 } catch (RemoteException ex) { 671 // give up 672 throw new RuntimeException(ex); 673 } 674 675 mInputDevicesChangedListeners.put(callingPid, record); 676 } 677 } 678 679 private void onInputDevicesChangedListenerDied(int pid) { 680 synchronized (mInputDevicesLock) { 681 mInputDevicesChangedListeners.remove(pid); 682 } 683 } 684 685 // Must be called on handler. 686 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) { 687 // Scan for changes. 688 int numFullKeyboardsAdded = 0; 689 mTempInputDevicesChangedListenersToNotify.clear(); 690 mTempFullKeyboards.clear(); 691 final int numListeners; 692 final int[] deviceIdAndGeneration; 693 synchronized (mInputDevicesLock) { 694 if (!mInputDevicesChangedPending) { 695 return; 696 } 697 mInputDevicesChangedPending = false; 698 699 numListeners = mInputDevicesChangedListeners.size(); 700 for (int i = 0; i < numListeners; i++) { 701 mTempInputDevicesChangedListenersToNotify.add( 702 mInputDevicesChangedListeners.valueAt(i)); 703 } 704 705 final int numDevices = mInputDevices.length; 706 deviceIdAndGeneration = new int[numDevices * 2]; 707 for (int i = 0; i < numDevices; i++) { 708 final InputDevice inputDevice = mInputDevices[i]; 709 deviceIdAndGeneration[i * 2] = inputDevice.getId(); 710 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration(); 711 712 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) { 713 if (!containsInputDeviceWithDescriptor(oldInputDevices, 714 inputDevice.getDescriptor())) { 715 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice); 716 } else { 717 mTempFullKeyboards.add(inputDevice); 718 } 719 } 720 } 721 } 722 723 // Notify listeners. 724 for (int i = 0; i < numListeners; i++) { 725 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged( 726 deviceIdAndGeneration); 727 } 728 mTempInputDevicesChangedListenersToNotify.clear(); 729 730 // Check for missing keyboard layouts. 731 List<InputDevice> keyboardsMissingLayout = new ArrayList<>(); 732 final int numFullKeyboards = mTempFullKeyboards.size(); 733 synchronized (mDataStore) { 734 for (int i = 0; i < numFullKeyboards; i++) { 735 final InputDevice inputDevice = mTempFullKeyboards.get(i); 736 String layout = 737 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier()); 738 if (layout == null) { 739 layout = getDefaultKeyboardLayout(inputDevice); 740 if (layout != null) { 741 setCurrentKeyboardLayoutForInputDevice( 742 inputDevice.getIdentifier(), layout); 743 } 744 } 745 if (layout == null) { 746 keyboardsMissingLayout.add(inputDevice); 747 } 748 } 749 } 750 751 if (mNotificationManager != null) { 752 if (!keyboardsMissingLayout.isEmpty()) { 753 if (keyboardsMissingLayout.size() > 1) { 754 // We have more than one keyboard missing a layout, so drop the 755 // user at the generic input methods page so they can pick which 756 // one to set. 757 showMissingKeyboardLayoutNotification(null); 758 } else { 759 showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0)); 760 } 761 } else if (mKeyboardLayoutNotificationShown) { 762 hideMissingKeyboardLayoutNotification(); 763 } 764 } 765 mTempFullKeyboards.clear(); 766 } 767 768 private String getDefaultKeyboardLayout(final InputDevice d) { 769 final Locale systemLocale = mContext.getResources().getConfiguration().locale; 770 // If our locale doesn't have a language for some reason, then we don't really have a 771 // reasonable default. 772 if (TextUtils.isEmpty(systemLocale.getLanguage())) { 773 return null; 774 } 775 final List<KeyboardLayout> layouts = new ArrayList<>(); 776 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 777 @Override 778 public void visitKeyboardLayout(Resources resources, 779 int keyboardLayoutResId, KeyboardLayout layout) { 780 // Only select a default when we know the layout is appropriate. For now, this 781 // means its a custom layout for a specific keyboard. 782 if (layout.getVendorId() != d.getVendorId() 783 || layout.getProductId() != d.getProductId()) { 784 return; 785 } 786 final LocaleList locales = layout.getLocales(); 787 final int numLocales = locales.size(); 788 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) { 789 if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) { 790 layouts.add(layout); 791 break; 792 } 793 } 794 } 795 }); 796 797 if (layouts.isEmpty()) { 798 return null; 799 } 800 801 // First sort so that ones with higher priority are listed at the top 802 Collections.sort(layouts); 803 // Next we want to try to find an exact match of language, country and variant. 804 final int N = layouts.size(); 805 for (int i = 0; i < N; i++) { 806 KeyboardLayout layout = layouts.get(i); 807 final LocaleList locales = layout.getLocales(); 808 final int numLocales = locales.size(); 809 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) { 810 final Locale locale = locales.get(localeIndex); 811 if (locale.getCountry().equals(systemLocale.getCountry()) 812 && locale.getVariant().equals(systemLocale.getVariant())) { 813 return layout.getDescriptor(); 814 } 815 } 816 } 817 // Then try an exact match of language and country 818 for (int i = 0; i < N; i++) { 819 KeyboardLayout layout = layouts.get(i); 820 final LocaleList locales = layout.getLocales(); 821 final int numLocales = locales.size(); 822 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) { 823 final Locale locale = locales.get(localeIndex); 824 if (locale.getCountry().equals(systemLocale.getCountry())) { 825 return layout.getDescriptor(); 826 } 827 } 828 } 829 830 // Give up and just use the highest priority layout with matching language 831 return layouts.get(0).getDescriptor(); 832 } 833 834 private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) { 835 // Different languages are never compatible 836 if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) { 837 return false; 838 } 839 // If both the system and the keyboard layout have a country specifier, they must be equal. 840 if (!TextUtils.isEmpty(systemLocale.getCountry()) 841 && !TextUtils.isEmpty(keyboardLocale.getCountry()) 842 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) { 843 return false; 844 } 845 return true; 846 } 847 848 @Override // Binder call & native callback 849 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor, 850 int surfaceRotation) { 851 if (inputDeviceDescriptor == null) { 852 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 853 } 854 855 synchronized (mDataStore) { 856 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation); 857 } 858 } 859 860 @Override // Binder call 861 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation, 862 TouchCalibration calibration) { 863 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION, 864 "setTouchCalibrationForInputDevice()")) { 865 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission"); 866 } 867 if (inputDeviceDescriptor == null) { 868 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 869 } 870 if (calibration == null) { 871 throw new IllegalArgumentException("calibration must not be null"); 872 } 873 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) { 874 throw new IllegalArgumentException("surfaceRotation value out of bounds"); 875 } 876 877 synchronized (mDataStore) { 878 try { 879 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation, 880 calibration)) { 881 nativeReloadCalibration(mPtr); 882 } 883 } finally { 884 mDataStore.saveIfNeeded(); 885 } 886 } 887 } 888 889 @Override // Binder call 890 public int isInTabletMode() { 891 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE, 892 "isInTabletMode()")) { 893 throw new SecurityException("Requires TABLET_MODE permission"); 894 } 895 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE); 896 } 897 898 @Override // Binder call 899 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) { 900 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE, 901 "registerTabletModeChangedListener()")) { 902 throw new SecurityException("Requires TABLET_MODE_LISTENER permission"); 903 } 904 if (listener == null) { 905 throw new IllegalArgumentException("listener must not be null"); 906 } 907 908 synchronized (mTabletModeLock) { 909 final int callingPid = Binder.getCallingPid(); 910 if (mTabletModeChangedListeners.get(callingPid) != null) { 911 throw new IllegalStateException("The calling process has already registered " 912 + "a TabletModeChangedListener."); 913 } 914 TabletModeChangedListenerRecord record = 915 new TabletModeChangedListenerRecord(callingPid, listener); 916 try { 917 IBinder binder = listener.asBinder(); 918 binder.linkToDeath(record, 0); 919 } catch (RemoteException ex) { 920 throw new RuntimeException(ex); 921 } 922 mTabletModeChangedListeners.put(callingPid, record); 923 } 924 } 925 926 private void onTabletModeChangedListenerDied(int pid) { 927 synchronized (mTabletModeLock) { 928 mTabletModeChangedListeners.remove(pid); 929 } 930 } 931 932 // Must be called on handler 933 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) { 934 mTempTabletModeChangedListenersToNotify.clear(); 935 final int numListeners; 936 synchronized (mTabletModeLock) { 937 numListeners = mTabletModeChangedListeners.size(); 938 for (int i = 0; i < numListeners; i++) { 939 mTempTabletModeChangedListenersToNotify.add( 940 mTabletModeChangedListeners.valueAt(i)); 941 } 942 } 943 for (int i = 0; i < numListeners; i++) { 944 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged( 945 whenNanos, inTabletMode); 946 } 947 } 948 949 // Must be called on handler. 950 private void showMissingKeyboardLayoutNotification(InputDevice device) { 951 if (!mKeyboardLayoutNotificationShown) { 952 final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS); 953 if (device != null) { 954 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier()); 955 } 956 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 957 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 958 | Intent.FLAG_ACTIVITY_CLEAR_TOP); 959 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0, 960 intent, 0, null, UserHandle.CURRENT); 961 962 Resources r = mContext.getResources(); 963 Notification notification = new Notification.Builder(mContext) 964 .setContentTitle(r.getString( 965 R.string.select_keyboard_layout_notification_title)) 966 .setContentText(r.getString( 967 R.string.select_keyboard_layout_notification_message)) 968 .setContentIntent(keyboardLayoutIntent) 969 .setSmallIcon(R.drawable.ic_settings_language) 970 .setPriority(Notification.PRIORITY_LOW) 971 .setColor(mContext.getColor( 972 com.android.internal.R.color.system_notification_accent_color)) 973 .build(); 974 mNotificationManager.notifyAsUser(null, 975 R.string.select_keyboard_layout_notification_title, 976 notification, UserHandle.ALL); 977 mKeyboardLayoutNotificationShown = true; 978 } 979 } 980 981 // Must be called on handler. 982 private void hideMissingKeyboardLayoutNotification() { 983 if (mKeyboardLayoutNotificationShown) { 984 mKeyboardLayoutNotificationShown = false; 985 mNotificationManager.cancelAsUser(null, 986 R.string.select_keyboard_layout_notification_title, 987 UserHandle.ALL); 988 } 989 } 990 991 // Must be called on handler. 992 private void updateKeyboardLayouts() { 993 // Scan all input devices state for keyboard layouts that have been uninstalled. 994 final HashSet<String> availableKeyboardLayouts = new HashSet<String>(); 995 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 996 @Override 997 public void visitKeyboardLayout(Resources resources, 998 int keyboardLayoutResId, KeyboardLayout layout) { 999 availableKeyboardLayouts.add(layout.getDescriptor()); 1000 } 1001 }); 1002 synchronized (mDataStore) { 1003 try { 1004 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts); 1005 } finally { 1006 mDataStore.saveIfNeeded(); 1007 } 1008 } 1009 1010 // Reload keyboard layouts. 1011 reloadKeyboardLayouts(); 1012 } 1013 1014 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices, 1015 String descriptor) { 1016 final int numDevices = inputDevices.length; 1017 for (int i = 0; i < numDevices; i++) { 1018 final InputDevice inputDevice = inputDevices[i]; 1019 if (inputDevice.getDescriptor().equals(descriptor)) { 1020 return true; 1021 } 1022 } 1023 return false; 1024 } 1025 1026 @Override // Binder call 1027 public KeyboardLayout[] getKeyboardLayouts() { 1028 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>(); 1029 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 1030 @Override 1031 public void visitKeyboardLayout(Resources resources, 1032 int keyboardLayoutResId, KeyboardLayout layout) { 1033 list.add(layout); 1034 } 1035 }); 1036 return list.toArray(new KeyboardLayout[list.size()]); 1037 } 1038 1039 @Override // Binder call 1040 public KeyboardLayout[] getKeyboardLayoutsForInputDevice( 1041 final InputDeviceIdentifier identifier) { 1042 final String[] enabledLayoutDescriptors = 1043 getEnabledKeyboardLayoutsForInputDevice(identifier); 1044 final ArrayList<KeyboardLayout> enabledLayouts = 1045 new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length); 1046 final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>(); 1047 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 1048 boolean mHasSeenDeviceSpecificLayout; 1049 1050 @Override 1051 public void visitKeyboardLayout(Resources resources, 1052 int keyboardLayoutResId, KeyboardLayout layout) { 1053 // First check if it's enabled. If the keyboard layout is enabled then we always 1054 // want to return it as a possible layout for the device. 1055 for (String s : enabledLayoutDescriptors) { 1056 if (s != null && s.equals(layout.getDescriptor())) { 1057 enabledLayouts.add(layout); 1058 return; 1059 } 1060 } 1061 // Next find any potential layouts that aren't yet enabled for the device. For 1062 // devices that have special layouts we assume there's a reason that the generic 1063 // layouts don't work for them so we don't want to return them since it's likely 1064 // to result in a poor user experience. 1065 if (layout.getVendorId() == identifier.getVendorId() 1066 && layout.getProductId() == identifier.getProductId()) { 1067 if (!mHasSeenDeviceSpecificLayout) { 1068 mHasSeenDeviceSpecificLayout = true; 1069 potentialLayouts.clear(); 1070 } 1071 potentialLayouts.add(layout); 1072 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1 1073 && !mHasSeenDeviceSpecificLayout) { 1074 potentialLayouts.add(layout); 1075 } 1076 } 1077 }); 1078 final int enabledLayoutSize = enabledLayouts.size(); 1079 final int potentialLayoutSize = potentialLayouts.size(); 1080 KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize]; 1081 enabledLayouts.toArray(layouts); 1082 for (int i = 0; i < potentialLayoutSize; i++) { 1083 layouts[enabledLayoutSize + i] = potentialLayouts.get(i); 1084 } 1085 return layouts; 1086 } 1087 1088 @Override // Binder call 1089 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) { 1090 if (keyboardLayoutDescriptor == null) { 1091 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1092 } 1093 1094 final KeyboardLayout[] result = new KeyboardLayout[1]; 1095 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 1096 @Override 1097 public void visitKeyboardLayout(Resources resources, 1098 int keyboardLayoutResId, KeyboardLayout layout) { 1099 result[0] = layout; 1100 } 1101 }); 1102 if (result[0] == null) { 1103 Slog.w(TAG, "Could not get keyboard layout with descriptor '" 1104 + keyboardLayoutDescriptor + "'."); 1105 } 1106 return result[0]; 1107 } 1108 1109 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) { 1110 final PackageManager pm = mContext.getPackageManager(); 1111 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS); 1112 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent, 1113 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE 1114 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) { 1115 final ActivityInfo activityInfo = resolveInfo.activityInfo; 1116 final int priority = resolveInfo.priority; 1117 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor); 1118 } 1119 } 1120 1121 private void visitKeyboardLayout(String keyboardLayoutDescriptor, 1122 KeyboardLayoutVisitor visitor) { 1123 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor); 1124 if (d != null) { 1125 final PackageManager pm = mContext.getPackageManager(); 1126 try { 1127 ActivityInfo receiver = pm.getReceiverInfo( 1128 new ComponentName(d.packageName, d.receiverName), 1129 PackageManager.GET_META_DATA 1130 | PackageManager.MATCH_DIRECT_BOOT_AWARE 1131 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); 1132 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor); 1133 } catch (NameNotFoundException ex) { 1134 } 1135 } 1136 } 1137 1138 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, 1139 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) { 1140 Bundle metaData = receiver.metaData; 1141 if (metaData == null) { 1142 return; 1143 } 1144 1145 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS); 1146 if (configResId == 0) { 1147 Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS 1148 + "' on receiver " + receiver.packageName + "/" + receiver.name); 1149 return; 1150 } 1151 1152 CharSequence receiverLabel = receiver.loadLabel(pm); 1153 String collection = receiverLabel != null ? receiverLabel.toString() : ""; 1154 int priority; 1155 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 1156 priority = requestedPriority; 1157 } else { 1158 priority = 0; 1159 } 1160 1161 try { 1162 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo); 1163 XmlResourceParser parser = resources.getXml(configResId); 1164 try { 1165 XmlUtils.beginDocument(parser, "keyboard-layouts"); 1166 1167 for (;;) { 1168 XmlUtils.nextElement(parser); 1169 String element = parser.getName(); 1170 if (element == null) { 1171 break; 1172 } 1173 if (element.equals("keyboard-layout")) { 1174 TypedArray a = resources.obtainAttributes( 1175 parser, com.android.internal.R.styleable.KeyboardLayout); 1176 try { 1177 String name = a.getString( 1178 com.android.internal.R.styleable.KeyboardLayout_name); 1179 String label = a.getString( 1180 com.android.internal.R.styleable.KeyboardLayout_label); 1181 int keyboardLayoutResId = a.getResourceId( 1182 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout, 1183 0); 1184 String languageTags = a.getString( 1185 com.android.internal.R.styleable.KeyboardLayout_locale); 1186 LocaleList locales = getLocalesFromLanguageTags(languageTags); 1187 int vid = a.getInt( 1188 com.android.internal.R.styleable.KeyboardLayout_vendorId, -1); 1189 int pid = a.getInt( 1190 com.android.internal.R.styleable.KeyboardLayout_productId, -1); 1191 1192 if (name == null || label == null || keyboardLayoutResId == 0) { 1193 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' " 1194 + "attributes in keyboard layout " 1195 + "resource from receiver " 1196 + receiver.packageName + "/" + receiver.name); 1197 } else { 1198 String descriptor = KeyboardLayoutDescriptor.format( 1199 receiver.packageName, receiver.name, name); 1200 if (keyboardName == null || name.equals(keyboardName)) { 1201 KeyboardLayout layout = new KeyboardLayout( 1202 descriptor, label, collection, priority, 1203 locales, vid, pid); 1204 visitor.visitKeyboardLayout( 1205 resources, keyboardLayoutResId, layout); 1206 } 1207 } 1208 } finally { 1209 a.recycle(); 1210 } 1211 } else { 1212 Slog.w(TAG, "Skipping unrecognized element '" + element 1213 + "' in keyboard layout resource from receiver " 1214 + receiver.packageName + "/" + receiver.name); 1215 } 1216 } 1217 } finally { 1218 parser.close(); 1219 } 1220 } catch (Exception ex) { 1221 Slog.w(TAG, "Could not parse keyboard layout resource from receiver " 1222 + receiver.packageName + "/" + receiver.name, ex); 1223 } 1224 } 1225 1226 @NonNull 1227 private static LocaleList getLocalesFromLanguageTags(String languageTags) { 1228 if (TextUtils.isEmpty(languageTags)) { 1229 return LocaleList.getEmptyLocaleList(); 1230 } 1231 return LocaleList.forLanguageTags(languageTags.replace('|', ',')); 1232 } 1233 1234 /** 1235 * Builds a layout descriptor for the vendor/product. This returns the 1236 * descriptor for ids that aren't useful (such as the default 0, 0). 1237 */ 1238 private String getLayoutDescriptor(InputDeviceIdentifier identifier) { 1239 if (identifier == null || identifier.getDescriptor() == null) { 1240 throw new IllegalArgumentException("identifier and descriptor must not be null"); 1241 } 1242 1243 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) { 1244 return identifier.getDescriptor(); 1245 } 1246 StringBuilder bob = new StringBuilder(); 1247 bob.append("vendor:").append(identifier.getVendorId()); 1248 bob.append(",product:").append(identifier.getProductId()); 1249 return bob.toString(); 1250 } 1251 1252 @Override // Binder call 1253 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) { 1254 1255 String key = getLayoutDescriptor(identifier); 1256 synchronized (mDataStore) { 1257 String layout = null; 1258 // try loading it using the layout descriptor if we have it 1259 layout = mDataStore.getCurrentKeyboardLayout(key); 1260 if (layout == null && !key.equals(identifier.getDescriptor())) { 1261 // if it doesn't exist fall back to the device descriptor 1262 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1263 } 1264 if (DEBUG) { 1265 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got " 1266 + layout); 1267 } 1268 return layout; 1269 } 1270 } 1271 1272 @Override // Binder call 1273 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1274 String keyboardLayoutDescriptor) { 1275 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1276 "setCurrentKeyboardLayoutForInputDevice()")) { 1277 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1278 } 1279 if (keyboardLayoutDescriptor == null) { 1280 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1281 } 1282 1283 String key = getLayoutDescriptor(identifier); 1284 synchronized (mDataStore) { 1285 try { 1286 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) { 1287 if (DEBUG) { 1288 Slog.d(TAG, "Saved keyboard layout using " + key); 1289 } 1290 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1291 } 1292 } finally { 1293 mDataStore.saveIfNeeded(); 1294 } 1295 } 1296 } 1297 1298 @Override // Binder call 1299 public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { 1300 String key = getLayoutDescriptor(identifier); 1301 synchronized (mDataStore) { 1302 String[] layouts = mDataStore.getKeyboardLayouts(key); 1303 if ((layouts == null || layouts.length == 0) 1304 && !key.equals(identifier.getDescriptor())) { 1305 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor()); 1306 } 1307 return layouts; 1308 } 1309 } 1310 1311 @Override // Binder call 1312 @Nullable 1313 public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1314 InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) { 1315 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype); 1316 String key = getLayoutDescriptor(identifier); 1317 final String keyboardLayoutDescriptor; 1318 synchronized (mDataStore) { 1319 keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle); 1320 } 1321 1322 if (keyboardLayoutDescriptor == null) { 1323 return null; 1324 } 1325 1326 final KeyboardLayout[] result = new KeyboardLayout[1]; 1327 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 1328 @Override 1329 public void visitKeyboardLayout(Resources resources, 1330 int keyboardLayoutResId, KeyboardLayout layout) { 1331 result[0] = layout; 1332 } 1333 }); 1334 if (result[0] == null) { 1335 Slog.w(TAG, "Could not get keyboard layout with descriptor '" 1336 + keyboardLayoutDescriptor + "'."); 1337 } 1338 return result[0]; 1339 } 1340 1341 @Override 1342 public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1343 InputMethodInfo imeInfo, InputMethodSubtype imeSubtype, 1344 String keyboardLayoutDescriptor) { 1345 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1346 "setKeyboardLayoutForInputDevice()")) { 1347 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1348 } 1349 if (keyboardLayoutDescriptor == null) { 1350 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1351 } 1352 if (imeInfo == null) { 1353 throw new IllegalArgumentException("imeInfo must not be null"); 1354 } 1355 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype); 1356 setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor); 1357 } 1358 1359 private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier, 1360 InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) { 1361 String key = getLayoutDescriptor(identifier); 1362 synchronized (mDataStore) { 1363 try { 1364 if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) { 1365 if (DEBUG) { 1366 Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor + 1367 " for subtype " + imeHandle + " and device " + identifier + 1368 " using key " + key); 1369 } 1370 if (imeHandle.equals(mCurrentImeHandle)) { 1371 if (DEBUG) { 1372 Slog.d(TAG, "Layout for current subtype changed, switching layout"); 1373 } 1374 SomeArgs args = SomeArgs.obtain(); 1375 args.arg1 = identifier; 1376 args.arg2 = imeHandle; 1377 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget(); 1378 } 1379 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1380 } 1381 } finally { 1382 mDataStore.saveIfNeeded(); 1383 } 1384 } 1385 } 1386 1387 @Override // Binder call 1388 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1389 String keyboardLayoutDescriptor) { 1390 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1391 "addKeyboardLayoutForInputDevice()")) { 1392 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1393 } 1394 if (keyboardLayoutDescriptor == null) { 1395 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1396 } 1397 1398 String key = getLayoutDescriptor(identifier); 1399 synchronized (mDataStore) { 1400 try { 1401 String oldLayout = mDataStore.getCurrentKeyboardLayout(key); 1402 if (oldLayout == null && !key.equals(identifier.getDescriptor())) { 1403 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1404 } 1405 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor) 1406 && !Objects.equal(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) { 1407 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1408 } 1409 } finally { 1410 mDataStore.saveIfNeeded(); 1411 } 1412 } 1413 } 1414 1415 @Override // Binder call 1416 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1417 String keyboardLayoutDescriptor) { 1418 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1419 "removeKeyboardLayoutForInputDevice()")) { 1420 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1421 } 1422 if (keyboardLayoutDescriptor == null) { 1423 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1424 } 1425 1426 String key = getLayoutDescriptor(identifier); 1427 synchronized (mDataStore) { 1428 try { 1429 String oldLayout = mDataStore.getCurrentKeyboardLayout(key); 1430 if (oldLayout == null && !key.equals(identifier.getDescriptor())) { 1431 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1432 } 1433 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor); 1434 if (!key.equals(identifier.getDescriptor())) { 1435 // We need to remove from both places to ensure it is gone 1436 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(), 1437 keyboardLayoutDescriptor); 1438 } 1439 if (removed && !Objects.equal(oldLayout, 1440 mDataStore.getCurrentKeyboardLayout(key))) { 1441 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1442 } 1443 } finally { 1444 mDataStore.saveIfNeeded(); 1445 } 1446 } 1447 } 1448 1449 // Must be called on handler. 1450 private void handleSwitchInputMethodSubtype(int userId, 1451 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) { 1452 if (DEBUG) { 1453 Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId 1454 + " ime=" + inputMethodInfo + " subtype=" + subtype); 1455 } 1456 if (inputMethodInfo == null) { 1457 Slog.d(TAG, "No InputMethod is running, ignoring change"); 1458 return; 1459 } 1460 if (subtype != null && !"keyboard".equals(subtype.getMode())) { 1461 Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change"); 1462 return; 1463 } 1464 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype); 1465 if (!handle.equals(mCurrentImeHandle)) { 1466 mCurrentImeHandle = handle; 1467 handleSwitchKeyboardLayout(null, handle); 1468 } 1469 } 1470 1471 // Must be called on handler. 1472 private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier, 1473 InputMethodSubtypeHandle handle) { 1474 synchronized (mInputDevicesLock) { 1475 for (InputDevice device : mInputDevices) { 1476 if (identifier != null && !device.getIdentifier().equals(identifier) || 1477 !device.isFullKeyboard()) { 1478 continue; 1479 } 1480 String key = getLayoutDescriptor(device.getIdentifier()); 1481 boolean changed = false; 1482 synchronized (mDataStore) { 1483 try { 1484 if (mDataStore.switchKeyboardLayout(key, handle)) { 1485 changed = true; 1486 } 1487 } finally { 1488 mDataStore.saveIfNeeded(); 1489 } 1490 } 1491 if (changed) { 1492 reloadKeyboardLayouts(); 1493 } 1494 } 1495 } 1496 } 1497 1498 public void setInputWindows(InputWindowHandle[] windowHandles) { 1499 nativeSetInputWindows(mPtr, windowHandles); 1500 } 1501 1502 public void setFocusedApplication(InputApplicationHandle application) { 1503 nativeSetFocusedApplication(mPtr, application); 1504 } 1505 1506 @Override 1507 public void setPointerIconDetached(boolean detached) { 1508 nativeSetPointerIconDetached(mPtr, detached); 1509 } 1510 1511 public void setInputDispatchMode(boolean enabled, boolean frozen) { 1512 nativeSetInputDispatchMode(mPtr, enabled, frozen); 1513 } 1514 1515 public void setSystemUiVisibility(int visibility) { 1516 nativeSetSystemUiVisibility(mPtr, visibility); 1517 } 1518 1519 /** 1520 * Atomically transfers touch focus from one window to another as identified by 1521 * their input channels. It is possible for multiple windows to have 1522 * touch focus if they support split touch dispatch 1523 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this 1524 * method only transfers touch focus of the specified window without affecting 1525 * other windows that may also have touch focus at the same time. 1526 * @param fromChannel The channel of a window that currently has touch focus. 1527 * @param toChannel The channel of the window that should receive touch focus in 1528 * place of the first. 1529 * @return True if the transfer was successful. False if the window with the 1530 * specified channel did not actually have touch focus at the time of the request. 1531 */ 1532 public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) { 1533 if (fromChannel == null) { 1534 throw new IllegalArgumentException("fromChannel must not be null."); 1535 } 1536 if (toChannel == null) { 1537 throw new IllegalArgumentException("toChannel must not be null."); 1538 } 1539 return nativeTransferTouchFocus(mPtr, fromChannel, toChannel); 1540 } 1541 1542 @Override // Binder call 1543 public void tryPointerSpeed(int speed) { 1544 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, 1545 "tryPointerSpeed()")) { 1546 throw new SecurityException("Requires SET_POINTER_SPEED permission"); 1547 } 1548 1549 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) { 1550 throw new IllegalArgumentException("speed out of range"); 1551 } 1552 1553 setPointerSpeedUnchecked(speed); 1554 } 1555 1556 public void updatePointerSpeedFromSettings() { 1557 int speed = getPointerSpeedSetting(); 1558 setPointerSpeedUnchecked(speed); 1559 } 1560 1561 private void setPointerSpeedUnchecked(int speed) { 1562 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED), 1563 InputManager.MAX_POINTER_SPEED); 1564 nativeSetPointerSpeed(mPtr, speed); 1565 } 1566 1567 private void registerPointerSpeedSettingObserver() { 1568 mContext.getContentResolver().registerContentObserver( 1569 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true, 1570 new ContentObserver(mHandler) { 1571 @Override 1572 public void onChange(boolean selfChange) { 1573 updatePointerSpeedFromSettings(); 1574 } 1575 }, UserHandle.USER_ALL); 1576 } 1577 1578 private int getPointerSpeedSetting() { 1579 int speed = InputManager.DEFAULT_POINTER_SPEED; 1580 try { 1581 speed = Settings.System.getIntForUser(mContext.getContentResolver(), 1582 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT); 1583 } catch (SettingNotFoundException snfe) { 1584 } 1585 return speed; 1586 } 1587 1588 public void updateShowTouchesFromSettings() { 1589 int setting = getShowTouchesSetting(0); 1590 nativeSetShowTouches(mPtr, setting != 0); 1591 } 1592 1593 private void registerShowTouchesSettingObserver() { 1594 mContext.getContentResolver().registerContentObserver( 1595 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true, 1596 new ContentObserver(mHandler) { 1597 @Override 1598 public void onChange(boolean selfChange) { 1599 updateShowTouchesFromSettings(); 1600 } 1601 }, UserHandle.USER_ALL); 1602 } 1603 1604 public void updateAccessibilityLargePointerFromSettings() { 1605 final int accessibilityConfig = Settings.Secure.getIntForUser( 1606 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, 1607 0, UserHandle.USER_CURRENT); 1608 PointerIcon.setUseLargeIcons(accessibilityConfig == 1); 1609 nativeReloadPointerIcons(mPtr); 1610 } 1611 1612 private void registerAccessibilityLargePointerSettingObserver() { 1613 mContext.getContentResolver().registerContentObserver( 1614 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true, 1615 new ContentObserver(mHandler) { 1616 @Override 1617 public void onChange(boolean selfChange) { 1618 updateAccessibilityLargePointerFromSettings(); 1619 } 1620 }, UserHandle.USER_ALL); 1621 } 1622 1623 private int getShowTouchesSetting(int defaultValue) { 1624 int result = defaultValue; 1625 try { 1626 result = Settings.System.getIntForUser(mContext.getContentResolver(), 1627 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT); 1628 } catch (SettingNotFoundException snfe) { 1629 } 1630 return result; 1631 } 1632 1633 // Binder call 1634 @Override 1635 public void vibrate(int deviceId, long[] pattern, int repeat, IBinder token) { 1636 if (repeat >= pattern.length) { 1637 throw new ArrayIndexOutOfBoundsException(); 1638 } 1639 1640 VibratorToken v; 1641 synchronized (mVibratorLock) { 1642 v = mVibratorTokens.get(token); 1643 if (v == null) { 1644 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++); 1645 try { 1646 token.linkToDeath(v, 0); 1647 } catch (RemoteException ex) { 1648 // give up 1649 throw new RuntimeException(ex); 1650 } 1651 mVibratorTokens.put(token, v); 1652 } 1653 } 1654 1655 synchronized (v) { 1656 v.mVibrating = true; 1657 nativeVibrate(mPtr, deviceId, pattern, repeat, v.mTokenValue); 1658 } 1659 } 1660 1661 // Binder call 1662 @Override 1663 public void cancelVibrate(int deviceId, IBinder token) { 1664 VibratorToken v; 1665 synchronized (mVibratorLock) { 1666 v = mVibratorTokens.get(token); 1667 if (v == null || v.mDeviceId != deviceId) { 1668 return; // nothing to cancel 1669 } 1670 } 1671 1672 cancelVibrateIfNeeded(v); 1673 } 1674 1675 void onVibratorTokenDied(VibratorToken v) { 1676 synchronized (mVibratorLock) { 1677 mVibratorTokens.remove(v.mToken); 1678 } 1679 1680 cancelVibrateIfNeeded(v); 1681 } 1682 1683 private void cancelVibrateIfNeeded(VibratorToken v) { 1684 synchronized (v) { 1685 if (v.mVibrating) { 1686 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue); 1687 v.mVibrating = false; 1688 } 1689 } 1690 } 1691 1692 // Binder call 1693 @Override 1694 public void setPointerIconShape(int iconId) { 1695 nativeSetPointerIconShape(mPtr, iconId); 1696 } 1697 1698 // Binder call 1699 @Override 1700 public void setCustomPointerIcon(PointerIcon icon) { 1701 nativeSetCustomPointerIcon(mPtr, icon); 1702 } 1703 1704 @Override 1705 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 1706 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 1707 != PackageManager.PERMISSION_GRANTED) { 1708 pw.println("Permission Denial: can't dump InputManager from from pid=" 1709 + Binder.getCallingPid() 1710 + ", uid=" + Binder.getCallingUid()); 1711 return; 1712 } 1713 1714 pw.println("INPUT MANAGER (dumpsys input)\n"); 1715 String dumpStr = nativeDump(mPtr); 1716 if (dumpStr != null) { 1717 pw.println(dumpStr); 1718 } 1719 pw.println(" Keyboard Layouts:"); 1720 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 1721 @Override 1722 public void visitKeyboardLayout(Resources resources, 1723 int keyboardLayoutResId, KeyboardLayout layout) { 1724 pw.println(" \"" + layout + "\": " + layout.getDescriptor()); 1725 } 1726 }); 1727 pw.println(); 1728 synchronized(mDataStore) { 1729 mDataStore.dump(pw, " "); 1730 } 1731 } 1732 1733 @Override 1734 public void onShellCommand(FileDescriptor in, FileDescriptor out, 1735 FileDescriptor err, String[] args, ResultReceiver resultReceiver) { 1736 (new Shell()).exec(this, in, out, err, args, resultReceiver); 1737 } 1738 1739 public int onShellCommand(Shell shell, String cmd) { 1740 if (TextUtils.isEmpty(cmd)) { 1741 shell.onHelp(); 1742 return 1; 1743 } 1744 if (cmd.equals("setlayout")) { 1745 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1746 "onShellCommand()")) { 1747 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1748 } 1749 InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle( 1750 shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired())); 1751 String descriptor = shell.getNextArgRequired(); 1752 int vid = Integer.decode(shell.getNextArgRequired()); 1753 int pid = Integer.decode(shell.getNextArgRequired()); 1754 InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid); 1755 setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired()); 1756 } 1757 return 0; 1758 } 1759 1760 1761 private boolean checkCallingPermission(String permission, String func) { 1762 // Quick check: if the calling permission is me, it's all okay. 1763 if (Binder.getCallingPid() == Process.myPid()) { 1764 return true; 1765 } 1766 1767 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { 1768 return true; 1769 } 1770 String msg = "Permission Denial: " + func + " from pid=" 1771 + Binder.getCallingPid() 1772 + ", uid=" + Binder.getCallingUid() 1773 + " requires " + permission; 1774 Slog.w(TAG, msg); 1775 return false; 1776 } 1777 1778 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). 1779 @Override 1780 public void monitor() { 1781 synchronized (mInputFilterLock) { } 1782 nativeMonitor(mPtr); 1783 } 1784 1785 // Native callback. 1786 private void notifyConfigurationChanged(long whenNanos) { 1787 mWindowManagerCallbacks.notifyConfigurationChanged(); 1788 } 1789 1790 // Native callback. 1791 private void notifyInputDevicesChanged(InputDevice[] inputDevices) { 1792 synchronized (mInputDevicesLock) { 1793 if (!mInputDevicesChangedPending) { 1794 mInputDevicesChangedPending = true; 1795 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED, 1796 mInputDevices).sendToTarget(); 1797 } 1798 1799 mInputDevices = inputDevices; 1800 } 1801 } 1802 1803 // Native callback. 1804 private void notifySwitch(long whenNanos, int switchValues, int switchMask) { 1805 if (DEBUG) { 1806 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues) 1807 + ", mask=" + Integer.toHexString(switchMask)); 1808 } 1809 1810 if ((switchMask & SW_LID_BIT) != 0) { 1811 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0); 1812 mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); 1813 } 1814 1815 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) { 1816 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0); 1817 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered); 1818 } 1819 1820 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) { 1821 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues, 1822 switchMask); 1823 } 1824 1825 if ((switchMask & SW_TABLET_MODE_BIT) != 0) { 1826 SomeArgs args = SomeArgs.obtain(); 1827 args.argi1 = (int) (whenNanos & 0xFFFFFFFF); 1828 args.argi2 = (int) (whenNanos >> 32); 1829 args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0); 1830 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED, 1831 args).sendToTarget(); 1832 } 1833 } 1834 1835 // Native callback. 1836 private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { 1837 mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle); 1838 } 1839 1840 // Native callback. 1841 private long notifyANR(InputApplicationHandle inputApplicationHandle, 1842 InputWindowHandle inputWindowHandle, String reason) { 1843 return mWindowManagerCallbacks.notifyANR( 1844 inputApplicationHandle, inputWindowHandle, reason); 1845 } 1846 1847 // Native callback. 1848 final boolean filterInputEvent(InputEvent event, int policyFlags) { 1849 synchronized (mInputFilterLock) { 1850 if (mInputFilter != null) { 1851 try { 1852 mInputFilter.filterInputEvent(event, policyFlags); 1853 } catch (RemoteException e) { 1854 /* ignore */ 1855 } 1856 return false; 1857 } 1858 } 1859 event.recycle(); 1860 return true; 1861 } 1862 1863 // Native callback. 1864 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { 1865 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags); 1866 } 1867 1868 // Native callback. 1869 private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) { 1870 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive( 1871 whenNanos, policyFlags); 1872 } 1873 1874 // Native callback. 1875 private long interceptKeyBeforeDispatching(InputWindowHandle focus, 1876 KeyEvent event, int policyFlags) { 1877 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); 1878 } 1879 1880 // Native callback. 1881 private KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 1882 KeyEvent event, int policyFlags) { 1883 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags); 1884 } 1885 1886 // Native callback. 1887 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) { 1888 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS, 1889 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED; 1890 } 1891 1892 // Native callback. 1893 private int getVirtualKeyQuietTimeMillis() { 1894 return mContext.getResources().getInteger( 1895 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis); 1896 } 1897 1898 // Native callback. 1899 private String[] getExcludedDeviceNames() { 1900 ArrayList<String> names = new ArrayList<String>(); 1901 1902 // Read partner-provided list of excluded input devices 1903 XmlPullParser parser = null; 1904 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". 1905 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH); 1906 FileReader confreader = null; 1907 try { 1908 confreader = new FileReader(confFile); 1909 parser = Xml.newPullParser(); 1910 parser.setInput(confreader); 1911 XmlUtils.beginDocument(parser, "devices"); 1912 1913 while (true) { 1914 XmlUtils.nextElement(parser); 1915 if (!"device".equals(parser.getName())) { 1916 break; 1917 } 1918 String name = parser.getAttributeValue(null, "name"); 1919 if (name != null) { 1920 names.add(name); 1921 } 1922 } 1923 } catch (FileNotFoundException e) { 1924 // It's ok if the file does not exist. 1925 } catch (Exception e) { 1926 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e); 1927 } finally { 1928 try { if (confreader != null) confreader.close(); } catch (IOException e) { } 1929 } 1930 1931 return names.toArray(new String[names.size()]); 1932 } 1933 1934 // Native callback. 1935 private int getKeyRepeatTimeout() { 1936 return ViewConfiguration.getKeyRepeatTimeout(); 1937 } 1938 1939 // Native callback. 1940 private int getKeyRepeatDelay() { 1941 return ViewConfiguration.getKeyRepeatDelay(); 1942 } 1943 1944 // Native callback. 1945 private int getHoverTapTimeout() { 1946 return ViewConfiguration.getHoverTapTimeout(); 1947 } 1948 1949 // Native callback. 1950 private int getHoverTapSlop() { 1951 return ViewConfiguration.getHoverTapSlop(); 1952 } 1953 1954 // Native callback. 1955 private int getDoubleTapTimeout() { 1956 return ViewConfiguration.getDoubleTapTimeout(); 1957 } 1958 1959 // Native callback. 1960 private int getLongPressTimeout() { 1961 return ViewConfiguration.getLongPressTimeout(); 1962 } 1963 1964 // Native callback. 1965 private int getPointerLayer() { 1966 return mWindowManagerCallbacks.getPointerLayer(); 1967 } 1968 1969 // Native callback. 1970 private PointerIcon getPointerIcon() { 1971 return PointerIcon.getDefaultIcon(mContext); 1972 } 1973 1974 // Native callback. 1975 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) { 1976 if (!mSystemReady) { 1977 return null; 1978 } 1979 1980 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier); 1981 if (keyboardLayoutDescriptor == null) { 1982 return null; 1983 } 1984 1985 final String[] result = new String[2]; 1986 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 1987 @Override 1988 public void visitKeyboardLayout(Resources resources, 1989 int keyboardLayoutResId, KeyboardLayout layout) { 1990 try { 1991 result[0] = layout.getDescriptor(); 1992 result[1] = Streams.readFully(new InputStreamReader( 1993 resources.openRawResource(keyboardLayoutResId))); 1994 } catch (IOException ex) { 1995 } catch (NotFoundException ex) { 1996 } 1997 } 1998 }); 1999 if (result[0] == null) { 2000 Slog.w(TAG, "Could not get keyboard layout with descriptor '" 2001 + keyboardLayoutDescriptor + "'."); 2002 return null; 2003 } 2004 return result; 2005 } 2006 2007 // Native callback. 2008 private String getDeviceAlias(String uniqueId) { 2009 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) { 2010 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId) 2011 return null; 2012 } 2013 return null; 2014 } 2015 2016 /** 2017 * Callback interface implemented by the Window Manager. 2018 */ 2019 public interface WindowManagerCallbacks { 2020 public void notifyConfigurationChanged(); 2021 2022 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen); 2023 2024 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered); 2025 2026 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle); 2027 2028 public long notifyANR(InputApplicationHandle inputApplicationHandle, 2029 InputWindowHandle inputWindowHandle, String reason); 2030 2031 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags); 2032 2033 public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags); 2034 2035 public long interceptKeyBeforeDispatching(InputWindowHandle focus, 2036 KeyEvent event, int policyFlags); 2037 2038 public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, 2039 KeyEvent event, int policyFlags); 2040 2041 public int getPointerLayer(); 2042 } 2043 2044 /** 2045 * Callback interface implemented by WiredAccessoryObserver. 2046 */ 2047 public interface WiredAccessoryCallbacks { 2048 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask); 2049 public void systemReady(); 2050 } 2051 2052 /** 2053 * Private handler for the input manager. 2054 */ 2055 private final class InputManagerHandler extends Handler { 2056 public InputManagerHandler(Looper looper) { 2057 super(looper, null, true /*async*/); 2058 } 2059 2060 @Override 2061 public void handleMessage(Message msg) { 2062 switch (msg.what) { 2063 case MSG_DELIVER_INPUT_DEVICES_CHANGED: 2064 deliverInputDevicesChanged((InputDevice[])msg.obj); 2065 break; 2066 case MSG_SWITCH_KEYBOARD_LAYOUT: { 2067 SomeArgs args = (SomeArgs)msg.obj; 2068 handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1, 2069 (InputMethodSubtypeHandle)args.arg2); 2070 break; 2071 } 2072 case MSG_RELOAD_KEYBOARD_LAYOUTS: 2073 reloadKeyboardLayouts(); 2074 break; 2075 case MSG_UPDATE_KEYBOARD_LAYOUTS: 2076 updateKeyboardLayouts(); 2077 break; 2078 case MSG_RELOAD_DEVICE_ALIASES: 2079 reloadDeviceAliases(); 2080 break; 2081 case MSG_DELIVER_TABLET_MODE_CHANGED: { 2082 SomeArgs args = (SomeArgs) msg.obj; 2083 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32); 2084 boolean inTabletMode = (boolean) args.arg1; 2085 deliverTabletModeChanged(whenNanos, inTabletMode); 2086 break; 2087 } 2088 case MSG_INPUT_METHOD_SUBTYPE_CHANGED: { 2089 final int userId = msg.arg1; 2090 final SomeArgs args = (SomeArgs) msg.obj; 2091 final InputMethodInfo inputMethodInfo = (InputMethodInfo) args.arg1; 2092 final InputMethodSubtype subtype = (InputMethodSubtype) args.arg2; 2093 args.recycle(); 2094 handleSwitchInputMethodSubtype(userId, inputMethodInfo, subtype); 2095 break; 2096 } 2097 } 2098 } 2099 } 2100 2101 /** 2102 * Hosting interface for input filters to call back into the input manager. 2103 */ 2104 private final class InputFilterHost extends IInputFilterHost.Stub { 2105 private boolean mDisconnected; 2106 2107 public void disconnectLocked() { 2108 mDisconnected = true; 2109 } 2110 2111 @Override 2112 public void sendInputEvent(InputEvent event, int policyFlags) { 2113 if (event == null) { 2114 throw new IllegalArgumentException("event must not be null"); 2115 } 2116 2117 synchronized (mInputFilterLock) { 2118 if (!mDisconnected) { 2119 nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0, 2120 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0, 2121 policyFlags | WindowManagerPolicy.FLAG_FILTERED); 2122 } 2123 } 2124 } 2125 } 2126 2127 private static final class KeyboardLayoutDescriptor { 2128 public String packageName; 2129 public String receiverName; 2130 public String keyboardLayoutName; 2131 2132 public static String format(String packageName, 2133 String receiverName, String keyboardName) { 2134 return packageName + "/" + receiverName + "/" + keyboardName; 2135 } 2136 2137 public static KeyboardLayoutDescriptor parse(String descriptor) { 2138 int pos = descriptor.indexOf('/'); 2139 if (pos < 0 || pos + 1 == descriptor.length()) { 2140 return null; 2141 } 2142 int pos2 = descriptor.indexOf('/', pos + 1); 2143 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) { 2144 return null; 2145 } 2146 2147 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor(); 2148 result.packageName = descriptor.substring(0, pos); 2149 result.receiverName = descriptor.substring(pos + 1, pos2); 2150 result.keyboardLayoutName = descriptor.substring(pos2 + 1); 2151 return result; 2152 } 2153 } 2154 2155 private interface KeyboardLayoutVisitor { 2156 void visitKeyboardLayout(Resources resources, 2157 int keyboardLayoutResId, KeyboardLayout layout); 2158 } 2159 2160 private final class InputDevicesChangedListenerRecord implements DeathRecipient { 2161 private final int mPid; 2162 private final IInputDevicesChangedListener mListener; 2163 2164 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) { 2165 mPid = pid; 2166 mListener = listener; 2167 } 2168 2169 @Override 2170 public void binderDied() { 2171 if (DEBUG) { 2172 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died."); 2173 } 2174 onInputDevicesChangedListenerDied(mPid); 2175 } 2176 2177 public void notifyInputDevicesChanged(int[] info) { 2178 try { 2179 mListener.onInputDevicesChanged(info); 2180 } catch (RemoteException ex) { 2181 Slog.w(TAG, "Failed to notify process " 2182 + mPid + " that input devices changed, assuming it died.", ex); 2183 binderDied(); 2184 } 2185 } 2186 } 2187 2188 private final class TabletModeChangedListenerRecord implements DeathRecipient { 2189 private final int mPid; 2190 private final ITabletModeChangedListener mListener; 2191 2192 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) { 2193 mPid = pid; 2194 mListener = listener; 2195 } 2196 2197 @Override 2198 public void binderDied() { 2199 if (DEBUG) { 2200 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died."); 2201 } 2202 onTabletModeChangedListenerDied(mPid); 2203 } 2204 2205 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) { 2206 try { 2207 mListener.onTabletModeChanged(whenNanos, inTabletMode); 2208 } catch (RemoteException ex) { 2209 Slog.w(TAG, "Failed to notify process " + mPid + 2210 " that tablet mode changed, assuming it died.", ex); 2211 binderDied(); 2212 } 2213 } 2214 } 2215 2216 private final class VibratorToken implements DeathRecipient { 2217 public final int mDeviceId; 2218 public final IBinder mToken; 2219 public final int mTokenValue; 2220 2221 public boolean mVibrating; 2222 2223 public VibratorToken(int deviceId, IBinder token, int tokenValue) { 2224 mDeviceId = deviceId; 2225 mToken = token; 2226 mTokenValue = tokenValue; 2227 } 2228 2229 @Override 2230 public void binderDied() { 2231 if (DEBUG) { 2232 Slog.d(TAG, "Vibrator token died."); 2233 } 2234 onVibratorTokenDied(this); 2235 } 2236 } 2237 2238 private class Shell extends ShellCommand { 2239 @Override 2240 public int onCommand(String cmd) { 2241 return onShellCommand(this, cmd); 2242 } 2243 2244 @Override 2245 public void onHelp() { 2246 final PrintWriter pw = getOutPrintWriter(); 2247 pw.println("Input manager commands:"); 2248 pw.println(" help"); 2249 pw.println(" Print this help text."); 2250 pw.println(""); 2251 pw.println(" setlayout IME_ID IME_SUPTYPE_HASH_CODE" 2252 + " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR"); 2253 pw.println(" Sets a keyboard layout for a given IME subtype and input device pair"); 2254 } 2255 } 2256 2257 private final class LocalService extends InputManagerInternal { 2258 @Override 2259 public void setDisplayViewports( 2260 DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) { 2261 setDisplayViewportsInternal(defaultViewport, externalTouchViewport); 2262 } 2263 2264 @Override 2265 public boolean injectInputEvent(InputEvent event, int displayId, int mode) { 2266 return injectInputEventInternal(event, displayId, mode); 2267 } 2268 2269 @Override 2270 public void setInteractive(boolean interactive) { 2271 nativeSetInteractive(mPtr, interactive); 2272 } 2273 2274 @Override 2275 public void onInputMethodSubtypeChanged(int userId, 2276 @Nullable InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype subtype) { 2277 final SomeArgs someArgs = SomeArgs.obtain(); 2278 someArgs.arg1 = inputMethodInfo; 2279 someArgs.arg2 = subtype; 2280 mHandler.obtainMessage(MSG_INPUT_METHOD_SUBTYPE_CHANGED, userId, 0, someArgs) 2281 .sendToTarget(); 2282 } 2283 2284 @Override 2285 public void toggleCapsLock(int deviceId) { 2286 nativeToggleCapsLock(mPtr, deviceId); 2287 } 2288 } 2289} 2290