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