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