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