/* * 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.occupantawareness; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.car.Car; import android.car.CarManagerBase; import android.car.annotation.RequiredFeature; import android.car.occupantawareness.OccupantAwarenessDetection.VehicleOccupantRole; import android.car.occupantawareness.SystemStatusEvent.DetectionTypeFlags; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import java.lang.ref.WeakReference; /** * API exposing Occupant Awareness System data. * *
Supported detections include: presence detection, {@link GazeDetection} and {@link * DriverMonitoringDetection}. * * @hide */ @RequiredFeature(Car.OCCUPANT_AWARENESS_SERVICE) public class OccupantAwarenessManager extends CarManagerBase { private static final String TAG = "OAS.Manager"; private static final boolean DBG = false; private static final int MSG_HANDLE_SYSTEM_STATUS_CHANGE = 0; private static final int MSG_HANDLE_DETECTION_EVENT = 1; private final android.car.occupantawareness.IOccupantAwarenessManager mOccupantAwarenessService; private final Object mLock = new Object(); @GuardedBy("mLock") private ChangeCallback mChangeCallback; private final EventCallbackHandler mEventCallbackHandler; @GuardedBy("mLock") private ChangeListenerToService mListenerToService; /** @hide */ public OccupantAwarenessManager(Car car, IBinder service) { super(car); mOccupantAwarenessService = android.car.occupantawareness.IOccupantAwarenessManager.Stub.asInterface(service); mEventCallbackHandler = new EventCallbackHandler(this, getEventHandler().getLooper()); } /** @hide */ @Override public void onCarDisconnected() { synchronized (mLock) { mChangeCallback = null; mListenerToService = null; } } /** * Gets the detection capabilities for a given {@link VehicleOccupantRole} in this vehicle. * *
There may be different detection capabilities for different {@link VehicleOccupantRole}. * Each role should be queried independently. * *
Capabilities are static for a given vehicle configuration and need only be queried once * per vehicle. Once capability is determined, clients should query system status via {@link * SystemStatusEvent} to see if the subsystem is currently online and ready to serve. * * @param role {@link VehicleOccupantRole} to query for. * @return {@link SystemStatusEvent.DetectionTypeFlags} indicating supported capabilities for * the role. */ @RequiresPermission(value = Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE) public @DetectionTypeFlags int getCapabilityForRole(@VehicleOccupantRole int role) { try { return mOccupantAwarenessService.getCapabilityForRole(role); } catch (RemoteException e) { return handleRemoteExceptionFromCarService(e, 0); } } /** * Callbacks for listening to changes to {@link SystemStatusEvent} and {@link * OccupantAwarenessDetection}. */ public abstract static class ChangeCallback { /** * Called when the system state changes changes. * * @param systemStatus The new system state as a {@link SystemStatusEvent}. */ public abstract void onSystemStateChanged(@NonNull SystemStatusEvent systemStatus); /** * Called when a detection event is generated. * * @param event The new detection state as a {@link OccupantAwarenessDetection}. */ public abstract void onDetectionEvent(@NonNull OccupantAwarenessDetection event); } /** * Registers a {@link ChangeCallback} for listening for events. * *
If a listener has already been registered, it has to be unregistered before registering
* the new one.
*
* @param callback {@link ChangeCallback} to register.
* @throws IllegalStateException if an existing callback is already registered.
*/
@RequiresPermission(value = Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE)
public void registerChangeCallback(@NonNull ChangeCallback callback) {
if (DBG) {
Slog.d(TAG, "Registering change listener");
}
synchronized (mLock) {
// Check if the listener has been already registered.
if (mChangeCallback != null) {
throw new IllegalStateException(
"Attempting to register a new listener when an existing listener has"
+ " already been registered.");
}
mChangeCallback = callback;
try {
if (mListenerToService == null) {
mListenerToService = new ChangeListenerToService(this);
}
mOccupantAwarenessService.registerEventListener(mListenerToService);
} catch (RemoteException e) {
handleRemoteExceptionFromCarService(e);
}
}
}
/** Unregisters a previously registered {@link ChangeCallback}. */
@RequiresPermission(value = Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE)
public void unregisterChangeCallback() {
if (DBG) {
Slog.d(TAG, "Unregistering change listener");
}
synchronized (mLock) {
if (mChangeCallback == null) {
Slog.e(TAG, "No listener exists to unregister.");
return;
}
mChangeCallback = null;
}
synchronized (mLock) {
try {
mOccupantAwarenessService.unregisterEventListener(mListenerToService);
} catch (RemoteException e) {
handleRemoteExceptionFromCarService(e);
}
mListenerToService = null;
}
}
/**
* Class that implements the listener interface and gets called back from the {@link
* com.android.car.IOccupantAwarenessEventCallback} across the binder interface.
*/
private static class ChangeListenerToService extends IOccupantAwarenessEventCallback.Stub {
private final WeakReference