1 /* 2 * Copyright (C) 2020 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 android.car.input; 18 19 import static android.car.CarOccupantZoneManager.DisplayTypeEnum; 20 21 import android.annotation.CallbackExecutor; 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.RequiresPermission; 25 import android.annotation.SystemApi; 26 import android.car.Car; 27 import android.car.CarManagerBase; 28 import android.car.CarOccupantZoneManager; 29 import android.car.annotation.AddedInOrBefore; 30 import android.car.builtin.util.Slogf; 31 import android.os.Handler; 32 import android.os.IBinder; 33 import android.os.RemoteException; 34 import android.util.SparseArray; 35 import android.view.KeyEvent; 36 37 import com.android.internal.annotations.GuardedBy; 38 39 import java.lang.annotation.ElementType; 40 import java.lang.annotation.Retention; 41 import java.lang.annotation.RetentionPolicy; 42 import java.lang.annotation.Target; 43 import java.lang.ref.WeakReference; 44 import java.util.List; 45 import java.util.Objects; 46 import java.util.concurrent.Executor; 47 48 /** 49 * This API allows capturing selected input events. 50 * 51 * @hide 52 */ 53 @SystemApi 54 public final class CarInputManager extends CarManagerBase { 55 56 private static final String TAG = CarInputManager.class.getSimpleName(); 57 58 private static final boolean DEBUG = false; 59 60 private static final String PERMISSION_FRAMEWORK_MONITOR_INPUT = 61 "android.permission.MONITOR_INPUT"; 62 63 /** 64 * Callback for capturing input events. 65 * <p> 66 * Events (key, rotary and custom input events) are associated with display types. 67 * Display types are defined in {@link android.car.CarOccupantZoneManager}. This manager only 68 * accepts the driver display types ({@link CarOccupantZoneManager#DISPLAY_TYPE_MAIN} and 69 * {@link CarOccupantZoneManager#DISPLAY_TYPE_INSTRUMENT_CLUSTER}). 70 */ 71 public interface CarInputCaptureCallback { 72 /** 73 * Key events were captured. 74 * 75 * @param targetDisplayType the display type associated with the events passed as parameter 76 * @param keyEvents the key events to process 77 */ 78 @AddedInOrBefore(majorVersion = 33) onKeyEvents(@isplayTypeEnum int targetDisplayType, @NonNull List<KeyEvent> keyEvents)79 default void onKeyEvents(@DisplayTypeEnum int targetDisplayType, 80 @NonNull List<KeyEvent> keyEvents) {} 81 82 /** 83 * Rotary events were captured. 84 * 85 * @param targetDisplayType the display type associated with the events passed as parameter 86 * @param events the rotary events to process 87 */ 88 @AddedInOrBefore(majorVersion = 33) onRotaryEvents(@isplayTypeEnum int targetDisplayType, @NonNull List<RotaryEvent> events)89 default void onRotaryEvents(@DisplayTypeEnum int targetDisplayType, 90 @NonNull List<RotaryEvent> events) {} 91 92 /** 93 * Capture state for the display has changed due to other client making requests or 94 * releasing capture. Client should check {@code activeInputTypes} for which input types 95 * are currently captured. 96 * 97 * @param targetDisplayType the display type associated with the events passed as parameter 98 * @param activeInputTypes the input types to watch 99 */ 100 @AddedInOrBefore(majorVersion = 33) onCaptureStateChanged(@isplayTypeEnum int targetDisplayType, @NonNull @InputTypeEnum int[] activeInputTypes)101 default void onCaptureStateChanged(@DisplayTypeEnum int targetDisplayType, 102 @NonNull @InputTypeEnum int[] activeInputTypes) {} 103 104 /** 105 * Custom input events were captured. 106 * 107 * @param targetDisplayType the display type associated with the events passed as parameter 108 * @param events the custom input events to process 109 */ 110 @AddedInOrBefore(majorVersion = 33) onCustomInputEvents(@isplayTypeEnum int targetDisplayType, @NonNull List<CustomInputEvent> events)111 default void onCustomInputEvents(@DisplayTypeEnum int targetDisplayType, 112 @NonNull List<CustomInputEvent> events) {} 113 } 114 115 /** 116 * Client will wait for grant if the request is failing due to higher priority client. 117 */ 118 @AddedInOrBefore(majorVersion = 33) 119 public static final int CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT = 0x1; 120 121 /** 122 * Client wants to capture the keys for the whole display. This is only allowed to system 123 * process. 124 */ 125 @AddedInOrBefore(majorVersion = 33) 126 public static final int CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY = 0x2; 127 128 /** @hide */ 129 @IntDef(flag = true, prefix = {"CAPTURE_REQ_FLAGS_"}, value = { 130 CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT, 131 CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, 132 }) 133 @Retention(RetentionPolicy.SOURCE) 134 public @interface CaptureRequestFlags {} 135 136 /** 137 * This is special type to cover all INPUT_TYPE_*. This is used for clients using 138 * {@link #CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY} flag. 139 */ 140 @AddedInOrBefore(majorVersion = 33) 141 public static final int INPUT_TYPE_ALL_INPUTS = 1; 142 143 /** 144 * This covers rotary input device for navigation. 145 */ 146 @AddedInOrBefore(majorVersion = 33) 147 public static final int INPUT_TYPE_ROTARY_NAVIGATION = 10; 148 149 /** 150 * Volume knob. 151 */ 152 @AddedInOrBefore(majorVersion = 33) 153 public static final int INPUT_TYPE_ROTARY_VOLUME = 11; 154 155 /** 156 * This is the group of keys for DPAD. 157 * Included key events are: {@link KeyEvent#KEYCODE_DPAD_UP}, 158 * {@link KeyEvent#KEYCODE_DPAD_DOWN}, {@link KeyEvent#KEYCODE_DPAD_LEFT}, 159 * {@link KeyEvent#KEYCODE_DPAD_RIGHT}, {@link KeyEvent#KEYCODE_DPAD_CENTER}, 160 * {@link KeyEvent#KEYCODE_DPAD_DOWN_LEFT}, {@link KeyEvent#KEYCODE_DPAD_DOWN_RIGHT}, 161 * {@link KeyEvent#KEYCODE_DPAD_UP_LEFT}, {@link KeyEvent#KEYCODE_DPAD_UP_RIGHT} 162 */ 163 @AddedInOrBefore(majorVersion = 33) 164 public static final int INPUT_TYPE_DPAD_KEYS = 100; 165 166 /** 167 * This is for all {@code KeyEvent#KEYCODE_NAVIGATE_*} keys and {@link KeyEvent#KEYCODE_BACK}. 168 */ 169 @AddedInOrBefore(majorVersion = 33) 170 public static final int INPUT_TYPE_NAVIGATE_KEYS = 101; 171 172 /** 173 * This is for all {@code KeyEvent#KEYCODE_SYSTEM_NAVIGATE_*} keys. 174 */ 175 @AddedInOrBefore(majorVersion = 33) 176 public static final int INPUT_TYPE_SYSTEM_NAVIGATE_KEYS = 102; 177 178 /** 179 * This is for {@code HW_CUSTOM_INPUT} events. 180 */ 181 @AddedInOrBefore(majorVersion = 33) 182 public static final int INPUT_TYPE_CUSTOM_INPUT_EVENT = 200; 183 184 /** @hide */ 185 @Retention(RetentionPolicy.SOURCE) 186 @IntDef(prefix = "INPUT_TYPE_", value = { 187 INPUT_TYPE_ALL_INPUTS, 188 INPUT_TYPE_ROTARY_NAVIGATION, 189 INPUT_TYPE_ROTARY_VOLUME, 190 INPUT_TYPE_DPAD_KEYS, 191 INPUT_TYPE_NAVIGATE_KEYS, 192 INPUT_TYPE_SYSTEM_NAVIGATE_KEYS, 193 INPUT_TYPE_CUSTOM_INPUT_EVENT, 194 }) 195 @Target({ElementType.TYPE_USE}) 196 public @interface InputTypeEnum {} 197 198 /** 199 * The client's request has succeeded and capture will start. 200 */ 201 @AddedInOrBefore(majorVersion = 33) 202 public static final int INPUT_CAPTURE_RESPONSE_SUCCEEDED = 0; 203 204 /** 205 * The client's request has failed due to higher priority client already capturing. If priority 206 * for the clients are the same, last client making request will be allowed to capture. 207 */ 208 @AddedInOrBefore(majorVersion = 33) 209 public static final int INPUT_CAPTURE_RESPONSE_FAILED = 1; 210 211 /** 212 * This is used when client has set {@link #CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT} in 213 * {@code requestFlags} and capturing is blocked due to existing higher priority client. 214 * When the higher priority client stops capturing, this client can capture events after 215 * getting @link CarInputCaptureCallback#onCaptureStateChanged(int, int[])} call. 216 */ 217 @AddedInOrBefore(majorVersion = 33) 218 public static final int INPUT_CAPTURE_RESPONSE_DELAYED = 2; 219 220 /** @hide */ 221 @Retention(RetentionPolicy.SOURCE) 222 @IntDef(prefix = "INPUT_CAPTURE_RESPONSE_", value = { 223 INPUT_CAPTURE_RESPONSE_SUCCEEDED, 224 INPUT_CAPTURE_RESPONSE_FAILED, 225 INPUT_CAPTURE_RESPONSE_DELAYED 226 }) 227 @Target({ElementType.TYPE_USE}) 228 public @interface InputCaptureResponseEnum {} 229 230 private final ICarInput mService; 231 private final ICarInputCallback mServiceCallback = new ICarInputCallbackImpl(this); 232 233 private final Object mLock = new Object(); 234 235 @GuardedBy("mLock") 236 private final SparseArray<CallbackHolder> mCarInputCaptureCallbacks = new SparseArray<>(1); 237 238 /** 239 * @hide 240 */ CarInputManager(Car car, IBinder service)241 public CarInputManager(Car car, IBinder service) { 242 super(car); 243 mService = ICarInput.Stub.asInterface(service); 244 } 245 246 /** 247 * Requests capturing of input event for the specified display for all requested input types. 248 * 249 * <p>The request can fail if a high priority client is holding it. The client can set 250 * {@link #CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT} in {@code requestFlags} to wait for the 251 * current high priority client to release it. 252 * 253 * <p>If only some of the input types specified are available, the request will either: 254 * <ul> 255 * <li>fail, returning {@link #INPUT_CAPTURE_RESPONSE_FAILED}, or 256 * <li>be deferred, returning {@link #INPUT_CAPTURE_RESPONSE_DELAYED}, if the 257 * {@link #CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT} flag is used. 258 * </ul> 259 * 260 * <p> After {@link #INPUT_CAPTURE_RESPONSE_DELAYED} is returned, no input types are captured 261 * until the client receives a {@link CarInputCaptureCallback#onCaptureStateChanged(int, int[])} 262 * call with valid input types. 263 * 264 * <p> The targetDisplayType parameter must only contain driver display types (which are 265 * {@link CarOccupantZoneManager#DISPLAY_TYPE_MAIN} and 266 * {@link CarOccupantZoneManager#DISPLAY_TYPE_INSTRUMENT_CLUSTER}. 267 * 268 * <p>Callbacks are grouped and stacked per display types. Only the most recently 269 * registered callback will receive the incoming events for the associated display and input 270 * types. For instance, if two callbacks are registered against the same display type, on the 271 * same {@link CarInputManager} instance, then only the last registered callback will receive 272 * events, even if they were registered for different input event types. 273 * 274 * @throws SecurityException if caller doesn't have one of the following permissions granted: 275 * {@code android.car.permission.CAR_MONITOR_INPUT} nor 276 * {@code android.Manifest.permission.MONITOR_INPUT} 277 * @throws IllegalArgumentException if targetDisplayType parameter correspond to a non supported 278 * display type 279 * @throws IllegalArgumentException if inputTypes parameter contains invalid or non supported 280 * values 281 * @param targetDisplayType the display type to register callback for 282 * @param inputTypes the input type to register callback for 283 * @param requestFlags the capture request flag 284 * @param callback the callback to receive the input events 285 * @return the input capture response indicating if registration succeed, failed or delayed 286 */ 287 @RequiresPermission(anyOf = {PERMISSION_FRAMEWORK_MONITOR_INPUT, 288 Car.PERMISSION_CAR_MONITOR_INPUT}) 289 @InputCaptureResponseEnum 290 @AddedInOrBefore(majorVersion = 33) requestInputEventCapture(@isplayTypeEnum int targetDisplayType, @NonNull @InputTypeEnum int[] inputTypes, @CaptureRequestFlags int requestFlags, @NonNull CarInputCaptureCallback callback)291 public int requestInputEventCapture(@DisplayTypeEnum int targetDisplayType, 292 @NonNull @InputTypeEnum int[] inputTypes, 293 @CaptureRequestFlags int requestFlags, 294 @NonNull CarInputCaptureCallback callback) { 295 Handler handler = getEventHandler(); 296 return requestInputEventCapture(targetDisplayType, inputTypes, requestFlags, handler::post, 297 callback); 298 } 299 300 /** 301 * Works just like {@link CarInputManager#requestInputEventCapture(int, int[], int, 302 * CarInputCaptureCallback)} except that callbacks are invoked using 303 * the executor passed as parameter. 304 * 305 * @throws SecurityException if caller doesn't have one of the following permissions granted: 306 * {@code android.car.permission.CAR_MONITOR_INPUT} nor 307 * {@code android.Manifest.permission.MONITOR_INPUT} 308 * @param targetDisplayType the display type to register callback against 309 * @param inputTypes the input type to register callback against 310 * @param requestFlags the capture request flag 311 * @param executor {@link Executor} to handle the callbacks 312 * @param callback the callback to receive the input events 313 * @return the input capture response indicating if registration succeed, failed or delayed 314 * @see CarInputManager#requestInputEventCapture(int, int[], int, CarInputCaptureCallback) 315 */ 316 @RequiresPermission(anyOf = {PERMISSION_FRAMEWORK_MONITOR_INPUT, 317 Car.PERMISSION_CAR_MONITOR_INPUT}) 318 @InputCaptureResponseEnum 319 @AddedInOrBefore(majorVersion = 33) requestInputEventCapture(@isplayTypeEnum int targetDisplayType, @NonNull @InputTypeEnum int[] inputTypes, @CaptureRequestFlags int requestFlags, @NonNull @CallbackExecutor Executor executor, @NonNull CarInputCaptureCallback callback)320 public int requestInputEventCapture(@DisplayTypeEnum int targetDisplayType, 321 @NonNull @InputTypeEnum int[] inputTypes, 322 @CaptureRequestFlags int requestFlags, 323 @NonNull @CallbackExecutor Executor executor, 324 @NonNull CarInputCaptureCallback callback) { 325 Objects.requireNonNull(executor); 326 Objects.requireNonNull(callback); 327 328 synchronized (mLock) { 329 mCarInputCaptureCallbacks.put(targetDisplayType, 330 new CallbackHolder(callback, executor)); 331 } 332 try { 333 return mService.requestInputEventCapture(mServiceCallback, targetDisplayType, 334 inputTypes, requestFlags); 335 } catch (RemoteException e) { 336 return handleRemoteExceptionFromCarService(e, INPUT_CAPTURE_RESPONSE_FAILED); 337 } 338 } 339 340 /** 341 * Stops capturing of given display. 342 */ 343 @AddedInOrBefore(majorVersion = 33) releaseInputEventCapture(@isplayTypeEnum int targetDisplayType)344 public void releaseInputEventCapture(@DisplayTypeEnum int targetDisplayType) { 345 CallbackHolder callbackHolder; 346 synchronized (mLock) { 347 callbackHolder = mCarInputCaptureCallbacks.get(targetDisplayType); 348 mCarInputCaptureCallbacks.delete(targetDisplayType); 349 } 350 if (callbackHolder == null) { 351 return; 352 } 353 try { 354 mService.releaseInputEventCapture(mServiceCallback, targetDisplayType); 355 } catch (RemoteException e) { 356 // ignore 357 } 358 } 359 360 /** 361 * Injects the {@link KeyEvent} passed as parameter against Car Input API. 362 * <p> 363 * The event parameter display id will be overridden accordingly to the display type also passed 364 * as parameter. 365 * 366 * @param event the key event to inject 367 * @param targetDisplayType the display type associated with the key event 368 * @throws RemoteException in case of failure when invoking car input service 369 */ 370 @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) 371 @AddedInOrBefore(majorVersion = 33) injectKeyEvent(@onNull KeyEvent event, @DisplayTypeEnum int targetDisplayType)372 public void injectKeyEvent(@NonNull KeyEvent event, @DisplayTypeEnum int targetDisplayType) { 373 try { 374 mService.injectKeyEvent(event, targetDisplayType); 375 } catch (RemoteException e) { 376 e.rethrowFromSystemServer(); 377 } 378 } 379 380 /** @hide */ 381 @Override 382 @AddedInOrBefore(majorVersion = 33) onCarDisconnected()383 protected void onCarDisconnected() { 384 synchronized (mLock) { 385 mCarInputCaptureCallbacks.clear(); 386 } 387 } 388 getCallback(@isplayTypeEnum int targetDisplayType)389 private CallbackHolder getCallback(@DisplayTypeEnum int targetDisplayType) { 390 synchronized (mLock) { 391 return mCarInputCaptureCallbacks.get(targetDisplayType); 392 } 393 } 394 dispatchKeyEvents(@isplayTypeEnum int targetDisplayType, List<KeyEvent> keyEvents)395 private void dispatchKeyEvents(@DisplayTypeEnum int targetDisplayType, 396 List<KeyEvent> keyEvents) { 397 CallbackHolder callbackHolder = getCallback(targetDisplayType); 398 if (callbackHolder == null) { 399 return; 400 } 401 callbackHolder.mExecutor.execute(() -> { 402 callbackHolder.mCallback.onKeyEvents(targetDisplayType, keyEvents); 403 }); 404 } 405 dispatchRotaryEvents(@isplayTypeEnum int targetDisplayType, List<RotaryEvent> events)406 private void dispatchRotaryEvents(@DisplayTypeEnum int targetDisplayType, 407 List<RotaryEvent> events) { 408 CallbackHolder callbackHolder = getCallback(targetDisplayType); 409 if (callbackHolder == null) { 410 return; 411 } 412 callbackHolder.mExecutor.execute(() -> { 413 callbackHolder.mCallback.onRotaryEvents(targetDisplayType, events); 414 }); 415 } 416 dispatchOnCaptureStateChanged(@isplayTypeEnum int targetDisplayType, int[] activeInputTypes)417 private void dispatchOnCaptureStateChanged(@DisplayTypeEnum int targetDisplayType, 418 int[] activeInputTypes) { 419 CallbackHolder callbackHolder = getCallback(targetDisplayType); 420 if (callbackHolder == null) { 421 return; 422 } 423 callbackHolder.mExecutor.execute(() -> { 424 callbackHolder.mCallback.onCaptureStateChanged(targetDisplayType, activeInputTypes); 425 }); 426 } 427 dispatchCustomInputEvents(@isplayTypeEnum int targetDisplayType, List<CustomInputEvent> events)428 private void dispatchCustomInputEvents(@DisplayTypeEnum int targetDisplayType, 429 List<CustomInputEvent> events) { 430 CallbackHolder callbackHolder = getCallback(targetDisplayType); 431 if (callbackHolder == null) { 432 return; 433 } 434 callbackHolder.mExecutor.execute(() -> { 435 if (DEBUG) { 436 Slogf.d(TAG, "Firing events " + events + " on callback " 437 + callbackHolder.mCallback); 438 } 439 callbackHolder.mCallback.onCustomInputEvents(targetDisplayType, events); 440 }); 441 } 442 443 private static final class ICarInputCallbackImpl extends ICarInputCallback.Stub { 444 445 private final WeakReference<CarInputManager> mManager; 446 ICarInputCallbackImpl(CarInputManager manager)447 private ICarInputCallbackImpl(CarInputManager manager) { 448 mManager = new WeakReference<>(manager); 449 } 450 451 @Override onKeyEvents(@isplayTypeEnum int targetDisplayType, @NonNull List<KeyEvent> keyEvents)452 public void onKeyEvents(@DisplayTypeEnum int targetDisplayType, 453 @NonNull List<KeyEvent> keyEvents) { 454 CarInputManager manager = mManager.get(); 455 if (manager == null) { 456 return; 457 } 458 manager.dispatchKeyEvents(targetDisplayType, keyEvents); 459 } 460 461 @Override onRotaryEvents(@isplayTypeEnum int targetDisplayType, @NonNull List<RotaryEvent> events)462 public void onRotaryEvents(@DisplayTypeEnum int targetDisplayType, 463 @NonNull List<RotaryEvent> events) { 464 CarInputManager manager = mManager.get(); 465 if (manager == null) { 466 return; 467 } 468 manager.dispatchRotaryEvents(targetDisplayType, events); 469 } 470 471 @Override onCaptureStateChanged(@isplayTypeEnum int targetDisplayType, @NonNull @InputTypeEnum int[] activeInputTypes)472 public void onCaptureStateChanged(@DisplayTypeEnum int targetDisplayType, 473 @NonNull @InputTypeEnum int[] activeInputTypes) { 474 CarInputManager manager = mManager.get(); 475 if (manager == null) { 476 return; 477 } 478 manager.dispatchOnCaptureStateChanged(targetDisplayType, activeInputTypes); 479 } 480 481 @Override onCustomInputEvents(@isplayTypeEnum int targetDisplayType, @NonNull List<CustomInputEvent> events)482 public void onCustomInputEvents(@DisplayTypeEnum int targetDisplayType, 483 @NonNull List<CustomInputEvent> events) { 484 CarInputManager manager = mManager.get(); 485 if (manager == null) { 486 return; 487 } 488 manager.dispatchCustomInputEvents(targetDisplayType, events); 489 } 490 } 491 492 /** 493 * Class used to bind {@link CarInputCaptureCallback} and their associated {@link Executor}. 494 */ 495 private static final class CallbackHolder { 496 497 final CarInputCaptureCallback mCallback; 498 499 final Executor mExecutor; 500 CallbackHolder(CarInputCaptureCallback callback, Executor executor)501 CallbackHolder(CarInputCaptureCallback callback, Executor executor) { 502 mCallback = callback; 503 mExecutor = executor; 504 } 505 } 506 } 507