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