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