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 mDisplayContext; 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 if (event instanceof MotionEvent) { 843 final Context dispCtx = getContextForDisplay(event.getDisplayId()); 844 final Display display = dispCtx.getDisplay(); 845 final int rotation = display.getRotation(); 846 if (rotation != ROTATION_0) { 847 final MotionEvent motion = (MotionEvent) event; 848 // Injections are currently expected to be in the space of the injector (ie. 849 // usually assumed to be post-rotated). Thus we need to unrotate into raw 850 // input coordinates for dispatch. 851 final Point sz = new Point(); 852 display.getRealSize(sz); 853 if ((rotation % 2) != 0) { 854 final int tmpX = sz.x; 855 sz.x = sz.y; 856 sz.y = tmpX; 857 } 858 motion.applyTransform(MotionEvent.createRotateMatrix( 859 (4 - rotation), sz.x, sz.y)); 860 } 861 } 862 } 863 864 final int pid = Binder.getCallingPid(); 865 final int uid = Binder.getCallingUid(); 866 final long ident = Binder.clearCallingIdentity(); 867 final int result; 868 try { 869 result = nativeInjectInputEvent(mPtr, event, pid, uid, mode, 870 INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); 871 } finally { 872 Binder.restoreCallingIdentity(ident); 873 } 874 switch (result) { 875 case InputEventInjectionResult.PERMISSION_DENIED: 876 Slog.w(TAG, "Input event injection from pid " + pid + " permission denied."); 877 throw new SecurityException( 878 "Injecting to another application requires INJECT_EVENTS permission"); 879 case InputEventInjectionResult.SUCCEEDED: 880 return true; 881 case InputEventInjectionResult.TIMED_OUT: 882 Slog.w(TAG, "Input event injection from pid " + pid + " timed out."); 883 return false; 884 case InputEventInjectionResult.FAILED: 885 default: 886 Slog.w(TAG, "Input event injection from pid " + pid + " failed."); 887 return false; 888 } 889 } 890 891 @Override // Binder call verifyInputEvent(InputEvent event)892 public VerifiedInputEvent verifyInputEvent(InputEvent event) { 893 return nativeVerifyInputEvent(mPtr, event); 894 } 895 896 /** 897 * Gets information about the input device with the specified id. 898 * @param deviceId The device id. 899 * @return The input device or null if not found. 900 */ 901 @Override // Binder call getInputDevice(int deviceId)902 public InputDevice getInputDevice(int deviceId) { 903 synchronized (mInputDevicesLock) { 904 final int count = mInputDevices.length; 905 for (int i = 0; i < count; i++) { 906 final InputDevice inputDevice = mInputDevices[i]; 907 if (inputDevice.getId() == deviceId) { 908 return inputDevice; 909 } 910 } 911 } 912 return null; 913 } 914 915 // Binder call 916 @Override isInputDeviceEnabled(int deviceId)917 public boolean isInputDeviceEnabled(int deviceId) { 918 return nativeIsInputDeviceEnabled(mPtr, deviceId); 919 } 920 921 // Binder call 922 @Override enableInputDevice(int deviceId)923 public void enableInputDevice(int deviceId) { 924 if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE, 925 "enableInputDevice()")) { 926 throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission"); 927 } 928 nativeEnableInputDevice(mPtr, deviceId); 929 } 930 931 // Binder call 932 @Override disableInputDevice(int deviceId)933 public void disableInputDevice(int deviceId) { 934 if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE, 935 "disableInputDevice()")) { 936 throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission"); 937 } 938 nativeDisableInputDevice(mPtr, deviceId); 939 } 940 941 /** 942 * Gets the ids of all input devices in the system. 943 * @return The input device ids. 944 */ 945 @Override // Binder call getInputDeviceIds()946 public int[] getInputDeviceIds() { 947 synchronized (mInputDevicesLock) { 948 final int count = mInputDevices.length; 949 int[] ids = new int[count]; 950 for (int i = 0; i < count; i++) { 951 ids[i] = mInputDevices[i].getId(); 952 } 953 return ids; 954 } 955 } 956 957 /** 958 * Gets all input devices in the system. 959 * @return The array of input devices. 960 */ getInputDevices()961 public InputDevice[] getInputDevices() { 962 synchronized (mInputDevicesLock) { 963 return mInputDevices; 964 } 965 } 966 967 @Override // Binder call registerInputDevicesChangedListener(IInputDevicesChangedListener listener)968 public void registerInputDevicesChangedListener(IInputDevicesChangedListener listener) { 969 if (listener == null) { 970 throw new IllegalArgumentException("listener must not be null"); 971 } 972 973 synchronized (mInputDevicesLock) { 974 int callingPid = Binder.getCallingPid(); 975 if (mInputDevicesChangedListeners.get(callingPid) != null) { 976 throw new SecurityException("The calling process has already " 977 + "registered an InputDevicesChangedListener."); 978 } 979 980 InputDevicesChangedListenerRecord record = 981 new InputDevicesChangedListenerRecord(callingPid, listener); 982 try { 983 IBinder binder = listener.asBinder(); 984 binder.linkToDeath(record, 0); 985 } catch (RemoteException ex) { 986 // give up 987 throw new RuntimeException(ex); 988 } 989 990 mInputDevicesChangedListeners.put(callingPid, record); 991 } 992 } 993 onInputDevicesChangedListenerDied(int pid)994 private void onInputDevicesChangedListenerDied(int pid) { 995 synchronized (mInputDevicesLock) { 996 mInputDevicesChangedListeners.remove(pid); 997 } 998 } 999 1000 // Must be called on handler. deliverInputDevicesChanged(InputDevice[] oldInputDevices)1001 private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) { 1002 // Scan for changes. 1003 int numFullKeyboardsAdded = 0; 1004 mTempInputDevicesChangedListenersToNotify.clear(); 1005 mTempFullKeyboards.clear(); 1006 final int numListeners; 1007 final int[] deviceIdAndGeneration; 1008 synchronized (mInputDevicesLock) { 1009 if (!mInputDevicesChangedPending) { 1010 return; 1011 } 1012 mInputDevicesChangedPending = false; 1013 1014 numListeners = mInputDevicesChangedListeners.size(); 1015 for (int i = 0; i < numListeners; i++) { 1016 mTempInputDevicesChangedListenersToNotify.add( 1017 mInputDevicesChangedListeners.valueAt(i)); 1018 } 1019 1020 final int numDevices = mInputDevices.length; 1021 deviceIdAndGeneration = new int[numDevices * 2]; 1022 for (int i = 0; i < numDevices; i++) { 1023 final InputDevice inputDevice = mInputDevices[i]; 1024 deviceIdAndGeneration[i * 2] = inputDevice.getId(); 1025 deviceIdAndGeneration[i * 2 + 1] = inputDevice.getGeneration(); 1026 1027 if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) { 1028 if (!containsInputDeviceWithDescriptor(oldInputDevices, 1029 inputDevice.getDescriptor())) { 1030 mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice); 1031 } else { 1032 mTempFullKeyboards.add(inputDevice); 1033 } 1034 } 1035 } 1036 } 1037 1038 // Notify listeners. 1039 for (int i = 0; i < numListeners; i++) { 1040 mTempInputDevicesChangedListenersToNotify.get(i).notifyInputDevicesChanged( 1041 deviceIdAndGeneration); 1042 } 1043 mTempInputDevicesChangedListenersToNotify.clear(); 1044 1045 // Check for missing keyboard layouts. 1046 List<InputDevice> keyboardsMissingLayout = new ArrayList<>(); 1047 final int numFullKeyboards = mTempFullKeyboards.size(); 1048 synchronized (mDataStore) { 1049 for (int i = 0; i < numFullKeyboards; i++) { 1050 final InputDevice inputDevice = mTempFullKeyboards.get(i); 1051 String layout = 1052 getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier()); 1053 if (layout == null) { 1054 layout = getDefaultKeyboardLayout(inputDevice); 1055 if (layout != null) { 1056 setCurrentKeyboardLayoutForInputDevice( 1057 inputDevice.getIdentifier(), layout); 1058 } 1059 } 1060 if (layout == null) { 1061 keyboardsMissingLayout.add(inputDevice); 1062 } 1063 } 1064 } 1065 1066 if (mNotificationManager != null) { 1067 if (!keyboardsMissingLayout.isEmpty()) { 1068 if (keyboardsMissingLayout.size() > 1) { 1069 // We have more than one keyboard missing a layout, so drop the 1070 // user at the generic input methods page so they can pick which 1071 // one to set. 1072 showMissingKeyboardLayoutNotification(null); 1073 } else { 1074 showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0)); 1075 } 1076 } else if (mKeyboardLayoutNotificationShown) { 1077 hideMissingKeyboardLayoutNotification(); 1078 } 1079 } 1080 mTempFullKeyboards.clear(); 1081 } 1082 getDefaultKeyboardLayout(final InputDevice d)1083 private String getDefaultKeyboardLayout(final InputDevice d) { 1084 final Locale systemLocale = mContext.getResources().getConfiguration().locale; 1085 // If our locale doesn't have a language for some reason, then we don't really have a 1086 // reasonable default. 1087 if (TextUtils.isEmpty(systemLocale.getLanguage())) { 1088 return null; 1089 } 1090 final List<KeyboardLayout> layouts = new ArrayList<>(); 1091 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 1092 @Override 1093 public void visitKeyboardLayout(Resources resources, 1094 int keyboardLayoutResId, KeyboardLayout layout) { 1095 // Only select a default when we know the layout is appropriate. For now, this 1096 // means its a custom layout for a specific keyboard. 1097 if (layout.getVendorId() != d.getVendorId() 1098 || layout.getProductId() != d.getProductId()) { 1099 return; 1100 } 1101 final LocaleList locales = layout.getLocales(); 1102 final int numLocales = locales.size(); 1103 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) { 1104 if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) { 1105 layouts.add(layout); 1106 break; 1107 } 1108 } 1109 } 1110 }); 1111 1112 if (layouts.isEmpty()) { 1113 return null; 1114 } 1115 1116 // First sort so that ones with higher priority are listed at the top 1117 Collections.sort(layouts); 1118 // Next we want to try to find an exact match of language, country and variant. 1119 final int N = layouts.size(); 1120 for (int i = 0; i < N; i++) { 1121 KeyboardLayout layout = layouts.get(i); 1122 final LocaleList locales = layout.getLocales(); 1123 final int numLocales = locales.size(); 1124 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) { 1125 final Locale locale = locales.get(localeIndex); 1126 if (locale.getCountry().equals(systemLocale.getCountry()) 1127 && locale.getVariant().equals(systemLocale.getVariant())) { 1128 return layout.getDescriptor(); 1129 } 1130 } 1131 } 1132 // Then try an exact match of language and country 1133 for (int i = 0; i < N; i++) { 1134 KeyboardLayout layout = layouts.get(i); 1135 final LocaleList locales = layout.getLocales(); 1136 final int numLocales = locales.size(); 1137 for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) { 1138 final Locale locale = locales.get(localeIndex); 1139 if (locale.getCountry().equals(systemLocale.getCountry())) { 1140 return layout.getDescriptor(); 1141 } 1142 } 1143 } 1144 1145 // Give up and just use the highest priority layout with matching language 1146 return layouts.get(0).getDescriptor(); 1147 } 1148 isCompatibleLocale(Locale systemLocale, Locale keyboardLocale)1149 private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) { 1150 // Different languages are never compatible 1151 if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) { 1152 return false; 1153 } 1154 // If both the system and the keyboard layout have a country specifier, they must be equal. 1155 if (!TextUtils.isEmpty(systemLocale.getCountry()) 1156 && !TextUtils.isEmpty(keyboardLocale.getCountry()) 1157 && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) { 1158 return false; 1159 } 1160 return true; 1161 } 1162 1163 @Override // Binder call & native callback getTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation)1164 public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor, 1165 int surfaceRotation) { 1166 if (inputDeviceDescriptor == null) { 1167 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 1168 } 1169 1170 synchronized (mDataStore) { 1171 return mDataStore.getTouchCalibration(inputDeviceDescriptor, surfaceRotation); 1172 } 1173 } 1174 1175 @Override // Binder call setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation, TouchCalibration calibration)1176 public void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation, 1177 TouchCalibration calibration) { 1178 if (!checkCallingPermission(android.Manifest.permission.SET_INPUT_CALIBRATION, 1179 "setTouchCalibrationForInputDevice()")) { 1180 throw new SecurityException("Requires SET_INPUT_CALIBRATION permission"); 1181 } 1182 if (inputDeviceDescriptor == null) { 1183 throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); 1184 } 1185 if (calibration == null) { 1186 throw new IllegalArgumentException("calibration must not be null"); 1187 } 1188 if (surfaceRotation < Surface.ROTATION_0 || surfaceRotation > Surface.ROTATION_270) { 1189 throw new IllegalArgumentException("surfaceRotation value out of bounds"); 1190 } 1191 1192 synchronized (mDataStore) { 1193 try { 1194 if (mDataStore.setTouchCalibration(inputDeviceDescriptor, surfaceRotation, 1195 calibration)) { 1196 nativeReloadCalibration(mPtr); 1197 } 1198 } finally { 1199 mDataStore.saveIfNeeded(); 1200 } 1201 } 1202 } 1203 1204 @Override // Binder call isInTabletMode()1205 public int isInTabletMode() { 1206 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE, 1207 "isInTabletMode()")) { 1208 throw new SecurityException("Requires TABLET_MODE permission"); 1209 } 1210 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE); 1211 } 1212 1213 @Override // Binder call isMicMuted()1214 public int isMicMuted() { 1215 return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MUTE_DEVICE); 1216 } 1217 1218 @Override // Binder call registerTabletModeChangedListener(ITabletModeChangedListener listener)1219 public void registerTabletModeChangedListener(ITabletModeChangedListener listener) { 1220 if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE, 1221 "registerTabletModeChangedListener()")) { 1222 throw new SecurityException("Requires TABLET_MODE_LISTENER permission"); 1223 } 1224 if (listener == null) { 1225 throw new IllegalArgumentException("listener must not be null"); 1226 } 1227 1228 synchronized (mTabletModeLock) { 1229 final int callingPid = Binder.getCallingPid(); 1230 if (mTabletModeChangedListeners.get(callingPid) != null) { 1231 throw new IllegalStateException("The calling process has already registered " 1232 + "a TabletModeChangedListener."); 1233 } 1234 TabletModeChangedListenerRecord record = 1235 new TabletModeChangedListenerRecord(callingPid, listener); 1236 try { 1237 IBinder binder = listener.asBinder(); 1238 binder.linkToDeath(record, 0); 1239 } catch (RemoteException ex) { 1240 throw new RuntimeException(ex); 1241 } 1242 mTabletModeChangedListeners.put(callingPid, record); 1243 } 1244 } 1245 onTabletModeChangedListenerDied(int pid)1246 private void onTabletModeChangedListenerDied(int pid) { 1247 synchronized (mTabletModeLock) { 1248 mTabletModeChangedListeners.remove(pid); 1249 } 1250 } 1251 1252 // Must be called on handler deliverTabletModeChanged(long whenNanos, boolean inTabletMode)1253 private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) { 1254 mTempTabletModeChangedListenersToNotify.clear(); 1255 final int numListeners; 1256 synchronized (mTabletModeLock) { 1257 numListeners = mTabletModeChangedListeners.size(); 1258 for (int i = 0; i < numListeners; i++) { 1259 mTempTabletModeChangedListenersToNotify.add( 1260 mTabletModeChangedListeners.valueAt(i)); 1261 } 1262 } 1263 for (int i = 0; i < numListeners; i++) { 1264 mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged( 1265 whenNanos, inTabletMode); 1266 } 1267 } 1268 1269 // Must be called on handler. showMissingKeyboardLayoutNotification(InputDevice device)1270 private void showMissingKeyboardLayoutNotification(InputDevice device) { 1271 if (!mKeyboardLayoutNotificationShown) { 1272 final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS); 1273 if (device != null) { 1274 intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier()); 1275 } 1276 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1277 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 1278 | Intent.FLAG_ACTIVITY_CLEAR_TOP); 1279 final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0, 1280 intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT); 1281 1282 Resources r = mContext.getResources(); 1283 Notification notification = 1284 new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD) 1285 .setContentTitle(r.getString( 1286 R.string.select_keyboard_layout_notification_title)) 1287 .setContentText(r.getString( 1288 R.string.select_keyboard_layout_notification_message)) 1289 .setContentIntent(keyboardLayoutIntent) 1290 .setSmallIcon(R.drawable.ic_settings_language) 1291 .setColor(mContext.getColor( 1292 com.android.internal.R.color.system_notification_accent_color)) 1293 .build(); 1294 mNotificationManager.notifyAsUser(null, 1295 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT, 1296 notification, UserHandle.ALL); 1297 mKeyboardLayoutNotificationShown = true; 1298 } 1299 } 1300 1301 // Must be called on handler. hideMissingKeyboardLayoutNotification()1302 private void hideMissingKeyboardLayoutNotification() { 1303 if (mKeyboardLayoutNotificationShown) { 1304 mKeyboardLayoutNotificationShown = false; 1305 mNotificationManager.cancelAsUser(null, 1306 SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT, 1307 UserHandle.ALL); 1308 } 1309 } 1310 1311 // Must be called on handler. updateKeyboardLayouts()1312 private void updateKeyboardLayouts() { 1313 // Scan all input devices state for keyboard layouts that have been uninstalled. 1314 final HashSet<String> availableKeyboardLayouts = new HashSet<String>(); 1315 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 1316 @Override 1317 public void visitKeyboardLayout(Resources resources, 1318 int keyboardLayoutResId, KeyboardLayout layout) { 1319 availableKeyboardLayouts.add(layout.getDescriptor()); 1320 } 1321 }); 1322 synchronized (mDataStore) { 1323 try { 1324 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts); 1325 } finally { 1326 mDataStore.saveIfNeeded(); 1327 } 1328 } 1329 1330 // Reload keyboard layouts. 1331 reloadKeyboardLayouts(); 1332 } 1333 containsInputDeviceWithDescriptor(InputDevice[] inputDevices, String descriptor)1334 private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices, 1335 String descriptor) { 1336 final int numDevices = inputDevices.length; 1337 for (int i = 0; i < numDevices; i++) { 1338 final InputDevice inputDevice = inputDevices[i]; 1339 if (inputDevice.getDescriptor().equals(descriptor)) { 1340 return true; 1341 } 1342 } 1343 return false; 1344 } 1345 1346 @Override // Binder call getKeyboardLayouts()1347 public KeyboardLayout[] getKeyboardLayouts() { 1348 final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>(); 1349 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 1350 @Override 1351 public void visitKeyboardLayout(Resources resources, 1352 int keyboardLayoutResId, KeyboardLayout layout) { 1353 list.add(layout); 1354 } 1355 }); 1356 return list.toArray(new KeyboardLayout[list.size()]); 1357 } 1358 1359 @Override // Binder call getKeyboardLayoutsForInputDevice( final InputDeviceIdentifier identifier)1360 public KeyboardLayout[] getKeyboardLayoutsForInputDevice( 1361 final InputDeviceIdentifier identifier) { 1362 final String[] enabledLayoutDescriptors = 1363 getEnabledKeyboardLayoutsForInputDevice(identifier); 1364 final ArrayList<KeyboardLayout> enabledLayouts = 1365 new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length); 1366 final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>(); 1367 visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { 1368 boolean mHasSeenDeviceSpecificLayout; 1369 1370 @Override 1371 public void visitKeyboardLayout(Resources resources, 1372 int keyboardLayoutResId, KeyboardLayout layout) { 1373 // First check if it's enabled. If the keyboard layout is enabled then we always 1374 // want to return it as a possible layout for the device. 1375 for (String s : enabledLayoutDescriptors) { 1376 if (s != null && s.equals(layout.getDescriptor())) { 1377 enabledLayouts.add(layout); 1378 return; 1379 } 1380 } 1381 // Next find any potential layouts that aren't yet enabled for the device. For 1382 // devices that have special layouts we assume there's a reason that the generic 1383 // layouts don't work for them so we don't want to return them since it's likely 1384 // to result in a poor user experience. 1385 if (layout.getVendorId() == identifier.getVendorId() 1386 && layout.getProductId() == identifier.getProductId()) { 1387 if (!mHasSeenDeviceSpecificLayout) { 1388 mHasSeenDeviceSpecificLayout = true; 1389 potentialLayouts.clear(); 1390 } 1391 potentialLayouts.add(layout); 1392 } else if (layout.getVendorId() == -1 && layout.getProductId() == -1 1393 && !mHasSeenDeviceSpecificLayout) { 1394 potentialLayouts.add(layout); 1395 } 1396 } 1397 }); 1398 final int enabledLayoutSize = enabledLayouts.size(); 1399 final int potentialLayoutSize = potentialLayouts.size(); 1400 KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize]; 1401 enabledLayouts.toArray(layouts); 1402 for (int i = 0; i < potentialLayoutSize; i++) { 1403 layouts[enabledLayoutSize + i] = potentialLayouts.get(i); 1404 } 1405 return layouts; 1406 } 1407 1408 @Override // Binder call getKeyboardLayout(String keyboardLayoutDescriptor)1409 public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) { 1410 if (keyboardLayoutDescriptor == null) { 1411 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1412 } 1413 1414 final KeyboardLayout[] result = new KeyboardLayout[1]; 1415 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 1416 @Override 1417 public void visitKeyboardLayout(Resources resources, 1418 int keyboardLayoutResId, KeyboardLayout layout) { 1419 result[0] = layout; 1420 } 1421 }); 1422 if (result[0] == null) { 1423 Slog.w(TAG, "Could not get keyboard layout with descriptor '" 1424 + keyboardLayoutDescriptor + "'."); 1425 } 1426 return result[0]; 1427 } 1428 visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor)1429 private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) { 1430 final PackageManager pm = mContext.getPackageManager(); 1431 Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS); 1432 for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent, 1433 PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE 1434 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) { 1435 final ActivityInfo activityInfo = resolveInfo.activityInfo; 1436 final int priority = resolveInfo.priority; 1437 visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor); 1438 } 1439 } 1440 visitKeyboardLayout(String keyboardLayoutDescriptor, KeyboardLayoutVisitor visitor)1441 private void visitKeyboardLayout(String keyboardLayoutDescriptor, 1442 KeyboardLayoutVisitor visitor) { 1443 KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor); 1444 if (d != null) { 1445 final PackageManager pm = mContext.getPackageManager(); 1446 try { 1447 ActivityInfo receiver = pm.getReceiverInfo( 1448 new ComponentName(d.packageName, d.receiverName), 1449 PackageManager.GET_META_DATA 1450 | PackageManager.MATCH_DIRECT_BOOT_AWARE 1451 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); 1452 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor); 1453 } catch (NameNotFoundException ex) { 1454 } 1455 } 1456 } 1457 visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor)1458 private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver, 1459 String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) { 1460 Bundle metaData = receiver.metaData; 1461 if (metaData == null) { 1462 return; 1463 } 1464 1465 int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS); 1466 if (configResId == 0) { 1467 Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS 1468 + "' on receiver " + receiver.packageName + "/" + receiver.name); 1469 return; 1470 } 1471 1472 CharSequence receiverLabel = receiver.loadLabel(pm); 1473 String collection = receiverLabel != null ? receiverLabel.toString() : ""; 1474 int priority; 1475 if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 1476 priority = requestedPriority; 1477 } else { 1478 priority = 0; 1479 } 1480 1481 try { 1482 Resources resources = pm.getResourcesForApplication(receiver.applicationInfo); 1483 XmlResourceParser parser = resources.getXml(configResId); 1484 try { 1485 XmlUtils.beginDocument(parser, "keyboard-layouts"); 1486 1487 for (;;) { 1488 XmlUtils.nextElement(parser); 1489 String element = parser.getName(); 1490 if (element == null) { 1491 break; 1492 } 1493 if (element.equals("keyboard-layout")) { 1494 TypedArray a = resources.obtainAttributes( 1495 parser, com.android.internal.R.styleable.KeyboardLayout); 1496 try { 1497 String name = a.getString( 1498 com.android.internal.R.styleable.KeyboardLayout_name); 1499 String label = a.getString( 1500 com.android.internal.R.styleable.KeyboardLayout_label); 1501 int keyboardLayoutResId = a.getResourceId( 1502 com.android.internal.R.styleable.KeyboardLayout_keyboardLayout, 1503 0); 1504 String languageTags = a.getString( 1505 com.android.internal.R.styleable.KeyboardLayout_locale); 1506 LocaleList locales = getLocalesFromLanguageTags(languageTags); 1507 int vid = a.getInt( 1508 com.android.internal.R.styleable.KeyboardLayout_vendorId, -1); 1509 int pid = a.getInt( 1510 com.android.internal.R.styleable.KeyboardLayout_productId, -1); 1511 1512 if (name == null || label == null || keyboardLayoutResId == 0) { 1513 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' " 1514 + "attributes in keyboard layout " 1515 + "resource from receiver " 1516 + receiver.packageName + "/" + receiver.name); 1517 } else { 1518 String descriptor = KeyboardLayoutDescriptor.format( 1519 receiver.packageName, receiver.name, name); 1520 if (keyboardName == null || name.equals(keyboardName)) { 1521 KeyboardLayout layout = new KeyboardLayout( 1522 descriptor, label, collection, priority, 1523 locales, vid, pid); 1524 visitor.visitKeyboardLayout( 1525 resources, keyboardLayoutResId, layout); 1526 } 1527 } 1528 } finally { 1529 a.recycle(); 1530 } 1531 } else { 1532 Slog.w(TAG, "Skipping unrecognized element '" + element 1533 + "' in keyboard layout resource from receiver " 1534 + receiver.packageName + "/" + receiver.name); 1535 } 1536 } 1537 } finally { 1538 parser.close(); 1539 } 1540 } catch (Exception ex) { 1541 Slog.w(TAG, "Could not parse keyboard layout resource from receiver " 1542 + receiver.packageName + "/" + receiver.name, ex); 1543 } 1544 } 1545 1546 @NonNull getLocalesFromLanguageTags(String languageTags)1547 private static LocaleList getLocalesFromLanguageTags(String languageTags) { 1548 if (TextUtils.isEmpty(languageTags)) { 1549 return LocaleList.getEmptyLocaleList(); 1550 } 1551 return LocaleList.forLanguageTags(languageTags.replace('|', ',')); 1552 } 1553 1554 /** 1555 * Builds a layout descriptor for the vendor/product. This returns the 1556 * descriptor for ids that aren't useful (such as the default 0, 0). 1557 */ getLayoutDescriptor(InputDeviceIdentifier identifier)1558 private String getLayoutDescriptor(InputDeviceIdentifier identifier) { 1559 if (identifier == null || identifier.getDescriptor() == null) { 1560 throw new IllegalArgumentException("identifier and descriptor must not be null"); 1561 } 1562 1563 if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) { 1564 return identifier.getDescriptor(); 1565 } 1566 StringBuilder bob = new StringBuilder(); 1567 bob.append("vendor:").append(identifier.getVendorId()); 1568 bob.append(",product:").append(identifier.getProductId()); 1569 return bob.toString(); 1570 } 1571 1572 @Override // Binder call getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier)1573 public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) { 1574 1575 String key = getLayoutDescriptor(identifier); 1576 synchronized (mDataStore) { 1577 String layout = null; 1578 // try loading it using the layout descriptor if we have it 1579 layout = mDataStore.getCurrentKeyboardLayout(key); 1580 if (layout == null && !key.equals(identifier.getDescriptor())) { 1581 // if it doesn't exist fall back to the device descriptor 1582 layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1583 } 1584 if (DEBUG) { 1585 Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got " 1586 + layout); 1587 } 1588 return layout; 1589 } 1590 } 1591 1592 @Override // Binder call setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1593 public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1594 String keyboardLayoutDescriptor) { 1595 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1596 "setCurrentKeyboardLayoutForInputDevice()")) { 1597 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1598 } 1599 if (keyboardLayoutDescriptor == null) { 1600 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1601 } 1602 1603 String key = getLayoutDescriptor(identifier); 1604 synchronized (mDataStore) { 1605 try { 1606 if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) { 1607 if (DEBUG) { 1608 Slog.d(TAG, "Saved keyboard layout using " + key); 1609 } 1610 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1611 } 1612 } finally { 1613 mDataStore.saveIfNeeded(); 1614 } 1615 } 1616 } 1617 1618 @Override // Binder call getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier)1619 public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { 1620 String key = getLayoutDescriptor(identifier); 1621 synchronized (mDataStore) { 1622 String[] layouts = mDataStore.getKeyboardLayouts(key); 1623 if ((layouts == null || layouts.length == 0) 1624 && !key.equals(identifier.getDescriptor())) { 1625 layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor()); 1626 } 1627 return layouts; 1628 } 1629 } 1630 1631 @Override // Binder call addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1632 public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1633 String keyboardLayoutDescriptor) { 1634 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1635 "addKeyboardLayoutForInputDevice()")) { 1636 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1637 } 1638 if (keyboardLayoutDescriptor == null) { 1639 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1640 } 1641 1642 String key = getLayoutDescriptor(identifier); 1643 synchronized (mDataStore) { 1644 try { 1645 String oldLayout = mDataStore.getCurrentKeyboardLayout(key); 1646 if (oldLayout == null && !key.equals(identifier.getDescriptor())) { 1647 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1648 } 1649 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor) 1650 && !Objects.equals(oldLayout, 1651 mDataStore.getCurrentKeyboardLayout(key))) { 1652 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1653 } 1654 } finally { 1655 mDataStore.saveIfNeeded(); 1656 } 1657 } 1658 } 1659 1660 @Override // Binder call removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, String keyboardLayoutDescriptor)1661 public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, 1662 String keyboardLayoutDescriptor) { 1663 if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT, 1664 "removeKeyboardLayoutForInputDevice()")) { 1665 throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission"); 1666 } 1667 if (keyboardLayoutDescriptor == null) { 1668 throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); 1669 } 1670 1671 String key = getLayoutDescriptor(identifier); 1672 synchronized (mDataStore) { 1673 try { 1674 String oldLayout = mDataStore.getCurrentKeyboardLayout(key); 1675 if (oldLayout == null && !key.equals(identifier.getDescriptor())) { 1676 oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor()); 1677 } 1678 boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor); 1679 if (!key.equals(identifier.getDescriptor())) { 1680 // We need to remove from both places to ensure it is gone 1681 removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(), 1682 keyboardLayoutDescriptor); 1683 } 1684 if (removed && !Objects.equals(oldLayout, 1685 mDataStore.getCurrentKeyboardLayout(key))) { 1686 mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); 1687 } 1688 } finally { 1689 mDataStore.saveIfNeeded(); 1690 } 1691 } 1692 } 1693 switchKeyboardLayout(int deviceId, int direction)1694 public void switchKeyboardLayout(int deviceId, int direction) { 1695 mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget(); 1696 } 1697 1698 // Must be called on handler. handleSwitchKeyboardLayout(int deviceId, int direction)1699 private void handleSwitchKeyboardLayout(int deviceId, int direction) { 1700 final InputDevice device = getInputDevice(deviceId); 1701 if (device != null) { 1702 final boolean changed; 1703 final String keyboardLayoutDescriptor; 1704 1705 String key = getLayoutDescriptor(device.getIdentifier()); 1706 synchronized (mDataStore) { 1707 try { 1708 changed = mDataStore.switchKeyboardLayout(key, direction); 1709 keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout( 1710 key); 1711 } finally { 1712 mDataStore.saveIfNeeded(); 1713 } 1714 } 1715 1716 if (changed) { 1717 if (mSwitchedKeyboardLayoutToast != null) { 1718 mSwitchedKeyboardLayoutToast.cancel(); 1719 mSwitchedKeyboardLayoutToast = null; 1720 } 1721 if (keyboardLayoutDescriptor != null) { 1722 KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor); 1723 if (keyboardLayout != null) { 1724 mSwitchedKeyboardLayoutToast = Toast.makeText( 1725 mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT); 1726 mSwitchedKeyboardLayoutToast.show(); 1727 } 1728 } 1729 1730 reloadKeyboardLayouts(); 1731 } 1732 } 1733 } 1734 setFocusedApplication(int displayId, InputApplicationHandle application)1735 public void setFocusedApplication(int displayId, InputApplicationHandle application) { 1736 nativeSetFocusedApplication(mPtr, displayId, application); 1737 } 1738 setFocusedDisplay(int displayId)1739 public void setFocusedDisplay(int displayId) { 1740 nativeSetFocusedDisplay(mPtr, displayId); 1741 } 1742 1743 /** Clean up input window handles of the given display. */ onDisplayRemoved(int displayId)1744 public void onDisplayRemoved(int displayId) { 1745 nativeDisplayRemoved(mPtr, displayId); 1746 } 1747 1748 @Override requestPointerCapture(IBinder inputChannelToken, boolean enabled)1749 public void requestPointerCapture(IBinder inputChannelToken, boolean enabled) { 1750 if (inputChannelToken == null) { 1751 return; 1752 } 1753 1754 nativeRequestPointerCapture(mPtr, inputChannelToken, enabled); 1755 } 1756 setInputDispatchMode(boolean enabled, boolean frozen)1757 public void setInputDispatchMode(boolean enabled, boolean frozen) { 1758 nativeSetInputDispatchMode(mPtr, enabled, frozen); 1759 } 1760 setSystemUiLightsOut(boolean lightsOut)1761 public void setSystemUiLightsOut(boolean lightsOut) { 1762 nativeSetSystemUiLightsOut(mPtr, lightsOut); 1763 } 1764 1765 /** 1766 * Atomically transfers touch focus from one window to another as identified by 1767 * their input channels. It is possible for multiple windows to have 1768 * touch focus if they support split touch dispatch 1769 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this 1770 * method only transfers touch focus of the specified window without affecting 1771 * other windows that may also have touch focus at the same time. 1772 * @param fromChannel The channel of a window that currently has touch focus. 1773 * @param toChannel The channel of the window that should receive touch focus in 1774 * place of the first. 1775 * @param isDragDrop True if transfer touch focus for drag and drop. 1776 * @return True if the transfer was successful. False if the window with the 1777 * specified channel did not actually have touch focus at the time of the request. 1778 */ transferTouchFocus(@onNull InputChannel fromChannel, @NonNull InputChannel toChannel, boolean isDragDrop)1779 public boolean transferTouchFocus(@NonNull InputChannel fromChannel, 1780 @NonNull InputChannel toChannel, boolean isDragDrop) { 1781 return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken(), 1782 isDragDrop); 1783 } 1784 1785 /** 1786 * Atomically transfers touch focus from one window to another as identified by 1787 * their input channels. It is possible for multiple windows to have 1788 * touch focus if they support split touch dispatch 1789 * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this 1790 * method only transfers touch focus of the specified window without affecting 1791 * other windows that may also have touch focus at the same time. 1792 * @param fromChannelToken The channel token of a window that currently has touch focus. 1793 * @param toChannelToken The channel token of the window that should receive touch focus in 1794 * place of the first. 1795 * @return True if the transfer was successful. False if the window with the 1796 * specified channel did not actually have touch focus at the time of the request. 1797 */ transferTouchFocus(@onNull IBinder fromChannelToken, @NonNull IBinder toChannelToken)1798 public boolean transferTouchFocus(@NonNull IBinder fromChannelToken, 1799 @NonNull IBinder toChannelToken) { 1800 Objects.nonNull(fromChannelToken); 1801 Objects.nonNull(toChannelToken); 1802 return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken, 1803 false /* isDragDrop */); 1804 } 1805 1806 @Override // Binder call tryPointerSpeed(int speed)1807 public void tryPointerSpeed(int speed) { 1808 if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, 1809 "tryPointerSpeed()")) { 1810 throw new SecurityException("Requires SET_POINTER_SPEED permission"); 1811 } 1812 1813 if (speed < InputManager.MIN_POINTER_SPEED || speed > InputManager.MAX_POINTER_SPEED) { 1814 throw new IllegalArgumentException("speed out of range"); 1815 } 1816 1817 setPointerSpeedUnchecked(speed); 1818 } 1819 updatePointerSpeedFromSettings()1820 private void updatePointerSpeedFromSettings() { 1821 int speed = getPointerSpeedSetting(); 1822 setPointerSpeedUnchecked(speed); 1823 } 1824 setPointerSpeedUnchecked(int speed)1825 private void setPointerSpeedUnchecked(int speed) { 1826 speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED), 1827 InputManager.MAX_POINTER_SPEED); 1828 nativeSetPointerSpeed(mPtr, speed); 1829 } 1830 registerPointerSpeedSettingObserver()1831 private void registerPointerSpeedSettingObserver() { 1832 mContext.getContentResolver().registerContentObserver( 1833 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true, 1834 new ContentObserver(mHandler) { 1835 @Override 1836 public void onChange(boolean selfChange) { 1837 updatePointerSpeedFromSettings(); 1838 } 1839 }, UserHandle.USER_ALL); 1840 } 1841 getPointerSpeedSetting()1842 private int getPointerSpeedSetting() { 1843 int speed = InputManager.DEFAULT_POINTER_SPEED; 1844 try { 1845 speed = Settings.System.getIntForUser(mContext.getContentResolver(), 1846 Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT); 1847 } catch (SettingNotFoundException snfe) { 1848 } 1849 return speed; 1850 } 1851 updateShowTouchesFromSettings()1852 private void updateShowTouchesFromSettings() { 1853 int setting = getShowTouchesSetting(0); 1854 nativeSetShowTouches(mPtr, setting != 0); 1855 } 1856 registerShowTouchesSettingObserver()1857 private void registerShowTouchesSettingObserver() { 1858 mContext.getContentResolver().registerContentObserver( 1859 Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true, 1860 new ContentObserver(mHandler) { 1861 @Override 1862 public void onChange(boolean selfChange) { 1863 updateShowTouchesFromSettings(); 1864 } 1865 }, UserHandle.USER_ALL); 1866 } 1867 updateAccessibilityLargePointerFromSettings()1868 private void updateAccessibilityLargePointerFromSettings() { 1869 final int accessibilityConfig = Settings.Secure.getIntForUser( 1870 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, 1871 0, UserHandle.USER_CURRENT); 1872 PointerIcon.setUseLargeIcons(accessibilityConfig == 1); 1873 nativeReloadPointerIcons(mPtr); 1874 } 1875 registerAccessibilityLargePointerSettingObserver()1876 private void registerAccessibilityLargePointerSettingObserver() { 1877 mContext.getContentResolver().registerContentObserver( 1878 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true, 1879 new ContentObserver(mHandler) { 1880 @Override 1881 public void onChange(boolean selfChange) { 1882 updateAccessibilityLargePointerFromSettings(); 1883 } 1884 }, UserHandle.USER_ALL); 1885 } 1886 updateDeepPressStatusFromSettings(String reason)1887 private void updateDeepPressStatusFromSettings(String reason) { 1888 // Not using ViewConfiguration.getLongPressTimeout here because it may return a stale value 1889 final int timeout = Settings.Secure.getIntForUser(mContext.getContentResolver(), 1890 Settings.Secure.LONG_PRESS_TIMEOUT, ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT, 1891 UserHandle.USER_CURRENT); 1892 final boolean featureEnabledFlag = 1893 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT, 1894 DEEP_PRESS_ENABLED, true /* default */); 1895 final boolean enabled = 1896 featureEnabledFlag && timeout <= ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT; 1897 Log.i(TAG, 1898 (enabled ? "Enabling" : "Disabling") + " motion classifier because " + reason 1899 + ": feature " + (featureEnabledFlag ? "enabled" : "disabled") 1900 + ", long press timeout = " + timeout); 1901 nativeSetMotionClassifierEnabled(mPtr, enabled); 1902 } 1903 registerLongPressTimeoutObserver()1904 private void registerLongPressTimeoutObserver() { 1905 mContext.getContentResolver().registerContentObserver( 1906 Settings.Secure.getUriFor(Settings.Secure.LONG_PRESS_TIMEOUT), true, 1907 new ContentObserver(mHandler) { 1908 @Override 1909 public void onChange(boolean selfChange) { 1910 updateDeepPressStatusFromSettings("timeout changed"); 1911 } 1912 }, UserHandle.USER_ALL); 1913 } 1914 registerBlockUntrustedTouchesModeSettingObserver()1915 private void registerBlockUntrustedTouchesModeSettingObserver() { 1916 mContext.getContentResolver().registerContentObserver( 1917 Settings.Global.getUriFor(Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE), 1918 /* notifyForDescendants */ true, 1919 new ContentObserver(mHandler) { 1920 @Override 1921 public void onChange(boolean selfChange) { 1922 updateBlockUntrustedTouchesModeFromSettings(); 1923 } 1924 }, UserHandle.USER_ALL); 1925 } 1926 updateBlockUntrustedTouchesModeFromSettings()1927 private void updateBlockUntrustedTouchesModeFromSettings() { 1928 final int mode = InputManager.getInstance().getBlockUntrustedTouchesMode(mContext); 1929 nativeSetBlockUntrustedTouchesMode(mPtr, mode); 1930 } 1931 registerMaximumObscuringOpacityForTouchSettingObserver()1932 private void registerMaximumObscuringOpacityForTouchSettingObserver() { 1933 mContext.getContentResolver().registerContentObserver( 1934 Settings.Global.getUriFor(Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH), 1935 /* notifyForDescendants */ true, 1936 new ContentObserver(mHandler) { 1937 @Override 1938 public void onChange(boolean selfChange) { 1939 updateMaximumObscuringOpacityForTouchFromSettings(); 1940 } 1941 }, UserHandle.USER_ALL); 1942 } 1943 updateMaximumObscuringOpacityForTouchFromSettings()1944 private void updateMaximumObscuringOpacityForTouchFromSettings() { 1945 final float opacity = InputManager.getInstance().getMaximumObscuringOpacityForTouch(); 1946 if (opacity < 0 || opacity > 1) { 1947 Log.e(TAG, "Invalid maximum obscuring opacity " + opacity 1948 + ", it should be >= 0 and <= 1, rejecting update."); 1949 return; 1950 } 1951 nativeSetMaximumObscuringOpacityForTouch(mPtr, opacity); 1952 } 1953 getShowTouchesSetting(int defaultValue)1954 private int getShowTouchesSetting(int defaultValue) { 1955 int result = defaultValue; 1956 try { 1957 result = Settings.System.getIntForUser(mContext.getContentResolver(), 1958 Settings.System.SHOW_TOUCHES, UserHandle.USER_CURRENT); 1959 } catch (SettingNotFoundException snfe) { 1960 } 1961 return result; 1962 } 1963 1964 private static class VibrationInfo { 1965 private final long[] mPattern; 1966 private final int[] mAmplitudes; 1967 private final int mRepeat; 1968 getPattern()1969 public long[] getPattern() { 1970 return mPattern; 1971 } 1972 getAmplitudes()1973 public int[] getAmplitudes() { 1974 return mAmplitudes; 1975 } 1976 getRepeatIndex()1977 public int getRepeatIndex() { 1978 return mRepeat; 1979 } 1980 VibrationInfo(VibrationEffect effect)1981 VibrationInfo(VibrationEffect effect) { 1982 long[] pattern = null; 1983 int[] amplitudes = null; 1984 int patternRepeatIndex = -1; 1985 int amplitudeCount = -1; 1986 1987 if (effect instanceof VibrationEffect.Composed) { 1988 VibrationEffect.Composed composed = (VibrationEffect.Composed) effect; 1989 int segmentCount = composed.getSegments().size(); 1990 pattern = new long[segmentCount]; 1991 amplitudes = new int[segmentCount]; 1992 patternRepeatIndex = composed.getRepeatIndex(); 1993 amplitudeCount = 0; 1994 for (int i = 0; i < segmentCount; i++) { 1995 VibrationEffectSegment segment = composed.getSegments().get(i); 1996 if (composed.getRepeatIndex() == i) { 1997 patternRepeatIndex = amplitudeCount; 1998 } 1999 if (!(segment instanceof StepSegment)) { 2000 Slog.w(TAG, "Input devices don't support segment " + segment); 2001 amplitudeCount = -1; 2002 break; 2003 } 2004 float amplitude = ((StepSegment) segment).getAmplitude(); 2005 if (Float.compare(amplitude, VibrationEffect.DEFAULT_AMPLITUDE) == 0) { 2006 amplitudes[amplitudeCount] = DEFAULT_VIBRATION_MAGNITUDE; 2007 } else { 2008 amplitudes[amplitudeCount] = 2009 (int) (amplitude * VibrationEffect.MAX_AMPLITUDE); 2010 } 2011 pattern[amplitudeCount++] = segment.getDuration(); 2012 } 2013 } 2014 2015 if (amplitudeCount < 0) { 2016 Slog.w(TAG, "Only oneshot and step waveforms are supported on input devices"); 2017 mPattern = new long[0]; 2018 mAmplitudes = new int[0]; 2019 mRepeat = -1; 2020 } else { 2021 mRepeat = patternRepeatIndex; 2022 mPattern = new long[amplitudeCount]; 2023 mAmplitudes = new int[amplitudeCount]; 2024 System.arraycopy(pattern, 0, mPattern, 0, amplitudeCount); 2025 System.arraycopy(amplitudes, 0, mAmplitudes, 0, amplitudeCount); 2026 if (mRepeat >= mPattern.length) { 2027 throw new ArrayIndexOutOfBoundsException("Repeat index " + mRepeat 2028 + " must be within the bounds of the pattern.length " 2029 + mPattern.length); 2030 } 2031 } 2032 } 2033 } 2034 getVibratorToken(int deviceId, IBinder token)2035 private VibratorToken getVibratorToken(int deviceId, IBinder token) { 2036 VibratorToken v; 2037 synchronized (mVibratorLock) { 2038 v = mVibratorTokens.get(token); 2039 if (v == null) { 2040 v = new VibratorToken(deviceId, token, mNextVibratorTokenValue++); 2041 try { 2042 token.linkToDeath(v, 0); 2043 } catch (RemoteException ex) { 2044 // give up 2045 throw new RuntimeException(ex); 2046 } 2047 mVibratorTokens.put(token, v); 2048 } 2049 } 2050 return v; 2051 } 2052 2053 // Binder call 2054 @Override vibrate(int deviceId, VibrationEffect effect, IBinder token)2055 public void vibrate(int deviceId, VibrationEffect effect, IBinder token) { 2056 VibrationInfo info = new VibrationInfo(effect); 2057 VibratorToken v = getVibratorToken(deviceId, token); 2058 synchronized (v) { 2059 v.mVibrating = true; 2060 nativeVibrate(mPtr, deviceId, info.getPattern(), info.getAmplitudes(), 2061 info.getRepeatIndex(), v.mTokenValue); 2062 } 2063 } 2064 2065 // Binder call 2066 @Override getVibratorIds(int deviceId)2067 public int[] getVibratorIds(int deviceId) { 2068 return nativeGetVibratorIds(mPtr, deviceId); 2069 } 2070 2071 // Binder call 2072 @Override isVibrating(int deviceId)2073 public boolean isVibrating(int deviceId) { 2074 return nativeIsVibrating(mPtr, deviceId); 2075 } 2076 2077 // Binder call 2078 @Override vibrateCombined(int deviceId, CombinedVibration effect, IBinder token)2079 public void vibrateCombined(int deviceId, CombinedVibration effect, IBinder token) { 2080 VibratorToken v = getVibratorToken(deviceId, token); 2081 synchronized (v) { 2082 if (!(effect instanceof CombinedVibration.Mono) 2083 && !(effect instanceof CombinedVibration.Stereo)) { 2084 Slog.e(TAG, "Only Mono and Stereo effects are supported"); 2085 return; 2086 } 2087 2088 v.mVibrating = true; 2089 if (effect instanceof CombinedVibration.Mono) { 2090 CombinedVibration.Mono mono = (CombinedVibration.Mono) effect; 2091 VibrationInfo info = new VibrationInfo(mono.getEffect()); 2092 nativeVibrate(mPtr, deviceId, info.getPattern(), info.getAmplitudes(), 2093 info.getRepeatIndex(), v.mTokenValue); 2094 } else if (effect instanceof CombinedVibration.Stereo) { 2095 CombinedVibration.Stereo stereo = (CombinedVibration.Stereo) effect; 2096 SparseArray<VibrationEffect> effects = stereo.getEffects(); 2097 long[] pattern = new long[0]; 2098 int repeat = Integer.MIN_VALUE; 2099 SparseArray<int[]> amplitudes = new SparseArray<int[]>(effects.size()); 2100 for (int i = 0; i < effects.size(); i++) { 2101 VibrationInfo info = new VibrationInfo(effects.valueAt(i)); 2102 // Pattern of all effects should be same 2103 if (pattern.length == 0) { 2104 pattern = info.getPattern(); 2105 } 2106 if (repeat == Integer.MIN_VALUE) { 2107 repeat = info.getRepeatIndex(); 2108 } 2109 amplitudes.put(effects.keyAt(i), info.getAmplitudes()); 2110 } 2111 nativeVibrateCombined(mPtr, deviceId, pattern, amplitudes, repeat, 2112 v.mTokenValue); 2113 } 2114 } 2115 } 2116 2117 // Binder call 2118 @Override cancelVibrate(int deviceId, IBinder token)2119 public void cancelVibrate(int deviceId, IBinder token) { 2120 VibratorToken v; 2121 synchronized (mVibratorLock) { 2122 v = mVibratorTokens.get(token); 2123 if (v == null || v.mDeviceId != deviceId) { 2124 return; // nothing to cancel 2125 } 2126 } 2127 2128 cancelVibrateIfNeeded(v); 2129 } 2130 onVibratorTokenDied(VibratorToken v)2131 void onVibratorTokenDied(VibratorToken v) { 2132 synchronized (mVibratorLock) { 2133 mVibratorTokens.remove(v.mToken); 2134 } 2135 2136 cancelVibrateIfNeeded(v); 2137 } 2138 cancelVibrateIfNeeded(VibratorToken v)2139 private void cancelVibrateIfNeeded(VibratorToken v) { 2140 synchronized (v) { 2141 if (v.mVibrating) { 2142 nativeCancelVibrate(mPtr, v.mDeviceId, v.mTokenValue); 2143 v.mVibrating = false; 2144 } 2145 } 2146 } 2147 2148 // Native callback. notifyVibratorState(int deviceId, boolean isOn)2149 private void notifyVibratorState(int deviceId, boolean isOn) { 2150 if (DEBUG) { 2151 Slog.d(TAG, "notifyVibratorState: deviceId=" + deviceId + " isOn=" + isOn); 2152 } 2153 synchronized (mVibratorLock) { 2154 mIsVibrating.put(deviceId, isOn); 2155 notifyVibratorStateListenersLocked(deviceId); 2156 } 2157 } 2158 2159 @GuardedBy("mVibratorLock") notifyVibratorStateListenersLocked(int deviceId)2160 private void notifyVibratorStateListenersLocked(int deviceId) { 2161 if (!mVibratorStateListeners.contains(deviceId)) { 2162 if (DEBUG) { 2163 Slog.v(TAG, "Device " + deviceId + " doesn't have vibrator state listener."); 2164 } 2165 return; 2166 } 2167 RemoteCallbackList<IVibratorStateListener> listeners = 2168 mVibratorStateListeners.get(deviceId); 2169 final int length = listeners.beginBroadcast(); 2170 try { 2171 for (int i = 0; i < length; i++) { 2172 notifyVibratorStateListenerLocked(deviceId, listeners.getBroadcastItem(i)); 2173 } 2174 } finally { 2175 listeners.finishBroadcast(); 2176 } 2177 } 2178 2179 @GuardedBy("mVibratorLock") notifyVibratorStateListenerLocked(int deviceId, IVibratorStateListener listener)2180 private void notifyVibratorStateListenerLocked(int deviceId, IVibratorStateListener listener) { 2181 try { 2182 listener.onVibrating(mIsVibrating.get(deviceId)); 2183 } catch (RemoteException | RuntimeException e) { 2184 Slog.e(TAG, "Vibrator state listener failed to call", e); 2185 } 2186 } 2187 2188 @Override // Binder call registerVibratorStateListener(int deviceId, IVibratorStateListener listener)2189 public boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) { 2190 Preconditions.checkNotNull(listener, "listener must not be null"); 2191 2192 RemoteCallbackList<IVibratorStateListener> listeners; 2193 synchronized (mVibratorLock) { 2194 if (!mVibratorStateListeners.contains(deviceId)) { 2195 listeners = new RemoteCallbackList<>(); 2196 mVibratorStateListeners.put(deviceId, listeners); 2197 } else { 2198 listeners = mVibratorStateListeners.get(deviceId); 2199 } 2200 2201 final long token = Binder.clearCallingIdentity(); 2202 try { 2203 if (!listeners.register(listener)) { 2204 Slog.e(TAG, "Could not register vibrator state listener " + listener); 2205 return false; 2206 } 2207 // Notify its callback after new client registered. 2208 notifyVibratorStateListenerLocked(deviceId, listener); 2209 return true; 2210 } finally { 2211 Binder.restoreCallingIdentity(token); 2212 } 2213 } 2214 } 2215 2216 @Override // Binder call unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener)2217 public boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) { 2218 synchronized (mVibratorLock) { 2219 final long token = Binder.clearCallingIdentity(); 2220 try { 2221 if (!mVibratorStateListeners.contains(deviceId)) { 2222 Slog.w(TAG, "Vibrator state listener " + deviceId + " doesn't exist"); 2223 return false; 2224 } 2225 RemoteCallbackList<IVibratorStateListener> listeners = 2226 mVibratorStateListeners.get(deviceId); 2227 return listeners.unregister(listener); 2228 } finally { 2229 Binder.restoreCallingIdentity(token); 2230 } 2231 } 2232 } 2233 2234 // Binder call 2235 @Override getBatteryStatus(int deviceId)2236 public int getBatteryStatus(int deviceId) { 2237 return nativeGetBatteryStatus(mPtr, deviceId); 2238 } 2239 2240 // Binder call 2241 @Override getBatteryCapacity(int deviceId)2242 public int getBatteryCapacity(int deviceId) { 2243 return nativeGetBatteryCapacity(mPtr, deviceId); 2244 } 2245 2246 // Binder call 2247 @Override setPointerIconType(int iconId)2248 public void setPointerIconType(int iconId) { 2249 nativeSetPointerIconType(mPtr, iconId); 2250 } 2251 2252 // Binder call 2253 @Override setCustomPointerIcon(PointerIcon icon)2254 public void setCustomPointerIcon(PointerIcon icon) { 2255 Objects.requireNonNull(icon); 2256 nativeSetCustomPointerIcon(mPtr, icon); 2257 } 2258 2259 /** 2260 * Add a runtime association between the input port and the display port. This overrides any 2261 * static associations. 2262 * @param inputPort The port of the input device. 2263 * @param displayPort The physical port of the associated display. 2264 */ 2265 @Override // Binder call addPortAssociation(@onNull String inputPort, int displayPort)2266 public void addPortAssociation(@NonNull String inputPort, int displayPort) { 2267 if (!checkCallingPermission( 2268 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, 2269 "addPortAssociation()")) { 2270 throw new SecurityException( 2271 "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); 2272 } 2273 2274 Objects.requireNonNull(inputPort); 2275 synchronized (mAssociationsLock) { 2276 mRuntimeAssociations.put(inputPort, displayPort); 2277 } 2278 nativeNotifyPortAssociationsChanged(mPtr); 2279 } 2280 2281 /** 2282 * Remove the runtime association between the input port and the display port. Any existing 2283 * static association for the cleared input port will be restored. 2284 * @param inputPort The port of the input device to be cleared. 2285 */ 2286 @Override // Binder call removePortAssociation(@onNull String inputPort)2287 public void removePortAssociation(@NonNull String inputPort) { 2288 if (!checkCallingPermission( 2289 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, 2290 "clearPortAssociations()")) { 2291 throw new SecurityException( 2292 "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); 2293 } 2294 2295 Objects.requireNonNull(inputPort); 2296 synchronized (mAssociationsLock) { 2297 mRuntimeAssociations.remove(inputPort); 2298 } 2299 nativeNotifyPortAssociationsChanged(mPtr); 2300 } 2301 2302 /** 2303 * Add a runtime association between the input device name and the display unique id. 2304 * @param inputDeviceName The name of the input device. 2305 * @param displayUniqueId The unique id of the associated display. 2306 */ 2307 @Override // Binder call addUniqueIdAssociation(@onNull String inputDeviceName, @NonNull String displayUniqueId)2308 public void addUniqueIdAssociation(@NonNull String inputDeviceName, 2309 @NonNull String displayUniqueId) { 2310 if (!checkCallingPermission( 2311 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, 2312 "addNameAssociation()")) { 2313 throw new SecurityException( 2314 "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); 2315 } 2316 2317 Objects.requireNonNull(inputDeviceName); 2318 Objects.requireNonNull(displayUniqueId); 2319 synchronized (mAssociationsLock) { 2320 mUniqueIdAssociations.put(inputDeviceName, displayUniqueId); 2321 } 2322 nativeChangeUniqueIdAssociation(mPtr); 2323 } 2324 2325 /** 2326 * Remove the runtime association between the input device and the display. 2327 * @param inputDeviceName The port of the input device to be cleared. 2328 */ 2329 @Override // Binder call removeUniqueIdAssociation(@onNull String inputDeviceName)2330 public void removeUniqueIdAssociation(@NonNull String inputDeviceName) { 2331 if (!checkCallingPermission( 2332 android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY, 2333 "removeUniqueIdAssociation()")) { 2334 throw new SecurityException( 2335 "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission"); 2336 } 2337 2338 Objects.requireNonNull(inputDeviceName); 2339 synchronized (mAssociationsLock) { 2340 mUniqueIdAssociations.remove(inputDeviceName); 2341 } 2342 nativeChangeUniqueIdAssociation(mPtr); 2343 } 2344 2345 @Override // Binder call getSensorList(int deviceId)2346 public InputSensorInfo[] getSensorList(int deviceId) { 2347 return nativeGetSensorList(mPtr, deviceId); 2348 } 2349 2350 @Override // Binder call registerSensorListener(IInputSensorEventListener listener)2351 public boolean registerSensorListener(IInputSensorEventListener listener) { 2352 if (DEBUG) { 2353 Slog.d(TAG, "registerSensorListener: listener=" + listener + " callingPid=" 2354 + Binder.getCallingPid()); 2355 } 2356 if (listener == null) { 2357 Slog.e(TAG, "listener must not be null"); 2358 return false; 2359 } 2360 2361 synchronized (mInputDevicesLock) { 2362 int callingPid = Binder.getCallingPid(); 2363 if (mSensorEventListeners.get(callingPid) != null) { 2364 Slog.e(TAG, "The calling process " + callingPid + " has already " 2365 + "registered an InputSensorEventListener."); 2366 return false; 2367 } 2368 2369 SensorEventListenerRecord record = 2370 new SensorEventListenerRecord(callingPid, listener); 2371 try { 2372 IBinder binder = listener.asBinder(); 2373 binder.linkToDeath(record, 0); 2374 } catch (RemoteException ex) { 2375 // give up 2376 throw new RuntimeException(ex); 2377 } 2378 2379 mSensorEventListeners.put(callingPid, record); 2380 } 2381 return true; 2382 } 2383 2384 @Override // Binder call unregisterSensorListener(IInputSensorEventListener listener)2385 public void unregisterSensorListener(IInputSensorEventListener listener) { 2386 if (DEBUG) { 2387 Slog.d(TAG, "unregisterSensorListener: listener=" + listener + " callingPid=" 2388 + Binder.getCallingPid()); 2389 } 2390 2391 if (listener == null) { 2392 throw new IllegalArgumentException("listener must not be null"); 2393 } 2394 2395 synchronized (mInputDevicesLock) { 2396 int callingPid = Binder.getCallingPid(); 2397 if (mSensorEventListeners.get(callingPid) != null) { 2398 SensorEventListenerRecord record = mSensorEventListeners.get(callingPid); 2399 if (record.getListener().asBinder() != listener.asBinder()) { 2400 throw new IllegalArgumentException("listener is not registered"); 2401 } 2402 mSensorEventListeners.remove(callingPid); 2403 } 2404 } 2405 } 2406 2407 @Override // Binder call flushSensor(int deviceId, int sensorType)2408 public boolean flushSensor(int deviceId, int sensorType) { 2409 synchronized (mInputDevicesLock) { 2410 int callingPid = Binder.getCallingPid(); 2411 SensorEventListenerRecord listener = mSensorEventListeners.get(callingPid); 2412 if (listener != null) { 2413 return nativeFlushSensor(mPtr, deviceId, sensorType); 2414 } 2415 return false; 2416 } 2417 } 2418 2419 @Override // Binder call enableSensor(int deviceId, int sensorType, int samplingPeriodUs, int maxBatchReportLatencyUs)2420 public boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs, 2421 int maxBatchReportLatencyUs) { 2422 synchronized (mInputDevicesLock) { 2423 return nativeEnableSensor(mPtr, deviceId, sensorType, samplingPeriodUs, 2424 maxBatchReportLatencyUs); 2425 } 2426 } 2427 2428 @Override // Binder call disableSensor(int deviceId, int sensorType)2429 public void disableSensor(int deviceId, int sensorType) { 2430 synchronized (mInputDevicesLock) { 2431 nativeDisableSensor(mPtr, deviceId, sensorType); 2432 } 2433 } 2434 2435 /** 2436 * LightSession represents a light session for lights manager. 2437 */ 2438 private final class LightSession implements DeathRecipient { 2439 private final int mDeviceId; 2440 private final IBinder mToken; 2441 private final String mOpPkg; 2442 // The light ids and states that are requested by the light seesion 2443 private int[] mLightIds; 2444 private LightState[] mLightStates; 2445 LightSession(int deviceId, String opPkg, IBinder token)2446 LightSession(int deviceId, String opPkg, IBinder token) { 2447 mDeviceId = deviceId; 2448 mOpPkg = opPkg; 2449 mToken = token; 2450 } 2451 2452 @Override binderDied()2453 public void binderDied() { 2454 if (DEBUG) { 2455 Slog.d(TAG, "Light token died."); 2456 } 2457 synchronized (mLightLock) { 2458 closeLightSession(mDeviceId, mToken); 2459 mLightSessions.remove(mToken); 2460 } 2461 } 2462 } 2463 2464 /** 2465 * Returns the lights available for apps to control on the specified input device. 2466 * Only lights that aren't reserved for system use are available to apps. 2467 */ 2468 @Override // Binder call getLights(int deviceId)2469 public List<Light> getLights(int deviceId) { 2470 return nativeGetLights(mPtr, deviceId); 2471 } 2472 2473 /** 2474 * Set specified light state with for a specific input device. 2475 */ setLightStateInternal(int deviceId, Light light, LightState lightState)2476 private void setLightStateInternal(int deviceId, Light light, LightState lightState) { 2477 Preconditions.checkNotNull(light, "light does not exist"); 2478 if (DEBUG) { 2479 Slog.d(TAG, "setLightStateInternal device " + deviceId + " light " + light 2480 + "lightState " + lightState); 2481 } 2482 if (light.getType() == Light.LIGHT_TYPE_PLAYER_ID) { 2483 nativeSetLightPlayerId(mPtr, deviceId, light.getId(), lightState.getPlayerId()); 2484 } else { 2485 // Set ARGB format color to input device light 2486 // Refer to https://developer.android.com/reference/kotlin/android/graphics/Color 2487 nativeSetLightColor(mPtr, deviceId, light.getId(), lightState.getColor()); 2488 } 2489 } 2490 2491 /** 2492 * Set multiple light states with multiple light ids for a specific input device. 2493 */ setLightStatesInternal(int deviceId, int[] lightIds, LightState[] lightStates)2494 private void setLightStatesInternal(int deviceId, int[] lightIds, LightState[] lightStates) { 2495 final List<Light> lights = nativeGetLights(mPtr, deviceId); 2496 SparseArray<Light> lightArray = new SparseArray<>(); 2497 for (int i = 0; i < lights.size(); i++) { 2498 lightArray.put(lights.get(i).getId(), lights.get(i)); 2499 } 2500 for (int i = 0; i < lightIds.length; i++) { 2501 if (lightArray.contains(lightIds[i])) { 2502 setLightStateInternal(deviceId, lightArray.get(lightIds[i]), lightStates[i]); 2503 } 2504 } 2505 } 2506 2507 /** 2508 * Set states for multiple lights for an opened light session. 2509 */ 2510 @Override setLightStates(int deviceId, int[] lightIds, LightState[] lightStates, IBinder token)2511 public void setLightStates(int deviceId, int[] lightIds, LightState[] lightStates, 2512 IBinder token) { 2513 Preconditions.checkArgument(lightIds.length == lightStates.length, 2514 "lights and light states are not same length"); 2515 synchronized (mLightLock) { 2516 LightSession lightSession = mLightSessions.get(token); 2517 Preconditions.checkArgument(lightSession != null, "not registered"); 2518 Preconditions.checkState(lightSession.mDeviceId == deviceId, "Incorrect device ID"); 2519 lightSession.mLightIds = lightIds.clone(); 2520 lightSession.mLightStates = lightStates.clone(); 2521 if (DEBUG) { 2522 Slog.d(TAG, "setLightStates for " + lightSession.mOpPkg + " device " + deviceId); 2523 } 2524 } 2525 setLightStatesInternal(deviceId, lightIds, lightStates); 2526 } 2527 2528 @Override getLightState(int deviceId, int lightId)2529 public @Nullable LightState getLightState(int deviceId, int lightId) { 2530 synchronized (mLightLock) { 2531 int color = nativeGetLightColor(mPtr, deviceId, lightId); 2532 int playerId = nativeGetLightPlayerId(mPtr, deviceId, lightId); 2533 2534 return new LightState(color, playerId); 2535 } 2536 } 2537 2538 @Override openLightSession(int deviceId, String opPkg, IBinder token)2539 public void openLightSession(int deviceId, String opPkg, IBinder token) { 2540 Preconditions.checkNotNull(token); 2541 synchronized (mLightLock) { 2542 Preconditions.checkState(mLightSessions.get(token) == null, "already registered"); 2543 LightSession lightSession = new LightSession(deviceId, opPkg, token); 2544 try { 2545 token.linkToDeath(lightSession, 0); 2546 } catch (RemoteException ex) { 2547 // give up 2548 ex.rethrowAsRuntimeException(); 2549 } 2550 mLightSessions.put(token, lightSession); 2551 if (DEBUG) { 2552 Slog.d(TAG, "Open light session for " + opPkg + " device " + deviceId); 2553 } 2554 } 2555 } 2556 2557 @Override closeLightSession(int deviceId, IBinder token)2558 public void closeLightSession(int deviceId, IBinder token) { 2559 Preconditions.checkNotNull(token); 2560 synchronized (mLightLock) { 2561 LightSession lightSession = mLightSessions.get(token); 2562 Preconditions.checkState(lightSession != null, "not registered"); 2563 // Turn off the lights that were previously requested by the session to be closed. 2564 Arrays.fill(lightSession.mLightStates, new LightState(0)); 2565 setLightStatesInternal(deviceId, lightSession.mLightIds, 2566 lightSession.mLightStates); 2567 mLightSessions.remove(token); 2568 // If any other session is still pending with light request, apply the first session's 2569 // request. 2570 if (!mLightSessions.isEmpty()) { 2571 LightSession nextSession = mLightSessions.valueAt(0); 2572 setLightStatesInternal(deviceId, nextSession.mLightIds, nextSession.mLightStates); 2573 } 2574 } 2575 } 2576 2577 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)2578 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2579 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 2580 2581 pw.println("INPUT MANAGER (dumpsys input)\n"); 2582 String dumpStr = nativeDump(mPtr); 2583 if (dumpStr != null) { 2584 pw.println(dumpStr); 2585 dumpAssociations(pw); 2586 } 2587 } 2588 dumpAssociations(PrintWriter pw)2589 private void dumpAssociations(PrintWriter pw) { 2590 if (!mStaticAssociations.isEmpty()) { 2591 pw.println("Static Associations:"); 2592 mStaticAssociations.forEach((k, v) -> { 2593 pw.print(" port: " + k); 2594 pw.println(" display: " + v); 2595 }); 2596 } 2597 2598 synchronized (mAssociationsLock) { 2599 if (!mRuntimeAssociations.isEmpty()) { 2600 pw.println("Runtime Associations:"); 2601 mRuntimeAssociations.forEach((k, v) -> { 2602 pw.print(" port: " + k); 2603 pw.println(" display: " + v); 2604 }); 2605 } 2606 } 2607 } 2608 checkCallingPermission(String permission, String func)2609 private boolean checkCallingPermission(String permission, String func) { 2610 // Quick check: if the calling permission is me, it's all okay. 2611 if (Binder.getCallingPid() == Process.myPid()) { 2612 return true; 2613 } 2614 2615 if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { 2616 return true; 2617 } 2618 String msg = "Permission Denial: " + func + " from pid=" 2619 + Binder.getCallingPid() 2620 + ", uid=" + Binder.getCallingUid() 2621 + " requires " + permission; 2622 Slog.w(TAG, msg); 2623 return false; 2624 } 2625 2626 // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). 2627 @Override monitor()2628 public void monitor() { 2629 synchronized (mInputFilterLock) { } 2630 synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */} 2631 synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ } 2632 nativeMonitor(mPtr); 2633 } 2634 2635 // Native callback. notifyConfigurationChanged(long whenNanos)2636 private void notifyConfigurationChanged(long whenNanos) { 2637 mWindowManagerCallbacks.notifyConfigurationChanged(); 2638 } 2639 2640 // Native callback. notifyInputDevicesChanged(InputDevice[] inputDevices)2641 private void notifyInputDevicesChanged(InputDevice[] inputDevices) { 2642 synchronized (mInputDevicesLock) { 2643 if (!mInputDevicesChangedPending) { 2644 mInputDevicesChangedPending = true; 2645 mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED, 2646 mInputDevices).sendToTarget(); 2647 } 2648 2649 mInputDevices = inputDevices; 2650 } 2651 } 2652 2653 // Native callback. notifySwitch(long whenNanos, int switchValues, int switchMask)2654 private void notifySwitch(long whenNanos, int switchValues, int switchMask) { 2655 if (DEBUG) { 2656 Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues) 2657 + ", mask=" + Integer.toHexString(switchMask)); 2658 } 2659 2660 if ((switchMask & SW_LID_BIT) != 0) { 2661 final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0); 2662 synchronized (mLidSwitchLock) { 2663 if (mSystemReady) { 2664 for (int i = 0; i < mLidSwitchCallbacks.size(); i++) { 2665 LidSwitchCallback callbacks = mLidSwitchCallbacks.get(i); 2666 callbacks.notifyLidSwitchChanged(whenNanos, lidOpen); 2667 } 2668 } 2669 } 2670 } 2671 2672 if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) { 2673 final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0); 2674 mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered); 2675 } 2676 2677 if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) { 2678 mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues, 2679 switchMask); 2680 } 2681 2682 if ((switchMask & SW_TABLET_MODE_BIT) != 0) { 2683 SomeArgs args = SomeArgs.obtain(); 2684 args.argi1 = (int) (whenNanos & 0xFFFFFFFF); 2685 args.argi2 = (int) (whenNanos >> 32); 2686 args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0); 2687 mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED, 2688 args).sendToTarget(); 2689 } 2690 2691 if ((switchMask & SW_MUTE_DEVICE_BIT) != 0) { 2692 final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0); 2693 AudioManager audioManager = mContext.getSystemService(AudioManager.class); 2694 audioManager.setMicrophoneMuteFromSwitch(micMute); 2695 } 2696 } 2697 2698 // Native callback. notifyInputChannelBroken(IBinder token)2699 private void notifyInputChannelBroken(IBinder token) { 2700 mWindowManagerCallbacks.notifyInputChannelBroken(token); 2701 } 2702 2703 // Native callback notifyFocusChanged(IBinder oldToken, IBinder newToken)2704 private void notifyFocusChanged(IBinder oldToken, IBinder newToken) { 2705 mWindowManagerCallbacks.notifyFocusChanged(oldToken, newToken); 2706 } 2707 2708 // Native callback notifyDropWindow(IBinder token, float x, float y)2709 private void notifyDropWindow(IBinder token, float x, float y) { 2710 mWindowManagerCallbacks.notifyDropWindow(token, x, y); 2711 } 2712 2713 // Native callback notifyUntrustedTouch(String packageName)2714 private void notifyUntrustedTouch(String packageName) { 2715 // TODO(b/169067926): Remove toast after gathering feedback on dogfood. 2716 if (!UNTRUSTED_TOUCHES_TOAST || ArrayUtils.contains( 2717 PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) { 2718 Log.i(TAG, "Suppressing untrusted touch toast for " + packageName); 2719 return; 2720 } 2721 DisplayThread.getHandler().post(() -> 2722 Toast.makeText(mContext, 2723 "Touch obscured by " + packageName 2724 + " will be blocked. Check go/untrusted-touches", 2725 Toast.LENGTH_SHORT).show()); 2726 } 2727 2728 // Native callback. notifyNoFocusedWindowAnr(InputApplicationHandle inputApplicationHandle)2729 private void notifyNoFocusedWindowAnr(InputApplicationHandle inputApplicationHandle) { 2730 mWindowManagerCallbacks.notifyNoFocusedWindowAnr(inputApplicationHandle); 2731 } 2732 2733 // Native callback notifyWindowUnresponsive(IBinder token, String reason)2734 private void notifyWindowUnresponsive(IBinder token, String reason) { 2735 mWindowManagerCallbacks.notifyWindowUnresponsive(token, reason); 2736 } 2737 2738 // Native callback notifyMonitorUnresponsive(int pid, String reason)2739 private void notifyMonitorUnresponsive(int pid, String reason) { 2740 mWindowManagerCallbacks.notifyGestureMonitorUnresponsive(pid, reason); 2741 } 2742 2743 // Native callback notifyWindowResponsive(IBinder token)2744 private void notifyWindowResponsive(IBinder token) { 2745 mWindowManagerCallbacks.notifyWindowResponsive(token); 2746 } 2747 2748 // Native callback notifyMonitorResponsive(int pid)2749 private void notifyMonitorResponsive(int pid) { 2750 mWindowManagerCallbacks.notifyGestureMonitorResponsive(pid); 2751 } 2752 2753 // Native callback. notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, float[] values)2754 private void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, 2755 float[] values) { 2756 if (DEBUG) { 2757 Slog.d(TAG, "notifySensorEvent: deviceId=" + deviceId + " sensorType=" 2758 + sensorType + " values=" + Arrays.toString(values)); 2759 } 2760 mSensorEventListenersToNotify.clear(); 2761 final int numListeners; 2762 synchronized (mSensorEventLock) { 2763 numListeners = mSensorEventListeners.size(); 2764 for (int i = 0; i < numListeners; i++) { 2765 mSensorEventListenersToNotify.add( 2766 mSensorEventListeners.valueAt(i)); 2767 } 2768 } 2769 for (int i = 0; i < numListeners; i++) { 2770 mSensorEventListenersToNotify.get(i).notifySensorEvent(deviceId, sensorType, 2771 accuracy, timestamp, values); 2772 } 2773 mSensorEventListenersToNotify.clear(); 2774 } 2775 2776 // Native callback. notifySensorAccuracy(int deviceId, int sensorType, int accuracy)2777 private void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) { 2778 mSensorAccuracyListenersToNotify.clear(); 2779 final int numListeners; 2780 synchronized (mSensorEventLock) { 2781 numListeners = mSensorEventListeners.size(); 2782 for (int i = 0; i < numListeners; i++) { 2783 mSensorAccuracyListenersToNotify.add(mSensorEventListeners.valueAt(i)); 2784 } 2785 } 2786 for (int i = 0; i < numListeners; i++) { 2787 mSensorAccuracyListenersToNotify.get(i).notifySensorAccuracy( 2788 deviceId, sensorType, accuracy); 2789 } 2790 mSensorAccuracyListenersToNotify.clear(); 2791 } 2792 2793 // Native callback. filterInputEvent(InputEvent event, int policyFlags)2794 final boolean filterInputEvent(InputEvent event, int policyFlags) { 2795 synchronized (mInputFilterLock) { 2796 if (mInputFilter != null) { 2797 try { 2798 mInputFilter.filterInputEvent(event, policyFlags); 2799 } catch (RemoteException e) { 2800 /* ignore */ 2801 } 2802 return false; 2803 } 2804 } 2805 event.recycle(); 2806 return true; 2807 } 2808 2809 // Native callback. interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)2810 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { 2811 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags); 2812 } 2813 2814 // Native callback. interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)2815 private int interceptMotionBeforeQueueingNonInteractive(int displayId, 2816 long whenNanos, int policyFlags) { 2817 return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive( 2818 displayId, whenNanos, policyFlags); 2819 } 2820 2821 // Native callback. interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags)2822 private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) { 2823 return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); 2824 } 2825 2826 // Native callback. dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags)2827 private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) { 2828 return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags); 2829 } 2830 2831 // Native callback. checkInjectEventsPermission(int injectorPid, int injectorUid)2832 private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) { 2833 return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS, 2834 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED; 2835 } 2836 2837 // Native callback. onPointerDownOutsideFocus(IBinder touchedToken)2838 private void onPointerDownOutsideFocus(IBinder touchedToken) { 2839 mWindowManagerCallbacks.onPointerDownOutsideFocus(touchedToken); 2840 } 2841 2842 // Native callback. getVirtualKeyQuietTimeMillis()2843 private int getVirtualKeyQuietTimeMillis() { 2844 return mContext.getResources().getInteger( 2845 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis); 2846 } 2847 2848 // Native callback. getExcludedDeviceNames()2849 private static String[] getExcludedDeviceNames() { 2850 List<String> names = new ArrayList<>(); 2851 // Read partner-provided list of excluded input devices 2852 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". 2853 final File[] baseDirs = { 2854 Environment.getRootDirectory(), 2855 Environment.getVendorDirectory() 2856 }; 2857 for (File baseDir: baseDirs) { 2858 File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH); 2859 try { 2860 InputStream stream = new FileInputStream(confFile); 2861 names.addAll(ConfigurationProcessor.processExcludedDeviceNames(stream)); 2862 } catch (FileNotFoundException e) { 2863 // It's ok if the file does not exist. 2864 } catch (Exception e) { 2865 Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e); 2866 } 2867 } 2868 return names.toArray(new String[0]); 2869 } 2870 2871 /** 2872 * Flatten a map into a string list, with value positioned directly next to the 2873 * key. 2874 * @return Flattened list 2875 */ flatten(@onNull Map<String, T> map)2876 private static <T> String[] flatten(@NonNull Map<String, T> map) { 2877 final List<String> list = new ArrayList<>(map.size() * 2); 2878 map.forEach((k, v)-> { 2879 list.add(k); 2880 list.add(v.toString()); 2881 }); 2882 return list.toArray(new String[0]); 2883 } 2884 2885 /** 2886 * Ports are highly platform-specific, so only allow these to be specified in the vendor 2887 * directory. 2888 */ loadStaticInputPortAssociations()2889 private static Map<String, Integer> loadStaticInputPortAssociations() { 2890 final File baseDir = Environment.getVendorDirectory(); 2891 final File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH); 2892 2893 try { 2894 final InputStream stream = new FileInputStream(confFile); 2895 return ConfigurationProcessor.processInputPortAssociations(stream); 2896 } catch (FileNotFoundException e) { 2897 // Most of the time, file will not exist, which is expected. 2898 } catch (Exception e) { 2899 Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e); 2900 } 2901 2902 return new HashMap<>(); 2903 } 2904 2905 // Native callback getInputPortAssociations()2906 private String[] getInputPortAssociations() { 2907 final Map<String, Integer> associations = new HashMap<>(mStaticAssociations); 2908 2909 // merge the runtime associations. 2910 synchronized (mAssociationsLock) { 2911 associations.putAll(mRuntimeAssociations); 2912 } 2913 2914 return flatten(associations); 2915 } 2916 2917 // Native callback getInputUniqueIdAssociations()2918 private String[] getInputUniqueIdAssociations() { 2919 final Map<String, String> associations; 2920 synchronized (mAssociationsLock) { 2921 associations = new HashMap<>(mUniqueIdAssociations); 2922 } 2923 2924 return flatten(associations); 2925 } 2926 2927 /** 2928 * Gets if an input device could dispatch to the given display". 2929 * @param deviceId The input device id. 2930 * @param displayId The specific display id. 2931 * @return True if the device could dispatch to the given display, false otherwise. 2932 */ canDispatchToDisplay(int deviceId, int displayId)2933 public boolean canDispatchToDisplay(int deviceId, int displayId) { 2934 return nativeCanDispatchToDisplay(mPtr, deviceId, displayId); 2935 } 2936 2937 // Native callback. getKeyRepeatTimeout()2938 private int getKeyRepeatTimeout() { 2939 return ViewConfiguration.getKeyRepeatTimeout(); 2940 } 2941 2942 // Native callback. getKeyRepeatDelay()2943 private int getKeyRepeatDelay() { 2944 return ViewConfiguration.getKeyRepeatDelay(); 2945 } 2946 2947 // Native callback. getHoverTapTimeout()2948 private int getHoverTapTimeout() { 2949 return ViewConfiguration.getHoverTapTimeout(); 2950 } 2951 2952 // Native callback. getHoverTapSlop()2953 private int getHoverTapSlop() { 2954 return ViewConfiguration.getHoverTapSlop(); 2955 } 2956 2957 // Native callback. getDoubleTapTimeout()2958 private int getDoubleTapTimeout() { 2959 return ViewConfiguration.getDoubleTapTimeout(); 2960 } 2961 2962 // Native callback. getLongPressTimeout()2963 private int getLongPressTimeout() { 2964 return ViewConfiguration.getLongPressTimeout(); 2965 } 2966 2967 // Native callback. getPointerLayer()2968 private int getPointerLayer() { 2969 return mWindowManagerCallbacks.getPointerLayer(); 2970 } 2971 2972 // Native callback. getPointerIcon(int displayId)2973 private PointerIcon getPointerIcon(int displayId) { 2974 return PointerIcon.getDefaultIcon(getContextForDisplay(displayId)); 2975 } 2976 getContextForDisplay(int displayId)2977 private Context getContextForDisplay(int displayId) { 2978 if (mDisplayContext != null && mDisplayContext.getDisplay().getDisplayId() == displayId) { 2979 return mDisplayContext; 2980 } 2981 2982 if (mContext.getDisplay().getDisplayId() == displayId) { 2983 mDisplayContext = mContext; 2984 return mDisplayContext; 2985 } 2986 2987 // Create and cache context for non-default display. 2988 final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); 2989 final Display display = displayManager.getDisplay(displayId); 2990 mDisplayContext = mContext.createDisplayContext(display); 2991 return mDisplayContext; 2992 } 2993 2994 // Native callback. getPointerDisplayId()2995 private int getPointerDisplayId() { 2996 return mWindowManagerCallbacks.getPointerDisplayId(); 2997 } 2998 2999 // Native callback. getKeyboardLayoutOverlay(InputDeviceIdentifier identifier)3000 private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) { 3001 if (!mSystemReady) { 3002 return null; 3003 } 3004 3005 String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier); 3006 if (keyboardLayoutDescriptor == null) { 3007 return null; 3008 } 3009 3010 final String[] result = new String[2]; 3011 visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { 3012 @Override 3013 public void visitKeyboardLayout(Resources resources, 3014 int keyboardLayoutResId, KeyboardLayout layout) { 3015 try { 3016 result[0] = layout.getDescriptor(); 3017 result[1] = Streams.readFully(new InputStreamReader( 3018 resources.openRawResource(keyboardLayoutResId))); 3019 } catch (IOException ex) { 3020 } catch (NotFoundException ex) { 3021 } 3022 } 3023 }); 3024 if (result[0] == null) { 3025 Slog.w(TAG, "Could not get keyboard layout with descriptor '" 3026 + keyboardLayoutDescriptor + "'."); 3027 return null; 3028 } 3029 return result; 3030 } 3031 3032 // Native callback. getDeviceAlias(String uniqueId)3033 private String getDeviceAlias(String uniqueId) { 3034 if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) { 3035 // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId) 3036 return null; 3037 } 3038 return null; 3039 } 3040 3041 /** 3042 * Callback interface implemented by the Window Manager. 3043 */ 3044 public interface WindowManagerCallbacks extends LidSwitchCallback { 3045 /** 3046 * This callback is invoked when the configuration changes. 3047 */ notifyConfigurationChanged()3048 void notifyConfigurationChanged(); 3049 3050 /** 3051 * This callback is invoked when the camera lens cover switch changes state. 3052 * @param whenNanos the time when the change occurred 3053 * @param lensCovered true is the lens is covered 3054 */ notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered)3055 void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered); 3056 3057 /** 3058 * This callback is invoked when an input channel is closed unexpectedly. 3059 * @param token the connection token of the broken channel 3060 */ notifyInputChannelBroken(IBinder token)3061 void notifyInputChannelBroken(IBinder token); 3062 3063 /** 3064 * Notify the window manager about the focused application that does not have any focused 3065 * window and is unable to respond to focused input events. 3066 */ notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle)3067 void notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle); 3068 3069 /** 3070 * Notify the window manager about a gesture monitor that is unresponsive. 3071 * 3072 * @param pid the pid of the gesture monitor process 3073 * @param reason the reason why this connection is unresponsive 3074 */ notifyGestureMonitorUnresponsive(int pid, @NonNull String reason)3075 void notifyGestureMonitorUnresponsive(int pid, @NonNull String reason); 3076 3077 /** 3078 * Notify the window manager about a window that is unresponsive. 3079 * 3080 * @param token the token that can be used to look up the window 3081 * @param reason the reason why this connection is unresponsive 3082 */ notifyWindowUnresponsive(@onNull IBinder token, @NonNull String reason)3083 void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull String reason); 3084 3085 /** 3086 * Notify the window manager about a gesture monitor that has become responsive. 3087 * 3088 * @param pid the pid of the gesture monitor process 3089 */ notifyGestureMonitorResponsive(int pid)3090 void notifyGestureMonitorResponsive(int pid); 3091 3092 /** 3093 * Notify the window manager about a window that has become responsive. 3094 * 3095 * @param token the token that can be used to look up the window 3096 */ notifyWindowResponsive(@onNull IBinder token)3097 void notifyWindowResponsive(@NonNull IBinder token); 3098 3099 /** 3100 * This callback is invoked when an event first arrives to InputDispatcher and before it is 3101 * placed onto InputDispatcher's queue. If this event is intercepted, it will never be 3102 * processed by InputDispacher. 3103 * @param event The key event that's arriving to InputDispatcher 3104 * @param policyFlags The policy flags 3105 * @return the flags that tell InputDispatcher how to handle the event (for example, whether 3106 * to pass it to the user) 3107 */ interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)3108 int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags); 3109 3110 /** 3111 * Provides an opportunity for the window manager policy to intercept early motion event 3112 * processing when the device is in a non-interactive state since these events are normally 3113 * dropped. 3114 */ interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, int policyFlags)3115 int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos, 3116 int policyFlags); 3117 3118 /** 3119 * This callback is invoked just before the key is about to be sent to an application. 3120 * This allows the policy to make some last minute decisions on whether to intercept this 3121 * key. 3122 * @param token the window token that's about to receive this event 3123 * @param event the key event that's being dispatched 3124 * @param policyFlags the policy flags 3125 * @return negative value if the key should be skipped (not sent to the app). 0 if the key 3126 * should proceed getting dispatched to the app. positive value to indicate the additional 3127 * time delay, in nanoseconds, to wait before sending this key to the app. 3128 */ interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags)3129 long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags); 3130 3131 /** 3132 * Dispatch unhandled key 3133 */ dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags)3134 KeyEvent dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags); 3135 getPointerLayer()3136 int getPointerLayer(); 3137 getPointerDisplayId()3138 int getPointerDisplayId(); 3139 3140 /** 3141 * Notifies window manager that a {@link android.view.MotionEvent#ACTION_DOWN} pointer event 3142 * occurred on a window that did not have focus. 3143 * 3144 * @param touchedToken The token for the window that received the input event. 3145 */ onPointerDownOutsideFocus(IBinder touchedToken)3146 void onPointerDownOutsideFocus(IBinder touchedToken); 3147 3148 /** 3149 * Called when the focused window has changed. 3150 */ notifyFocusChanged(IBinder oldToken, IBinder newToken)3151 void notifyFocusChanged(IBinder oldToken, IBinder newToken); 3152 3153 /** 3154 * Called when the drag over window has changed. 3155 */ notifyDropWindow(IBinder token, float x, float y)3156 void notifyDropWindow(IBinder token, float x, float y); 3157 } 3158 3159 /** 3160 * Callback interface implemented by WiredAccessoryObserver. 3161 */ 3162 public interface WiredAccessoryCallbacks { notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask)3163 public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask); systemReady()3164 public void systemReady(); 3165 } 3166 3167 /** 3168 * Private handler for the input manager. 3169 */ 3170 private final class InputManagerHandler extends Handler { InputManagerHandler(Looper looper)3171 public InputManagerHandler(Looper looper) { 3172 super(looper, null, true /*async*/); 3173 } 3174 3175 @Override handleMessage(Message msg)3176 public void handleMessage(Message msg) { 3177 switch (msg.what) { 3178 case MSG_DELIVER_INPUT_DEVICES_CHANGED: 3179 deliverInputDevicesChanged((InputDevice[])msg.obj); 3180 break; 3181 case MSG_SWITCH_KEYBOARD_LAYOUT: 3182 handleSwitchKeyboardLayout(msg.arg1, msg.arg2); 3183 break; 3184 case MSG_RELOAD_KEYBOARD_LAYOUTS: 3185 reloadKeyboardLayouts(); 3186 break; 3187 case MSG_UPDATE_KEYBOARD_LAYOUTS: 3188 updateKeyboardLayouts(); 3189 break; 3190 case MSG_RELOAD_DEVICE_ALIASES: 3191 reloadDeviceAliases(); 3192 break; 3193 case MSG_DELIVER_TABLET_MODE_CHANGED: 3194 SomeArgs args = (SomeArgs) msg.obj; 3195 long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32); 3196 boolean inTabletMode = (boolean) args.arg1; 3197 deliverTabletModeChanged(whenNanos, inTabletMode); 3198 break; 3199 } 3200 } 3201 } 3202 3203 /** 3204 * Hosting interface for input filters to call back into the input manager. 3205 */ 3206 private final class InputFilterHost extends IInputFilterHost.Stub { 3207 private boolean mDisconnected; 3208 disconnectLocked()3209 public void disconnectLocked() { 3210 mDisconnected = true; 3211 } 3212 3213 @Override sendInputEvent(InputEvent event, int policyFlags)3214 public void sendInputEvent(InputEvent event, int policyFlags) { 3215 if (event == null) { 3216 throw new IllegalArgumentException("event must not be null"); 3217 } 3218 3219 synchronized (mInputFilterLock) { 3220 if (!mDisconnected) { 3221 nativeInjectInputEvent(mPtr, event, 0, 0, 3222 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0, 3223 policyFlags | WindowManagerPolicy.FLAG_FILTERED); 3224 } 3225 } 3226 } 3227 } 3228 3229 /** 3230 * Interface for the system to handle request from InputMonitors. 3231 */ 3232 private final class InputMonitorHost extends IInputMonitorHost.Stub { 3233 private IBinder mToken; 3234 InputMonitorHost(IBinder token)3235 InputMonitorHost(IBinder token) { 3236 mToken = token; 3237 } 3238 3239 @Override pilferPointers()3240 public void pilferPointers() { 3241 if (mToken == null) { 3242 throw new IllegalStateException( 3243 "Illegal call to pilferPointers after InputMonitorHost is disposed."); 3244 } 3245 nativePilferPointers(mPtr, mToken); 3246 } 3247 3248 @Override dispose()3249 public void dispose() { 3250 // We do not remove the input monitor here by calling nativeRemoveInputChannel because 3251 // it causes a race in InputDispatcher between the removal of the InputChannel through 3252 // that call and the InputChannel#dispose call (which causes an FD hangup) from the 3253 // client (b/189135695). 3254 // 3255 // NOTE: This means the client is responsible for properly closing the InputMonitor by 3256 // disposing the InputChannel and all its duplicates. 3257 mToken = null; 3258 } 3259 } 3260 3261 private static final class KeyboardLayoutDescriptor { 3262 public String packageName; 3263 public String receiverName; 3264 public String keyboardLayoutName; 3265 format(String packageName, String receiverName, String keyboardName)3266 public static String format(String packageName, 3267 String receiverName, String keyboardName) { 3268 return packageName + "/" + receiverName + "/" + keyboardName; 3269 } 3270 parse(String descriptor)3271 public static KeyboardLayoutDescriptor parse(String descriptor) { 3272 int pos = descriptor.indexOf('/'); 3273 if (pos < 0 || pos + 1 == descriptor.length()) { 3274 return null; 3275 } 3276 int pos2 = descriptor.indexOf('/', pos + 1); 3277 if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) { 3278 return null; 3279 } 3280 3281 KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor(); 3282 result.packageName = descriptor.substring(0, pos); 3283 result.receiverName = descriptor.substring(pos + 1, pos2); 3284 result.keyboardLayoutName = descriptor.substring(pos2 + 1); 3285 return result; 3286 } 3287 } 3288 3289 private interface KeyboardLayoutVisitor { visitKeyboardLayout(Resources resources, int keyboardLayoutResId, KeyboardLayout layout)3290 void visitKeyboardLayout(Resources resources, 3291 int keyboardLayoutResId, KeyboardLayout layout); 3292 } 3293 3294 private final class InputDevicesChangedListenerRecord implements DeathRecipient { 3295 private final int mPid; 3296 private final IInputDevicesChangedListener mListener; 3297 InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener)3298 public InputDevicesChangedListenerRecord(int pid, IInputDevicesChangedListener listener) { 3299 mPid = pid; 3300 mListener = listener; 3301 } 3302 3303 @Override binderDied()3304 public void binderDied() { 3305 if (DEBUG) { 3306 Slog.d(TAG, "Input devices changed listener for pid " + mPid + " died."); 3307 } 3308 onInputDevicesChangedListenerDied(mPid); 3309 } 3310 notifyInputDevicesChanged(int[] info)3311 public void notifyInputDevicesChanged(int[] info) { 3312 try { 3313 mListener.onInputDevicesChanged(info); 3314 } catch (RemoteException ex) { 3315 Slog.w(TAG, "Failed to notify process " 3316 + mPid + " that input devices changed, assuming it died.", ex); 3317 binderDied(); 3318 } 3319 } 3320 } 3321 3322 private final class TabletModeChangedListenerRecord implements DeathRecipient { 3323 private final int mPid; 3324 private final ITabletModeChangedListener mListener; 3325 TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener)3326 public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) { 3327 mPid = pid; 3328 mListener = listener; 3329 } 3330 3331 @Override binderDied()3332 public void binderDied() { 3333 if (DEBUG) { 3334 Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died."); 3335 } 3336 onTabletModeChangedListenerDied(mPid); 3337 } 3338 notifyTabletModeChanged(long whenNanos, boolean inTabletMode)3339 public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) { 3340 try { 3341 mListener.onTabletModeChanged(whenNanos, inTabletMode); 3342 } catch (RemoteException ex) { 3343 Slog.w(TAG, "Failed to notify process " + mPid + 3344 " that tablet mode changed, assuming it died.", ex); 3345 binderDied(); 3346 } 3347 } 3348 } 3349 onSensorEventListenerDied(int pid)3350 private void onSensorEventListenerDied(int pid) { 3351 synchronized (mSensorEventLock) { 3352 mSensorEventListeners.remove(pid); 3353 } 3354 } 3355 3356 private final class SensorEventListenerRecord implements DeathRecipient { 3357 private final int mPid; 3358 private final IInputSensorEventListener mListener; 3359 SensorEventListenerRecord(int pid, IInputSensorEventListener listener)3360 SensorEventListenerRecord(int pid, IInputSensorEventListener listener) { 3361 mPid = pid; 3362 mListener = listener; 3363 } 3364 3365 @Override binderDied()3366 public void binderDied() { 3367 if (DEBUG) { 3368 Slog.d(TAG, "Sensor event listener for pid " + mPid + " died."); 3369 } 3370 onSensorEventListenerDied(mPid); 3371 } 3372 getListener()3373 public IInputSensorEventListener getListener() { 3374 return mListener; 3375 } 3376 notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, float[] values)3377 public void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp, 3378 float[] values) { 3379 try { 3380 mListener.onInputSensorChanged(deviceId, sensorType, accuracy, timestamp, 3381 values); 3382 } catch (RemoteException ex) { 3383 Slog.w(TAG, "Failed to notify process " + mPid 3384 + " that sensor event notified, assuming it died.", ex); 3385 binderDied(); 3386 } 3387 } 3388 notifySensorAccuracy(int deviceId, int sensorType, int accuracy)3389 public void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) { 3390 try { 3391 mListener.onInputSensorAccuracyChanged(deviceId, sensorType, accuracy); 3392 } catch (RemoteException ex) { 3393 Slog.w(TAG, "Failed to notify process " + mPid 3394 + " that sensor accuracy notified, assuming it died.", ex); 3395 binderDied(); 3396 } 3397 } 3398 } 3399 3400 private final class VibratorToken implements DeathRecipient { 3401 public final int mDeviceId; 3402 public final IBinder mToken; 3403 public final int mTokenValue; 3404 3405 public boolean mVibrating; 3406 VibratorToken(int deviceId, IBinder token, int tokenValue)3407 public VibratorToken(int deviceId, IBinder token, int tokenValue) { 3408 mDeviceId = deviceId; 3409 mToken = token; 3410 mTokenValue = tokenValue; 3411 } 3412 3413 @Override binderDied()3414 public void binderDied() { 3415 if (DEBUG) { 3416 Slog.d(TAG, "Vibrator token died."); 3417 } 3418 onVibratorTokenDied(this); 3419 } 3420 } 3421 3422 private final class LocalService extends InputManagerInternal { 3423 @Override setDisplayViewports(List<DisplayViewport> viewports)3424 public void setDisplayViewports(List<DisplayViewport> viewports) { 3425 setDisplayViewportsInternal(viewports); 3426 } 3427 3428 @Override injectInputEvent(InputEvent event, int mode)3429 public boolean injectInputEvent(InputEvent event, int mode) { 3430 return injectInputEventInternal(event, mode); 3431 } 3432 3433 @Override setInteractive(boolean interactive)3434 public void setInteractive(boolean interactive) { 3435 nativeSetInteractive(mPtr, interactive); 3436 } 3437 3438 @Override toggleCapsLock(int deviceId)3439 public void toggleCapsLock(int deviceId) { 3440 nativeToggleCapsLock(mPtr, deviceId); 3441 } 3442 3443 @Override setPulseGestureEnabled(boolean enabled)3444 public void setPulseGestureEnabled(boolean enabled) { 3445 if (mDoubleTouchGestureEnableFile != null) { 3446 FileWriter writer = null; 3447 try { 3448 writer = new FileWriter(mDoubleTouchGestureEnableFile); 3449 writer.write(enabled ? "1" : "0"); 3450 } catch (IOException e) { 3451 Log.wtf(TAG, "Unable to setPulseGestureEnabled", e); 3452 } finally { 3453 IoUtils.closeQuietly(writer); 3454 } 3455 } 3456 } 3457 3458 @Override transferTouchFocus(@onNull IBinder fromChannelToken, @NonNull IBinder toChannelToken)3459 public boolean transferTouchFocus(@NonNull IBinder fromChannelToken, 3460 @NonNull IBinder toChannelToken) { 3461 return InputManagerService.this.transferTouchFocus(fromChannelToken, toChannelToken); 3462 } 3463 3464 @Override registerLidSwitchCallback(LidSwitchCallback callbacks)3465 public void registerLidSwitchCallback(LidSwitchCallback callbacks) { 3466 registerLidSwitchCallbackInternal(callbacks); 3467 } 3468 3469 @Override unregisterLidSwitchCallback(LidSwitchCallback callbacks)3470 public void unregisterLidSwitchCallback(LidSwitchCallback callbacks) { 3471 unregisterLidSwitchCallbackInternal(callbacks); 3472 } 3473 } 3474 3475 @Override onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)3476 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 3477 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 3478 new InputShellCommand().exec(this, in, out, err, args, callback, resultReceiver); 3479 } 3480 3481 } 3482