1 /*
2  * Copyright (C) 2019 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.Nullable;
20 import android.car.occupantawareness.DriverMonitoringDetection;
21 import android.car.occupantawareness.GazeDetection;
22 import android.car.occupantawareness.OccupantAwarenessDetection;
23 import android.car.occupantawareness.OccupantAwarenessDetection.ConfidenceLevel;
24 import android.car.occupantawareness.Point3D;
25 import android.car.occupantawareness.SystemStatusEvent;
26 import android.car.occupantawareness.SystemStatusEvent.DetectionTypeFlags;
27 import android.car.occupantawareness.SystemStatusEvent.SystemStatus;
28 import android.hardware.automotive.occupant_awareness.IOccupantAwareness;
29 import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
30 import android.util.Slog;
31 
32 /*package*/ final class OccupantAwarenessUtils {
33     private static final String TAG = CarLog.tagFor(OccupantAwarenessUtils.class);
34 
OccupantAwarenessUtils()35     private OccupantAwarenessUtils() {}
36 
37     /** Converts status flags into to a SystemStatusEvent. */
convertToStatusEvent(int inputDetectionFlags, byte inputStatus)38     static SystemStatusEvent convertToStatusEvent(int inputDetectionFlags, byte inputStatus) {
39         // Parse the system status from the hardware layer.
40         @SystemStatus int outputStatus = SystemStatusEvent.SYSTEM_STATUS_NOT_READY;
41 
42         switch (inputStatus) {
43             case OccupantAwarenessStatus.READY:
44                 outputStatus = SystemStatusEvent.SYSTEM_STATUS_READY;
45                 break;
46 
47             case OccupantAwarenessStatus.NOT_SUPPORTED:
48                 outputStatus = SystemStatusEvent.SYSTEM_STATUS_NOT_SUPPORTED;
49                 break;
50 
51             case OccupantAwarenessStatus.NOT_INITIALIZED:
52                 outputStatus = SystemStatusEvent.SYSTEM_STATUS_NOT_READY;
53                 break;
54 
55             case OccupantAwarenessStatus.FAILURE:
56                 outputStatus = SystemStatusEvent.SYSTEM_STATUS_SYSTEM_FAILURE;
57                 break;
58 
59             default:
60                 Slog.e(TAG, "Invalid status code: " + inputStatus);
61                 break;
62         }
63 
64         // Parse the detection flags from the hardware layer.
65         @DetectionTypeFlags int outputFlags = SystemStatusEvent.DETECTION_TYPE_NONE;
66 
67         switch (inputDetectionFlags) {
68             case IOccupantAwareness.CAP_NONE:
69                 outputFlags = SystemStatusEvent.DETECTION_TYPE_NONE;
70                 break;
71 
72             case IOccupantAwareness.CAP_PRESENCE_DETECTION:
73                 outputFlags = SystemStatusEvent.DETECTION_TYPE_PRESENCE;
74                 break;
75 
76             case IOccupantAwareness.CAP_GAZE_DETECTION:
77                 outputFlags = SystemStatusEvent.DETECTION_TYPE_GAZE;
78                 break;
79 
80             case IOccupantAwareness.CAP_DRIVER_MONITORING_DETECTION:
81                 outputFlags = SystemStatusEvent.DETECTION_TYPE_DRIVER_MONITORING;
82                 break;
83 
84             default:
85                 Slog.e(TAG, "Invalid status code: " + inputDetectionFlags);
86                 break;
87         }
88 
89         return new SystemStatusEvent(outputStatus, outputFlags);
90     }
91 
92     /** Converts an input confidence to a ConfidenceLevel. */
convertToConfidenceScore( @ndroid.hardware.automotive.occupant_awareness.ConfidenceLevel int inputConfidence)93     static @ConfidenceLevel int convertToConfidenceScore(
94             @android.hardware.automotive.occupant_awareness.ConfidenceLevel int inputConfidence) {
95         switch (inputConfidence) {
96             case android.hardware.automotive.occupant_awareness.ConfidenceLevel.MAX:
97                 return OccupantAwarenessDetection.CONFIDENCE_LEVEL_MAX;
98 
99             case android.hardware.automotive.occupant_awareness.ConfidenceLevel.HIGH:
100                 return OccupantAwarenessDetection.CONFIDENCE_LEVEL_HIGH;
101 
102             case android.hardware.automotive.occupant_awareness.ConfidenceLevel.LOW:
103                 return OccupantAwarenessDetection.CONFIDENCE_LEVEL_LOW;
104 
105             case android.hardware.automotive.occupant_awareness.ConfidenceLevel.NONE:
106             default:
107                 return OccupantAwarenessDetection.CONFIDENCE_LEVEL_NONE;
108         }
109     }
110 
111     /**
112      * Converts an input point to a Point3D. Returns null if the source vector was null or empty.
113      */
convertToPoint3D(@ullable double[] vector)114     static Point3D convertToPoint3D(@Nullable double[] vector) {
115         if (vector != null && vector.length == 3) {
116             return new Point3D(vector[0], vector[1], vector[2]);
117         } else {
118             return null;
119         }
120     }
121 
122     /** Converts an input timestamp to milliseconds since boot. */
convertTimestamp(long inputTimestamp)123     static long convertTimestamp(long inputTimestamp) {
124         return inputTimestamp;
125     }
126 
127     /**
128      * Converts an input @android.hardware.automotive.occupant_awareness.Role to a
129      * VehicleOccupantRole.
130      */
convertToRole(int inputRole)131     static @OccupantAwarenessDetection.VehicleOccupantRole int convertToRole(int inputRole) {
132         if (inputRole == android.hardware.automotive.occupant_awareness.Role.INVALID
133                 || inputRole == android.hardware.automotive.occupant_awareness.Role.UNKNOWN) {
134             return OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE;
135         } else if (inputRole == android.hardware.automotive.occupant_awareness.Role.ALL_OCCUPANTS) {
136             return OccupantAwarenessDetection.VEHICLE_OCCUPANT_ALL_OCCUPANTS;
137         }
138 
139         int outputRole = OccupantAwarenessDetection.VEHICLE_OCCUPANT_NONE;
140 
141         if ((inputRole & android.hardware.automotive.occupant_awareness.Role.DRIVER) > 0) {
142             outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_DRIVER;
143         }
144 
145         if ((inputRole & android.hardware.automotive.occupant_awareness.Role.FRONT_PASSENGER) > 0) {
146             outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_FRONT_PASSENGER;
147         }
148 
149         if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_2_PASSENGER_LEFT)
150                 > 0) {
151             outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_LEFT;
152         }
153 
154         if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_2_PASSENGER_CENTER)
155                 > 0) {
156             outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_CENTER;
157         }
158 
159         if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_2_PASSENGER_RIGHT)
160                 > 0) {
161             outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_2_PASSENGER_RIGHT;
162         }
163 
164         if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_3_PASSENGER_LEFT)
165                 > 0) {
166             outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_3_PASSENGER_LEFT;
167         }
168 
169         if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_3_PASSENGER_CENTER)
170                 > 0) {
171             outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_3_PASSENGER_CENTER;
172         }
173 
174         if ((inputRole & android.hardware.automotive.occupant_awareness.Role.ROW_3_PASSENGER_RIGHT)
175                 > 0) {
176             outputRole |= OccupantAwarenessDetection.VEHICLE_OCCUPANT_ROW_3_PASSENGER_RIGHT;
177         }
178 
179         return outputRole;
180     }
181 
182     /** Converts an input detection to a GazeDetection. */
convertToGazeDetection( android.hardware.automotive.occupant_awareness.GazeDetection inputDetection)183     static GazeDetection convertToGazeDetection(
184             android.hardware.automotive.occupant_awareness.GazeDetection inputDetection) {
185 
186         return new GazeDetection(
187                 convertToConfidenceScore(inputDetection.gazeConfidence),
188                 convertToPoint3D(inputDetection.headPosition),
189                 convertToPoint3D(inputDetection.headPosition),
190                 convertToPoint3D(inputDetection.headAngleUnitVector),
191                 convertToPoint3D(inputDetection.gazeAngleUnitVector),
192                 inputDetection.gazeTarget,
193                 inputDetection.timeOnTargetMillis);
194     }
195 
196     /** Converts an input detection to a DriverMonitoringDetection. */
convertToDriverMonitoringDetection( android.hardware.automotive.occupant_awareness.DriverMonitoringDetection inputDetection)197     static DriverMonitoringDetection convertToDriverMonitoringDetection(
198             android.hardware.automotive.occupant_awareness.DriverMonitoringDetection
199                     inputDetection) {
200         return new DriverMonitoringDetection(
201                 convertToConfidenceScore(inputDetection.confidenceScore),
202                 inputDetection.isLookingOnRoad,
203                 inputDetection.gazeDurationMillis);
204     }
205 
206     /** Converts a PresenceDetection to a boolean indicating if an occupant was present. */
convertToPresence( android.hardware.automotive.occupant_awareness.PresenceDetection inputDetection)207     static boolean convertToPresence(
208             android.hardware.automotive.occupant_awareness.PresenceDetection inputDetection) {
209         return inputDetection.isOccupantDetected;
210     }
211 
212     /** Converts an OccupantDetection to OccupantAwarenessDetection. */
convertToDetectionEvent( long timestamp, android.hardware.automotive.occupant_awareness.OccupantDetection inputDetection)213     static OccupantAwarenessDetection convertToDetectionEvent(
214             long timestamp,
215             android.hardware.automotive.occupant_awareness.OccupantDetection inputDetection) {
216         // Populate presence, if data is available for this frame.
217         boolean isPresent = false;
218         if (inputDetection.presenceData != null && inputDetection.presenceData.length > 0) {
219             isPresent = convertToPresence(inputDetection.presenceData[0]);
220         }
221 
222         // Populate gaze, if data is available for this frame.
223         GazeDetection gazeDetection = null;
224         if (inputDetection.gazeData != null && inputDetection.gazeData.length > 0) {
225             gazeDetection = convertToGazeDetection(inputDetection.gazeData[0]);
226         }
227 
228         // Populate driver monitoring, if data is available for this frame.
229         DriverMonitoringDetection driverMonitoringDetection = null;
230         if (inputDetection.attentionData != null && inputDetection.attentionData.length > 0) {
231             driverMonitoringDetection =
232                     convertToDriverMonitoringDetection(inputDetection.attentionData[0]);
233         }
234 
235         return new OccupantAwarenessDetection(
236                 convertToRole(inputDetection.role),
237                 timestamp,
238                 isPresent,
239                 gazeDetection,
240                 driverMonitoringDetection);
241     }
242 }
243