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