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 static android.view.KeyEvent.KEYCODE_UNKNOWN; 20 21 import android.Manifest; 22 import android.annotation.EnforcePermission; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.app.ActivityManagerInternal; 26 import android.app.Notification; 27 import android.app.NotificationManager; 28 import android.app.PendingIntent; 29 import android.bluetooth.BluetoothAdapter; 30 import android.bluetooth.BluetoothDevice; 31 import android.content.BroadcastReceiver; 32 import android.content.ComponentName; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.IntentFilter; 36 import android.content.pm.ActivityInfo; 37 import android.content.pm.ApplicationInfo; 38 import android.content.pm.PackageManager; 39 import android.content.pm.PackageManager.NameNotFoundException; 40 import android.content.pm.ResolveInfo; 41 import android.content.res.Resources; 42 import android.content.res.Resources.NotFoundException; 43 import android.content.res.TypedArray; 44 import android.content.res.XmlResourceParser; 45 import android.database.ContentObserver; 46 import android.graphics.PointF; 47 import android.hardware.SensorPrivacyManager; 48 import android.hardware.SensorPrivacyManager.Sensors; 49 import android.hardware.SensorPrivacyManagerInternal; 50 import android.hardware.display.DisplayManager; 51 import android.hardware.display.DisplayViewport; 52 import android.hardware.input.IInputDeviceBatteryListener; 53 import android.hardware.input.IInputDevicesChangedListener; 54 import android.hardware.input.IInputManager; 55 import android.hardware.input.IInputSensorEventListener; 56 import android.hardware.input.ITabletModeChangedListener; 57 import android.hardware.input.InputDeviceIdentifier; 58 import android.hardware.input.InputManager; 59 import android.hardware.input.InputManagerInternal; 60 import android.hardware.input.InputManagerInternal.LidSwitchCallback; 61 import android.hardware.input.InputSensorInfo; 62 import android.hardware.input.KeyboardLayout; 63 import android.hardware.input.TouchCalibration; 64 import android.hardware.lights.Light; 65 import android.hardware.lights.LightState; 66 import android.media.AudioManager; 67 import android.os.Binder; 68 import android.os.Bundle; 69 import android.os.CombinedVibration; 70 import android.os.Environment; 71 import android.os.Handler; 72 import android.os.IBinder; 73 import android.os.IInputConstants; 74 import android.os.IVibratorStateListener; 75 import android.os.InputEventInjectionResult; 76 import android.os.InputEventInjectionSync; 77 import android.os.LocaleList; 78 import android.os.Looper; 79 import android.os.Message; 80 import android.os.Process; 81 import android.os.RemoteCallbackList; 82 import android.os.RemoteException; 83 import android.os.ResultReceiver; 84 import android.os.ShellCallback; 85 import android.os.UserHandle; 86 import android.os.VibrationEffect; 87 import android.os.vibrator.StepSegment; 88 import android.os.vibrator.VibrationEffectSegment; 89 import android.provider.DeviceConfig; 90 import android.provider.Settings; 91 import android.provider.Settings.SettingNotFoundException; 92 import android.text.TextUtils; 93 import android.util.ArrayMap; 94 import android.util.Log; 95 import android.util.Slog; 96 import android.util.SparseArray; 97 import android.util.SparseBooleanArray; 98 import android.view.Display; 99 import android.view.IInputFilter; 100 import android.view.IInputFilterHost; 101 import android.view.IInputMonitorHost; 102 import android.view.InputApplicationHandle; 103 import android.view.InputChannel; 104 import android.view.InputDevice; 105 import android.view.InputEvent; 106 import android.view.InputMonitor; 107 import android.view.KeyEvent; 108 import android.view.PointerIcon; 109 import android.view.Surface; 110 import android.view.SurfaceControl; 111 import android.view.VerifiedInputEvent; 112 import android.view.ViewConfiguration; 113 import android.widget.Toast; 114 115 import com.android.internal.R; 116 import com.android.internal.annotations.GuardedBy; 117 import com.android.internal.annotations.VisibleForTesting; 118 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 119 import com.android.internal.notification.SystemNotificationChannels; 120 import com.android.internal.os.SomeArgs; 121 import com.android.internal.util.ArrayUtils; 122 import com.android.internal.util.DumpUtils; 123 import com.android.internal.util.Preconditions; 124 import com.android.internal.util.XmlUtils; 125 import com.android.server.DisplayThread; 126 import com.android.server.LocalServices; 127 import com.android.server.Watchdog; 128 import com.android.server.policy.WindowManagerPolicy; 129 130 import libcore.io.IoUtils; 131 import libcore.io.Streams; 132 133 import java.io.File; 134 import java.io.FileDescriptor; 135 import java.io.FileInputStream; 136 import java.io.FileNotFoundException; 137 import java.io.FileWriter; 138 import java.io.IOException; 139 import java.io.InputStream; 140 import java.io.InputStreamReader; 141 import java.io.PrintWriter; 142 import java.util.ArrayList; 143 import java.util.Arrays; 144 import java.util.Collections; 145 import java.util.HashMap; 146 import java.util.HashSet; 147 import java.util.List; 148 import java.util.Locale; 149 import java.util.Map; 150 import java.util.Objects; 151 import java.util.OptionalInt; 152 import java.util.function.Consumer; 153 154 /** The system implementation of {@link IInputManager} that manages input devices. */ 155 public class InputManagerService extends IInputManager.Stub 156 implements Watchdog.Monitor { 157 static final String TAG = "InputManager"; 158 static final boolean DEBUG = false; 159 160 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; 161 private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml"; 162 163 // Feature flag name for the deep press feature 164 private static final String DEEP_PRESS_ENABLED = "deep_press_enabled"; 165 166 private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1; 167 private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2; 168 private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3; 169 private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4; 170 private static final int MSG_RELOAD_DEVICE_ALIASES = 5; 171 private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6; 172 private static final int MSG_POINTER_DISPLAY_ID_CHANGED = 7; 173 174 private static final int DEFAULT_VIBRATION_MAGNITUDE = 192; 175 private static final AdditionalDisplayInputProperties 176 DEFAULT_ADDITIONAL_DISPLAY_INPUT_PROPERTIES = new AdditionalDisplayInputProperties(); 177 178 /** 179 * We know the issue and are working to fix it, so suppressing the toast to not annoy 180 * dogfooders. 181 * 182 * TODO(b/169067926): Remove this 183 */ 184 private static final String[] PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST = { 185 "com.snapchat.android" // b/173297887 186 }; 187 188 /** TODO(b/169067926): Remove this. */ 189 private static final boolean UNTRUSTED_TOUCHES_TOAST = false; 190 191 private final NativeInputManagerService mNative; 192 193 private final Context mContext; 194 private final InputManagerHandler mHandler; 195 196 // Context cache used for loading pointer resources. 197 private Context mPointerIconDisplayContext; 198 199 private final File mDoubleTouchGestureEnableFile; 200 201 private WindowManagerCallbacks mWindowManagerCallbacks; 202 private WiredAccessoryCallbacks mWiredAccessoryCallbacks; 203 private boolean mSystemReady; 204 private NotificationManager mNotificationManager; 205 206 private final Object mTabletModeLock = new Object(); 207 // List of currently registered tablet mode changed listeners by process id 208 @GuardedBy("mTabletModeLock") 209 private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners = 210 new SparseArray<>(); 211 private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify = 212 new ArrayList<>(); 213 214 private final Object mSensorEventLock = new Object(); 215 // List of currently registered sensor event listeners by process id 216 @GuardedBy("mSensorEventLock") 217 private final SparseArray<SensorEventListenerRecord> mSensorEventListeners = 218 new SparseArray<>(); 219 private final List<SensorEventListenerRecord> mSensorEventListenersToNotify = 220 new ArrayList<>(); 221 private final List<SensorEventListenerRecord> mSensorAccuracyListenersToNotify = 222 new ArrayList<>(); 223 224 // Persistent data store. Must be locked each time during use. 225 private final PersistentDataStore mDataStore = new PersistentDataStore(); 226 227 // List of currently registered input devices changed listeners by process id. 228 private final Object mInputDevicesLock = new Object(); 229 @GuardedBy("mInputDevicesLock") 230 private boolean mInputDevicesChangedPending; 231 @GuardedBy("mInputDevicesLock") 232 private InputDevice[] mInputDevices = new InputDevice[0]; 233 @GuardedBy("mInputDevicesLock") 234 private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners = 235 new SparseArray<>(); 236 private final ArrayList<InputDevicesChangedListenerRecord> 237 mTempInputDevicesChangedListenersToNotify = new ArrayList<>(); // handler thread only 238 private final ArrayList<InputDevice> mTempFullKeyboards = 239 new ArrayList<>(); // handler thread only 240 private boolean mKeyboardLayoutNotificationShown; 241 private Toast mSwitchedKeyboardLayoutToast; 242 243 // State for vibrator tokens. 244 private final Object mVibratorLock = new Object(); 245 private final Map<IBinder, VibratorToken> mVibratorTokens = new ArrayMap<>(); 246 private int mNextVibratorTokenValue; 247 248 // List of currently registered vibrator state changed listeners by device id. 249 @GuardedBy("mVibratorLock") 250 private final SparseArray<RemoteCallbackList<IVibratorStateListener>> mVibratorStateListeners = 251 new SparseArray<>(); 252 // List of vibrator states by device id. 253 @GuardedBy("mVibratorLock") 254 private final SparseBooleanArray mIsVibrating = new SparseBooleanArray(); 255 private final Object mLightLock = new Object(); 256 // State for light tokens. A light token marks a lights manager session, it is generated 257 // by light session open() and deleted in session close(). 258 // When lights session requests light states, the token will be used to find the light session. 259 @GuardedBy("mLightLock") 260 private final ArrayMap<IBinder, LightSession> mLightSessions = new ArrayMap<>(); 261 262 // State for lid switch 263 // Lock for the lid switch state. Held when triggering callbacks to guarantee lid switch events 264 // are delivered in order. For ex, when a new lid switch callback is registered the lock is held 265 // while the callback is processing the initial lid switch event which guarantees that any 266 // events that occur at the same time are delivered after the callback has returned. 267 private final Object mLidSwitchLock = new Object(); 268 @GuardedBy("mLidSwitchLock") 269 private final List<LidSwitchCallback> mLidSwitchCallbacks = new ArrayList<>(); 270 271 // State for the currently installed input filter. 272 final Object mInputFilterLock = new Object(); 273 @GuardedBy("mInputFilterLock") 274 IInputFilter mInputFilter; 275 @GuardedBy("mInputFilterLock") 276 InputFilterHost mInputFilterHost; 277 278 // The associations of input devices to displays by port. Maps from input device port (String) 279 // to display id (int). Currently only accessed by InputReader. 280 private final Map<String, Integer> mStaticAssociations; 281 private final Object mAssociationsLock = new Object(); 282 @GuardedBy("mAssociationLock") 283 private final Map<String, Integer> mRuntimeAssociations = new ArrayMap<>(); 284 @GuardedBy("mAssociationLock") 285 private final Map<String, String> mUniqueIdAssociations = new ArrayMap<>(); 286 287 // Guards per-display input properties and properties relating to the mouse pointer. 288 // Threads can wait on this lock to be notified the next time the display on which the mouse 289 // pointer is shown has changed. 290 // WARNING: Do not call other services outside of input while holding this lock. 291 private final Object mAdditionalDisplayInputPropertiesLock = new Object(); 292 293 // Forces the PointerController to target a specific display id. 294 @GuardedBy("mAdditionalDisplayInputPropertiesLock") 295 private int mOverriddenPointerDisplayId = Display.INVALID_DISPLAY; 296 297 // PointerController is the source of truth of the pointer display. This is the value of the 298 // latest pointer display id reported by PointerController. 299 @GuardedBy("mAdditionalDisplayInputPropertiesLock") 300 private int mAcknowledgedPointerDisplayId = Display.INVALID_DISPLAY; 301 // This is the latest display id that IMS has requested PointerController to use. If there are 302 // no devices that can control the pointer, PointerController may end up disregarding this 303 // value. 304 @GuardedBy("mAdditionalDisplayInputPropertiesLock") 305 private int mRequestedPointerDisplayId = Display.INVALID_DISPLAY; 306 @GuardedBy("mAdditionalDisplayInputPropertiesLock") 307 private final SparseArray<AdditionalDisplayInputProperties> mAdditionalDisplayInputProperties = 308 new SparseArray<>(); 309 // This contains the per-display properties that are currently applied by native code. It should 310 // be kept in sync with the properties for mRequestedPointerDisplayId. 311 @GuardedBy("mAdditionalDisplayInputPropertiesLock") 312 private final AdditionalDisplayInputProperties mCurrentDisplayProperties = 313 new AdditionalDisplayInputProperties(); 314 @GuardedBy("mAdditionalDisplayInputPropertiesLock") 315 private int mIconType = PointerIcon.TYPE_NOT_SPECIFIED; 316 @GuardedBy("mAdditionalDisplayInputPropertiesLock") 317 private PointerIcon mIcon; 318 319 // Holds all the registered gesture monitors that are implemented as spy windows. The spy 320 // windows are mapped by their InputChannel tokens. 321 @GuardedBy("mInputMonitors") 322 final Map<IBinder, GestureMonitorSpyWindow> mInputMonitors = new HashMap<>(); 323 324 // Manages battery state for input devices. 325 private final BatteryController mBatteryController; 326 327 // Maximum number of milliseconds to wait for input event injection. 328 private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000; 329 330 // Key states (may be returned by queries about the current state of a 331 // particular key code, scan code or switch). 332 333 /** The key state is unknown or the requested key itself is not supported. */ 334 public static final int KEY_STATE_UNKNOWN = -1; 335 336 /** The key is up. /*/ 337 public static final int KEY_STATE_UP = 0; 338 339 /** The key is down. */ 340 public static final int KEY_STATE_DOWN = 1; 341 342 /** The key is down but is a virtual key press that is being emulated by the system. */ 343 public static final int KEY_STATE_VIRTUAL = 2; 344 345 /** Scan code: Mouse / trackball button. */ 346 public static final int BTN_MOUSE = 0x110; 347 348 // Switch code values must match bionic/libc/kernel/common/linux/input.h 349 /** Switch code: Lid switch. When set, lid is shut. */ 350 public static final int SW_LID = 0x00; 351 352 /** Switch code: Tablet mode switch. 353 * When set, the device is in tablet mode (i.e. no keyboard is connected). 354 */ 355 public static final int SW_TABLET_MODE = 0x01; 356 357 /** Switch code: Keypad slide. When set, keyboard is exposed. */ 358 public static final int SW_KEYPAD_SLIDE = 0x0a; 359 360 /** Switch code: Headphone. When set, headphone is inserted. */ 361 public static final int SW_HEADPHONE_INSERT = 0x02; 362 363 /** Switch code: Microphone. When set, microphone is inserted. */ 364 public static final int SW_MICROPHONE_INSERT = 0x04; 365 366 /** Switch code: Line out. When set, Line out (hi-Z) is inserted. */ 367 public static final int SW_LINEOUT_INSERT = 0x06; 368 369 /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */ 370 public static final int SW_JACK_PHYSICAL_INSERT = 0x07; 371 372 /** Switch code: Camera lens cover. When set the lens is covered. */ 373 public static final int SW_CAMERA_LENS_COVER = 0x09; 374 375 /** Switch code: Microphone. When set it is off. */ 376 public static final int SW_MUTE_DEVICE = 0x0e; 377 378 public static final int SW_LID_BIT = 1 << SW_LID; 379 public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE; 380 public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE; 381 public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT; 382 public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT; 383 public static final int SW_LINEOUT_INSERT_BIT = 1 << SW_LINEOUT_INSERT; 384 public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT; 385 public static final int SW_JACK_BITS = 386 SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT; 387 public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER; 388 public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE; 389 390 /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */ 391 final boolean mUseDevInputEventForAudioJack; 392 393 /** Point of injection for test dependencies. */ 394 @VisibleForTesting 395 static class Injector { 396 private final Context mContext; 397 private final Looper mLooper; 398 Injector(Context context, Looper looper)399 Injector(Context context, Looper looper) { 400 mContext = context; 401 mLooper = looper; 402 } 403 getContext()404 Context getContext() { 405 return mContext; 406 } 407 getLooper()408 Looper getLooper() { 409 return mLooper; 410 } 411 getNativeService(InputManagerService service)412 NativeInputManagerService getNativeService(InputManagerService service) { 413 return new NativeInputManagerService.NativeImpl(service, mContext, mLooper.getQueue()); 414 } 415 registerLocalService(InputManagerInternal localService)416 void registerLocalService(InputManagerInternal localService) { 417 LocalServices.addService(InputManagerInternal.class, localService); 418 } 419 } 420 InputManagerService(Context context)421 public InputManagerService(Context context) { 422 this(new Injector(context, DisplayThread.get().getLooper())); 423 } 424 425 @VisibleForTesting InputManagerService(Injector injector)426 InputManagerService(Injector injector) { 427 // The static association map is accessed by both java and native code, so it must be 428 // initialized before initializing the native service. 429 mStaticAssociations = loadStaticInputPortAssociations(); 430 431 mContext = injector.getContext(); 432 mHandler = new InputManagerHandler(injector.getLooper()); 433 mNative = injector.getNativeService(this); 434 mBatteryController = new BatteryController(mContext, mNative); 435 436 mUseDevInputEventForAudioJack = 437 mContext.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); 438 Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack=" 439 + mUseDevInputEventForAudioJack); 440 441 String doubleTouchGestureEnablePath = mContext.getResources().getString( 442 R.string.config_doubleTouchGestureEnableFile); 443 mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null : 444 new File(doubleTouchGestureEnablePath); 445 446 injector.registerLocalService(new LocalService()); 447 } 448 setWindowManagerCallbacks(WindowManagerCallbacks callbacks)449 public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) { 450 if (mWindowManagerCallbacks != null) { 451 unregisterLidSwitchCallbackInternal(mWindowManagerCallbacks); 452 } 453 mWindowManagerCallbacks = callbacks; 454 registerLidSwitchCallbackInternal(mWindowManagerCallbacks); 455 } 456 setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks)457 public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) { 458 mWiredAccessoryCallbacks = callbacks; 459 } 460 registerLidSwitchCallbackInternal(@onNull LidSwitchCallback callback)461 void registerLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) { 462 synchronized (mLidSwitchLock) { 463 mLidSwitchCallbacks.add(callback); 464 465 // Skip triggering the initial callback if the system is not yet ready as the switch 466 // state will be reported as KEY_STATE_UNKNOWN. The callback will be triggered in 467 // systemRunning(). 468 if (mSystemReady) { 469 boolean lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID) 470 == KEY_STATE_UP; 471 callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen); 472 } 473 } 474 } 475 unregisterLidSwitchCallbackInternal(@onNull LidSwitchCallback callback)476 void unregisterLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) { 477 synchronized (mLidSwitchLock) { 478 mLidSwitchCallbacks.remove(callback); 479 } 480 } 481 start()482 public void start() { 483 Slog.i(TAG, "Starting input manager"); 484 mNative.start(); 485 486 // Add ourselves to the Watchdog monitors. 487 Watchdog.getInstance().addMonitor(this); 488 489 registerPointerSpeedSettingObserver(); 490 registerShowTouchesSettingObserver(); 491 registerAccessibilityLargePointerSettingObserver(); 492 registerLongPressTimeoutObserver(); 493 registerMaximumObscuringOpacityForTouchSettingObserver(); 494 registerBlockUntrustedTouchesModeSettingObserver(); 495 496 mContext.registerReceiver(new BroadcastReceiver() { 497 @Override 498 public void onReceive(Context context, Intent intent) { 499 updatePointerSpeedFromSettings(); 500 updateShowTouchesFromSettings(); 501 updateAccessibilityLargePointerFromSettings(); 502 updateDeepPressStatusFromSettings("user switched"); 503 } 504 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler); 505 506 updatePointerSpeedFromSettings(); 507 updateShowTouchesFromSettings(); 508 updateAccessibilityLargePointerFromSettings(); 509 updateDeepPressStatusFromSettings("just booted"); 510 updateMaximumObscuringOpacityForTouchFromSettings(); 511 updateBlockUntrustedTouchesModeFromSettings(); 512 } 513 514 // TODO(BT) Pass in parameter for bluetooth system systemRunning()515 public void systemRunning() { 516 if (DEBUG) { 517 Slog.d(TAG, "System ready."); 518 } 519 mNotificationManager = (NotificationManager)mContext.getSystemService( 520 Context.NOTIFICATION_SERVICE); 521 522 synchronized (mLidSwitchLock) { 523 mSystemReady = true; 524 525 // Send the initial lid switch state to any callback registered before the system was 526 // ready. 527 int switchState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID); 528 for (int i = 0; i < mLidSwitchCallbacks.size(); i++) { 529 LidSwitchCallback callback = mLidSwitchCallbacks.get(i); 530 callback.notifyLidSwitchChanged(0 /* whenNanos */, switchState == KEY_STATE_UP); 531 } 532 } 533 534 // Set the HW mic toggle switch state 535 final int micMuteState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, 536 SW_MUTE_DEVICE); 537 if (micMuteState != InputManager.SWITCH_STATE_UNKNOWN) { 538 setSensorPrivacy(Sensors.MICROPHONE, micMuteState != InputManager.SWITCH_STATE_OFF); 539 } 540 // Set the HW camera toggle switch state 541 final int cameraMuteState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, 542 SW_CAMERA_LENS_COVER); 543 if (cameraMuteState != InputManager.SWITCH_STATE_UNKNOWN) { 544 setSensorPrivacy(Sensors.CAMERA, cameraMuteState != InputManager.SWITCH_STATE_OFF); 545 } 546 547 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); 548 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 549 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 550 filter.addAction(Intent.ACTION_PACKAGE_REPLACED); 551 filter.addDataScheme("package"); 552 mContext.registerReceiver(new BroadcastReceiver() { 553 @Override 554 public void onReceive(Context context, Intent intent) { 555 updateKeyboardLayouts(); 556 } 557 }, filter, null, mHandler); 558 559 filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED); 560 mContext.registerReceiver(new BroadcastReceiver() { 561 @Override 562 public void onReceive(Context context, Intent intent) { 563 reloadDeviceAliases(); 564 } 565 }, filter, null, mHandler); 566 567 mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES); 568 mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS); 569 570 if (mWiredAccessoryCallbacks != null) { 571 mWiredAccessoryCallbacks.systemReady(); 572 } 573 } 574 reloadKeyboardLayouts()575 private void reloadKeyboardLayouts() { 576 if (DEBUG) { 577 Slog.d(TAG, "Reloading keyboard layouts."); 578 } 579 mNative.reloadKeyboardLayouts(); 580 } 581 reloadDeviceAliases()582 private void reloadDeviceAliases() { 583 if (DEBUG) { 584 Slog.d(TAG, "Reloading device names."); 585 } 586 mNative.reloadDeviceAliases(); 587 } 588 setDisplayViewportsInternal(List<DisplayViewport> viewports)589 private void setDisplayViewportsInternal(List<DisplayViewport> viewports) { 590 final DisplayViewport[] vArray = new DisplayViewport[viewports.size()]; 591 for (int i = viewports.size() - 1; i >= 0; --i) { 592 vArray[i] = viewports.get(i); 593 } 594 mNative.setDisplayViewports(vArray); 595 596 // Attempt to update the pointer display when viewports change when there is no override. 597 // Take care to not make calls to window manager while holding internal locks. 598 final int pointerDisplayId = mWindowManagerCallbacks.getPointerDisplayId(); 599 synchronized (mAdditionalDisplayInputPropertiesLock) { 600 if (mOverriddenPointerDisplayId == Display.INVALID_DISPLAY) { 601 updatePointerDisplayIdLocked(pointerDisplayId); 602 } 603 } 604 } 605 606 /** 607 * Gets the current state of a key or button by key code. 608 * @param deviceId The input device id, or -1 to consult all devices. 609 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 610 * consider all input sources. An input device is consulted if at least one of its 611 * non-class input source bits matches the specified source mask. 612 * @param keyCode The key code to check. 613 * @return The key state. 614 */ getKeyCodeState(int deviceId, int sourceMask, int keyCode)615 public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) { 616 return mNative.getKeyCodeState(deviceId, sourceMask, keyCode); 617 } 618 619 /** 620 * Gets the current state of a key or button by scan code. 621 * @param deviceId The input device id, or -1 to consult all devices. 622 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 623 * consider all input sources. An input device is consulted if at least one of its 624 * non-class input source bits matches the specified source mask. 625 * @param scanCode The scan code to check. 626 * @return The key state. 627 */ getScanCodeState(int deviceId, int sourceMask, int scanCode)628 public int getScanCodeState(int deviceId, int sourceMask, int scanCode) { 629 return mNative.getScanCodeState(deviceId, sourceMask, scanCode); 630 } 631 632 /** 633 * Gets the current state of a switch by switch code. 634 * @param deviceId The input device id, or -1 to consult all devices. 635 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 636 * consider all input sources. An input device is consulted if at least one of its 637 * non-class input source bits matches the specified source mask. 638 * @param switchCode The switch code to check. 639 * @return The switch state. 640 */ getSwitchState(int deviceId, int sourceMask, int switchCode)641 public int getSwitchState(int deviceId, int sourceMask, int switchCode) { 642 return mNative.getSwitchState(deviceId, sourceMask, switchCode); 643 } 644 645 /** 646 * Determines whether the specified key codes are supported by a particular device. 647 * @param deviceId The input device id, or -1 to consult all devices. 648 * @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to 649 * consider all input sources. An input device is consulted if at least one of its 650 * non-class input source bits matches the specified source mask. 651 * @param keyCodes The array of key codes to check. 652 * @param keyExists An array at least as large as keyCodes whose entries will be set 653 * to true or false based on the presence or absence of support for the corresponding 654 * key codes. 655 * @return True if the lookup was successful, false otherwise. 656 */ 657 @Override // Binder call hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists)658 public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) { 659 Objects.requireNonNull(keyCodes, "keyCodes must not be null"); 660 Objects.requireNonNull(keyExists, "keyExists must not be null"); 661 if (keyExists.length < keyCodes.length) { 662 throw new IllegalArgumentException("keyExists must be at least as large as keyCodes"); 663 } 664 665 return mNative.hasKeys(deviceId, sourceMask, keyCodes, keyExists); 666 } 667 668 /** 669 * Returns the keyCode generated by the specified location on a US keyboard layout. 670 * This takes into consideration the currently active keyboard layout. 671 * 672 * @param deviceId The input device id. 673 * @param locationKeyCode The location of a key on a US keyboard layout. 674 * @return The KeyCode this physical key location produces. 675 */ 676 @Override // Binder call getKeyCodeForKeyLocation(int deviceId, int locationKeyCode)677 public int getKeyCodeForKeyLocation(int deviceId, int locationKeyCode) { 678 if (locationKeyCode <= KEYCODE_UNKNOWN || locationKeyCode > KeyEvent.getMaxKeyCode()) { 679 return KEYCODE_UNKNOWN; 680 } 681 return mNative.getKeyCodeForKeyLocation(deviceId, locationKeyCode); 682 } 683 684 /** 685 * Transfer the current touch gesture to the provided window. 686 * 687 * @param destChannelToken The token of the window or input channel that should receive the 688 * gesture 689 * @return True if the transfer succeeded, false if there was no active touch gesture happening 690 */ transferTouch(IBinder destChannelToken, int displayId)691 public boolean transferTouch(IBinder destChannelToken, int displayId) { 692 // TODO(b/162194035): Replace this with a SPY window 693 Objects.requireNonNull(destChannelToken, "destChannelToken must not be null"); 694 return mNative.transferTouch(destChannelToken, displayId); 695 } 696 697 /** 698 * Creates an input channel that will receive all input from the input dispatcher. 699 * @param inputChannelName The input channel name. 700 * @param displayId Target display id. 701 * @return The input channel. 702 */ monitorInput(String inputChannelName, int displayId)703 public InputChannel monitorInput(String inputChannelName, int displayId) { 704 Objects.requireNonNull(inputChannelName, "inputChannelName not be null"); 705 706 if (displayId < Display.DEFAULT_DISPLAY) { 707 throw new IllegalArgumentException("displayId must >= 0."); 708 } 709 710 return mNative.createInputMonitor(displayId, inputChannelName, Binder.getCallingPid()); 711 } 712 713 @NonNull createSpyWindowGestureMonitor(IBinder monitorToken, String name, int displayId, int pid, int uid)714 private InputChannel createSpyWindowGestureMonitor(IBinder monitorToken, String name, 715 int displayId, int pid, int uid) { 716 final SurfaceControl sc = mWindowManagerCallbacks.createSurfaceForGestureMonitor(name, 717 displayId); 718 if (sc == null) { 719 throw new IllegalArgumentException( 720 "Could not create gesture monitor surface on display: " + displayId); 721 } 722 final InputChannel channel = createInputChannel(name); 723 724 try { 725 monitorToken.linkToDeath(() -> removeSpyWindowGestureMonitor(channel.getToken()), 0); 726 } catch (RemoteException e) { 727 Slog.i(TAG, "Client died before '" + name + "' could be created."); 728 return null; 729 } 730 synchronized (mInputMonitors) { 731 mInputMonitors.put(channel.getToken(), 732 new GestureMonitorSpyWindow(monitorToken, name, displayId, pid, uid, sc, 733 channel)); 734 } 735 736 final InputChannel outInputChannel = new InputChannel(); 737 channel.copyTo(outInputChannel); 738 return outInputChannel; 739 } 740 removeSpyWindowGestureMonitor(IBinder inputChannelToken)741 private void removeSpyWindowGestureMonitor(IBinder inputChannelToken) { 742 final GestureMonitorSpyWindow monitor; 743 synchronized (mInputMonitors) { 744 monitor = mInputMonitors.remove(inputChannelToken); 745 } 746 removeInputChannel(inputChannelToken); 747 if (monitor == null) return; 748 monitor.remove(); 749 } 750 751 /** 752 * Creates an input monitor that will receive pointer events for the purposes of system-wide 753 * gesture interpretation. 754 * 755 * @param requestedName The input channel name. 756 * @param displayId Target display id. 757 * @return The input channel. 758 */ 759 @Override // Binder call monitorGestureInput(IBinder monitorToken, @NonNull String requestedName, int displayId)760 public InputMonitor monitorGestureInput(IBinder monitorToken, @NonNull String requestedName, 761 int displayId) { 762 if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT, 763 "monitorGestureInput()")) { 764 throw new SecurityException("Requires MONITOR_INPUT permission"); 765 } 766 Objects.requireNonNull(requestedName, "name must not be null."); 767 Objects.requireNonNull(monitorToken, "token must not be null."); 768 769 if (displayId < Display.DEFAULT_DISPLAY) { 770 throw new IllegalArgumentException("displayId must >= 0."); 771 } 772 final String name = "[Gesture Monitor] " + requestedName; 773 final int pid = Binder.getCallingPid(); 774 final int uid = Binder.getCallingUid(); 775 776 final long ident = Binder.clearCallingIdentity(); 777 try { 778 final InputChannel inputChannel = 779 createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid); 780 return new InputMonitor(inputChannel, new InputMonitorHost(inputChannel.getToken())); 781 } finally { 782 Binder.restoreCallingIdentity(ident); 783 } 784 } 785 786 /** 787 * Creates an input channel to be used as an input event target. 788 * 789 * @param name The name of this input channel 790 */ createInputChannel(String name)791 public InputChannel createInputChannel(String name) { 792 return mNative.createInputChannel(name); 793 } 794 795 /** 796 * Removes an input channel. 797 * @param connectionToken The input channel to unregister. 798 */ removeInputChannel(IBinder connectionToken)799 public void removeInputChannel(IBinder connectionToken) { 800 Objects.requireNonNull(connectionToken, "connectionToken must not be null"); 801 mNative.removeInputChannel(connectionToken); 802 } 803 804 /** 805 * Sets an input filter that will receive all input events before they are dispatched. 806 * The input filter may then reinterpret input events or inject new ones. 807 * 808 * To ensure consistency, the input dispatcher automatically drops all events 809 * in progress whenever an input filter is installed or uninstalled. After an input 810 * filter is uninstalled, it can no longer send input events unless it is reinstalled. 811 * Any events it attempts to send after it has been uninstalled will be dropped. 812 * 813 * @param filter The input filter, or null to remove the current filter. 814 */ setInputFilter(IInputFilter filter)815 public void setInputFilter(IInputFilter filter) { 816 synchronized (mInputFilterLock) { 817 final IInputFilter oldFilter = mInputFilter; 818 if (oldFilter == filter) { 819 return; // nothing to do 820 } 821 822 if (oldFilter != null) { 823 mInputFilter = null; 824 mInputFilterHost.disconnectLocked(); 825 mInputFilterHost = null; 826 try { 827 oldFilter.uninstall(); 828 } catch (RemoteException re) { 829 /* ignore */ 830 } 831 } 832 833 if (filter != null) { 834 mInputFilter = filter; 835 mInputFilterHost = new InputFilterHost(); 836 try { 837 filter.install(mInputFilterHost); 838 } catch (RemoteException re) { 839 /* ignore */ 840 } 841 } 842 843 mNative.setInputFilterEnabled(filter != null); 844 } 845 } 846 847 /** 848 * Set the state of the touch mode. 849 * 850 * WindowManager remains the source of truth of the touch mode state. 851 * However, we need to keep a copy of this state in input. 852 * 853 * The apps determine the touch mode state. Therefore, a single app will 854 * affect the global state. That state change needs to be propagated to 855 * other apps, when they become focused. 856 * 857 * When input dispatches focus to the apps, the touch mode state 858 * will be sent together with the focus change (but each one in its own event). 859 * 860 * @param inTouchMode true if the device is in touch mode 861 * @param pid the pid of the process that requested to switch touch mode state 862 * @param uid the uid of the process that requested to switch touch mode state 863 * @param hasPermission if set to {@code true} then no further authorization will be performed 864 * @return {@code true} if the touch mode was successfully changed, {@code false} otherwise 865 */ setInTouchMode(boolean inTouchMode, int pid, int uid, boolean hasPermission)866 public boolean setInTouchMode(boolean inTouchMode, int pid, int uid, boolean hasPermission) { 867 return mNative.setInTouchMode(inTouchMode, pid, uid, hasPermission); 868 } 869 870 @Override // Binder call injectInputEvent(InputEvent event, int mode)871 public boolean injectInputEvent(InputEvent event, int mode) { 872 return injectInputEventToTarget(event, mode, Process.INVALID_UID); 873 } 874 875 @Override // Binder call injectInputEventToTarget(InputEvent event, int mode, int targetUid)876 public boolean injectInputEventToTarget(InputEvent event, int mode, int targetUid) { 877 if (!checkCallingPermission(android.Manifest.permission.INJECT_EVENTS, 878 "injectInputEvent()", true /*checkInstrumentationSource*/)) { 879 throw new SecurityException( 880 "Injecting input events requires the caller (or the source of the " 881 + "instrumentation, if any) to have the INJECT_EVENTS permission."); 882 } 883 // We are not checking if targetUid matches the callingUid, since having the permission 884 // already means you can inject into any window. 885 Objects.requireNonNull(event, "event must not be null"); 886 if (mode != InputEventInjectionSync.NONE 887 && mode != InputEventInjectionSync.WAIT_FOR_FINISHED 888 && mode != InputEventInjectionSync.WAIT_FOR_RESULT) { 889 throw new IllegalArgumentException("mode is invalid"); 890 } 891 892 final int pid = Binder.getCallingPid(); 893 final long ident = Binder.clearCallingIdentity(); 894 final boolean injectIntoUid = targetUid != Process.INVALID_UID; 895 final int result; 896 try { 897 result = mNative.injectInputEvent(event, injectIntoUid, 898 targetUid, mode, INJECTION_TIMEOUT_MILLIS, 899 WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); 900 } finally { 901 Binder.restoreCallingIdentity(ident); 902 } 903 switch (result) { 904 case InputEventInjectionResult.SUCCEEDED: 905 return true; 906 case InputEventInjectionResult.TARGET_MISMATCH: 907 if (!injectIntoUid) { 908 throw new IllegalStateException("Injection should not result in TARGET_MISMATCH" 909 + " when it is not targeted into to a specific uid."); 910 } 911 // TODO(b/228161340): Remove the fallback of targeting injection into all windows 912 // when the caller has the injection permission. 913 // Explicitly maintain the same behavior as previous versions of Android, where 914 // injection is allowed into all windows if the caller has the INJECT_EVENTS 915 // permission, even if it is targeting a certain uid. 916 if (checkCallingPermission(android.Manifest.permission.INJECT_EVENTS, 917 "injectInputEvent-target-mismatch-fallback")) { 918 Slog.w(TAG, "Targeted input event was not directed at a window owned by uid " 919 + targetUid + ". Falling back to injecting into all windows."); 920 return injectInputEventToTarget(event, mode, Process.INVALID_UID); 921 } 922 throw new IllegalArgumentException( 923 "Targeted input event injection from pid " + pid 924 + " was not directed at a window owned by uid " 925 + targetUid + "."); 926 case InputEventInjectionResult.TIMED_OUT: 927 Slog.w(TAG, "Input event injection from pid " + pid + " timed out."); 928 return false; 929 case InputEventInjectionResult.FAILED: 930 default: 931 Slog.w(TAG, "Input event injection from pid " + pid + " failed."); 932 return false; 933 } 934 } 935 936 @Override // Binder call verifyInputEvent(InputEvent event)937 public VerifiedInputEvent verifyInputEvent(InputEvent event) { 938 Objects.requireNonNull(event, "event must not be null"); 939 return mNative.verifyInputEvent(event); 940 } 941 942 /** 943 * Gets information about the input device with the specified id. 944 * @param deviceId The device id. 945 * @return The input device or null if not found. 946 */ 947 @Override // Binder call getInputDevice(int deviceId)948 public InputDevice getInputDevice(int deviceId) { 949 synchronized (mInputDevicesLock) { 950 for (final InputDevice inputDevice : mInputDevices) { 951 if (inputDevice.getId() == deviceId) { 952 return inputDevice; 953 } 954 } 955 } 956 return null; 957 } 958 959 // Binder call 960 @Override isInputDeviceEnabled(int deviceId)961 public boolean isInputDeviceEnabled(int deviceId) { 962 return mNative.isInputDeviceEnabled(deviceId); 963 } 964 965 // Binder call 966 @Override enableInputDevice(int deviceId)967 public void enableInputDevice(int deviceId) { 968 if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE, 969 "enableInputDevice()")) { 970 throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission"); 971 } 972 mNative.enableInputDevice(deviceId); 973 } 974 975 // Binder call 976 @Override disableInputDevice(int deviceId)977 public void disableInputDevice(int deviceId) { 978 if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE, 979 "disableInputDevice()")) { 980 throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission"); 981 } 982 mNative.disableInputDevice(deviceId); 983 } 984 985 /** 986 * Gets the ids of all input devices in the system. 987 * @return The input device ids. 988 */ 989 @Override // Binder call getInputDeviceIds()990 public int[] getInputDeviceIds() { 991 synchronized (mInputDevicesLock) { 992 final int count = mInputDevices.length; 993 int[] ids = new int[count]; 994 for (int i = 0; i < count; i++) { 995 ids[i] = mInputDevices[i].getId(); 996 } 997 return ids; 998 } 999 } 1000 1001 /** 1002 * Gets all input devices in the system. 1003 * @return The array of input devices. 1004 */ getInputDevices()1005 public InputDevice[] getInputDevices() { 1006 synchronized (mInputDevicesLock) { 1007 return mInputDevices; 1008 } 1009 } 1010 1011 @Override // Binder call registerInputDevicesChangedListener(IInputDevicesChangedListener listener)1012 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) { 1013 Objects.requireNonNull(listener, "listener must not be null"); 1014 1015 synchronized (mInputDevicesLock) { 1016 int callingPid = Binder.getCallingPid(); 1017 if (mInputDevicesChangedListeners.get(callingPid) != null) { 1018 throw new SecurityException("The calling process has already " 1019 + "registered an InputDevicesChangedListener."); 1020 } 1021 1022 InputDevicesChangedListenerRecord record = 1023 new InputDevicesChangedListenerRecord(callingPid, listener); 1024 try { 1025 IBinder binder = listener.asBinder(); 1026 binder.linkToDeath(record, 0); 1027 } catch (RemoteException ex) { 1028 // give up 1029 throw new RuntimeException(ex); 1030 } 1031 1032 mInputDevicesChangedListeners.put(callingPid, record); 1033 } 1034 } 1035 onInputDevicesChangedListenerDied(int pid)1036 private void onInputDevicesChangedListenerDied(int pid) { 1037 synchronized (mInputDevicesLock) { 1038 mInputDevicesChangedListeners.remove(pid); 1039 } 1040 } 1041 1042 // Must be called on handler. deliverInputDevicesChanged(InputDevice[] oldInputDevices)1043 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) { 1044 // Scan for changes. 1045 int numFullKeyboardsAdded = 0; 1046 mTempInputDevicesChangedListenersToNotify.clear(); 1047 mTempFullKeyboards.clear(); 1048 final int numListeners; 1049 final int[] deviceIdAndGeneration; 1050 synchronized (mInputDevicesLock) { 1051 if (!mInputDevicesChangedPending) { 1052 return; 1053 } 1054 mInputDevicesChangedPending = false; 1055 1056 numListeners = mInputDevicesChangedListeners.size(); 1057 for (int i = 0; i < numListeners; i++) { 1058 mTempInputDevicesChangedListenersToNotify.add( 1059 mInputDevicesChangedListeners.valueAt(i)); 1060 } 1061 1062 final int numDevices = mInputDevices.length; 1063 deviceIdAndGeneration = new int[numDevices * 2]; 1064 for (int i = 0; i < numDevices; i++) { 1065 final InputDevice inputDevice = mInputDevices[i]; 1066 deviceIdAndGeneration[i * 2] = inputDevice.getId(); 1067 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration(); 1068 1069 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) { 1070 if (!containsInputDeviceWithDescriptor(oldInputDevices, 1071 inputDevice.getDescriptor())) { 1072 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice); 1073 } else { 1074 mTempFullKeyboards.add(inputDevice); 1075 } 1076 } 1077 } 1078 } 1079 1080 // Notify listeners. 1081 for (int i = 0; i < numListeners; i++) { 1082 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged( 1083 deviceIdAndGeneration); 1084 } 1085 mTempInputDevicesChangedListenersToNotify.clear(); 1086 1087 // Check for missing keyboard layouts. 1088 List<InputDevice> keyboardsMissingLayout = new ArrayList<>(); 1089 final int numFullKeyboards = mTempFullKeyboards.size(); 1090 synchronized (mDataStore) { 1091 for (int i = 0; i < numFullKeyboards; i++) { 1092 final InputDevice inputDevice = mTempFullKeyboards.get(i); 1093 String layout = 1094 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier()); 1095 if (layout == null) { 1096 layout = getDefaultKeyboardLayout(inputDevice); 1097 if (layout != null) { 1098 setCurrentKeyboardLayoutForInputDevice( 1099 inputDevice.getIdentifier(), layout); 1100 } 1101 } 1102 if (layout == null) { 1103 keyboardsMissingLayout.add(inputDevice); 1104 } 1105 } 1106 } 1107 1108 if (mNotificationManager != null) { 1109 if (!keyboardsMissingLayout.isEmpty()) { 1110 if (keyboardsMissingLayout.size() > 1) { 1111 // We have more than one keyboard missing a layout, so drop the 1112 // user at the generic input methods page so they can pick which 1113 // one to set. 1114 showMissingKeyboardLayoutNotification(null); 1115 } else { 1116 showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0)); 1117 } 1118 } else if (mKeyboardLayoutNotificationShown) { 1119 hideMissingKeyboardLayoutNotification(); 1120 } 1121 } 1122 mTempFullKeyboards.clear(); 1123 } 1124 getDefaultKeyboardLayout(final InputDevice d)1125 private String getDefaultKeyboardLayout(final InputDevice d) { 1126 final Locale systemLocale = mContext.getResources().getConfiguration().locale; 1127 // If our locale doesn't have a language for some reason, then we don't really have a 1128 // reasonable default. 1129 if (TextUtils.isEmpty(systemLocale.getLanguage())) { 1130 return null; 1131 } 1132 final List<KeyboardLayout> layouts = new ArrayList<>(); 1133 visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> { 1134 // Only select a default when we know the layout is appropriate. For now, this 1135 // means it's a custom layout for a specific keyboard. 1136 if (layout.getVendorId() != d.getVendorId() 1137 || layout.getProductId() != d.getProductId()) { 1138 return; 1139 } 1140 final LocaleList locales = layout.getLocales(); 1141 final int numLocales = locales.size(); 1142 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) { 1143 if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) { 1144 layouts.add(layout); 1145 break; 1146 } 1147 } 1148 }); 1149 1150 if (layouts.isEmpty()) { 1151 return null; 1152 } 1153 1154 // First sort so that ones with higher priority are listed at the top 1155 Collections.sort(layouts); 1156 // Next we want to try to find an exact match of language, country and variant. 1157 final int N = layouts.size(); 1158 for (int i = 0; i < N; i++) { 1159 KeyboardLayout layout = layouts.get(i); 1160 final LocaleList locales = layout.getLocales(); 1161 final int numLocales = locales.size(); 1162 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) { 1163 final Locale locale = locales.get(localeIndex); 1164 if (locale.getCountry().equals(systemLocale.getCountry()) 1165 && locale.getVariant().equals(systemLocale.getVariant())) { 1166 return layout.getDescriptor(); 1167 } 1168 } 1169 } 1170 // Then try an exact match of language and country 1171 for (int i = 0; i < N; i++) { 1172 KeyboardLayout layout = layouts.get(i); 1173 final LocaleList locales = layout.getLocales(); 1174 final int numLocales = locales.size(); 1175 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) { 1176 final Locale locale = locales.get(localeIndex); 1177 if (locale.getCountry().equals(systemLocale.getCountry())) { 1178 return layout.getDescriptor(); 1179 } 1180 } 1181 } 1182 1183 // Give up and just use the highest priority layout with matching language 1184 return layouts.get(0).getDescriptor(); 1185 } 1186 isCompatibleLocale(Locale systemLocale, Locale keyboardLocale)1187 private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) { 1188 // Different languages are never compatible 1189 if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) { 1190 return false; 1191 } 1192 // If both the system and the keyboard layout have a country specifier, they must be equal. 1193 if (!TextUtils.isEmpty(systemLocale.getCountry()) 1194 && !TextUtils.isEmpty(keyboardLocale.getCountry()) 1195 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) { 1196 return false; 1197 } 1198 return true; 1199 } 1200 1201 @Override // Binder call & native callback getTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation)1202 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor, 1203 int surfaceRotation) { 1204 Objects.requireNonNull(inputDeviceDescriptor, "inputDeviceDescriptor must not be null"); 1205 1206 synchronized (mDataStore) { 1207 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation); 1208 } 1209 } 1210 1211 @Override // Binder call setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation, TouchCalibration calibration)1212 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation, 1213 TouchCalibration calibration) { 1214 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION, 1215 "setTouchCalibrationForInputDevice()")) { 1216 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission"); 1217 } 1218 Objects.requireNonNull(inputDeviceDescriptor, "inputDeviceDescriptor must not be null"); 1219 Objects.requireNonNull(calibration, "calibration must not be null"); 1220 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) { 1221 throw new IllegalArgumentException("surfaceRotation value out of bounds"); 1222 } 1223 1224 synchronized (mDataStore) { 1225 try { 1226 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation, 1227 calibration)) { 1228 mNative.reloadCalibration(); 1229 } 1230 } finally { 1231 mDataStore.saveIfNeeded(); 1232 } 1233 } 1234 } 1235 1236 @Override // Binder call isInTabletMode()1237 public int isInTabletMode() { 1238 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE, 1239 "isInTabletMode()")) { 1240 throw new SecurityException("Requires TABLET_MODE permission"); 1241 } 1242 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE); 1243 } 1244 1245 @Override // Binder call isMicMuted()1246 public int isMicMuted() { 1247 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MUTE_DEVICE); 1248 } 1249 1250 @Override // Binder call registerTabletModeChangedListener(ITabletModeChangedListener listener)1251 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) { 1252 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE, 1253 "registerTabletModeChangedListener()")) { 1254 throw new SecurityException("Requires TABLET_MODE_LISTENER permission"); 1255 } 1256 Objects.requireNonNull(listener, "event must not be null"); 1257 1258 synchronized (mTabletModeLock) { 1259 final int callingPid = Binder.getCallingPid(); 1260 if (mTabletModeChangedListeners.get(callingPid) != null) { 1261 throw new IllegalStateException("The calling process has already registered " 1262 + "a TabletModeChangedListener."); 1263 } 1264 TabletModeChangedListenerRecord record = 1265 new TabletModeChangedListenerRecord(callingPid, listener); 1266 try { 1267 IBinder binder = listener.asBinder(); 1268 binder.linkToDeath(record, 0); 1269 } catch (RemoteException ex) { 1270 throw new RuntimeException(ex); 1271 } 1272 mTabletModeChangedListeners.put(callingPid, record); 1273 } 1274 } 1275 onTabletModeChangedListenerDied(int pid)1276 private void onTabletModeChangedListenerDied(int pid) { 1277 synchronized (mTabletModeLock) { 1278 mTabletModeChangedListeners.remove(pid); 1279 } 1280 } 1281 1282 // Must be called on handler deliverTabletModeChanged(long whenNanos, boolean inTabletMode)1283 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) { 1284 mTempTabletModeChangedListenersToNotify.clear(); 1285 final int numListeners; 1286 synchronized (mTabletModeLock) { 1287 numListeners = mTabletModeChangedListeners.size(); 1288 for (int i = 0; i < numListeners; i++) { 1289 mTempTabletModeChangedListenersToNotify.add( 1290 mTabletModeChangedListeners.valueAt(i)); 1291 } 1292 } 1293 for (int i = 0; i < numListeners; i++) { 1294 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged( 1295 whenNanos, inTabletMode); 1296 } 1297 } 1298 1299 // Must be called on handler. showMissingKeyboardLayoutNotification(InputDevice device)1300 private void showMissingKeyboardLayoutNotification(InputDevice device) { 1301 if (!mKeyboardLayoutNotificationShown) { 1302 final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS); 1303 if (device != null) { 1304 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier()); 1305 } 1306 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1307 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 1308 | Intent.FLAG_ACTIVITY_CLEAR_TOP); 1309 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0, 1310 intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT); 1311 1312 Resources r = mContext.getResources(); 1313 Notification notification = 1314 new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD) 1315 .setContentTitle(r.getString( 1316 R.string.select_keyboard_layout_notification_title)) 1317 .setContentText(r.getString( 1318 R.string.select_keyboard_layout_notification_message)) 1319 .setContentIntent(keyboardLayoutIntent) 1320 .setSmallIcon(R.drawable.ic_settings_language) 1321 .setColor(mContext.getColor( 1322 com.android.internal.R.color.system_notification_accent_color)) 1323 .build(); 1324 mNotificationManager.notifyAsUser(null, 1325 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT, 1326 notification, UserHandle.ALL); 1327 mKeyboardLayoutNotificationShown = true; 1328 } 1329 } 1330 1331 // Must be called on handler. hideMissingKeyboardLayoutNotification()1332 private void hideMissingKeyboardLayoutNotification() { 1333 if (mKeyboardLayoutNotificationShown) { 1334 mKeyboardLayoutNotificationShown = false; 1335 mNotificationManager.cancelAsUser(null, 1336 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT, 1337 UserHandle.ALL); 1338 } 1339 } 1340 1341 // Must be called on handler. updateKeyboardLayouts()1342 private void updateKeyboardLayouts() { 1343 // Scan all input devices state for keyboard layouts that have been uninstalled. 1344 final HashSet<String> availableKeyboardLayouts = new HashSet<String>(); 1345 visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> 1346 availableKeyboardLayouts.add(layout.getDescriptor())); 1347 synchronized (mDataStore) { 1348 try { 1349 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts); 1350 } finally { 1351 mDataStore.saveIfNeeded(); 1352 } 1353 } 1354 1355 // Reload keyboard layouts. 1356 reloadKeyboardLayouts(); 1357 } 1358 containsInputDeviceWithDescriptor(InputDevice[] inputDevices, String descriptor)1359 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices, 1360 String descriptor) { 1361 final int numDevices = inputDevices.length; 1362 for (int i = 0; i < numDevices; i++) { 1363 final InputDevice inputDevice = inputDevices[i]; 1364 if (inputDevice.getDescriptor().equals(descriptor)) { 1365 return true; 1366 } 1367 } 1368 return false; 1369 } 1370 1371 @Override // Binder call getKeyboardLayouts()1372 public KeyboardLayout[] getKeyboardLayouts() { 1373 final ArrayList<KeyboardLayout> list = new ArrayList<>(); 1374 visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> list.add(layout)); 1375 return list.toArray(new KeyboardLayout[list.size()]); 1376 } 1377 1378 @Override // Binder call getKeyboardLayoutsForInputDevice( final InputDeviceIdentifier identifier)1379 public KeyboardLayout[] getKeyboardLayoutsForInputDevice( 1380 final InputDeviceIdentifier identifier) { 1381 final String[] enabledLayoutDescriptors = 1382 getEnabledKeyboardLayoutsForInputDevice(identifier); 1383 final ArrayList<KeyboardLayout> enabledLayouts = 1384 new ArrayList<>(enabledLayoutDescriptors.length); 1385 final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<>(); 1386 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 1387 boolean mHasSeenDeviceSpecificLayout; 1388 1389 @Override 1390 public void visitKeyboardLayout(Resources resources, 1391 int keyboardLayoutResId, KeyboardLayout layout) { 1392 // First check if it's enabled. If the keyboard layout is enabled then we always 1393 // want to return it as a possible layout for the device. 1394 for (String s : enabledLayoutDescriptors) { 1395 if (s != null && s.equals(layout.getDescriptor())) { 1396 enabledLayouts.add(layout); 1397 return; 1398 } 1399 } 1400 // Next find any potential layouts that aren't yet enabled for the device. For 1401 // devices that have special layouts we assume there's a reason that the generic 1402 // layouts don't work for them so we don't want to return them since it's likely 1403 // to result in a poor user experience. 1404 if (layout.getVendorId() == identifier.getVendorId() 1405 && layout.getProductId() == identifier.getProductId()) { 1406 if (!mHasSeenDeviceSpecificLayout) { 1407 mHasSeenDeviceSpecificLayout = true; 1408 potentialLayouts.clear(); 1409 } 1410 potentialLayouts.add(layout); 1411 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1 1412 && !mHasSeenDeviceSpecificLayout) { 1413 potentialLayouts.add(layout); 1414 } 1415 } 1416 }); 1417 final int enabledLayoutSize = enabledLayouts.size(); 1418 final int potentialLayoutSize = potentialLayouts.size(); 1419 KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize]; 1420 enabledLayouts.toArray(layouts); 1421 for (int i = 0; i < potentialLayoutSize; i++) { 1422 layouts[enabledLayoutSize + i] = potentialLayouts.get(i); 1423 } 1424 return layouts; 1425 } 1426 1427 @Override // Binder call getKeyboardLayout(String keyboardLayoutDescriptor)1428 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) { 1429 Objects.requireNonNull(keyboardLayoutDescriptor, 1430 "keyboardLayoutDescriptor must not be null"); 1431 1432 final KeyboardLayout[] result = new KeyboardLayout[1]; 1433 visitKeyboardLayout(keyboardLayoutDescriptor, 1434 (resources, keyboardLayoutResId, layout) -> result[0] = layout); 1435 if (result[0] == null) { 1436 Slog.w(TAG, "Could not get keyboard layout with descriptor '" 1437 + keyboardLayoutDescriptor + "'."); 1438 } 1439 return result[0]; 1440 } 1441 visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor)1442 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) { 1443 final PackageManager pm = mContext.getPackageManager(); 1444 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS); 1445 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent, 1446 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE 1447 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) { 1448 final ActivityInfo activityInfo = resolveInfo.activityInfo; 1449 final int priority = resolveInfo.priority; 1450 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor); 1451 } 1452 } 1453 visitKeyboardLayout(String keyboardLayoutDescriptor, KeyboardLayoutVisitor visitor)1454 private void visitKeyboardLayout(String keyboardLayoutDescriptor, 1455 KeyboardLayoutVisitor visitor) { 1456 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor); 1457 if (d != null) { 1458 final PackageManager pm = mContext.getPackageManager(); 1459 try { 1460 ActivityInfo receiver = pm.getReceiverInfo( 1461 new ComponentName(d.packageName, d.receiverName), 1462 PackageManager.GET_META_DATA 1463 | PackageManager.MATCH_DIRECT_BOOT_AWARE 1464 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); 1465 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor); 1466 } catch (NameNotFoundException ignored) { 1467 } 1468 } 1469 } 1470 visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor)1471 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, 1472 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) { 1473 Bundle metaData = receiver.metaData; 1474 if (metaData == null) { 1475 return; 1476 } 1477 1478 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS); 1479 if (configResId == 0) { 1480 Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS 1481 + "' on receiver " + receiver.packageName + "/" + receiver.name); 1482 return; 1483 } 1484 1485 CharSequence receiverLabel = receiver.loadLabel(pm); 1486 String collection = receiverLabel != null ? receiverLabel.toString() : ""; 1487 int priority; 1488 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 1489 priority = requestedPriority; 1490 } else { 1491 priority = 0; 1492 } 1493 1494 try { 1495 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo); 1496 try (XmlResourceParser parser = resources.getXml(configResId)) { 1497 XmlUtils.beginDocument(parser, "keyboard-layouts"); 1498 1499 while (true) { 1500 XmlUtils.nextElement(parser); 1501 String element = parser.getName(); 1502 if (element == null) { 1503 break; 1504 } 1505 if (element.equals("keyboard-layout")) { 1506 TypedArray a = resources.obtainAttributes( 1507 parser, R.styleable.KeyboardLayout); 1508 try { 1509 String name = a.getString( 1510 R.styleable.KeyboardLayout_name); 1511 String label = a.getString( 1512 R.styleable.KeyboardLayout_label); 1513 int keyboardLayoutResId = a.getResourceId( 1514 R.styleable.KeyboardLayout_keyboardLayout, 1515 0); 1516 String languageTags = a.getString( 1517 R.styleable.KeyboardLayout_locale); 1518 LocaleList locales = getLocalesFromLanguageTags(languageTags); 1519 int vid = a.getInt( 1520 R.styleable.KeyboardLayout_vendorId, -1); 1521 int pid = a.getInt( 1522 R.styleable.KeyboardLayout_productId, -1); 1523 1524 if (name == null || label == null || keyboardLayoutResId == 0) { 1525 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' " 1526 + "attributes in keyboard layout " 1527 + "resource from receiver " 1528 + receiver.packageName + "/" + receiver.name); 1529 } else { 1530 String descriptor = KeyboardLayoutDescriptor.format( 1531 receiver.packageName, receiver.name, name); 1532 if (keyboardName == null || name.equals(keyboardName)) { 1533 KeyboardLayout layout = new KeyboardLayout( 1534 descriptor, label, collection, priority, 1535 locales, vid, pid); 1536 visitor.visitKeyboardLayout( 1537 resources, keyboardLayoutResId, layout); 1538 } 1539 } 1540 } finally { 1541 a.recycle(); 1542 } 1543 } else { 1544 Slog.w(TAG, "Skipping unrecognized element '" + element 1545 + "' in keyboard layout resource from receiver " 1546 + receiver.packageName + "/" + receiver.name); 1547 } 1548 } 1549 } 1550 } catch (Exception ex) { 1551 Slog.w(TAG, "Could not parse keyboard layout resource from receiver " 1552 + receiver.packageName + "/" + receiver.name, ex); 1553 } 1554 } 1555 1556 @NonNull getLocalesFromLanguageTags(String languageTags)1557 private static LocaleList getLocalesFromLanguageTags(String languageTags) { 1558 if (TextUtils.isEmpty(languageTags)) { 1559 return LocaleList.getEmptyLocaleList(); 1560 } 1561 return LocaleList.forLanguageTags(languageTags.replace('|', ',')); 1562 } 1563 1564 /** 1565 * Builds a layout descriptor for the vendor/product. This returns the 1566 * descriptor for ids that aren't useful (such as the default 0, 0). 1567 */ getLayoutDescriptor(InputDeviceIdentifier identifier)1568 private String getLayoutDescriptor(InputDeviceIdentifier identifier) { 1569 Objects.requireNonNull(identifier, "identifier must not be null"); 1570 Objects.requireNonNull(identifier.getDescriptor(), "descriptor must not be null"); 1571 1572 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) { 1573 return identifier.getDescriptor(); 1574 } 1575 return "vendor:" + identifier.getVendorId() + ",product:" + identifier.getProductId(); 1576 } 1577 1578 @Override // Binder call getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier)1579 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) { 1580 1581 String key = getLayoutDescriptor(identifier); 1582 synchronized (mDataStore) { 1583 String layout; 1584 // try loading it using the layout descriptor if we have it 1585 layout = mDataStore.getCurrentKeyboardLayout(key); 1586 if (layout == null && !key.equals(identifier.getDescriptor())) { 1587 // if it doesn't exist fall back to the device descriptor 1588 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1589 } 1590 if (DEBUG) { 1591 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got " 1592 + layout); 1593 } 1594 return layout; 1595 } 1596 } 1597 1598 @Override // Binder call setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1599 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1600 String keyboardLayoutDescriptor) { 1601 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1602 "setCurrentKeyboardLayoutForInputDevice()")) { 1603 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1604 } 1605 1606 Objects.requireNonNull(keyboardLayoutDescriptor, 1607 "keyboardLayoutDescriptor must not be null"); 1608 1609 String key = getLayoutDescriptor(identifier); 1610 synchronized (mDataStore) { 1611 try { 1612 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) { 1613 if (DEBUG) { 1614 Slog.d(TAG, "Saved keyboard layout using " + key); 1615 } 1616 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1617 } 1618 } finally { 1619 mDataStore.saveIfNeeded(); 1620 } 1621 } 1622 } 1623 1624 @Override // Binder call getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier)1625 public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { 1626 String key = getLayoutDescriptor(identifier); 1627 synchronized (mDataStore) { 1628 String[] layouts = mDataStore.getKeyboardLayouts(key); 1629 if ((layouts == null || layouts.length == 0) 1630 && !key.equals(identifier.getDescriptor())) { 1631 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor()); 1632 } 1633 return layouts; 1634 } 1635 } 1636 1637 @Override // Binder call addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1638 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1639 String keyboardLayoutDescriptor) { 1640 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1641 "addKeyboardLayoutForInputDevice()")) { 1642 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1643 } 1644 Objects.requireNonNull(keyboardLayoutDescriptor, 1645 "keyboardLayoutDescriptor must not be null"); 1646 1647 String key = getLayoutDescriptor(identifier); 1648 synchronized (mDataStore) { 1649 try { 1650 String oldLayout = mDataStore.getCurrentKeyboardLayout(key); 1651 if (oldLayout == null && !key.equals(identifier.getDescriptor())) { 1652 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1653 } 1654 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor) 1655 && !Objects.equals(oldLayout, 1656 mDataStore.getCurrentKeyboardLayout(key))) { 1657 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1658 } 1659 } finally { 1660 mDataStore.saveIfNeeded(); 1661 } 1662 } 1663 } 1664 1665 @Override // Binder call removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1666 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1667 String keyboardLayoutDescriptor) { 1668 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1669 "removeKeyboardLayoutForInputDevice()")) { 1670 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1671 } 1672 Objects.requireNonNull(keyboardLayoutDescriptor, 1673 "keyboardLayoutDescriptor must not be null"); 1674 1675 String key = getLayoutDescriptor(identifier); 1676 synchronized (mDataStore) { 1677 try { 1678 String oldLayout = mDataStore.getCurrentKeyboardLayout(key); 1679 if (oldLayout == null && !key.equals(identifier.getDescriptor())) { 1680 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1681 } 1682 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor); 1683 if (!key.equals(identifier.getDescriptor())) { 1684 // We need to remove from both places to ensure it is gone 1685 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(), 1686 keyboardLayoutDescriptor); 1687 } 1688 if (removed && !Objects.equals(oldLayout, 1689 mDataStore.getCurrentKeyboardLayout(key))) { 1690 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1691 } 1692 } finally { 1693 mDataStore.saveIfNeeded(); 1694 } 1695 } 1696 } 1697 switchKeyboardLayout(int deviceId, int direction)1698 public void switchKeyboardLayout(int deviceId, int direction) { 1699 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget(); 1700 } 1701 1702 // Must be called on handler. handleSwitchKeyboardLayout(int deviceId, int direction)1703 private void handleSwitchKeyboardLayout(int deviceId, int direction) { 1704 final InputDevice device = getInputDevice(deviceId); 1705 if (device != null) { 1706 final boolean changed; 1707 final String keyboardLayoutDescriptor; 1708 1709 String key = getLayoutDescriptor(device.getIdentifier()); 1710 synchronized (mDataStore) { 1711 try { 1712 changed = mDataStore.switchKeyboardLayout(key, direction); 1713 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout( 1714 key); 1715 } finally { 1716 mDataStore.saveIfNeeded(); 1717 } 1718 } 1719 1720 if (changed) { 1721 if (mSwitchedKeyboardLayoutToast != null) { 1722 mSwitchedKeyboardLayoutToast.cancel(); 1723 mSwitchedKeyboardLayoutToast = null; 1724 } 1725 if (keyboardLayoutDescriptor != null) { 1726 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor); 1727 if (keyboardLayout != null) { 1728 mSwitchedKeyboardLayoutToast = Toast.makeText( 1729 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT); 1730 mSwitchedKeyboardLayoutToast.show(); 1731 } 1732 } 1733 1734 reloadKeyboardLayouts(); 1735 } 1736 } 1737 } 1738 setFocusedApplication(int displayId, InputApplicationHandle application)1739 public void setFocusedApplication(int displayId, InputApplicationHandle application) { 1740 mNative.setFocusedApplication(displayId, application); 1741 } 1742 setFocusedDisplay(int displayId)1743 public void setFocusedDisplay(int displayId) { 1744 mNative.setFocusedDisplay(displayId); 1745 } 1746 1747 /** Clean up input window handles of the given display. */ onDisplayRemoved(int displayId)1748 public void onDisplayRemoved(int displayId) { 1749 if (mPointerIconDisplayContext != null 1750 && mPointerIconDisplayContext.getDisplay().getDisplayId() == displayId) { 1751 mPointerIconDisplayContext = null; 1752 } 1753 1754 updateAdditionalDisplayInputProperties(displayId, AdditionalDisplayInputProperties::reset); 1755 1756 mNative.displayRemoved(displayId); 1757 } 1758 1759 @Override requestPointerCapture(IBinder inputChannelToken, boolean enabled)1760 public void requestPointerCapture(IBinder inputChannelToken, boolean enabled) { 1761 Objects.requireNonNull(inputChannelToken, "event must not be null"); 1762 1763 mNative.requestPointerCapture(inputChannelToken, enabled); 1764 } 1765 setInputDispatchMode(boolean enabled, boolean frozen)1766 public void setInputDispatchMode(boolean enabled, boolean frozen) { 1767 mNative.setInputDispatchMode(enabled, frozen); 1768 } 1769 setSystemUiLightsOut(boolean lightsOut)1770 public void setSystemUiLightsOut(boolean lightsOut) { 1771 mNative.setSystemUiLightsOut(lightsOut); 1772 } 1773 1774 /** 1775 * Atomically transfers touch focus from one window to another as identified by 1776 * their input channels. It is possible for multiple windows to have 1777 * touch focus if they support split touch dispatch 1778 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this 1779 * method only transfers touch focus of the specified window without affecting 1780 * other windows that may also have touch focus at the same time. 1781 * @param fromChannel The channel of a window that currently has touch focus. 1782 * @param toChannel The channel of the window that should receive touch focus in 1783 * place of the first. 1784 * @param isDragDrop True if transfer touch focus for drag and drop. 1785 * @return True if the transfer was successful. False if the window with the 1786 * specified channel did not actually have touch focus at the time of the request. 1787 */ transferTouchFocus(@onNull InputChannel fromChannel, @NonNull InputChannel toChannel, boolean isDragDrop)1788 public boolean transferTouchFocus(@NonNull InputChannel fromChannel, 1789 @NonNull InputChannel toChannel, boolean isDragDrop) { 1790 return mNative.transferTouchFocus(fromChannel.getToken(), toChannel.getToken(), 1791 isDragDrop); 1792 } 1793 1794 /** 1795 * Atomically transfers touch focus from one window to another as identified by 1796 * their input channels. It is possible for multiple windows to have 1797 * touch focus if they support split touch dispatch 1798 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this 1799 * method only transfers touch focus of the specified window without affecting 1800 * other windows that may also have touch focus at the same time. 1801 * @param fromChannelToken The channel token of a window that currently has touch focus. 1802 * @param toChannelToken The channel token of the window that should receive touch focus in 1803 * place of the first. 1804 * @return True if the transfer was successful. False if the window with the 1805 * specified channel did not actually have touch focus at the time of the request. 1806 */ transferTouchFocus(@onNull IBinder fromChannelToken, @NonNull IBinder toChannelToken)1807 public boolean transferTouchFocus(@NonNull IBinder fromChannelToken, 1808 @NonNull IBinder toChannelToken) { 1809 Objects.nonNull(fromChannelToken); 1810 Objects.nonNull(toChannelToken); 1811 return mNative.transferTouchFocus(fromChannelToken, toChannelToken, 1812 false /* isDragDrop */); 1813 } 1814 1815 @Override // Binder call tryPointerSpeed(int speed)1816 public void tryPointerSpeed(int speed) { 1817 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, 1818 "tryPointerSpeed()")) { 1819 throw new SecurityException("Requires SET_POINTER_SPEED permission"); 1820 } 1821 1822 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) { 1823 throw new IllegalArgumentException("speed out of range"); 1824 } 1825 1826 setPointerSpeedUnchecked(speed); 1827 } 1828 updatePointerSpeedFromSettings()1829 private void updatePointerSpeedFromSettings() { 1830 int speed = getPointerSpeedSetting(); 1831 setPointerSpeedUnchecked(speed); 1832 } 1833 setPointerSpeedUnchecked(int speed)1834 private void setPointerSpeedUnchecked(int speed) { 1835 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED), 1836 InputManager.MAX_POINTER_SPEED); 1837 mNative.setPointerSpeed(speed); 1838 } 1839 setPointerAcceleration(float acceleration, int displayId)1840 private void setPointerAcceleration(float acceleration, int displayId) { 1841 updateAdditionalDisplayInputProperties(displayId, 1842 properties -> properties.pointerAcceleration = acceleration); 1843 } 1844 setPointerIconVisible(boolean visible, int displayId)1845 private void setPointerIconVisible(boolean visible, int displayId) { 1846 updateAdditionalDisplayInputProperties(displayId, 1847 properties -> properties.pointerIconVisible = visible); 1848 } 1849 registerPointerSpeedSettingObserver()1850 private void registerPointerSpeedSettingObserver() { 1851 mContext.getContentResolver().registerContentObserver( 1852 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true, 1853 new ContentObserver(mHandler) { 1854 @Override 1855 public void onChange(boolean selfChange) { 1856 updatePointerSpeedFromSettings(); 1857 } 1858 }, UserHandle.USER_ALL); 1859 } 1860 getPointerSpeedSetting()1861 private int getPointerSpeedSetting() { 1862 int speed = InputManager.DEFAULT_POINTER_SPEED; 1863 try { 1864 speed = Settings.System.getIntForUser(mContext.getContentResolver(), 1865 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT); 1866 } catch (SettingNotFoundException ignored) { 1867 } 1868 return speed; 1869 } 1870 updateShowTouchesFromSettings()1871 private void updateShowTouchesFromSettings() { 1872 int setting = getShowTouchesSetting(0); 1873 mNative.setShowTouches(setting != 0); 1874 } 1875 registerShowTouchesSettingObserver()1876 private void registerShowTouchesSettingObserver() { 1877 mContext.getContentResolver().registerContentObserver( 1878 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true, 1879 new ContentObserver(mHandler) { 1880 @Override 1881 public void onChange(boolean selfChange) { 1882 updateShowTouchesFromSettings(); 1883 } 1884 }, UserHandle.USER_ALL); 1885 } 1886 updateAccessibilityLargePointerFromSettings()1887 private void updateAccessibilityLargePointerFromSettings() { 1888 final int accessibilityConfig = Settings.Secure.getIntForUser( 1889 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, 1890 0, UserHandle.USER_CURRENT); 1891 PointerIcon.setUseLargeIcons(accessibilityConfig == 1); 1892 mNative.reloadPointerIcons(); 1893 } 1894 registerAccessibilityLargePointerSettingObserver()1895 private void registerAccessibilityLargePointerSettingObserver() { 1896 mContext.getContentResolver().registerContentObserver( 1897 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true, 1898 new ContentObserver(mHandler) { 1899 @Override 1900 public void onChange(boolean selfChange) { 1901 updateAccessibilityLargePointerFromSettings(); 1902 } 1903 }, UserHandle.USER_ALL); 1904 } 1905 updateDeepPressStatusFromSettings(String reason)1906 private void updateDeepPressStatusFromSettings(String reason) { 1907 // Not using ViewConfiguration.getLongPressTimeout here because it may return a stale value 1908 final int timeout = Settings.Secure.getIntForUser(mContext.getContentResolver(), 1909 Settings.Secure.LONG_PRESS_TIMEOUT, ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT, 1910 UserHandle.USER_CURRENT); 1911 final boolean featureEnabledFlag = 1912 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT, 1913 DEEP_PRESS_ENABLED, true /* default */); 1914 final boolean enabled = 1915 featureEnabledFlag && timeout <= ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT; 1916 Log.i(TAG, 1917 (enabled ? "Enabling" : "Disabling") + " motion classifier because " + reason 1918 + ": feature " + (featureEnabledFlag ? "enabled" : "disabled") 1919 + ", long press timeout = " + timeout); 1920 mNative.setMotionClassifierEnabled(enabled); 1921 } 1922 registerLongPressTimeoutObserver()1923 private void registerLongPressTimeoutObserver() { 1924 mContext.getContentResolver().registerContentObserver( 1925 Settings.Secure.getUriFor(Settings.Secure.LONG_PRESS_TIMEOUT), true, 1926 new ContentObserver(mHandler) { 1927 @Override 1928 public void onChange(boolean selfChange) { 1929 updateDeepPressStatusFromSettings("timeout changed"); 1930 } 1931 }, UserHandle.USER_ALL); 1932 } 1933 registerBlockUntrustedTouchesModeSettingObserver()1934 private void registerBlockUntrustedTouchesModeSettingObserver() { 1935 mContext.getContentResolver().registerContentObserver( 1936 Settings.Global.getUriFor(Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE), 1937 /* notifyForDescendants */ true, 1938 new ContentObserver(mHandler) { 1939 @Override 1940 public void onChange(boolean selfChange) { 1941 updateBlockUntrustedTouchesModeFromSettings(); 1942 } 1943 }, UserHandle.USER_ALL); 1944 } 1945 updateBlockUntrustedTouchesModeFromSettings()1946 private void updateBlockUntrustedTouchesModeFromSettings() { 1947 final int mode = InputManager.getInstance().getBlockUntrustedTouchesMode(mContext); 1948 mNative.setBlockUntrustedTouchesMode(mode); 1949 } 1950 registerMaximumObscuringOpacityForTouchSettingObserver()1951 private void registerMaximumObscuringOpacityForTouchSettingObserver() { 1952 mContext.getContentResolver().registerContentObserver( 1953 Settings.Global.getUriFor(Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH), 1954 /* notifyForDescendants */ true, 1955 new ContentObserver(mHandler) { 1956 @Override 1957 public void onChange(boolean selfChange) { 1958 updateMaximumObscuringOpacityForTouchFromSettings(); 1959 } 1960 }, UserHandle.USER_ALL); 1961 } 1962 updateMaximumObscuringOpacityForTouchFromSettings()1963 private void updateMaximumObscuringOpacityForTouchFromSettings() { 1964 final float opacity = InputManager.getInstance().getMaximumObscuringOpacityForTouch(); 1965 if (opacity < 0 || opacity > 1) { 1966 Log.e(TAG, "Invalid maximum obscuring opacity " + opacity 1967 + ", it should be >= 0 and <= 1, rejecting update."); 1968 return; 1969 } 1970 mNative.setMaximumObscuringOpacityForTouch(opacity); 1971 } 1972 getShowTouchesSetting(int defaultValue)1973 private int getShowTouchesSetting(int defaultValue) { 1974 int result = defaultValue; 1975 try { 1976 result = Settings.System.getIntForUser(mContext.getContentResolver(), 1977 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT); 1978 } catch (SettingNotFoundException snfe) { 1979 } 1980 return result; 1981 } 1982 1983 /** 1984 * Update the display on which the mouse pointer is shown. 1985 * 1986 * @return true if the pointer displayId changed, false otherwise. 1987 */ 1988 @GuardedBy("mAdditionalDisplayInputPropertiesLock") updatePointerDisplayIdLocked(int pointerDisplayId)1989 private boolean updatePointerDisplayIdLocked(int pointerDisplayId) { 1990 if (mRequestedPointerDisplayId == pointerDisplayId) { 1991 return false; 1992 } 1993 mRequestedPointerDisplayId = pointerDisplayId; 1994 mNative.setPointerDisplayId(pointerDisplayId); 1995 applyAdditionalDisplayInputProperties(); 1996 return true; 1997 } 1998 handlePointerDisplayIdChanged(PointerDisplayIdChangedArgs args)1999 private void handlePointerDisplayIdChanged(PointerDisplayIdChangedArgs args) { 2000 synchronized (mAdditionalDisplayInputPropertiesLock) { 2001 mAcknowledgedPointerDisplayId = args.mPointerDisplayId; 2002 // Notify waiting threads that the display of the mouse pointer has changed. 2003 mAdditionalDisplayInputPropertiesLock.notifyAll(); 2004 } 2005 mWindowManagerCallbacks.notifyPointerDisplayIdChanged( 2006 args.mPointerDisplayId, args.mXPosition, args.mYPosition); 2007 } 2008 setVirtualMousePointerDisplayIdBlocking(int overrideDisplayId)2009 private boolean setVirtualMousePointerDisplayIdBlocking(int overrideDisplayId) { 2010 final boolean isRemovingOverride = overrideDisplayId == Display.INVALID_DISPLAY; 2011 2012 // Take care to not make calls to window manager while holding internal locks. 2013 final int resolvedDisplayId = isRemovingOverride 2014 ? mWindowManagerCallbacks.getPointerDisplayId() 2015 : overrideDisplayId; 2016 2017 synchronized (mAdditionalDisplayInputPropertiesLock) { 2018 mOverriddenPointerDisplayId = overrideDisplayId; 2019 2020 if (!updatePointerDisplayIdLocked(resolvedDisplayId) 2021 && mAcknowledgedPointerDisplayId == resolvedDisplayId) { 2022 // The requested pointer display is already set. 2023 return true; 2024 } 2025 if (isRemovingOverride && mAcknowledgedPointerDisplayId == Display.INVALID_DISPLAY) { 2026 // The pointer display override is being removed, but the current pointer display 2027 // is already invalid. This can happen when the PointerController is destroyed as a 2028 // result of the removal of all input devices that can control the pointer. 2029 return true; 2030 } 2031 try { 2032 // The pointer display changed, so wait until the change has propagated. 2033 mAdditionalDisplayInputPropertiesLock.wait(5_000 /*mills*/); 2034 } catch (InterruptedException ignored) { 2035 } 2036 // This request succeeds in two cases: 2037 // - This request was to remove the override, in which case the new pointer display 2038 // could be anything that WM has set. 2039 // - We are setting a new override, in which case the request only succeeds if the 2040 // reported new displayId is the one we requested. This check ensures that if two 2041 // competing overrides are requested in succession, the caller can be notified if one 2042 // of them fails. 2043 return isRemovingOverride || mAcknowledgedPointerDisplayId == overrideDisplayId; 2044 } 2045 } 2046 getVirtualMousePointerDisplayId()2047 private int getVirtualMousePointerDisplayId() { 2048 synchronized (mAdditionalDisplayInputPropertiesLock) { 2049 return mOverriddenPointerDisplayId; 2050 } 2051 } 2052 setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible)2053 private void setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible) { 2054 mNative.setDisplayEligibilityForPointerCapture(displayId, isEligible); 2055 } 2056 2057 private static class VibrationInfo { 2058 private final long[] mPattern; 2059 private final int[] mAmplitudes; 2060 private final int mRepeat; 2061 getPattern()2062 public long[] getPattern() { 2063 return mPattern; 2064 } 2065 getAmplitudes()2066 public int[] getAmplitudes() { 2067 return mAmplitudes; 2068 } 2069 getRepeatIndex()2070 public int getRepeatIndex() { 2071 return mRepeat; 2072 } 2073 VibrationInfo(VibrationEffect effect)2074 VibrationInfo(VibrationEffect effect) { 2075 long[] pattern = null; 2076 int[] amplitudes = null; 2077 int patternRepeatIndex = -1; 2078 int amplitudeCount = -1; 2079 2080 if (effect instanceof VibrationEffect.Composed) { 2081 VibrationEffect.Composed composed = (VibrationEffect.Composed) effect; 2082 int segmentCount = composed.getSegments().size(); 2083 pattern = new long[segmentCount]; 2084 amplitudes = new int[segmentCount]; 2085 patternRepeatIndex = composed.getRepeatIndex(); 2086 amplitudeCount = 0; 2087 for (int i = 0; i < segmentCount; i++) { 2088 VibrationEffectSegment segment = composed.getSegments().get(i); 2089 if (composed.getRepeatIndex() == i) { 2090 patternRepeatIndex = amplitudeCount; 2091 } 2092 if (!(segment instanceof StepSegment)) { 2093 Slog.w(TAG, "Input devices don't support segment " + segment); 2094 amplitudeCount = -1; 2095 break; 2096 } 2097 float amplitude = ((StepSegment) segment).getAmplitude(); 2098 if (Float.compare(amplitude, VibrationEffect.DEFAULT_AMPLITUDE) == 0) { 2099 amplitudes[amplitudeCount] = DEFAULT_VIBRATION_MAGNITUDE; 2100 } else { 2101 amplitudes[amplitudeCount] = 2102 (int) (amplitude * VibrationEffect.MAX_AMPLITUDE); 2103 } 2104 pattern[amplitudeCount++] = segment.getDuration(); 2105 } 2106 } 2107 2108 if (amplitudeCount < 0) { 2109 Slog.w(TAG, "Only oneshot and step waveforms are supported on input devices"); 2110 mPattern = new long[0]; 2111 mAmplitudes = new int[0]; 2112 mRepeat = -1; 2113 } else { 2114 mRepeat = patternRepeatIndex; 2115 mPattern = new long[amplitudeCount]; 2116 mAmplitudes = new int[amplitudeCount]; 2117 System.arraycopy(pattern, 0, mPattern, 0, amplitudeCount); 2118 System.arraycopy(amplitudes, 0, mAmplitudes, 0, amplitudeCount); 2119 if (mRepeat >= mPattern.length) { 2120 throw new ArrayIndexOutOfBoundsException("Repeat index " + mRepeat 2121 + " must be within the bounds of the pattern.length " 2122 + mPattern.length); 2123 } 2124 } 2125 } 2126 } 2127 getVibratorToken(int deviceId, IBinder token)2128 private VibratorToken getVibratorToken(int deviceId, IBinder token) { 2129 VibratorToken v; 2130 synchronized (mVibratorLock) { 2131 v = mVibratorTokens.get(token); 2132 if (v == null) { 2133 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++); 2134 try { 2135 token.linkToDeath(v, 0); 2136 } catch (RemoteException ex) { 2137 // give up 2138 throw new RuntimeException(ex); 2139 } 2140 mVibratorTokens.put(token, v); 2141 } 2142 } 2143 return v; 2144 } 2145 2146 // Binder call 2147 @Override vibrate(int deviceId, VibrationEffect effect, IBinder token)2148 public void vibrate(int deviceId, VibrationEffect effect, IBinder token) { 2149 VibrationInfo info = new VibrationInfo(effect); 2150 VibratorToken v = getVibratorToken(deviceId, token); 2151 synchronized (v) { 2152 v.mVibrating = true; 2153 mNative.vibrate(deviceId, info.getPattern(), info.getAmplitudes(), 2154 info.getRepeatIndex(), v.mTokenValue); 2155 } 2156 } 2157 2158 // Binder call 2159 @Override getVibratorIds(int deviceId)2160 public int[] getVibratorIds(int deviceId) { 2161 return mNative.getVibratorIds(deviceId); 2162 } 2163 2164 // Binder call 2165 @Override isVibrating(int deviceId)2166 public boolean isVibrating(int deviceId) { 2167 return mNative.isVibrating(deviceId); 2168 } 2169 2170 // Binder call 2171 @Override vibrateCombined(int deviceId, CombinedVibration effect, IBinder token)2172 public void vibrateCombined(int deviceId, CombinedVibration effect, IBinder token) { 2173 VibratorToken v = getVibratorToken(deviceId, token); 2174 synchronized (v) { 2175 if (!(effect instanceof CombinedVibration.Mono) 2176 && !(effect instanceof CombinedVibration.Stereo)) { 2177 Slog.e(TAG, "Only Mono and Stereo effects are supported"); 2178 return; 2179 } 2180 2181 v.mVibrating = true; 2182 if (effect instanceof CombinedVibration.Mono) { 2183 CombinedVibration.Mono mono = (CombinedVibration.Mono) effect; 2184 VibrationInfo info = new VibrationInfo(mono.getEffect()); 2185 mNative.vibrate(deviceId, info.getPattern(), info.getAmplitudes(), 2186 info.getRepeatIndex(), v.mTokenValue); 2187 } else if (effect instanceof CombinedVibration.Stereo) { 2188 CombinedVibration.Stereo stereo = (CombinedVibration.Stereo) effect; 2189 SparseArray<VibrationEffect> effects = stereo.getEffects(); 2190 long[] pattern = new long[0]; 2191 int repeat = Integer.MIN_VALUE; 2192 SparseArray<int[]> amplitudes = new SparseArray<>(effects.size()); 2193 for (int i = 0; i < effects.size(); i++) { 2194 VibrationInfo info = new VibrationInfo(effects.valueAt(i)); 2195 // Pattern of all effects should be same 2196 if (pattern.length == 0) { 2197 pattern = info.getPattern(); 2198 } 2199 if (repeat == Integer.MIN_VALUE) { 2200 repeat = info.getRepeatIndex(); 2201 } 2202 amplitudes.put(effects.keyAt(i), info.getAmplitudes()); 2203 } 2204 mNative.vibrateCombined(deviceId, pattern, amplitudes, repeat, 2205 v.mTokenValue); 2206 } 2207 } 2208 } 2209 2210 // Binder call 2211 @Override cancelVibrate(int deviceId, IBinder token)2212 public void cancelVibrate(int deviceId, IBinder token) { 2213 VibratorToken v; 2214 synchronized (mVibratorLock) { 2215 v = mVibratorTokens.get(token); 2216 if (v == null || v.mDeviceId != deviceId) { 2217 return; // nothing to cancel 2218 } 2219 } 2220 2221 cancelVibrateIfNeeded(v); 2222 } 2223 onVibratorTokenDied(VibratorToken v)2224 void onVibratorTokenDied(VibratorToken v) { 2225 synchronized (mVibratorLock) { 2226 mVibratorTokens.remove(v.mToken); 2227 } 2228 2229 cancelVibrateIfNeeded(v); 2230 } 2231 cancelVibrateIfNeeded(VibratorToken v)2232 private void cancelVibrateIfNeeded(VibratorToken v) { 2233 synchronized (v) { 2234 if (v.mVibrating) { 2235 mNative.cancelVibrate(v.mDeviceId, v.mTokenValue); 2236 v.mVibrating = false; 2237 } 2238 } 2239 } 2240 2241 // Native callback. 2242 @SuppressWarnings("unused") notifyVibratorState(int deviceId, boolean isOn)2243 private void notifyVibratorState(int deviceId, boolean isOn) { 2244 if (DEBUG) { 2245 Slog.d(TAG, "notifyVibratorState: deviceId=" + deviceId + " isOn=" + isOn); 2246 } 2247 synchronized (mVibratorLock) { 2248 mIsVibrating.put(deviceId, isOn); 2249 notifyVibratorStateListenersLocked(deviceId); 2250 } 2251 } 2252 2253 @GuardedBy("mVibratorLock") notifyVibratorStateListenersLocked(int deviceId)2254 private void notifyVibratorStateListenersLocked(int deviceId) { 2255 if (!mVibratorStateListeners.contains(deviceId)) { 2256 if (DEBUG) { 2257 Slog.v(TAG, "Device " + deviceId + " doesn't have vibrator state listener."); 2258 } 2259 return; 2260 } 2261 RemoteCallbackList<IVibratorStateListener> listeners = 2262 mVibratorStateListeners.get(deviceId); 2263 final int length = listeners.beginBroadcast(); 2264 try { 2265 for (int i = 0; i < length; i++) { 2266 notifyVibratorStateListenerLocked(deviceId, listeners.getBroadcastItem(i)); 2267 } 2268 } finally { 2269 listeners.finishBroadcast(); 2270 } 2271 } 2272 2273 @GuardedBy("mVibratorLock") notifyVibratorStateListenerLocked(int deviceId, IVibratorStateListener listener)2274 private void notifyVibratorStateListenerLocked(int deviceId, IVibratorStateListener listener) { 2275 try { 2276 listener.onVibrating(mIsVibrating.get(deviceId)); 2277 } catch (RemoteException | RuntimeException e) { 2278 Slog.e(TAG, "Vibrator state listener failed to call", e); 2279 } 2280 } 2281 2282 @Override // Binder call registerVibratorStateListener(int deviceId, IVibratorStateListener listener)2283 public boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) { 2284 Objects.requireNonNull(listener, "listener must not be null"); 2285 2286 RemoteCallbackList<IVibratorStateListener> listeners; 2287 synchronized (mVibratorLock) { 2288 if (!mVibratorStateListeners.contains(deviceId)) { 2289 listeners = new RemoteCallbackList<>(); 2290 mVibratorStateListeners.put(deviceId, listeners); 2291 } else { 2292 listeners = mVibratorStateListeners.get(deviceId); 2293 } 2294 2295 final long token = Binder.clearCallingIdentity(); 2296 try { 2297 if (!listeners.register(listener)) { 2298 Slog.e(TAG, "Could not register vibrator state listener " + listener); 2299 return false; 2300 } 2301 // Notify its callback after new client registered. 2302 notifyVibratorStateListenerLocked(deviceId, listener); 2303 return true; 2304 } finally { 2305 Binder.restoreCallingIdentity(token); 2306 } 2307 } 2308 } 2309 2310 @Override // Binder call unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener)2311 public boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) { 2312 synchronized (mVibratorLock) { 2313 final long token = Binder.clearCallingIdentity(); 2314 try { 2315 if (!mVibratorStateListeners.contains(deviceId)) { 2316 Slog.w(TAG, "Vibrator state listener " + deviceId + " doesn't exist"); 2317 return false; 2318 } 2319 RemoteCallbackList<IVibratorStateListener> listeners = 2320 mVibratorStateListeners.get(deviceId); 2321 return listeners.unregister(listener); 2322 } finally { 2323 Binder.restoreCallingIdentity(token); 2324 } 2325 } 2326 } 2327 2328 // Binder call 2329 @Override getBatteryStatus(int deviceId)2330 public int getBatteryStatus(int deviceId) { 2331 return mNative.getBatteryStatus(deviceId); 2332 } 2333 2334 // Binder call 2335 @Override getBatteryCapacity(int deviceId)2336 public int getBatteryCapacity(int deviceId) { 2337 return mNative.getBatteryCapacity(deviceId); 2338 } 2339 2340 // Binder call 2341 @Override setPointerIconType(int iconType)2342 public void setPointerIconType(int iconType) { 2343 if (iconType == PointerIcon.TYPE_CUSTOM) { 2344 throw new IllegalArgumentException("Use setCustomPointerIcon to set custom pointers"); 2345 } 2346 synchronized (mAdditionalDisplayInputPropertiesLock) { 2347 mIcon = null; 2348 mIconType = iconType; 2349 2350 if (!mCurrentDisplayProperties.pointerIconVisible) return; 2351 2352 mNative.setPointerIconType(mIconType); 2353 } 2354 } 2355 2356 // Binder call 2357 @Override setCustomPointerIcon(PointerIcon icon)2358 public void setCustomPointerIcon(PointerIcon icon) { 2359 Objects.requireNonNull(icon); 2360 synchronized (mAdditionalDisplayInputPropertiesLock) { 2361 mIconType = PointerIcon.TYPE_CUSTOM; 2362 mIcon = icon; 2363 2364 if (!mCurrentDisplayProperties.pointerIconVisible) return; 2365 2366 mNative.setCustomPointerIcon(mIcon); 2367 } 2368 } 2369 2370 /** 2371 * Add a runtime association between the input port and the display port. This overrides any 2372 * static associations. 2373 * @param inputPort The port of the input device. 2374 * @param displayPort The physical port of the associated display. 2375 */ 2376 @Override // Binder call addPortAssociation(@onNull String inputPort, int displayPort)2377 public void addPortAssociation(@NonNull String inputPort, int displayPort) { 2378 if (!checkCallingPermission( 2379 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, 2380 "addPortAssociation()")) { 2381 throw new SecurityException( 2382 "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); 2383 } 2384 2385 Objects.requireNonNull(inputPort); 2386 synchronized (mAssociationsLock) { 2387 mRuntimeAssociations.put(inputPort, displayPort); 2388 } 2389 mNative.notifyPortAssociationsChanged(); 2390 } 2391 2392 /** 2393 * Remove the runtime association between the input port and the display port. Any existing 2394 * static association for the cleared input port will be restored. 2395 * @param inputPort The port of the input device to be cleared. 2396 */ 2397 @Override // Binder call removePortAssociation(@onNull String inputPort)2398 public void removePortAssociation(@NonNull String inputPort) { 2399 if (!checkCallingPermission( 2400 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, 2401 "clearPortAssociations()")) { 2402 throw new SecurityException( 2403 "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); 2404 } 2405 2406 Objects.requireNonNull(inputPort); 2407 synchronized (mAssociationsLock) { 2408 mRuntimeAssociations.remove(inputPort); 2409 } 2410 mNative.notifyPortAssociationsChanged(); 2411 } 2412 2413 @Override // Binder call addUniqueIdAssociation(@onNull String inputPort, @NonNull String displayUniqueId)2414 public void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) { 2415 if (!checkCallingPermission( 2416 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, 2417 "addNameAssociation()")) { 2418 throw new SecurityException( 2419 "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); 2420 } 2421 2422 Objects.requireNonNull(inputPort); 2423 Objects.requireNonNull(displayUniqueId); 2424 synchronized (mAssociationsLock) { 2425 mUniqueIdAssociations.put(inputPort, displayUniqueId); 2426 } 2427 mNative.changeUniqueIdAssociation(); 2428 } 2429 2430 @Override // Binder call removeUniqueIdAssociation(@onNull String inputPort)2431 public void removeUniqueIdAssociation(@NonNull String inputPort) { 2432 if (!checkCallingPermission( 2433 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, 2434 "removeUniqueIdAssociation()")) { 2435 throw new SecurityException( 2436 "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); 2437 } 2438 2439 Objects.requireNonNull(inputPort); 2440 synchronized (mAssociationsLock) { 2441 mUniqueIdAssociations.remove(inputPort); 2442 } 2443 mNative.changeUniqueIdAssociation(); 2444 } 2445 2446 @Override // Binder call getSensorList(int deviceId)2447 public InputSensorInfo[] getSensorList(int deviceId) { 2448 return mNative.getSensorList(deviceId); 2449 } 2450 2451 @Override // Binder call registerSensorListener(IInputSensorEventListener listener)2452 public boolean registerSensorListener(IInputSensorEventListener listener) { 2453 if (DEBUG) { 2454 Slog.d(TAG, "registerSensorListener: listener=" + listener + " callingPid=" 2455 + Binder.getCallingPid()); 2456 } 2457 Objects.requireNonNull(listener, "listener must not be null"); 2458 2459 synchronized (mSensorEventLock) { 2460 int callingPid = Binder.getCallingPid(); 2461 if (mSensorEventListeners.get(callingPid) != null) { 2462 Slog.e(TAG, "The calling process " + callingPid + " has already " 2463 + "registered an InputSensorEventListener."); 2464 return false; 2465 } 2466 2467 SensorEventListenerRecord record = 2468 new SensorEventListenerRecord(callingPid, listener); 2469 try { 2470 IBinder binder = listener.asBinder(); 2471 binder.linkToDeath(record, 0); 2472 } catch (RemoteException ex) { 2473 // give up 2474 throw new RuntimeException(ex); 2475 } 2476 2477 mSensorEventListeners.put(callingPid, record); 2478 } 2479 return true; 2480 } 2481 2482 @Override // Binder call unregisterSensorListener(IInputSensorEventListener listener)2483 public void unregisterSensorListener(IInputSensorEventListener listener) { 2484 if (DEBUG) { 2485 Slog.d(TAG, "unregisterSensorListener: listener=" + listener + " callingPid=" 2486 + Binder.getCallingPid()); 2487 } 2488 2489 Objects.requireNonNull(listener, "listener must not be null"); 2490 2491 synchronized (mSensorEventLock) { 2492 int callingPid = Binder.getCallingPid(); 2493 if (mSensorEventListeners.get(callingPid) != null) { 2494 SensorEventListenerRecord record = mSensorEventListeners.get(callingPid); 2495 if (record.getListener().asBinder() != listener.asBinder()) { 2496 throw new IllegalArgumentException("listener is not registered"); 2497 } 2498 mSensorEventListeners.remove(callingPid); 2499 } 2500 } 2501 } 2502 2503 @Override // Binder call flushSensor(int deviceId, int sensorType)2504 public boolean flushSensor(int deviceId, int sensorType) { 2505 synchronized (mSensorEventLock) { 2506 int callingPid = Binder.getCallingPid(); 2507 SensorEventListenerRecord listener = mSensorEventListeners.get(callingPid); 2508 if (listener != null) { 2509 return mNative.flushSensor(deviceId, sensorType); 2510 } 2511 return false; 2512 } 2513 } 2514 2515 @Override // Binder call enableSensor(int deviceId, int sensorType, int samplingPeriodUs, int maxBatchReportLatencyUs)2516 public boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs, 2517 int maxBatchReportLatencyUs) { 2518 synchronized (mInputDevicesLock) { 2519 return mNative.enableSensor(deviceId, sensorType, samplingPeriodUs, 2520 maxBatchReportLatencyUs); 2521 } 2522 } 2523 2524 @Override // Binder call disableSensor(int deviceId, int sensorType)2525 public void disableSensor(int deviceId, int sensorType) { 2526 synchronized (mInputDevicesLock) { 2527 mNative.disableSensor(deviceId, sensorType); 2528 } 2529 } 2530 2531 /** 2532 * LightSession represents a light session for lights manager. 2533 */ 2534 private final class LightSession implements DeathRecipient { 2535 private final int mDeviceId; 2536 private final IBinder mToken; 2537 private final String mOpPkg; 2538 // The light ids and states that are requested by the light seesion 2539 private int[] mLightIds; 2540 private LightState[] mLightStates; 2541 LightSession(int deviceId, String opPkg, IBinder token)2542 LightSession(int deviceId, String opPkg, IBinder token) { 2543 mDeviceId = deviceId; 2544 mOpPkg = opPkg; 2545 mToken = token; 2546 } 2547 2548 @Override binderDied()2549 public void binderDied() { 2550 if (DEBUG) { 2551 Slog.d(TAG, "Light token died."); 2552 } 2553 synchronized (mLightLock) { 2554 closeLightSession(mDeviceId, mToken); 2555 mLightSessions.remove(mToken); 2556 } 2557 } 2558 } 2559 2560 /** 2561 * Returns the lights available for apps to control on the specified input device. 2562 * Only lights that aren't reserved for system use are available to apps. 2563 */ 2564 @Override // Binder call getLights(int deviceId)2565 public List<Light> getLights(int deviceId) { 2566 return mNative.getLights(deviceId); 2567 } 2568 2569 /** 2570 * Set specified light state with for a specific input device. 2571 */ setLightStateInternal(int deviceId, Light light, LightState lightState)2572 private void setLightStateInternal(int deviceId, Light light, LightState lightState) { 2573 Objects.requireNonNull(light, "light does not exist"); 2574 if (DEBUG) { 2575 Slog.d(TAG, "setLightStateInternal device " + deviceId + " light " + light 2576 + "lightState " + lightState); 2577 } 2578 if (light.getType() == Light.LIGHT_TYPE_PLAYER_ID) { 2579 mNative.setLightPlayerId(deviceId, light.getId(), lightState.getPlayerId()); 2580 } else { 2581 // Set ARGB format color to input device light 2582 // Refer to https://developer.android.com/reference/kotlin/android/graphics/Color 2583 mNative.setLightColor(deviceId, light.getId(), lightState.getColor()); 2584 } 2585 } 2586 2587 /** 2588 * Set multiple light states with multiple light ids for a specific input device. 2589 */ setLightStatesInternal(int deviceId, int[] lightIds, LightState[] lightStates)2590 private void setLightStatesInternal(int deviceId, int[] lightIds, LightState[] lightStates) { 2591 final List<Light> lights = mNative.getLights(deviceId); 2592 SparseArray<Light> lightArray = new SparseArray<>(); 2593 for (int i = 0; i < lights.size(); i++) { 2594 lightArray.put(lights.get(i).getId(), lights.get(i)); 2595 } 2596 for (int i = 0; i < lightIds.length; i++) { 2597 if (lightArray.contains(lightIds[i])) { 2598 setLightStateInternal(deviceId, lightArray.get(lightIds[i]), lightStates[i]); 2599 } 2600 } 2601 } 2602 2603 /** 2604 * Set states for multiple lights for an opened light session. 2605 */ 2606 @Override setLightStates(int deviceId, int[] lightIds, LightState[] lightStates, IBinder token)2607 public void setLightStates(int deviceId, int[] lightIds, LightState[] lightStates, 2608 IBinder token) { 2609 Preconditions.checkArgument(lightIds.length == lightStates.length, 2610 "lights and light states are not same length"); 2611 synchronized (mLightLock) { 2612 LightSession lightSession = mLightSessions.get(token); 2613 Preconditions.checkArgument(lightSession != null, "not registered"); 2614 Preconditions.checkState(lightSession.mDeviceId == deviceId, "Incorrect device ID"); 2615 lightSession.mLightIds = lightIds.clone(); 2616 lightSession.mLightStates = lightStates.clone(); 2617 if (DEBUG) { 2618 Slog.d(TAG, "setLightStates for " + lightSession.mOpPkg + " device " + deviceId); 2619 } 2620 } 2621 setLightStatesInternal(deviceId, lightIds, lightStates); 2622 } 2623 2624 @Override getLightState(int deviceId, int lightId)2625 public @Nullable LightState getLightState(int deviceId, int lightId) { 2626 synchronized (mLightLock) { 2627 int color = mNative.getLightColor(deviceId, lightId); 2628 int playerId = mNative.getLightPlayerId(deviceId, lightId); 2629 2630 return new LightState(color, playerId); 2631 } 2632 } 2633 2634 @Override openLightSession(int deviceId, String opPkg, IBinder token)2635 public void openLightSession(int deviceId, String opPkg, IBinder token) { 2636 Objects.requireNonNull(token); 2637 synchronized (mLightLock) { 2638 Preconditions.checkState(mLightSessions.get(token) == null, "already registered"); 2639 LightSession lightSession = new LightSession(deviceId, opPkg, token); 2640 try { 2641 token.linkToDeath(lightSession, 0); 2642 } catch (RemoteException ex) { 2643 // give up 2644 ex.rethrowAsRuntimeException(); 2645 } 2646 mLightSessions.put(token, lightSession); 2647 if (DEBUG) { 2648 Slog.d(TAG, "Open light session for " + opPkg + " device " + deviceId); 2649 } 2650 } 2651 } 2652 2653 @Override closeLightSession(int deviceId, IBinder token)2654 public void closeLightSession(int deviceId, IBinder token) { 2655 Objects.requireNonNull(token); 2656 synchronized (mLightLock) { 2657 LightSession lightSession = mLightSessions.get(token); 2658 Preconditions.checkState(lightSession != null, "not registered"); 2659 // Turn off the lights that were previously requested by the session to be closed. 2660 Arrays.fill(lightSession.mLightStates, new LightState(0)); 2661 setLightStatesInternal(deviceId, lightSession.mLightIds, 2662 lightSession.mLightStates); 2663 mLightSessions.remove(token); 2664 // If any other session is still pending with light request, apply the first session's 2665 // request. 2666 if (!mLightSessions.isEmpty()) { 2667 LightSession nextSession = mLightSessions.valueAt(0); 2668 setLightStatesInternal(deviceId, nextSession.mLightIds, nextSession.mLightStates); 2669 } 2670 } 2671 } 2672 2673 @Override cancelCurrentTouch()2674 public void cancelCurrentTouch() { 2675 if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT, 2676 "cancelCurrentTouch()")) { 2677 throw new SecurityException("Requires MONITOR_INPUT permission"); 2678 } 2679 2680 mNative.cancelCurrentTouch(); 2681 } 2682 2683 @EnforcePermission(Manifest.permission.MONITOR_INPUT) 2684 @Override pilferPointers(IBinder inputChannelToken)2685 public void pilferPointers(IBinder inputChannelToken) { 2686 Objects.requireNonNull(inputChannelToken); 2687 mNative.pilferPointers(inputChannelToken); 2688 } 2689 2690 @Override registerBatteryListener(int deviceId, IInputDeviceBatteryListener listener)2691 public void registerBatteryListener(int deviceId, IInputDeviceBatteryListener listener) { 2692 Objects.requireNonNull(listener); 2693 mBatteryController.registerBatteryListener(deviceId, listener, Binder.getCallingPid()); 2694 } 2695 2696 @Override unregisterBatteryListener(int deviceId, IInputDeviceBatteryListener listener)2697 public void unregisterBatteryListener(int deviceId, IInputDeviceBatteryListener listener) { 2698 Objects.requireNonNull(listener); 2699 mBatteryController.unregisterBatteryListener(deviceId, listener, Binder.getCallingPid()); 2700 } 2701 2702 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)2703 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2704 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 2705 2706 pw.println("INPUT MANAGER (dumpsys input)\n"); 2707 String dumpStr = mNative.dump(); 2708 if (dumpStr != null) { 2709 pw.println(dumpStr); 2710 } 2711 2712 pw.println("Input Manager Service (Java) State:"); 2713 dumpAssociations(pw, " " /*prefix*/); 2714 dumpSpyWindowGestureMonitors(pw, " " /*prefix*/); 2715 dumpDisplayInputPropertiesValues(pw, " " /*prefix*/); 2716 mBatteryController.dump(pw, " " /*prefix*/); 2717 } 2718 dumpAssociations(PrintWriter pw, String prefix)2719 private void dumpAssociations(PrintWriter pw, String prefix) { 2720 if (!mStaticAssociations.isEmpty()) { 2721 pw.println(prefix + "Static Associations:"); 2722 mStaticAssociations.forEach((k, v) -> { 2723 pw.print(prefix + " port: " + k); 2724 pw.println(" display: " + v); 2725 }); 2726 } 2727 2728 synchronized (mAssociationsLock) { 2729 if (!mRuntimeAssociations.isEmpty()) { 2730 pw.println(prefix + "Runtime Associations:"); 2731 mRuntimeAssociations.forEach((k, v) -> { 2732 pw.print(prefix + " port: " + k); 2733 pw.println(" display: " + v); 2734 }); 2735 } 2736 if (!mUniqueIdAssociations.isEmpty()) { 2737 pw.println(prefix + "Unique Id Associations:"); 2738 mUniqueIdAssociations.forEach((k, v) -> { 2739 pw.print(prefix + " port: " + k); 2740 pw.println(" uniqueId: " + v); 2741 }); 2742 } 2743 } 2744 } 2745 dumpSpyWindowGestureMonitors(PrintWriter pw, String prefix)2746 private void dumpSpyWindowGestureMonitors(PrintWriter pw, String prefix) { 2747 synchronized (mInputMonitors) { 2748 if (mInputMonitors.isEmpty()) return; 2749 pw.println(prefix + "Gesture Monitors (implemented as spy windows):"); 2750 int i = 0; 2751 for (final GestureMonitorSpyWindow monitor : mInputMonitors.values()) { 2752 pw.append(prefix + " " + i++ + ": ").println(monitor.dump()); 2753 } 2754 } 2755 } 2756 dumpDisplayInputPropertiesValues(PrintWriter pw, String prefix)2757 private void dumpDisplayInputPropertiesValues(PrintWriter pw, String prefix) { 2758 synchronized (mAdditionalDisplayInputPropertiesLock) { 2759 if (mAdditionalDisplayInputProperties.size() != 0) { 2760 pw.println(prefix + "mAdditionalDisplayInputProperties:"); 2761 for (int i = 0; i < mAdditionalDisplayInputProperties.size(); i++) { 2762 pw.println(prefix + " displayId: " 2763 + mAdditionalDisplayInputProperties.keyAt(i)); 2764 final AdditionalDisplayInputProperties properties = 2765 mAdditionalDisplayInputProperties.valueAt(i); 2766 pw.println(prefix + " pointerAcceleration: " + properties.pointerAcceleration); 2767 pw.println(prefix + " pointerIconVisible: " + properties.pointerIconVisible); 2768 } 2769 } 2770 if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) { 2771 pw.println(prefix + "mOverriddenPointerDisplayId: " + mOverriddenPointerDisplayId); 2772 } 2773 } 2774 } checkCallingPermission(String permission, String func)2775 private boolean checkCallingPermission(String permission, String func) { 2776 return checkCallingPermission(permission, func, false /*checkInstrumentationSource*/); 2777 } 2778 checkCallingPermission(String permission, String func, boolean checkInstrumentationSource)2779 private boolean checkCallingPermission(String permission, String func, 2780 boolean checkInstrumentationSource) { 2781 // Quick check: if the calling permission is me, it's all okay. 2782 if (Binder.getCallingPid() == Process.myPid()) { 2783 return true; 2784 } 2785 2786 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { 2787 return true; 2788 } 2789 2790 if (checkInstrumentationSource) { 2791 final ActivityManagerInternal ami = 2792 LocalServices.getService(ActivityManagerInternal.class); 2793 Objects.requireNonNull(ami, "ActivityManagerInternal should not be null."); 2794 final int instrumentationUid = ami.getInstrumentationSourceUid(Binder.getCallingUid()); 2795 if (instrumentationUid != Process.INVALID_UID) { 2796 // Clear the calling identity when checking if the instrumentation source has 2797 // permission because PackageManager will deny all permissions to some callers, 2798 // such as instant apps. 2799 final long token = Binder.clearCallingIdentity(); 2800 try { 2801 if (mContext.checkPermission(permission, -1 /*pid*/, instrumentationUid) 2802 == PackageManager.PERMISSION_GRANTED) { 2803 return true; 2804 } 2805 } finally { 2806 Binder.restoreCallingIdentity(token); 2807 } 2808 } 2809 } 2810 2811 String msg = "Permission Denial: " + func + " from pid=" 2812 + Binder.getCallingPid() 2813 + ", uid=" + Binder.getCallingUid() 2814 + " requires " + permission; 2815 Slog.w(TAG, msg); 2816 return false; 2817 } 2818 2819 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). 2820 @Override monitor()2821 public void monitor() { 2822 synchronized (mInputFilterLock) { } 2823 synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */} 2824 synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ } 2825 synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ } 2826 synchronized (mAdditionalDisplayInputPropertiesLock) { /* Test if blocked by props lock */ } 2827 mBatteryController.monitor(); 2828 mNative.monitor(); 2829 } 2830 2831 // Native callback. 2832 @SuppressWarnings("unused") notifyConfigurationChanged(long whenNanos)2833 private void notifyConfigurationChanged(long whenNanos) { 2834 mWindowManagerCallbacks.notifyConfigurationChanged(); 2835 } 2836 2837 // Native callback. 2838 @SuppressWarnings("unused") notifyInputDevicesChanged(InputDevice[] inputDevices)2839 private void notifyInputDevicesChanged(InputDevice[] inputDevices) { 2840 synchronized (mInputDevicesLock) { 2841 if (!mInputDevicesChangedPending) { 2842 mInputDevicesChangedPending = true; 2843 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED, 2844 mInputDevices).sendToTarget(); 2845 } 2846 2847 mInputDevices = inputDevices; 2848 } 2849 } 2850 2851 // Native callback. 2852 @SuppressWarnings("unused") notifySwitch(long whenNanos, int switchValues, int switchMask)2853 private void notifySwitch(long whenNanos, int switchValues, int switchMask) { 2854 if (DEBUG) { 2855 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues) 2856 + ", mask=" + Integer.toHexString(switchMask)); 2857 } 2858 2859 if ((switchMask & SW_LID_BIT) != 0) { 2860 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0); 2861 synchronized (mLidSwitchLock) { 2862 if (mSystemReady) { 2863 for (int i = 0; i < mLidSwitchCallbacks.size(); i++) { 2864 LidSwitchCallback callbacks = mLidSwitchCallbacks.get(i); 2865 callbacks.notifyLidSwitchChanged(whenNanos, lidOpen); 2866 } 2867 } 2868 } 2869 } 2870 2871 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) { 2872 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0); 2873 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered); 2874 // Use SW_CAMERA_LENS_COVER code for camera privacy toggles 2875 setSensorPrivacy(Sensors.CAMERA, lensCovered); 2876 } 2877 2878 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) { 2879 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues, 2880 switchMask); 2881 } 2882 2883 if ((switchMask & SW_TABLET_MODE_BIT) != 0) { 2884 SomeArgs args = SomeArgs.obtain(); 2885 args.argi1 = (int) (whenNanos & 0xFFFFFFFF); 2886 args.argi2 = (int) (whenNanos >> 32); 2887 args.arg1 = (switchValues & SW_TABLET_MODE_BIT) != 0; 2888 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED, 2889 args).sendToTarget(); 2890 } 2891 2892 if ((switchMask & SW_MUTE_DEVICE_BIT) != 0) { 2893 final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0); 2894 AudioManager audioManager = mContext.getSystemService(AudioManager.class); 2895 audioManager.setMicrophoneMuteFromSwitch(micMute); 2896 2897 setSensorPrivacy(Sensors.MICROPHONE, micMute); 2898 } 2899 } 2900 2901 // Set the sensor privacy state based on the hardware toggles switch states setSensorPrivacy(@ensorPrivacyManager.Sensors.Sensor int sensor, boolean enablePrivacy)2902 private void setSensorPrivacy(@SensorPrivacyManager.Sensors.Sensor int sensor, 2903 boolean enablePrivacy) { 2904 final SensorPrivacyManagerInternal sensorPrivacyManagerInternal = 2905 LocalServices.getService(SensorPrivacyManagerInternal.class); 2906 sensorPrivacyManagerInternal.setPhysicalToggleSensorPrivacy(UserHandle.USER_CURRENT, sensor, 2907 enablePrivacy); 2908 } 2909 2910 // Native callback. 2911 @SuppressWarnings("unused") notifyInputChannelBroken(IBinder token)2912 private void notifyInputChannelBroken(IBinder token) { 2913 synchronized (mInputMonitors) { 2914 if (mInputMonitors.containsKey(token)) { 2915 removeSpyWindowGestureMonitor(token); 2916 } 2917 } 2918 mWindowManagerCallbacks.notifyInputChannelBroken(token); 2919 } 2920 2921 // Native callback 2922 @SuppressWarnings("unused") notifyFocusChanged(IBinder oldToken, IBinder newToken)2923 private void notifyFocusChanged(IBinder oldToken, IBinder newToken) { 2924 mWindowManagerCallbacks.notifyFocusChanged(oldToken, newToken); 2925 } 2926 2927 // Native callback 2928 @SuppressWarnings("unused") notifyDropWindow(IBinder token, float x, float y)2929 private void notifyDropWindow(IBinder token, float x, float y) { 2930 mWindowManagerCallbacks.notifyDropWindow(token, x, y); 2931 } 2932 2933 // Native callback 2934 @SuppressWarnings("unused") notifyUntrustedTouch(String packageName)2935 private void notifyUntrustedTouch(String packageName) { 2936 // TODO(b/169067926): Remove toast after gathering feedback on dogfood. 2937 if (!UNTRUSTED_TOUCHES_TOAST || ArrayUtils.contains( 2938 PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) { 2939 Log.i(TAG, "Suppressing untrusted touch toast for " + packageName); 2940 return; 2941 } 2942 DisplayThread.getHandler().post(() -> 2943 Toast.makeText(mContext, 2944 "Touch obscured by " + packageName 2945 + " will be blocked. Check go/untrusted-touches", 2946 Toast.LENGTH_SHORT).show()); 2947 } 2948 2949 // Native callback. 2950 @SuppressWarnings("unused") notifyNoFocusedWindowAnr(InputApplicationHandle inputApplicationHandle)2951 private void notifyNoFocusedWindowAnr(InputApplicationHandle inputApplicationHandle) { 2952 mWindowManagerCallbacks.notifyNoFocusedWindowAnr(inputApplicationHandle); 2953 } 2954 2955 // Native callback 2956 @SuppressWarnings("unused") notifyWindowUnresponsive(IBinder token, int pid, boolean isPidValid, String reason)2957 private void notifyWindowUnresponsive(IBinder token, int pid, boolean isPidValid, 2958 String reason) { 2959 mWindowManagerCallbacks.notifyWindowUnresponsive(token, 2960 isPidValid ? OptionalInt.of(pid) : OptionalInt.empty(), reason); 2961 } 2962 2963 // Native callback 2964 @SuppressWarnings("unused") notifyWindowResponsive(IBinder token, int pid, boolean isPidValid)2965 private void notifyWindowResponsive(IBinder token, int pid, boolean isPidValid) { 2966 mWindowManagerCallbacks.notifyWindowResponsive(token, 2967 isPidValid ? OptionalInt.of(pid) : OptionalInt.empty()); 2968 } 2969 2970 // Native callback. 2971 @SuppressWarnings("unused") notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, float[] values)2972 private void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, 2973 float[] values) { 2974 if (DEBUG) { 2975 Slog.d(TAG, "notifySensorEvent: deviceId=" + deviceId + " sensorType=" 2976 + sensorType + " values=" + Arrays.toString(values)); 2977 } 2978 mSensorEventListenersToNotify.clear(); 2979 final int numListeners; 2980 synchronized (mSensorEventLock) { 2981 numListeners = mSensorEventListeners.size(); 2982 for (int i = 0; i < numListeners; i++) { 2983 mSensorEventListenersToNotify.add( 2984 mSensorEventListeners.valueAt(i)); 2985 } 2986 } 2987 for (int i = 0; i < numListeners; i++) { 2988 mSensorEventListenersToNotify.get(i).notifySensorEvent(deviceId, sensorType, 2989 accuracy, timestamp, values); 2990 } 2991 mSensorEventListenersToNotify.clear(); 2992 } 2993 2994 // Native callback. 2995 @SuppressWarnings("unused") notifySensorAccuracy(int deviceId, int sensorType, int accuracy)2996 private void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) { 2997 mSensorAccuracyListenersToNotify.clear(); 2998 final int numListeners; 2999 synchronized (mSensorEventLock) { 3000 numListeners = mSensorEventListeners.size(); 3001 for (int i = 0; i < numListeners; i++) { 3002 mSensorAccuracyListenersToNotify.add(mSensorEventListeners.valueAt(i)); 3003 } 3004 } 3005 for (int i = 0; i < numListeners; i++) { 3006 mSensorAccuracyListenersToNotify.get(i).notifySensorAccuracy( 3007 deviceId, sensorType, accuracy); 3008 } 3009 mSensorAccuracyListenersToNotify.clear(); 3010 } 3011 3012 // Native callback. 3013 @SuppressWarnings("unused") filterInputEvent(InputEvent event, int policyFlags)3014 final boolean filterInputEvent(InputEvent event, int policyFlags) { 3015 synchronized (mInputFilterLock) { 3016 if (mInputFilter != null) { 3017 try { 3018 mInputFilter.filterInputEvent(event, policyFlags); 3019 } catch (RemoteException e) { 3020 /* ignore */ 3021 } 3022 return false; 3023 } 3024 } 3025 event.recycle(); 3026 return true; 3027 } 3028 3029 // Native callback. 3030 @SuppressWarnings("unused") interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)3031 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { 3032 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags); 3033 } 3034 3035 // Native callback. 3036 @SuppressWarnings("unused") interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)3037 private int interceptMotionBeforeQueueingNonInteractive(int displayId, 3038 long whenNanos, int policyFlags) { 3039 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive( 3040 displayId, whenNanos, policyFlags); 3041 } 3042 3043 // Native callback. 3044 @SuppressWarnings("unused") interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags)3045 private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) { 3046 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); 3047 } 3048 3049 // Native callback. 3050 @SuppressWarnings("unused") dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags)3051 private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) { 3052 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags); 3053 } 3054 3055 // Native callback. 3056 @SuppressWarnings("unused") onPointerDownOutsideFocus(IBinder touchedToken)3057 private void onPointerDownOutsideFocus(IBinder touchedToken) { 3058 mWindowManagerCallbacks.onPointerDownOutsideFocus(touchedToken); 3059 } 3060 3061 // Native callback. 3062 @SuppressWarnings("unused") getVirtualKeyQuietTimeMillis()3063 private int getVirtualKeyQuietTimeMillis() { 3064 return mContext.getResources().getInteger( 3065 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis); 3066 } 3067 3068 // Native callback. 3069 @SuppressWarnings("unused") getExcludedDeviceNames()3070 private static String[] getExcludedDeviceNames() { 3071 List<String> names = new ArrayList<>(); 3072 // Read partner-provided list of excluded input devices 3073 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". 3074 final File[] baseDirs = { 3075 Environment.getRootDirectory(), 3076 Environment.getVendorDirectory() 3077 }; 3078 for (File baseDir: baseDirs) { 3079 File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH); 3080 try (InputStream stream = new FileInputStream(confFile)) { 3081 names.addAll(ConfigurationProcessor.processExcludedDeviceNames(stream)); 3082 } catch (FileNotFoundException e) { 3083 // It's ok if the file does not exist. 3084 } catch (Exception e) { 3085 Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e); 3086 } 3087 } 3088 return names.toArray(new String[0]); 3089 } 3090 3091 /** 3092 * Flatten a map into a string list, with value positioned directly next to the 3093 * key. 3094 * @return Flattened list 3095 */ flatten(@onNull Map<String, T> map)3096 private static <T> String[] flatten(@NonNull Map<String, T> map) { 3097 final List<String> list = new ArrayList<>(map.size() * 2); 3098 map.forEach((k, v)-> { 3099 list.add(k); 3100 list.add(v.toString()); 3101 }); 3102 return list.toArray(new String[0]); 3103 } 3104 3105 /** 3106 * Ports are highly platform-specific, so only allow these to be specified in the vendor 3107 * directory. 3108 */ loadStaticInputPortAssociations()3109 private static Map<String, Integer> loadStaticInputPortAssociations() { 3110 final File baseDir = Environment.getVendorDirectory(); 3111 final File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH); 3112 3113 try (final InputStream stream = new FileInputStream(confFile)) { 3114 return ConfigurationProcessor.processInputPortAssociations(stream); 3115 } catch (FileNotFoundException e) { 3116 // Most of the time, file will not exist, which is expected. 3117 } catch (Exception e) { 3118 Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e); 3119 } 3120 3121 return new HashMap<>(); 3122 } 3123 3124 // Native callback 3125 @SuppressWarnings("unused") getInputPortAssociations()3126 private String[] getInputPortAssociations() { 3127 final Map<String, Integer> associations = new HashMap<>(mStaticAssociations); 3128 3129 // merge the runtime associations. 3130 synchronized (mAssociationsLock) { 3131 associations.putAll(mRuntimeAssociations); 3132 } 3133 3134 return flatten(associations); 3135 } 3136 3137 // Native callback 3138 @SuppressWarnings("unused") getInputUniqueIdAssociations()3139 private String[] getInputUniqueIdAssociations() { 3140 final Map<String, String> associations; 3141 synchronized (mAssociationsLock) { 3142 associations = new HashMap<>(mUniqueIdAssociations); 3143 } 3144 3145 return flatten(associations); 3146 } 3147 3148 /** 3149 * Gets if an input device could dispatch to the given display". 3150 * @param deviceId The input device id. 3151 * @param displayId The specific display id. 3152 * @return True if the device could dispatch to the given display, false otherwise. 3153 */ canDispatchToDisplay(int deviceId, int displayId)3154 public boolean canDispatchToDisplay(int deviceId, int displayId) { 3155 return mNative.canDispatchToDisplay(deviceId, displayId); 3156 } 3157 3158 // Native callback. 3159 @SuppressWarnings("unused") getKeyRepeatTimeout()3160 private int getKeyRepeatTimeout() { 3161 return ViewConfiguration.getKeyRepeatTimeout(); 3162 } 3163 3164 // Native callback. 3165 @SuppressWarnings("unused") getKeyRepeatDelay()3166 private int getKeyRepeatDelay() { 3167 return ViewConfiguration.getKeyRepeatDelay(); 3168 } 3169 3170 // Native callback. 3171 @SuppressWarnings("unused") getHoverTapTimeout()3172 private int getHoverTapTimeout() { 3173 return ViewConfiguration.getHoverTapTimeout(); 3174 } 3175 3176 // Native callback. 3177 @SuppressWarnings("unused") getHoverTapSlop()3178 private int getHoverTapSlop() { 3179 return ViewConfiguration.getHoverTapSlop(); 3180 } 3181 3182 // Native callback. 3183 @SuppressWarnings("unused") getDoubleTapTimeout()3184 private int getDoubleTapTimeout() { 3185 return ViewConfiguration.getDoubleTapTimeout(); 3186 } 3187 3188 // Native callback. 3189 @SuppressWarnings("unused") getLongPressTimeout()3190 private int getLongPressTimeout() { 3191 return ViewConfiguration.getLongPressTimeout(); 3192 } 3193 3194 // Native callback. 3195 @SuppressWarnings("unused") getPointerLayer()3196 private int getPointerLayer() { 3197 return mWindowManagerCallbacks.getPointerLayer(); 3198 } 3199 3200 // Native callback. 3201 @SuppressWarnings("unused") getPointerIcon(int displayId)3202 private PointerIcon getPointerIcon(int displayId) { 3203 return PointerIcon.getDefaultIcon(getContextForPointerIcon(displayId)); 3204 } 3205 3206 // Native callback. 3207 @SuppressWarnings("unused") getParentSurfaceForPointers(int displayId)3208 private long getParentSurfaceForPointers(int displayId) { 3209 final SurfaceControl sc = mWindowManagerCallbacks.getParentSurfaceForPointers(displayId); 3210 if (sc == null) { 3211 return 0; 3212 } 3213 return sc.mNativeObject; 3214 } 3215 3216 @NonNull getContextForPointerIcon(int displayId)3217 private Context getContextForPointerIcon(int displayId) { 3218 if (mPointerIconDisplayContext != null 3219 && mPointerIconDisplayContext.getDisplay().getDisplayId() == displayId) { 3220 return mPointerIconDisplayContext; 3221 } 3222 3223 // Create and cache context for non-default display. 3224 mPointerIconDisplayContext = getContextForDisplay(displayId); 3225 3226 // Fall back to default display if the requested displayId does not exist. 3227 if (mPointerIconDisplayContext == null) { 3228 mPointerIconDisplayContext = getContextForDisplay(Display.DEFAULT_DISPLAY); 3229 } 3230 return mPointerIconDisplayContext; 3231 } 3232 3233 @Nullable getContextForDisplay(int displayId)3234 private Context getContextForDisplay(int displayId) { 3235 if (displayId == Display.INVALID_DISPLAY) { 3236 return null; 3237 } 3238 if (mContext.getDisplay().getDisplayId() == displayId) { 3239 return mContext; 3240 } 3241 3242 final DisplayManager displayManager = Objects.requireNonNull( 3243 mContext.getSystemService(DisplayManager.class)); 3244 final Display display = displayManager.getDisplay(displayId); 3245 if (display == null) { 3246 return null; 3247 } 3248 3249 return mContext.createDisplayContext(display); 3250 } 3251 3252 // Native callback. 3253 @SuppressWarnings("unused") getKeyboardLayoutOverlay(InputDeviceIdentifier identifier)3254 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) { 3255 if (!mSystemReady) { 3256 return null; 3257 } 3258 3259 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier); 3260 if (keyboardLayoutDescriptor == null) { 3261 return null; 3262 } 3263 3264 final String[] result = new String[2]; 3265 visitKeyboardLayout(keyboardLayoutDescriptor, 3266 (resources, keyboardLayoutResId, layout) -> { 3267 try (InputStreamReader stream = new InputStreamReader( 3268 resources.openRawResource(keyboardLayoutResId))) { 3269 result[0] = layout.getDescriptor(); 3270 result[1] = Streams.readFully(stream); 3271 } catch (IOException | NotFoundException ignored) { 3272 } 3273 }); 3274 if (result[0] == null) { 3275 Slog.w(TAG, "Could not get keyboard layout with descriptor '" 3276 + keyboardLayoutDescriptor + "'."); 3277 return null; 3278 } 3279 return result; 3280 } 3281 3282 // Native callback. 3283 @SuppressWarnings("unused") getDeviceAlias(String uniqueId)3284 private String getDeviceAlias(String uniqueId) { 3285 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) { 3286 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId) 3287 return null; 3288 } 3289 return null; 3290 } 3291 3292 private static class PointerDisplayIdChangedArgs { 3293 final int mPointerDisplayId; 3294 final float mXPosition; 3295 final float mYPosition; PointerDisplayIdChangedArgs(int pointerDisplayId, float xPosition, float yPosition)3296 PointerDisplayIdChangedArgs(int pointerDisplayId, float xPosition, float yPosition) { 3297 mPointerDisplayId = pointerDisplayId; 3298 mXPosition = xPosition; 3299 mYPosition = yPosition; 3300 } 3301 } 3302 3303 // Native callback. 3304 @SuppressWarnings("unused") 3305 @VisibleForTesting onPointerDisplayIdChanged(int pointerDisplayId, float xPosition, float yPosition)3306 void onPointerDisplayIdChanged(int pointerDisplayId, float xPosition, float yPosition) { 3307 mHandler.obtainMessage(MSG_POINTER_DISPLAY_ID_CHANGED, 3308 new PointerDisplayIdChangedArgs(pointerDisplayId, xPosition, 3309 yPosition)).sendToTarget(); 3310 } 3311 3312 /** 3313 * Callback interface implemented by the Window Manager. 3314 */ 3315 public interface WindowManagerCallbacks extends LidSwitchCallback { 3316 /** 3317 * This callback is invoked when the configuration changes. 3318 */ notifyConfigurationChanged()3319 void notifyConfigurationChanged(); 3320 3321 /** 3322 * This callback is invoked when the camera lens cover switch changes state. 3323 * @param whenNanos the time when the change occurred 3324 * @param lensCovered true is the lens is covered 3325 */ notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered)3326 void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered); 3327 3328 /** 3329 * This callback is invoked when an input channel is closed unexpectedly. 3330 * @param token the connection token of the broken channel 3331 */ notifyInputChannelBroken(IBinder token)3332 void notifyInputChannelBroken(IBinder token); 3333 3334 /** 3335 * Notify the window manager about the focused application that does not have any focused 3336 * window and is unable to respond to focused input events. 3337 */ notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle)3338 void notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle); 3339 3340 /** 3341 * Notify the window manager about a window that is unresponsive. 3342 * 3343 * @param token the token that can be used to look up the window 3344 * @param pid the pid of the window owner, if known 3345 * @param reason the reason why this connection is unresponsive 3346 */ notifyWindowUnresponsive(@onNull IBinder token, @NonNull OptionalInt pid, @NonNull String reason)3347 void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid, 3348 @NonNull String reason); 3349 3350 /** 3351 * Notify the window manager about a window that has become responsive. 3352 * 3353 * @param token the token that can be used to look up the window 3354 * @param pid the pid of the window owner, if known 3355 */ notifyWindowResponsive(@onNull IBinder token, @NonNull OptionalInt pid)3356 void notifyWindowResponsive(@NonNull IBinder token, @NonNull OptionalInt pid); 3357 3358 /** 3359 * This callback is invoked when an event first arrives to InputDispatcher and before it is 3360 * placed onto InputDispatcher's queue. If this event is intercepted, it will never be 3361 * processed by InputDispacher. 3362 * @param event The key event that's arriving to InputDispatcher 3363 * @param policyFlags The policy flags 3364 * @return the flags that tell InputDispatcher how to handle the event (for example, whether 3365 * to pass it to the user) 3366 */ interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)3367 int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags); 3368 3369 /** 3370 * Provides an opportunity for the window manager policy to intercept early motion event 3371 * processing when the device is in a non-interactive state since these events are normally 3372 * dropped. 3373 */ interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)3374 int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, 3375 int policyFlags); 3376 3377 /** 3378 * This callback is invoked just before the key is about to be sent to an application. 3379 * This allows the policy to make some last minute decisions on whether to intercept this 3380 * key. 3381 * @param token the window token that's about to receive this event 3382 * @param event the key event that's being dispatched 3383 * @param policyFlags the policy flags 3384 * @return negative value if the key should be skipped (not sent to the app). 0 if the key 3385 * should proceed getting dispatched to the app. positive value to indicate the additional 3386 * time delay, in nanoseconds, to wait before sending this key to the app. 3387 */ interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags)3388 long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags); 3389 3390 /** 3391 * Dispatch unhandled key 3392 */ dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags)3393 KeyEvent dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags); 3394 getPointerLayer()3395 int getPointerLayer(); 3396 getPointerDisplayId()3397 int getPointerDisplayId(); 3398 3399 /** Gets the x and y coordinates of the cursor's current position. */ getCursorPosition()3400 PointF getCursorPosition(); 3401 3402 /** 3403 * Notifies window manager that a {@link android.view.MotionEvent#ACTION_DOWN} pointer event 3404 * occurred on a window that did not have focus. 3405 * 3406 * @param touchedToken The token for the window that received the input event. 3407 */ onPointerDownOutsideFocus(IBinder touchedToken)3408 void onPointerDownOutsideFocus(IBinder touchedToken); 3409 3410 /** 3411 * Called when the focused window has changed. 3412 */ notifyFocusChanged(IBinder oldToken, IBinder newToken)3413 void notifyFocusChanged(IBinder oldToken, IBinder newToken); 3414 3415 /** 3416 * Called when the drag over window has changed. 3417 */ notifyDropWindow(IBinder token, float x, float y)3418 void notifyDropWindow(IBinder token, float x, float y); 3419 3420 /** 3421 * Get the {@link SurfaceControl} that should be the parent for the surfaces created for 3422 * pointers such as the mouse cursor and touch spots for the given display. 3423 */ getParentSurfaceForPointers(int displayId)3424 SurfaceControl getParentSurfaceForPointers(int displayId); 3425 3426 /** 3427 * Create a {@link SurfaceControl} that can be configured to receive input over the entire 3428 * display to implement a gesture monitor. The surface will not have a graphical buffer. 3429 * @param name the name of the gesture monitor 3430 * @param displayId the display to create the window in 3431 * @return the SurfaceControl of the new layer container surface 3432 */ 3433 @Nullable createSurfaceForGestureMonitor(String name, int displayId)3434 SurfaceControl createSurfaceForGestureMonitor(String name, int displayId); 3435 3436 /** 3437 * Notify WindowManagerService when the display of the mouse pointer changes. 3438 * @param displayId The display on which the mouse pointer is shown. 3439 * @param x The x coordinate of the mouse pointer. 3440 * @param y The y coordinate of the mouse pointer. 3441 */ notifyPointerDisplayIdChanged(int displayId, float x, float y)3442 void notifyPointerDisplayIdChanged(int displayId, float x, float y); 3443 } 3444 3445 /** 3446 * Callback interface implemented by WiredAccessoryObserver. 3447 */ 3448 public interface WiredAccessoryCallbacks { 3449 /** 3450 * Notifies WiredAccessoryObserver that input state for wired accessories has changed 3451 * @param whenNanos When the wired accessories changed 3452 * @param switchValues The state of the switches 3453 * @param switchMask The mask of switches that changed 3454 */ notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask)3455 void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask); 3456 3457 /** 3458 * Notifies WiredAccessoryObserver that the system is now ready. 3459 */ systemReady()3460 void systemReady(); 3461 } 3462 3463 /** 3464 * Private handler for the input manager. 3465 */ 3466 private final class InputManagerHandler extends Handler { InputManagerHandler(Looper looper)3467 public InputManagerHandler(Looper looper) { 3468 super(looper, null, true /*async*/); 3469 } 3470 3471 @Override handleMessage(Message msg)3472 public void handleMessage(Message msg) { 3473 switch (msg.what) { 3474 case MSG_DELIVER_INPUT_DEVICES_CHANGED: 3475 deliverInputDevicesChanged((InputDevice[])msg.obj); 3476 break; 3477 case MSG_SWITCH_KEYBOARD_LAYOUT: 3478 handleSwitchKeyboardLayout(msg.arg1, msg.arg2); 3479 break; 3480 case MSG_RELOAD_KEYBOARD_LAYOUTS: 3481 reloadKeyboardLayouts(); 3482 break; 3483 case MSG_UPDATE_KEYBOARD_LAYOUTS: 3484 updateKeyboardLayouts(); 3485 break; 3486 case MSG_RELOAD_DEVICE_ALIASES: 3487 reloadDeviceAliases(); 3488 break; 3489 case MSG_DELIVER_TABLET_MODE_CHANGED: 3490 SomeArgs args = (SomeArgs) msg.obj; 3491 long whenNanos = (args.argi1 & 0xFFFFFFFFL) | ((long) args.argi2 << 32); 3492 boolean inTabletMode = (boolean) args.arg1; 3493 deliverTabletModeChanged(whenNanos, inTabletMode); 3494 break; 3495 case MSG_POINTER_DISPLAY_ID_CHANGED: 3496 handlePointerDisplayIdChanged((PointerDisplayIdChangedArgs) msg.obj); 3497 break; 3498 } 3499 } 3500 } 3501 3502 /** 3503 * Hosting interface for input filters to call back into the input manager. 3504 */ 3505 private final class InputFilterHost extends IInputFilterHost.Stub { 3506 @GuardedBy("mInputFilterLock") 3507 private boolean mDisconnected; 3508 3509 @GuardedBy("mInputFilterLock") disconnectLocked()3510 public void disconnectLocked() { 3511 mDisconnected = true; 3512 } 3513 3514 @Override sendInputEvent(InputEvent event, int policyFlags)3515 public void sendInputEvent(InputEvent event, int policyFlags) { 3516 if (!checkCallingPermission(android.Manifest.permission.INJECT_EVENTS, 3517 "sendInputEvent()")) { 3518 throw new SecurityException( 3519 "The INJECT_EVENTS permission is required for injecting input events."); 3520 } 3521 Objects.requireNonNull(event, "event must not be null"); 3522 3523 synchronized (mInputFilterLock) { 3524 if (!mDisconnected) { 3525 mNative.injectInputEvent(event, false /* injectIntoUid */, -1 /* uid */, 3526 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0 /* timeout */, 3527 policyFlags | WindowManagerPolicy.FLAG_FILTERED); 3528 } 3529 } 3530 } 3531 } 3532 3533 /** 3534 * Interface for the system to handle request from InputMonitors. 3535 */ 3536 private final class InputMonitorHost extends IInputMonitorHost.Stub { 3537 private final IBinder mInputChannelToken; 3538 InputMonitorHost(IBinder inputChannelToken)3539 InputMonitorHost(IBinder inputChannelToken) { 3540 mInputChannelToken = inputChannelToken; 3541 } 3542 3543 @Override pilferPointers()3544 public void pilferPointers() { 3545 mNative.pilferPointers(mInputChannelToken); 3546 } 3547 3548 @Override dispose()3549 public void dispose() { 3550 removeSpyWindowGestureMonitor(mInputChannelToken); 3551 } 3552 } 3553 3554 private static final class KeyboardLayoutDescriptor { 3555 public String packageName; 3556 public String receiverName; 3557 public String keyboardLayoutName; 3558 format(String packageName, String receiverName, String keyboardName)3559 public static String format(String packageName, 3560 String receiverName, String keyboardName) { 3561 return packageName + "/" + receiverName + "/" + keyboardName; 3562 } 3563 parse(String descriptor)3564 public static KeyboardLayoutDescriptor parse(String descriptor) { 3565 int pos = descriptor.indexOf('/'); 3566 if (pos < 0 || pos + 1 == descriptor.length()) { 3567 return null; 3568 } 3569 int pos2 = descriptor.indexOf('/', pos + 1); 3570 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) { 3571 return null; 3572 } 3573 3574 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor(); 3575 result.packageName = descriptor.substring(0, pos); 3576 result.receiverName = descriptor.substring(pos + 1, pos2); 3577 result.keyboardLayoutName = descriptor.substring(pos2 + 1); 3578 return result; 3579 } 3580 } 3581 3582 private interface KeyboardLayoutVisitor { visitKeyboardLayout(Resources resources, int keyboardLayoutResId, KeyboardLayout layout)3583 void visitKeyboardLayout(Resources resources, 3584 int keyboardLayoutResId, KeyboardLayout layout); 3585 } 3586 3587 private final class InputDevicesChangedListenerRecord implements DeathRecipient { 3588 private final int mPid; 3589 private final IInputDevicesChangedListener mListener; 3590 InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener)3591 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) { 3592 mPid = pid; 3593 mListener = listener; 3594 } 3595 3596 @Override binderDied()3597 public void binderDied() { 3598 if (DEBUG) { 3599 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died."); 3600 } 3601 onInputDevicesChangedListenerDied(mPid); 3602 } 3603 notifyInputDevicesChanged(int[] info)3604 public void notifyInputDevicesChanged(int[] info) { 3605 try { 3606 mListener.onInputDevicesChanged(info); 3607 } catch (RemoteException ex) { 3608 Slog.w(TAG, "Failed to notify process " 3609 + mPid + " that input devices changed, assuming it died.", ex); 3610 binderDied(); 3611 } 3612 } 3613 } 3614 3615 private final class TabletModeChangedListenerRecord implements DeathRecipient { 3616 private final int mPid; 3617 private final ITabletModeChangedListener mListener; 3618 TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener)3619 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) { 3620 mPid = pid; 3621 mListener = listener; 3622 } 3623 3624 @Override binderDied()3625 public void binderDied() { 3626 if (DEBUG) { 3627 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died."); 3628 } 3629 onTabletModeChangedListenerDied(mPid); 3630 } 3631 notifyTabletModeChanged(long whenNanos, boolean inTabletMode)3632 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) { 3633 try { 3634 mListener.onTabletModeChanged(whenNanos, inTabletMode); 3635 } catch (RemoteException ex) { 3636 Slog.w(TAG, "Failed to notify process " + mPid + 3637 " that tablet mode changed, assuming it died.", ex); 3638 binderDied(); 3639 } 3640 } 3641 } 3642 onSensorEventListenerDied(int pid)3643 private void onSensorEventListenerDied(int pid) { 3644 synchronized (mSensorEventLock) { 3645 mSensorEventListeners.remove(pid); 3646 } 3647 } 3648 3649 private final class SensorEventListenerRecord implements DeathRecipient { 3650 private final int mPid; 3651 private final IInputSensorEventListener mListener; 3652 SensorEventListenerRecord(int pid, IInputSensorEventListener listener)3653 SensorEventListenerRecord(int pid, IInputSensorEventListener listener) { 3654 mPid = pid; 3655 mListener = listener; 3656 } 3657 3658 @Override binderDied()3659 public void binderDied() { 3660 if (DEBUG) { 3661 Slog.d(TAG, "Sensor event listener for pid " + mPid + " died."); 3662 } 3663 onSensorEventListenerDied(mPid); 3664 } 3665 getListener()3666 public IInputSensorEventListener getListener() { 3667 return mListener; 3668 } 3669 notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, float[] values)3670 public void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, 3671 float[] values) { 3672 try { 3673 mListener.onInputSensorChanged(deviceId, sensorType, accuracy, timestamp, 3674 values); 3675 } catch (RemoteException ex) { 3676 Slog.w(TAG, "Failed to notify process " + mPid 3677 + " that sensor event notified, assuming it died.", ex); 3678 binderDied(); 3679 } 3680 } 3681 notifySensorAccuracy(int deviceId, int sensorType, int accuracy)3682 public void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) { 3683 try { 3684 mListener.onInputSensorAccuracyChanged(deviceId, sensorType, accuracy); 3685 } catch (RemoteException ex) { 3686 Slog.w(TAG, "Failed to notify process " + mPid 3687 + " that sensor accuracy notified, assuming it died.", ex); 3688 binderDied(); 3689 } 3690 } 3691 } 3692 3693 private final class VibratorToken implements DeathRecipient { 3694 public final int mDeviceId; 3695 public final IBinder mToken; 3696 public final int mTokenValue; 3697 3698 public boolean mVibrating; 3699 VibratorToken(int deviceId, IBinder token, int tokenValue)3700 public VibratorToken(int deviceId, IBinder token, int tokenValue) { 3701 mDeviceId = deviceId; 3702 mToken = token; 3703 mTokenValue = tokenValue; 3704 } 3705 3706 @Override binderDied()3707 public void binderDied() { 3708 if (DEBUG) { 3709 Slog.d(TAG, "Vibrator token died."); 3710 } 3711 onVibratorTokenDied(this); 3712 } 3713 } 3714 3715 private final class LocalService extends InputManagerInternal { 3716 @Override setDisplayViewports(List<DisplayViewport> viewports)3717 public void setDisplayViewports(List<DisplayViewport> viewports) { 3718 setDisplayViewportsInternal(viewports); 3719 } 3720 3721 @Override setInteractive(boolean interactive)3722 public void setInteractive(boolean interactive) { 3723 mNative.setInteractive(interactive); 3724 } 3725 3726 @Override toggleCapsLock(int deviceId)3727 public void toggleCapsLock(int deviceId) { 3728 mNative.toggleCapsLock(deviceId); 3729 } 3730 3731 @Override setPulseGestureEnabled(boolean enabled)3732 public void setPulseGestureEnabled(boolean enabled) { 3733 if (mDoubleTouchGestureEnableFile != null) { 3734 FileWriter writer = null; 3735 try { 3736 writer = new FileWriter(mDoubleTouchGestureEnableFile); 3737 writer.write(enabled ? "1" : "0"); 3738 } catch (IOException e) { 3739 Log.wtf(TAG, "Unable to setPulseGestureEnabled", e); 3740 } finally { 3741 IoUtils.closeQuietly(writer); 3742 } 3743 } 3744 } 3745 3746 @Override transferTouchFocus(@onNull IBinder fromChannelToken, @NonNull IBinder toChannelToken)3747 public boolean transferTouchFocus(@NonNull IBinder fromChannelToken, 3748 @NonNull IBinder toChannelToken) { 3749 return InputManagerService.this.transferTouchFocus(fromChannelToken, toChannelToken); 3750 } 3751 3752 @Override setVirtualMousePointerDisplayId(int pointerDisplayId)3753 public boolean setVirtualMousePointerDisplayId(int pointerDisplayId) { 3754 return InputManagerService.this 3755 .setVirtualMousePointerDisplayIdBlocking(pointerDisplayId); 3756 } 3757 3758 @Override getVirtualMousePointerDisplayId()3759 public int getVirtualMousePointerDisplayId() { 3760 return InputManagerService.this.getVirtualMousePointerDisplayId(); 3761 } 3762 3763 @Override getCursorPosition()3764 public PointF getCursorPosition() { 3765 return mWindowManagerCallbacks.getCursorPosition(); 3766 } 3767 3768 @Override setPointerAcceleration(float acceleration, int displayId)3769 public void setPointerAcceleration(float acceleration, int displayId) { 3770 InputManagerService.this.setPointerAcceleration(acceleration, displayId); 3771 } 3772 3773 @Override setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible)3774 public void setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible) { 3775 InputManagerService.this.setDisplayEligibilityForPointerCapture(displayId, isEligible); 3776 } 3777 3778 @Override setPointerIconVisible(boolean visible, int displayId)3779 public void setPointerIconVisible(boolean visible, int displayId) { 3780 InputManagerService.this.setPointerIconVisible(visible, displayId); 3781 } 3782 3783 @Override registerLidSwitchCallback(LidSwitchCallback callbacks)3784 public void registerLidSwitchCallback(LidSwitchCallback callbacks) { 3785 registerLidSwitchCallbackInternal(callbacks); 3786 } 3787 3788 @Override unregisterLidSwitchCallback(LidSwitchCallback callbacks)3789 public void unregisterLidSwitchCallback(LidSwitchCallback callbacks) { 3790 unregisterLidSwitchCallbackInternal(callbacks); 3791 } 3792 3793 @Override createInputChannel(String inputChannelName)3794 public InputChannel createInputChannel(String inputChannelName) { 3795 return InputManagerService.this.createInputChannel(inputChannelName); 3796 } 3797 3798 @Override pilferPointers(IBinder token)3799 public void pilferPointers(IBinder token) { 3800 mNative.pilferPointers(token); 3801 } 3802 } 3803 3804 @Override onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)3805 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 3806 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 3807 new InputShellCommand().exec(this, in, out, err, args, callback, resultReceiver); 3808 } 3809 3810 private static class AdditionalDisplayInputProperties { 3811 3812 static final boolean DEFAULT_POINTER_ICON_VISIBLE = true; 3813 static final float DEFAULT_POINTER_ACCELERATION = 3814 (float) IInputConstants.DEFAULT_POINTER_ACCELERATION; 3815 3816 // The pointer acceleration for this display. 3817 public float pointerAcceleration; 3818 3819 // Whether the pointer icon should be visible or hidden on this display. 3820 public boolean pointerIconVisible; 3821 AdditionalDisplayInputProperties()3822 AdditionalDisplayInputProperties() { 3823 reset(); 3824 } 3825 allDefaults()3826 public boolean allDefaults() { 3827 return Float.compare(pointerAcceleration, DEFAULT_POINTER_ACCELERATION) == 0 3828 && pointerIconVisible == DEFAULT_POINTER_ICON_VISIBLE; 3829 } 3830 reset()3831 public void reset() { 3832 pointerAcceleration = DEFAULT_POINTER_ACCELERATION; 3833 pointerIconVisible = DEFAULT_POINTER_ICON_VISIBLE; 3834 } 3835 } 3836 applyAdditionalDisplayInputProperties()3837 private void applyAdditionalDisplayInputProperties() { 3838 synchronized (mAdditionalDisplayInputPropertiesLock) { 3839 AdditionalDisplayInputProperties properties = 3840 mAdditionalDisplayInputProperties.get(mRequestedPointerDisplayId); 3841 if (properties == null) properties = DEFAULT_ADDITIONAL_DISPLAY_INPUT_PROPERTIES; 3842 applyAdditionalDisplayInputPropertiesLocked(properties); 3843 } 3844 } 3845 3846 @GuardedBy("mAdditionalDisplayInputPropertiesLock") applyAdditionalDisplayInputPropertiesLocked( AdditionalDisplayInputProperties properties)3847 private void applyAdditionalDisplayInputPropertiesLocked( 3848 AdditionalDisplayInputProperties properties) { 3849 // Handle changes to each of the individual properties. 3850 if (properties.pointerIconVisible != mCurrentDisplayProperties.pointerIconVisible) { 3851 mCurrentDisplayProperties.pointerIconVisible = properties.pointerIconVisible; 3852 if (properties.pointerIconVisible) { 3853 if (mIconType == PointerIcon.TYPE_CUSTOM) { 3854 Objects.requireNonNull(mIcon); 3855 mNative.setCustomPointerIcon(mIcon); 3856 } else { 3857 mNative.setPointerIconType(mIconType); 3858 } 3859 } else { 3860 mNative.setPointerIconType(PointerIcon.TYPE_NULL); 3861 } 3862 } 3863 3864 if (properties.pointerAcceleration != mCurrentDisplayProperties.pointerAcceleration) { 3865 mCurrentDisplayProperties.pointerAcceleration = properties.pointerAcceleration; 3866 mNative.setPointerAcceleration(properties.pointerAcceleration); 3867 } 3868 } 3869 updateAdditionalDisplayInputProperties(int displayId, Consumer<AdditionalDisplayInputProperties> updater)3870 private void updateAdditionalDisplayInputProperties(int displayId, 3871 Consumer<AdditionalDisplayInputProperties> updater) { 3872 synchronized (mAdditionalDisplayInputPropertiesLock) { 3873 AdditionalDisplayInputProperties properties = 3874 mAdditionalDisplayInputProperties.get(displayId); 3875 if (properties == null) { 3876 properties = new AdditionalDisplayInputProperties(); 3877 mAdditionalDisplayInputProperties.put(displayId, properties); 3878 } 3879 updater.accept(properties); 3880 if (properties.allDefaults()) { 3881 mAdditionalDisplayInputProperties.remove(displayId); 3882 } 3883 if (displayId != mRequestedPointerDisplayId) { 3884 Log.i(TAG, "Not applying additional properties for display " + displayId 3885 + " because the pointer is currently targeting display " 3886 + mRequestedPointerDisplayId + "."); 3887 return; 3888 } 3889 applyAdditionalDisplayInputPropertiesLocked(properties); 3890 } 3891 } 3892 } 3893