Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 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 com.android.car; |
| 18 | |
| 19 | import android.annotation.NonNull; |
| 20 | import android.car.Car; |
| 21 | import android.car.occupantawareness.IOccupantAwarenessEventCallback; |
| 22 | import android.car.occupantawareness.OccupantAwarenessDetection; |
| 23 | import android.car.occupantawareness.OccupantAwarenessDetection.VehicleOccupantRole; |
| 24 | import android.car.occupantawareness.SystemStatusEvent; |
| 25 | import android.car.occupantawareness.SystemStatusEvent.DetectionTypeFlags; |
| 26 | import android.content.Context; |
| 27 | import android.hardware.automotive.occupant_awareness.IOccupantAwareness; |
| 28 | import android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback; |
| 29 | import android.os.RemoteCallbackList; |
| 30 | import android.os.RemoteException; |
| 31 | import android.os.ServiceManager; |
Felipe Leme | 176a5fd | 2021-01-20 15:48:33 -0800 | [diff] [blame] | 32 | import android.util.IndentingPrintWriter; |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 33 | import android.util.Slog; |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 34 | |
| 35 | import com.android.internal.annotations.GuardedBy; |
| 36 | import com.android.internal.annotations.VisibleForTesting; |
| 37 | |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 38 | import java.lang.ref.WeakReference; |
| 39 | |
| 40 | /** |
| 41 | * A service that listens to an Occupant Awareness Detection system across a HAL boundary and |
| 42 | * exposes the data to system clients in Android via a {@link |
| 43 | * android.car.occupantawareness.OccupantAwarenessManager}. |
| 44 | * |
| 45 | * <p>The service exposes the following detections types: |
| 46 | * |
| 47 | * <h1>Presence Detection</h1> |
| 48 | * |
| 49 | * Detects whether a person is present for each seat location. |
| 50 | * |
| 51 | * <h1>Gaze Detection</h1> |
| 52 | * |
| 53 | * Detects where an occupant is looking and for how long they have been looking at the specified |
| 54 | * target. |
| 55 | * |
| 56 | * <h1>Driver Monitoring</h1> |
| 57 | * |
| 58 | * Detects whether a driver is looking on or off-road and for how long they have been looking there. |
| 59 | */ |
| 60 | public class OccupantAwarenessService |
| 61 | extends android.car.occupantawareness.IOccupantAwarenessManager.Stub |
| 62 | implements CarServiceBase { |
Mayank Garg | 72c71d2 | 2021-02-03 23:54:45 -0800 | [diff] [blame] | 63 | private static final String TAG = CarLog.tagFor(OccupantAwarenessService.class); |
Michael Keller | ac2ed20 | 2020-01-30 14:11:16 -0800 | [diff] [blame] | 64 | private static final boolean DBG = false; |
| 65 | |
| 66 | // HAL service identifier name. |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 67 | @VisibleForTesting |
| 68 | static final String OAS_SERVICE_ID = |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 69 | "android.hardware.automotive.occupant_awareness.IOccupantAwareness/default"; |
| 70 | |
| 71 | private final Object mLock = new Object(); |
| 72 | private final Context mContext; |
| 73 | |
| 74 | @GuardedBy("mLock") |
| 75 | private IOccupantAwareness mOasHal; |
| 76 | |
| 77 | private final ChangeListenerToHalService mHalListener = new ChangeListenerToHalService(this); |
| 78 | |
| 79 | private class ChangeCallbackList extends RemoteCallbackList<IOccupantAwarenessEventCallback> { |
| 80 | private final WeakReference<OccupantAwarenessService> mOasService; |
| 81 | |
| 82 | ChangeCallbackList(OccupantAwarenessService oasService) { |
| 83 | mOasService = new WeakReference<>(oasService); |
| 84 | } |
| 85 | |
| 86 | /** Handle callback death. */ |
| 87 | @Override |
| 88 | public void onCallbackDied(IOccupantAwarenessEventCallback listener) { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 89 | Slog.i(TAG, "binderDied: " + listener.asBinder()); |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 90 | |
| 91 | OccupantAwarenessService service = mOasService.get(); |
| 92 | if (service != null) { |
| 93 | service.handleClientDisconnected(); |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | @GuardedBy("mLock") |
| 99 | private final ChangeCallbackList mListeners = new ChangeCallbackList(this); |
| 100 | |
| 101 | /** Creates an OccupantAwarenessService instance given a {@link Context}. */ |
| 102 | public OccupantAwarenessService(Context context) { |
| 103 | mContext = context; |
| 104 | } |
| 105 | |
| 106 | /** Creates an OccupantAwarenessService instance given a {@link Context}. */ |
| 107 | @VisibleForTesting |
| 108 | OccupantAwarenessService(Context context, IOccupantAwareness oasInterface) { |
| 109 | mContext = context; |
| 110 | mOasHal = oasInterface; |
| 111 | } |
| 112 | |
| 113 | @Override |
| 114 | public void init() { |
Michael Keller | 16ac930 | 2020-02-14 10:44:51 -0800 | [diff] [blame] | 115 | logd("Initializing service"); |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 116 | connectToHalServiceIfNotConnected(); |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 117 | } |
| 118 | |
| 119 | @Override |
| 120 | public void release() { |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 121 | logd("Will stop detection and disconnect listeners"); |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 122 | stopDetectionGraph(); |
| 123 | mListeners.kill(); |
| 124 | } |
| 125 | |
| 126 | @Override |
Felipe Leme | 176a5fd | 2021-01-20 15:48:33 -0800 | [diff] [blame] | 127 | public void dump(IndentingPrintWriter writer) { |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 128 | writer.println("*OccupantAwarenessService*"); |
| 129 | writer.println( |
| 130 | String.format( |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 131 | "%s to HAL service", mOasHal == null ? "NOT connected" : "Connected")); |
| 132 | writer.println( |
| 133 | String.format( |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 134 | "%d change listeners subscribed.", |
| 135 | mListeners.getRegisteredCallbackCount())); |
| 136 | } |
| 137 | |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 138 | /** Attempts to connect to the HAL service if it is not already connected. */ |
| 139 | private void connectToHalServiceIfNotConnected() { |
| 140 | logd("connectToHalServiceIfNotConnected()"); |
| 141 | |
| 142 | synchronized (mLock) { |
| 143 | // If already connected, nothing more needs to be done. |
| 144 | if (mOasHal != null) { |
| 145 | logd("Client is already connected, nothing more to do"); |
| 146 | return; |
| 147 | } |
| 148 | |
| 149 | // Attempt to find the HAL service. |
| 150 | logd("Attempting to connect to client at: " + OAS_SERVICE_ID); |
| 151 | mOasHal = |
| 152 | android.hardware.automotive.occupant_awareness.IOccupantAwareness.Stub |
| 153 | .asInterface(ServiceManager.getService(OAS_SERVICE_ID)); |
| 154 | |
| 155 | if (mOasHal == null) { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 156 | Slog.e(TAG, "Failed to find OAS hal_service at: [" + OAS_SERVICE_ID + "]"); |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 157 | return; |
| 158 | } |
| 159 | |
| 160 | // Register for callbacks. |
| 161 | try { |
| 162 | mOasHal.setCallback(mHalListener); |
| 163 | } catch (RemoteException e) { |
| 164 | mOasHal = null; |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 165 | Slog.e(TAG, "Failed to set callback: " + e); |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 166 | return; |
| 167 | } |
| 168 | |
| 169 | logd("Successfully connected to hal_service at: [" + OAS_SERVICE_ID + "]"); |
| 170 | } |
| 171 | } |
| 172 | |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 173 | /** Sends a message via the HAL to start the detection graph. */ |
| 174 | private void startDetectionGraph() { |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 175 | logd("Attempting to start detection graph"); |
Michael Keller | ac2ed20 | 2020-01-30 14:11:16 -0800 | [diff] [blame] | 176 | |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 177 | // Grab a copy of 'mOasHal' to avoid sitting on the lock longer than is necessary. |
| 178 | IOccupantAwareness hal; |
| 179 | synchronized (mLock) { |
| 180 | hal = mOasHal; |
| 181 | } |
| 182 | |
| 183 | if (hal != null) { |
| 184 | try { |
| 185 | hal.startDetection(); |
| 186 | } catch (RemoteException e) { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 187 | Slog.e(TAG, "startDetection() HAL invocation failed: " + e, e); |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 188 | |
| 189 | synchronized (mLock) { |
| 190 | mOasHal = null; |
| 191 | } |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 192 | } |
Michael Keller | ac2ed20 | 2020-01-30 14:11:16 -0800 | [diff] [blame] | 193 | } else { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 194 | Slog.e(TAG, "No HAL is connected. Cannot request graph start"); |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 195 | } |
| 196 | } |
| 197 | |
| 198 | /** Sends a message via the HAL to stop the detection graph. */ |
| 199 | private void stopDetectionGraph() { |
Michael Keller | 16ac930 | 2020-02-14 10:44:51 -0800 | [diff] [blame] | 200 | logd("Attempting to stop detection graph."); |
| 201 | |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 202 | // Grab a copy of 'mOasHal' to avoid sitting on the lock longer than is necessary. |
| 203 | IOccupantAwareness hal; |
| 204 | synchronized (mLock) { |
| 205 | hal = mOasHal; |
| 206 | } |
| 207 | |
| 208 | if (hal != null) { |
| 209 | try { |
| 210 | hal.stopDetection(); |
| 211 | } catch (RemoteException e) { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 212 | Slog.e(TAG, "stopDetection() HAL invocation failed: " + e, e); |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 213 | |
| 214 | synchronized (mLock) { |
| 215 | mOasHal = null; |
| 216 | } |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 217 | } |
Michael Keller | ac2ed20 | 2020-01-30 14:11:16 -0800 | [diff] [blame] | 218 | } else { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 219 | Slog.e(TAG, "No HAL is connected. Cannot request graph stop"); |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 220 | } |
| 221 | } |
| 222 | |
| 223 | /** |
| 224 | * Gets the vehicle capabilities for a given role. |
| 225 | * |
| 226 | * <p>Capabilities are static for a given vehicle configuration and need only be queried once |
| 227 | * per vehicle. Once capability is determined, clients should query system status to see if the |
| 228 | * subsystem is currently ready to serve. |
| 229 | * |
| 230 | * <p>Requires {@link android.car.Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE} read |
| 231 | * permissions to access. |
| 232 | * |
| 233 | * @param role {@link VehicleOccupantRole} to query for. |
| 234 | * @return Flags indicating supported capabilities for the role. |
| 235 | */ |
| 236 | public @DetectionTypeFlags int getCapabilityForRole(@VehicleOccupantRole int role) { |
| 237 | ICarImpl.assertPermission(mContext, Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE); |
| 238 | |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 239 | connectToHalServiceIfNotConnected(); |
| 240 | |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 241 | // Grab a copy of 'mOasHal' to avoid sitting on the lock longer than is necessary. |
| 242 | IOccupantAwareness hal; |
| 243 | synchronized (mLock) { |
| 244 | hal = mOasHal; |
| 245 | } |
| 246 | |
| 247 | if (hal != null) { |
| 248 | try { |
| 249 | return hal.getCapabilityForRole(role); |
| 250 | } catch (RemoteException e) { |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 251 | |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 252 | Slog.e(TAG, "getCapabilityForRole() HAL invocation failed: " + e, e); |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 253 | |
| 254 | synchronized (mLock) { |
| 255 | mOasHal = null; |
| 256 | } |
| 257 | |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 258 | return SystemStatusEvent.DETECTION_TYPE_NONE; |
| 259 | } |
| 260 | } else { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 261 | Slog.e( |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 262 | TAG, |
| 263 | "getCapabilityForRole(): No HAL interface has been provided. Cannot get" |
| 264 | + " capabilities"); |
| 265 | return SystemStatusEvent.DETECTION_TYPE_NONE; |
| 266 | } |
| 267 | } |
| 268 | |
| 269 | /** |
| 270 | * Registers a {@link IOccupantAwarenessEventCallback} to be notified for changes in the system |
| 271 | * state. |
| 272 | * |
| 273 | * <p>Requires {@link android.car.Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE} read |
| 274 | * permissions to access. |
| 275 | * |
| 276 | * @param listener {@link IOccupantAwarenessEventCallback} listener to register. |
| 277 | */ |
| 278 | @Override |
| 279 | public void registerEventListener(@NonNull IOccupantAwarenessEventCallback listener) { |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 280 | ICarImpl.assertPermission(mContext, Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE); |
| 281 | |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 282 | connectToHalServiceIfNotConnected(); |
| 283 | |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 284 | synchronized (mLock) { |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 285 | if (mOasHal == null) { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 286 | Slog.e(TAG, "Attempting to register a listener, but could not connect to HAL."); |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 287 | return; |
| 288 | } |
| 289 | |
| 290 | logd("Registering a new listener"); |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 291 | mListeners.register(listener); |
| 292 | |
| 293 | // After the first client connects, request that the detection graph start. |
| 294 | if (mListeners.getRegisteredCallbackCount() == 1) { |
| 295 | startDetectionGraph(); |
| 296 | } |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | /** |
| 301 | * Unregister the given {@link IOccupantAwarenessEventCallback} listener from receiving events. |
| 302 | * |
| 303 | * <p>Requires {@link android.car.Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE} read |
| 304 | * permissions to access. |
| 305 | * |
| 306 | * @param listener {@link IOccupantAwarenessEventCallback} client to unregister. |
| 307 | */ |
| 308 | @Override |
| 309 | public void unregisterEventListener(@NonNull IOccupantAwarenessEventCallback listener) { |
| 310 | ICarImpl.assertPermission(mContext, Car.PERMISSION_READ_CAR_OCCUPANT_AWARENESS_STATE); |
| 311 | |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 312 | connectToHalServiceIfNotConnected(); |
| 313 | |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 314 | synchronized (mLock) { |
| 315 | mListeners.unregister(listener); |
| 316 | } |
| 317 | |
| 318 | // When the last client disconnects, request that the detection graph stop. |
| 319 | handleClientDisconnected(); |
| 320 | } |
| 321 | |
| 322 | /** Processes a detection event and propagates it to registered clients. */ |
| 323 | @VisibleForTesting |
| 324 | void processStatusEvent(@NonNull SystemStatusEvent statusEvent) { |
| 325 | int idx = mListeners.beginBroadcast(); |
| 326 | while (idx-- > 0) { |
| 327 | IOccupantAwarenessEventCallback listener = mListeners.getBroadcastItem(idx); |
| 328 | try { |
| 329 | listener.onStatusChanged(statusEvent); |
| 330 | } catch (RemoteException e) { |
| 331 | // It's likely the connection snapped. Let binder death handle the situation. |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 332 | Slog.e(TAG, "onStatusChanged() invocation failed: " + e, e); |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 333 | } |
| 334 | } |
| 335 | mListeners.finishBroadcast(); |
| 336 | } |
| 337 | |
| 338 | /** Processes a detection event and propagates it to registered clients. */ |
| 339 | @VisibleForTesting |
| 340 | void processDetectionEvent(@NonNull OccupantAwarenessDetection detection) { |
| 341 | int idx = mListeners.beginBroadcast(); |
| 342 | while (idx-- > 0) { |
| 343 | IOccupantAwarenessEventCallback listener = mListeners.getBroadcastItem(idx); |
| 344 | try { |
| 345 | listener.onDetectionEvent(detection); |
| 346 | } catch (RemoteException e) { |
| 347 | // It's likely the connection snapped. Let binder death handle the situation. |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 348 | Slog.e(TAG, "onDetectionEvent() invocation failed: " + e, e); |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 349 | } |
| 350 | } |
| 351 | mListeners.finishBroadcast(); |
| 352 | } |
| 353 | |
| 354 | /** Handle client disconnections, possibly stopping the detection graph. */ |
| 355 | void handleClientDisconnected() { |
| 356 | // If the last client disconnects, requests that the graph stops. |
| 357 | synchronized (mLock) { |
| 358 | if (mListeners.getRegisteredCallbackCount() == 0) { |
| 359 | stopDetectionGraph(); |
| 360 | } |
| 361 | } |
| 362 | } |
| 363 | |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 364 | private static void logd(String msg) { |
| 365 | if (DBG) { |
Eric Jeong | bd5fb56 | 2020-12-21 13:49:40 -0800 | [diff] [blame] | 366 | Slog.d(TAG, msg); |
Michael Keller | d399011 | 2020-02-03 10:41:06 -0800 | [diff] [blame] | 367 | } |
| 368 | } |
| 369 | |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 370 | /** |
| 371 | * Class that implements the listener interface and gets called back from the {@link |
| 372 | * android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback} across the |
| 373 | * binder interface. |
| 374 | */ |
| 375 | private static class ChangeListenerToHalService extends IOccupantAwarenessClientCallback.Stub { |
| 376 | private final WeakReference<OccupantAwarenessService> mOasService; |
| 377 | |
| 378 | ChangeListenerToHalService(OccupantAwarenessService oasService) { |
| 379 | mOasService = new WeakReference<>(oasService); |
| 380 | } |
| 381 | |
| 382 | @Override |
| 383 | public void onSystemStatusChanged(int inputDetectionFlags, byte inputStatus) { |
| 384 | OccupantAwarenessService service = mOasService.get(); |
| 385 | if (service != null) { |
| 386 | service.processStatusEvent( |
| 387 | OccupantAwarenessUtils.convertToStatusEvent( |
| 388 | inputDetectionFlags, inputStatus)); |
| 389 | } |
| 390 | } |
| 391 | |
| 392 | @Override |
| 393 | public void onDetectionEvent( |
| 394 | android.hardware.automotive.occupant_awareness.OccupantDetections detections) { |
| 395 | OccupantAwarenessService service = mOasService.get(); |
| 396 | if (service != null) { |
| 397 | for (android.hardware.automotive.occupant_awareness.OccupantDetection detection : |
| 398 | detections.detections) { |
| 399 | service.processDetectionEvent( |
| 400 | OccupantAwarenessUtils.convertToDetectionEvent( |
| 401 | detections.timeStampMillis, detection)); |
| 402 | } |
| 403 | } |
| 404 | } |
Jeongik Cha | 1d04bdd | 2020-04-08 22:19:52 +0900 | [diff] [blame] | 405 | |
| 406 | @Override |
| 407 | public int getInterfaceVersion() { |
| 408 | return this.VERSION; |
| 409 | } |
| 410 | |
| 411 | @Override |
| 412 | public String getInterfaceHash() { |
| 413 | return this.HASH; |
| 414 | } |
Michael Keller | c0f0bdb | 2019-12-11 14:58:19 -0800 | [diff] [blame] | 415 | } |
| 416 | } |