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