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