/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.car.input; import static android.car.CarOccupantZoneManager.DisplayTypeEnum; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.car.Car; import android.car.CarManagerBase; import android.car.CarOccupantZoneManager; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; import android.util.SparseArray; import android.view.KeyEvent; import com.android.internal.annotations.GuardedBy; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.ref.WeakReference; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; /** * This API allows capturing selected input events. * * @hide */ @SystemApi public final class CarInputManager extends CarManagerBase { private static final String TAG = CarInputManager.class.getSimpleName(); private static final boolean DEBUG = false; /** * Callback for capturing input events. *
* Events (key, rotary and custom input events) are associated with display types.
* Display types are defined in {@link android.car.CarOccupantZoneManager}. This manager only
* accepts the driver display types ({@link CarOccupantZoneManager#DISPLAY_TYPE_MAIN} and
* {@link CarOccupantZoneManager#DISPLAY_TYPE_INSTRUMENT_CLUSTER}).
*/
public interface CarInputCaptureCallback {
/**
* Key events were captured.
*
* @param targetDisplayType the display type associated with the events passed as parameter
* @param keyEvents the key events to process
*/
default void onKeyEvents(@DisplayTypeEnum int targetDisplayType,
@NonNull List The request can fail if a high priority client is holding it. The client can set
* {@link #CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT} in {@code requestFlags} to wait for the
* current high priority client to release it.
*
* If only some of the input types specified are available, the request will either:
* After {@link #INPUT_CAPTURE_RESPONSE_DELAYED} is returned, no input types are captured
* until the client receives a {@link CarInputCaptureCallback#onCaptureStateChanged(int, int[])}
* call with valid input types.
*
* The targetDisplayType parameter must only contain driver display types (which are
* {@link CarOccupantZoneManager#DISPLAY_TYPE_MAIN} and
* {@link CarOccupantZoneManager#DISPLAY_TYPE_INSTRUMENT_CLUSTER}.
*
* Callbacks are grouped and stacked per display types. Only the most recently
* registered callback will receive the incoming events for the associated display and input
* types. For instance, if two callbacks are registered against the same display type, on the
* same {@link CarInputManager} instance, then only the last registered callback will receive
* events, even if they were registered for different input event types.
*
* @throws SecurityException is caller doesn't have android.car.permission.CAR_MONITOR_INPUT
* permission granted
* @throws IllegalArgumentException if targetDisplayType parameter correspond to a non supported
* display type
* @throws IllegalArgumentException if inputTypes parameter contains invalid or non supported
* values
* @param targetDisplayType the display type to register callback for
* @param inputTypes the input type to register callback for
* @param requestFlags the capture request flag
* @param callback the callback to receive the input events
* @return the input capture response indicating if registration succeed, failed or delayed
*/
@RequiresPermission(Car.PERMISSION_CAR_MONITOR_INPUT)
@InputCaptureResponseEnum
public int requestInputEventCapture(@DisplayTypeEnum int targetDisplayType,
@NonNull @InputTypeEnum int[] inputTypes,
@CaptureRequestFlags int requestFlags,
@NonNull CarInputCaptureCallback callback) {
Handler handler = getEventHandler();
return requestInputEventCapture(targetDisplayType, inputTypes, requestFlags, handler::post,
callback);
}
/**
* Works just like {@link CarInputManager#requestInputEventCapture(int, int[], int,
* CarInputCaptureCallback)} except that callbacks are invoked using
* the executor passed as parameter.
*
* @param targetDisplayType the display type to register callback against
* @param inputTypes the input type to register callback against
* @param requestFlags the capture request flag
* @param executor {@link Executor} to handle the callbacks
* @param callback the callback to receive the input events
* @return the input capture response indicating if registration succeed, failed or delayed
* @see CarInputManager#requestInputEventCapture(int, int[], int, CarInputCaptureCallback)
*/
@RequiresPermission(android.Manifest.permission.MONITOR_INPUT)
@InputCaptureResponseEnum
public int requestInputEventCapture(@DisplayTypeEnum int targetDisplayType,
@NonNull @InputTypeEnum int[] inputTypes,
@CaptureRequestFlags int requestFlags,
@NonNull @CallbackExecutor Executor executor,
@NonNull CarInputCaptureCallback callback) {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
synchronized (mLock) {
mCarInputCaptureCallbacks.put(targetDisplayType,
new CallbackHolder(callback, executor));
}
try {
return mService.requestInputEventCapture(mServiceCallback, targetDisplayType,
inputTypes, requestFlags);
} catch (RemoteException e) {
return handleRemoteExceptionFromCarService(e, INPUT_CAPTURE_RESPONSE_FAILED);
}
}
/**
* Stops capturing of given display.
*/
public void releaseInputEventCapture(@DisplayTypeEnum int targetDisplayType) {
CallbackHolder callbackHolder;
synchronized (mLock) {
callbackHolder = mCarInputCaptureCallbacks.removeReturnOld(targetDisplayType);
}
if (callbackHolder == null) {
return;
}
try {
mService.releaseInputEventCapture(mServiceCallback, targetDisplayType);
} catch (RemoteException e) {
// ignore
}
}
/**
* Injects the {@link KeyEvent} passed as parameter against Car Input API.
*
* The event parameter display id will be overridden accordingly to the display type also passed
* as parameter.
*
* @param event the key event to inject
* @param targetDisplayType the display type associated with the key event
* @throws RemoteException in case of failure when invoking car input service
*/
@RequiresPermission(android.Manifest.permission.INJECT_EVENTS)
public void injectKeyEvent(@NonNull KeyEvent event, @DisplayTypeEnum int targetDisplayType) {
try {
mService.injectKeyEvent(event, targetDisplayType);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
/** @hide */
@Override
protected void onCarDisconnected() {
synchronized (mLock) {
mCarInputCaptureCallbacks.clear();
}
}
private CallbackHolder getCallback(@DisplayTypeEnum int targetDisplayType) {
synchronized (mLock) {
return mCarInputCaptureCallbacks.get(targetDisplayType);
}
}
private void dispatchKeyEvents(@DisplayTypeEnum int targetDisplayType,
List
*
*
*