• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.diagnostic;
18 
19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
20 
21 import android.annotation.IntDef;
22 import android.annotation.Nullable;
23 import android.annotation.SystemApi;
24 import android.car.annotation.AddedInOrBefore;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.util.JsonWriter;
28 import android.util.SparseArray;
29 import android.util.SparseIntArray;
30 
31 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
32 
33 import java.io.IOException;
34 import java.lang.annotation.Retention;
35 import java.lang.annotation.RetentionPolicy;
36 import java.util.Objects;
37 
38 /**
39  * A CarDiagnosticEvent object corresponds to a single diagnostic event frame coming from the car.
40  *
41  * @hide
42  */
43 @SystemApi
44 public final class CarDiagnosticEvent implements Parcelable {
45     /** Whether this frame represents a live or a freeze frame */
46     @AddedInOrBefore(majorVersion = 33)
47     public final int frameType;
48 
49     /**
50      * When this data was acquired in car or received from car. It is elapsed real-time of data
51      * reception from car in nanoseconds since system boot.
52      */
53     @AddedInOrBefore(majorVersion = 33)
54     public final long timestamp;
55 
56     /**
57      * Sparse array that contains the mapping of OBD2 diagnostic properties to their values for
58      * integer valued properties
59      */
60     private final SparseIntArray mIntValues;
61 
62     /**
63      * Sparse array that contains the mapping of OBD2 diagnostic properties to their values for
64      * float valued properties
65      */
66     private final SparseArray<Float> mFloatValues;
67 
68     /**
69      * Diagnostic Troubleshooting Code (DTC) that was detected and caused this frame to be stored
70      * (if a freeze frame). Always null for a live frame.
71      */
72     @AddedInOrBefore(majorVersion = 33)
73     public final String dtc;
74 
CarDiagnosticEvent(Parcel in)75     public CarDiagnosticEvent(Parcel in) {
76         frameType = in.readInt();
77         timestamp = in.readLong();
78         int len = in.readInt();
79         mFloatValues = new SparseArray<>(len);
80         for (int i = 0; i < len; ++i) {
81             int key = in.readInt();
82             float value = in.readFloat();
83             mFloatValues.put(key, value);
84         }
85         len = in.readInt();
86         mIntValues = new SparseIntArray(len);
87         for (int i = 0; i < len; ++i) {
88             int key = in.readInt();
89             int value = in.readInt();
90             mIntValues.put(key, value);
91         }
92         dtc = (String) in.readValue(String.class.getClassLoader());
93         // version 1 up to here
94     }
95 
96     @Override
97     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
98     @AddedInOrBefore(majorVersion = 33)
describeContents()99     public int describeContents() {
100         return 0;
101     }
102 
103     @Override
104     @AddedInOrBefore(majorVersion = 33)
writeToParcel(Parcel dest, int flags)105     public void writeToParcel(Parcel dest, int flags) {
106         dest.writeInt(frameType);
107         dest.writeLong(timestamp);
108         dest.writeInt(mFloatValues.size());
109         for (int i = 0; i < mFloatValues.size(); ++i) {
110             int key = mFloatValues.keyAt(i);
111             dest.writeInt(key);
112             dest.writeFloat(mFloatValues.get(key));
113         }
114         dest.writeInt(mIntValues.size());
115         for (int i = 0; i < mIntValues.size(); ++i) {
116             int key = mIntValues.keyAt(i);
117             dest.writeInt(key);
118             dest.writeInt(mIntValues.get(key));
119         }
120         dest.writeValue(dtc);
121     }
122 
123     /**
124      * Store the contents of this diagnostic event in a JsonWriter.
125      *
126      * The data is stored as a JSON object, with these fields:
127      *  type: either "live" or "freeze" depending on the type of frame;
128      *  timestamp: the timestamp at which this frame was generated;
129      *  intValues: an array of objects each of which has two elements:
130      *    id: the integer identifier of the sensor;
131      *    value: the integer value of the sensor;
132      *  floatValues: an array of objects each of which has two elements:
133      *    id: the integer identifier of the sensor;
134      *    value: the floating-point value of the sensor;
135      *  stringValue: the DTC for a freeze frame, omitted for a live frame
136      */
137     @AddedInOrBefore(majorVersion = 33)
writeToJson(JsonWriter jsonWriter)138     public void writeToJson(JsonWriter jsonWriter) throws IOException {
139         jsonWriter.beginObject();
140 
141         jsonWriter.name("type");
142         switch (frameType) {
143             case CarDiagnosticManager.FRAME_TYPE_LIVE:
144                 jsonWriter.value("live");
145                 break;
146             case CarDiagnosticManager.FRAME_TYPE_FREEZE:
147                 jsonWriter.value("freeze");
148                 break;
149             default:
150                 throw new IllegalStateException("unknown frameType " + frameType);
151         }
152 
153         jsonWriter.name("timestamp").value(timestamp);
154 
155         jsonWriter.name("intValues").beginArray();
156         for (int i = 0; i < mIntValues.size(); ++i) {
157             jsonWriter.beginObject();
158             jsonWriter.name("id").value(mIntValues.keyAt(i));
159             jsonWriter.name("value").value(mIntValues.valueAt(i));
160             jsonWriter.endObject();
161         }
162         jsonWriter.endArray();
163 
164         jsonWriter.name("floatValues").beginArray();
165         for (int i = 0; i < mFloatValues.size(); ++i) {
166             jsonWriter.beginObject();
167             jsonWriter.name("id").value(mFloatValues.keyAt(i));
168             jsonWriter.name("value").value(mFloatValues.valueAt(i));
169             jsonWriter.endObject();
170         }
171         jsonWriter.endArray();
172 
173         if (dtc != null) {
174             jsonWriter.name("stringValue").value(dtc);
175         }
176 
177         jsonWriter.endObject();
178     }
179 
180     @AddedInOrBefore(majorVersion = 33)
181     public static final Parcelable.Creator<CarDiagnosticEvent> CREATOR =
182             new Parcelable.Creator<CarDiagnosticEvent>() {
183                 public CarDiagnosticEvent createFromParcel(Parcel in) {
184                     return new CarDiagnosticEvent(in);
185                 }
186 
187                 public CarDiagnosticEvent[] newArray(int size) {
188                     return new CarDiagnosticEvent[size];
189                 }
190             };
191 
CarDiagnosticEvent( int frameType, long timestamp, SparseArray<Float> floatValues, SparseIntArray intValues, String dtc)192     private CarDiagnosticEvent(
193             int frameType,
194             long timestamp,
195             SparseArray<Float> floatValues,
196             SparseIntArray intValues,
197             String dtc) {
198         this.frameType = frameType;
199         this.timestamp = timestamp;
200         mFloatValues = floatValues;
201         mIntValues = intValues;
202         this.dtc = dtc;
203     }
204 
205     /**
206      * This class can be used to incrementally construct a CarDiagnosticEvent.
207      * CarDiagnosticEvent instances are immutable once built.
208      */
209     public static class Builder {
210         private int mType = CarDiagnosticManager.FRAME_TYPE_LIVE;
211         private long mTimestamp = 0;
212         private SparseArray<Float> mFloatValues = new SparseArray<>();
213         private SparseIntArray mIntValues = new SparseIntArray();
214         private String mDtc = null;
215 
Builder(int type)216         private Builder(int type) {
217             mType = type;
218         }
219 
220         /** Returns a new Builder for a live frame */
221         @AddedInOrBefore(majorVersion = 33)
newLiveFrameBuilder()222         public static Builder newLiveFrameBuilder() {
223             return new Builder(CarDiagnosticManager.FRAME_TYPE_LIVE);
224         }
225 
226         /** Returns a new Builder for a freeze frame */
227         @AddedInOrBefore(majorVersion = 33)
newFreezeFrameBuilder()228         public static Builder newFreezeFrameBuilder() {
229             return new Builder(CarDiagnosticManager.FRAME_TYPE_FREEZE);
230         }
231 
232         /**
233          * Sets the timestamp for the frame being built
234          * @deprecated Use {@link Builder#setTimeStamp(long)} instead.
235          */
236         @Deprecated
237         @AddedInOrBefore(majorVersion = 33)
atTimestamp(long timestamp)238         public Builder atTimestamp(long timestamp) {
239             mTimestamp = timestamp;
240             return this;
241         }
242 
243         /**
244          * Sets the timestamp for the frame being built
245          * @param timeStamp timeStamp for CarDiagnosticEvent
246          * @return Builder
247          */
248         @AddedInOrBefore(majorVersion = 33)
setTimeStamp(long timeStamp)249         public Builder setTimeStamp(long timeStamp) {
250             mTimestamp = timeStamp;
251             return this;
252         }
253 
254         /**
255          * Adds an integer-valued sensor to the frame being built
256          * @deprecated Use {@link Builder#setIntValue(int, int)} instead.
257          */
258         @Deprecated
259         @AddedInOrBefore(majorVersion = 33)
withIntValue(int key, int value)260         public Builder withIntValue(int key, int value) {
261             mIntValues.put(key, value);
262             return this;
263         }
264 
265         /**
266          * Adds an integer-valued sensor to the frame being built
267          * @param key key of integer value
268          * @param value int value
269          * @return Builder
270          */
271         @AddedInOrBefore(majorVersion = 33)
setIntValue(int key, int value)272         public Builder setIntValue(int key, int value) {
273             mIntValues.put(key, value);
274             return this;
275         }
276 
277         /**
278          * Adds a float-valued sensor to the frame being built
279          * @deprecated Use {@link Builder#setFloatValue(int, float)} instead.
280          */
281         @Deprecated
282         @AddedInOrBefore(majorVersion = 33)
withFloatValue(int key, float value)283         public Builder withFloatValue(int key, float value) {
284             mFloatValues.put(key, value);
285             return this;
286         }
287 
288         /**
289          * Adds a float-valued sensor to the frame being built
290          * @param key key of float value
291          * @param value float value
292          * @return Builder
293          */
294         @AddedInOrBefore(majorVersion = 33)
setFloatValue(int key, float value)295         public Builder setFloatValue(int key, float value) {
296             mFloatValues.put(key, value);
297             return this;
298         }
299 
300         /**
301          * Sets the DTC for the frame being built
302          * @deprecated Use {@link Builder#setDtc(String)} instead.
303          */
304         @Deprecated
305         @AddedInOrBefore(majorVersion = 33)
withDtc(String dtc)306         public Builder withDtc(String dtc) {
307             mDtc = dtc;
308             return this;
309         }
310 
311         /**
312          * Sets the DTC for the frame being built
313          * @param dtc string value of CarDiagnosticEvent
314          * @return Builder
315          */
316         @AddedInOrBefore(majorVersion = 33)
setDtc(String dtc)317         public Builder setDtc(String dtc) {
318             mDtc = dtc;
319             return this;
320         }
321 
322         /** Builds and returns the CarDiagnosticEvent */
323         @AddedInOrBefore(majorVersion = 33)
build()324         public CarDiagnosticEvent build() {
325             return new CarDiagnosticEvent(mType, mTimestamp, mFloatValues, mIntValues, mDtc);
326         }
327     }
328 
329     /**
330      * Returns a copy of this CarDiagnosticEvent with all vendor-specific sensors removed.
331      *
332      * @hide
333      */
334     @AddedInOrBefore(majorVersion = 33)
withVendorSensorsRemoved()335     public CarDiagnosticEvent withVendorSensorsRemoved() {
336         SparseIntArray newIntValues = mIntValues.clone();
337         SparseArray<Float> newFloatValues = mFloatValues.clone();
338         for (int i = 0; i < mIntValues.size(); ++i) {
339             int key = mIntValues.keyAt(i);
340             if (key >= android.car.diagnostic.IntegerSensorIndex.LAST_SYSTEM) {
341                 newIntValues.delete(key);
342             }
343         }
344         for (int i = 0; i < mFloatValues.size(); ++i) {
345             int key = mFloatValues.keyAt(i);
346             if (key >= android.car.diagnostic.FloatSensorIndex.LAST_SYSTEM) {
347                 newFloatValues.delete(key);
348             }
349         }
350         return new CarDiagnosticEvent(frameType, timestamp, newFloatValues, newIntValues, dtc);
351     }
352 
353     /** Returns true if this object is a live frame, false otherwise */
354     @AddedInOrBefore(majorVersion = 33)
isLiveFrame()355     public boolean isLiveFrame() {
356         return CarDiagnosticManager.FRAME_TYPE_LIVE == frameType;
357     }
358 
359     /** Returns true if this object is a freeze frame, false otherwise */
360     @AddedInOrBefore(majorVersion = 33)
isFreezeFrame()361     public boolean isFreezeFrame() {
362         return CarDiagnosticManager.FRAME_TYPE_FREEZE == frameType;
363     }
364 
365     /** @hide */
366     @AddedInOrBefore(majorVersion = 33)
isEmptyFrame()367     public boolean isEmptyFrame() {
368         boolean empty = (0 == mIntValues.size());
369         empty &= (0 == mFloatValues.size());
370         if (isFreezeFrame()) empty &= dtc.isEmpty();
371         return empty;
372     }
373 
374     /** @hide */
375     @AddedInOrBefore(majorVersion = 33)
checkLiveFrame()376     public CarDiagnosticEvent checkLiveFrame() {
377         if (!isLiveFrame()) throw new IllegalStateException("frame is not a live frame");
378         return this;
379     }
380 
381     /** @hide */
382     @AddedInOrBefore(majorVersion = 33)
checkFreezeFrame()383     public CarDiagnosticEvent checkFreezeFrame() {
384         if (!isFreezeFrame()) throw new IllegalStateException("frame is not a freeze frame");
385         return this;
386     }
387 
388     /** @hide */
389     @AddedInOrBefore(majorVersion = 33)
isEarlierThan(CarDiagnosticEvent otherEvent)390     public boolean isEarlierThan(CarDiagnosticEvent otherEvent) {
391         Objects.requireNonNull(otherEvent);
392         return (timestamp < otherEvent.timestamp);
393     }
394 
395     @Override
equals(Object otherObject)396     public boolean equals(Object otherObject) {
397         if (this == otherObject) {
398             return true;
399         }
400         if (null == otherObject) {
401             return false;
402         }
403         if (!(otherObject instanceof CarDiagnosticEvent)) {
404             return false;
405         }
406         CarDiagnosticEvent otherEvent = (CarDiagnosticEvent) otherObject;
407         if (otherEvent.frameType != frameType) {
408             return false;
409         }
410         if (otherEvent.timestamp != timestamp) {
411             return false;
412         }
413         if (otherEvent.mIntValues.size() != mIntValues.size()) {
414             return false;
415         }
416         if (otherEvent.mFloatValues.size() != mFloatValues.size()) {
417             return false;
418         }
419         if (!Objects.equals(dtc, otherEvent.dtc)) {
420             return false;
421         }
422         for (int i = 0; i < mIntValues.size(); ++i) {
423             int key = mIntValues.keyAt(i);
424             int otherKey = otherEvent.mIntValues.keyAt(i);
425             if (key != otherKey) {
426                 return false;
427             }
428             int value = mIntValues.valueAt(i);
429             int otherValue = otherEvent.mIntValues.valueAt(i);
430             if (value != otherValue) {
431                 return false;
432             }
433         }
434         for (int i = 0; i < mFloatValues.size(); ++i) {
435             int key = mFloatValues.keyAt(i);
436             int otherKey = otherEvent.mFloatValues.keyAt(i);
437             if (key != otherKey) {
438                 return false;
439             }
440             float value = mFloatValues.valueAt(i);
441             float otherValue = otherEvent.mFloatValues.valueAt(i);
442             if (value != otherValue) {
443                 return false;
444             }
445         }
446         return true;
447     }
448 
449     @Override
hashCode()450     public int hashCode() {
451         Integer[] intKeys = new Integer[mIntValues.size()];
452         Integer[] floatKeys = new Integer[mFloatValues.size()];
453         Integer[] intValues = new Integer[intKeys.length];
454         Float[] floatValues = new Float[floatKeys.length];
455         for (int i = 0; i < intKeys.length; ++i) {
456             intKeys[i] = mIntValues.keyAt(i);
457             intValues[i] = mIntValues.valueAt(i);
458         }
459         for (int i = 0; i < floatKeys.length; ++i) {
460             floatKeys[i] = mFloatValues.keyAt(i);
461             floatValues[i] = mFloatValues.valueAt(i);
462         }
463         int intKeysHash = Objects.hash((Object[]) intKeys);
464         int intValuesHash = Objects.hash((Object[]) intValues);
465         int floatKeysHash = Objects.hash((Object[]) floatKeys);
466         int floatValuesHash = Objects.hash((Object[]) floatValues);
467         return Objects.hash(frameType,
468                 timestamp,
469                 dtc,
470                 intKeysHash,
471                 intValuesHash,
472                 floatKeysHash,
473                 floatValuesHash);
474     }
475 
476     @Override
toString()477     public String toString() {
478         return String.format(
479                 "%s diagnostic frame {\n"
480                         + "\ttimestamp: %d, "
481                         + "DTC: %s\n"
482                         + "\tmIntValues: %s\n"
483                         + "\tmFloatValues: %s\n}",
484                 isLiveFrame() ? "live" : "freeze",
485                 timestamp,
486                 dtc,
487                 mIntValues.toString(),
488                 mFloatValues.toString());
489     }
490 
491     /**
492      * Returns the value of the given integer sensor, if present in this frame.
493      * Returns defaultValue otherwise.
494      */
495     @AddedInOrBefore(majorVersion = 33)
getSystemIntegerSensor( @ndroid.car.diagnostic.IntegerSensorIndex.SensorIndex int sensor, int defaultValue)496     public int getSystemIntegerSensor(
497             @android.car.diagnostic.IntegerSensorIndex.SensorIndex int sensor, int defaultValue) {
498         return mIntValues.get(sensor, defaultValue);
499     }
500 
501     /**
502      * Returns the value of the given float sensor, if present in this frame.
503      * Returns defaultValue otherwise.
504      */
505     @AddedInOrBefore(majorVersion = 33)
getSystemFloatSensor( @ndroid.car.diagnostic.FloatSensorIndex.SensorIndex int sensor, float defaultValue)506     public float getSystemFloatSensor(
507             @android.car.diagnostic.FloatSensorIndex.SensorIndex int sensor, float defaultValue) {
508         return mFloatValues.get(sensor, defaultValue);
509     }
510 
511     /**
512      * Returns the value of the given integer sensor, if present in this frame.
513      * Returns defaultValue otherwise.
514      */
515     @AddedInOrBefore(majorVersion = 33)
getVendorIntegerSensor(int sensor, int defaultValue)516     public int getVendorIntegerSensor(int sensor, int defaultValue) {
517         return mIntValues.get(sensor, defaultValue);
518     }
519 
520     /**
521      * Returns the value of the given float sensor, if present in this frame.
522      * Returns defaultValue otherwise.
523      */
524     @AddedInOrBefore(majorVersion = 33)
getVendorFloatSensor(int sensor, float defaultValue)525     public float getVendorFloatSensor(int sensor, float defaultValue) {
526         return mFloatValues.get(sensor, defaultValue);
527     }
528 
529     /**
530      * Returns the value of the given integer sensor, if present in this frame.
531      * Returns null otherwise.
532      */
533     @AddedInOrBefore(majorVersion = 33)
getSystemIntegerSensor( @ndroid.car.diagnostic.IntegerSensorIndex.SensorIndex int sensor)534     public @Nullable Integer getSystemIntegerSensor(
535             @android.car.diagnostic.IntegerSensorIndex.SensorIndex int sensor) {
536         int index = mIntValues.indexOfKey(sensor);
537         if (index < 0) return null;
538         return mIntValues.valueAt(index);
539     }
540 
541     /**
542      * Returns the value of the given float sensor, if present in this frame.
543      * Returns null otherwise.
544      */
545     @AddedInOrBefore(majorVersion = 33)
getSystemFloatSensor( @ndroid.car.diagnostic.FloatSensorIndex.SensorIndex int sensor)546     public @Nullable Float getSystemFloatSensor(
547             @android.car.diagnostic.FloatSensorIndex.SensorIndex int sensor) {
548         int index = mFloatValues.indexOfKey(sensor);
549         if (index < 0) return null;
550         return mFloatValues.valueAt(index);
551     }
552 
553     /**
554      * Returns the value of the given integer sensor, if present in this frame.
555      * Returns null otherwise.
556      */
557     @AddedInOrBefore(majorVersion = 33)
getVendorIntegerSensor(int sensor)558     public @Nullable Integer getVendorIntegerSensor(int sensor) {
559         int index = mIntValues.indexOfKey(sensor);
560         if (index < 0) return null;
561         return mIntValues.valueAt(index);
562     }
563 
564     /**
565      * Returns the value of the given float sensor, if present in this frame.
566      * Returns null otherwise.
567      */
568     @AddedInOrBefore(majorVersion = 33)
getVendorFloatSensor(int sensor)569     public @Nullable Float getVendorFloatSensor(int sensor) {
570         int index = mFloatValues.indexOfKey(sensor);
571         if (index < 0) return null;
572         return mFloatValues.valueAt(index);
573     }
574 
575     /**
576      * Represents possible states of the fuel system; see {@link
577      * android.car.diagnostic.IntegerSensorIndex#FUEL_SYSTEM_STATUS}
578      */
579     public static final class FuelSystemStatus {
FuelSystemStatus()580         private FuelSystemStatus() {}
581 
582         @AddedInOrBefore(majorVersion = 33)
583         public static final int OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 1;
584         @AddedInOrBefore(majorVersion = 33)
585         public static final int CLOSED_LOOP = 2;
586         @AddedInOrBefore(majorVersion = 33)
587         public static final int OPEN_ENGINE_LOAD_OR_DECELERATION = 4;
588         @AddedInOrBefore(majorVersion = 33)
589         public static final int OPEN_SYSTEM_FAILURE = 8;
590         @AddedInOrBefore(majorVersion = 33)
591         public static final int CLOSED_LOOP_BUT_FEEDBACK_FAULT = 16;
592 
593         @Retention(RetentionPolicy.SOURCE)
594         @IntDef({
595             OPEN_INSUFFICIENT_ENGINE_TEMPERATURE,
596             CLOSED_LOOP,
597             OPEN_ENGINE_LOAD_OR_DECELERATION,
598             OPEN_SYSTEM_FAILURE,
599             CLOSED_LOOP_BUT_FEEDBACK_FAULT
600         })
601         public @interface Status {}
602     }
603 
604     /**
605      * Represents possible states of the secondary air system; see {@link
606      * android.car.diagnostic.IntegerSensorIndex#COMMANDED_SECONDARY_AIR_STATUS}
607      */
608     public static final class SecondaryAirStatus {
SecondaryAirStatus()609         private SecondaryAirStatus() {}
610 
611         @AddedInOrBefore(majorVersion = 33)
612         public static final int UPSTREAM = 1;
613         @AddedInOrBefore(majorVersion = 33)
614         public static final int DOWNSTREAM_OF_CATALYCIC_CONVERTER = 2;
615         @AddedInOrBefore(majorVersion = 33)
616         public static final int FROM_OUTSIDE_OR_OFF = 4;
617         @AddedInOrBefore(majorVersion = 33)
618         public static final int PUMP_ON_FOR_DIAGNOSTICS = 8;
619 
620         @Retention(RetentionPolicy.SOURCE)
621         @IntDef({
622             UPSTREAM,
623             DOWNSTREAM_OF_CATALYCIC_CONVERTER,
624             FROM_OUTSIDE_OR_OFF,
625             PUMP_ON_FOR_DIAGNOSTICS
626         })
627         public @interface Status {}
628     }
629 
630     /**
631      * Represents possible types of fuel; see {@link
632      * android.car.diagnostic.IntegerSensorIndex#FUEL_TYPE}
633      */
634     public static final class FuelType {
FuelType()635         private FuelType() {}
636 
637         @AddedInOrBefore(majorVersion = 33)
638         public static final int NOT_AVAILABLE = 0;
639         @AddedInOrBefore(majorVersion = 33)
640         public static final int GASOLINE = 1;
641         @AddedInOrBefore(majorVersion = 33)
642         public static final int METHANOL = 2;
643         @AddedInOrBefore(majorVersion = 33)
644         public static final int ETHANOL = 3;
645         @AddedInOrBefore(majorVersion = 33)
646         public static final int DIESEL = 4;
647         @AddedInOrBefore(majorVersion = 33)
648         public static final int LPG = 5;
649         @AddedInOrBefore(majorVersion = 33)
650         public static final int CNG = 6;
651         @AddedInOrBefore(majorVersion = 33)
652         public static final int PROPANE = 7;
653         @AddedInOrBefore(majorVersion = 33)
654         public static final int ELECTRIC = 8;
655         @AddedInOrBefore(majorVersion = 33)
656         public static final int BIFUEL_RUNNING_GASOLINE = 9;
657         @AddedInOrBefore(majorVersion = 33)
658         public static final int BIFUEL_RUNNING_METHANOL = 10;
659         @AddedInOrBefore(majorVersion = 33)
660         public static final int BIFUEL_RUNNING_ETHANOL = 11;
661         @AddedInOrBefore(majorVersion = 33)
662         public static final int BIFUEL_RUNNING_LPG = 12;
663         @AddedInOrBefore(majorVersion = 33)
664         public static final int BIFUEL_RUNNING_CNG = 13;
665         @AddedInOrBefore(majorVersion = 33)
666         public static final int BIFUEL_RUNNING_PROPANE = 14;
667         @AddedInOrBefore(majorVersion = 33)
668         public static final int BIFUEL_RUNNING_ELECTRIC = 15;
669         @AddedInOrBefore(majorVersion = 33)
670         public static final int BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION = 16;
671         @AddedInOrBefore(majorVersion = 33)
672         public static final int HYBRID_GASOLINE = 17;
673         @AddedInOrBefore(majorVersion = 33)
674         public static final int HYBRID_ETHANOL = 18;
675         @AddedInOrBefore(majorVersion = 33)
676         public static final int HYBRID_DIESEL = 19;
677         @AddedInOrBefore(majorVersion = 33)
678         public static final int HYBRID_ELECTRIC = 20;
679         @AddedInOrBefore(majorVersion = 33)
680         public static final int HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION = 21;
681         @AddedInOrBefore(majorVersion = 33)
682         public static final int HYBRID_REGENERATIVE = 22;
683         @AddedInOrBefore(majorVersion = 33)
684         public static final int BIFUEL_RUNNING_DIESEL = 23;
685 
686         @Retention(RetentionPolicy.SOURCE)
687         @IntDef({
688             NOT_AVAILABLE,
689             GASOLINE,
690             METHANOL,
691             ETHANOL,
692             DIESEL,
693             LPG,
694             CNG,
695             PROPANE,
696             ELECTRIC,
697             BIFUEL_RUNNING_GASOLINE,
698             BIFUEL_RUNNING_METHANOL,
699             BIFUEL_RUNNING_ETHANOL,
700             BIFUEL_RUNNING_LPG,
701             BIFUEL_RUNNING_CNG,
702             BIFUEL_RUNNING_PROPANE,
703             BIFUEL_RUNNING_ELECTRIC,
704             BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION,
705             HYBRID_GASOLINE,
706             HYBRID_ETHANOL,
707             HYBRID_DIESEL,
708             HYBRID_ELECTRIC,
709             HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION,
710             HYBRID_REGENERATIVE,
711             BIFUEL_RUNNING_DIESEL
712         })
713         public @interface Type {}
714     }
715 
716     /**
717      * Represents the state of an ignition monitor on a vehicle.
718      */
719     public static final class IgnitionMonitor {
720         @AddedInOrBefore(majorVersion = 33)
721         public final boolean available;
722         @AddedInOrBefore(majorVersion = 33)
723         public final boolean incomplete;
724 
IgnitionMonitor(boolean available, boolean incomplete)725         IgnitionMonitor(boolean available, boolean incomplete) {
726             this.available = available;
727             this.incomplete = incomplete;
728         }
729 
730         /** @hide */
731         public static final class Decoder {
732             private final int mAvailableBitmask;
733             private final int mIncompleteBitmask;
734 
Decoder(int availableBitmask, int incompleteBitmask)735             Decoder(int availableBitmask, int incompleteBitmask) {
736                 mAvailableBitmask = availableBitmask;
737                 mIncompleteBitmask = incompleteBitmask;
738             }
739 
740             /**
741              * Returns the {@link IgnitionMonitor} associated with the value passed as parameter.
742              */
743             @AddedInOrBefore(majorVersion = 33)
fromValue(int value)744             public IgnitionMonitor fromValue(int value) {
745                 boolean available = (0 != (value & mAvailableBitmask));
746                 boolean incomplete = (0 != (value & mIncompleteBitmask));
747 
748                 return new IgnitionMonitor(available, incomplete);
749             }
750         }
751     }
752 
753     /**
754      * Contains information about ignition monitors common to all vehicle types.
755      */
756     public static class CommonIgnitionMonitors {
757         @AddedInOrBefore(majorVersion = 33)
758         public final IgnitionMonitor components;
759         @AddedInOrBefore(majorVersion = 33)
760         public final IgnitionMonitor fuelSystem;
761         @AddedInOrBefore(majorVersion = 33)
762         public final IgnitionMonitor misfire;
763 
764         /** @hide */
765         @AddedInOrBefore(majorVersion = 33)
766         public static final int COMPONENTS_AVAILABLE = 0x1 << 0;
767         /** @hide */
768         @AddedInOrBefore(majorVersion = 33)
769         public static final int COMPONENTS_INCOMPLETE = 0x1 << 1;
770 
771         /** @hide */
772         @AddedInOrBefore(majorVersion = 33)
773         public static final int FUEL_SYSTEM_AVAILABLE = 0x1 << 2;
774         /** @hide */
775         @AddedInOrBefore(majorVersion = 33)
776         public static final int FUEL_SYSTEM_INCOMPLETE = 0x1 << 3;
777 
778         /** @hide */
779         @AddedInOrBefore(majorVersion = 33)
780         public static final int MISFIRE_AVAILABLE = 0x1 << 4;
781         /** @hide */
782         @AddedInOrBefore(majorVersion = 33)
783         public static final int MISFIRE_INCOMPLETE = 0x1 << 5;
784 
785         static final IgnitionMonitor.Decoder COMPONENTS_DECODER =
786                 new IgnitionMonitor.Decoder(COMPONENTS_AVAILABLE, COMPONENTS_INCOMPLETE);
787 
788         static final IgnitionMonitor.Decoder FUEL_SYSTEM_DECODER =
789                 new IgnitionMonitor.Decoder(FUEL_SYSTEM_AVAILABLE, FUEL_SYSTEM_INCOMPLETE);
790 
791         static final IgnitionMonitor.Decoder MISFIRE_DECODER =
792                 new IgnitionMonitor.Decoder(MISFIRE_AVAILABLE, MISFIRE_INCOMPLETE);
793 
CommonIgnitionMonitors(int bitmask)794         CommonIgnitionMonitors(int bitmask) {
795             components = COMPONENTS_DECODER.fromValue(bitmask);
796             fuelSystem = FUEL_SYSTEM_DECODER.fromValue(bitmask);
797             misfire = MISFIRE_DECODER.fromValue(bitmask);
798         }
799 
800         /**
801          * Returns data about ignition monitors specific to spark vehicles, if this
802          * object represents ignition monitors for a spark vehicle.
803          * Returns null otherwise.
804          */
805         @AddedInOrBefore(majorVersion = 33)
asSparkIgnitionMonitors()806         public @Nullable SparkIgnitionMonitors asSparkIgnitionMonitors() {
807             if (this instanceof SparkIgnitionMonitors) return (SparkIgnitionMonitors) this;
808             return null;
809         }
810 
811         /**
812          * Returns data about ignition monitors specific to compression vehicles, if this
813          * object represents ignition monitors for a compression vehicle.
814          * Returns null otherwise.
815          */
816         @AddedInOrBefore(majorVersion = 33)
asCompressionIgnitionMonitors()817         public @Nullable CompressionIgnitionMonitors asCompressionIgnitionMonitors() {
818             if (this instanceof CompressionIgnitionMonitors) {
819                 return (CompressionIgnitionMonitors) this;
820             }
821             return null;
822         }
823     }
824 
825     /**
826      * Contains information about ignition monitors specific to spark vehicles.
827      */
828     public static final class SparkIgnitionMonitors extends CommonIgnitionMonitors {
829         @AddedInOrBefore(majorVersion = 33)
830         public final IgnitionMonitor EGR;
831         @AddedInOrBefore(majorVersion = 33)
832         public final IgnitionMonitor oxygenSensorHeater;
833         @AddedInOrBefore(majorVersion = 33)
834         public final IgnitionMonitor oxygenSensor;
835         @AddedInOrBefore(majorVersion = 33)
836         public final IgnitionMonitor ACRefrigerant;
837         @AddedInOrBefore(majorVersion = 33)
838         public final IgnitionMonitor secondaryAirSystem;
839         @AddedInOrBefore(majorVersion = 33)
840         public final IgnitionMonitor evaporativeSystem;
841         @AddedInOrBefore(majorVersion = 33)
842         public final IgnitionMonitor heatedCatalyst;
843         @AddedInOrBefore(majorVersion = 33)
844         public final IgnitionMonitor catalyst;
845 
846         /** @hide */
847         @AddedInOrBefore(majorVersion = 33)
848         public static final int EGR_AVAILABLE = 0x1 << 6;
849         /** @hide */
850         @AddedInOrBefore(majorVersion = 33)
851         public static final int EGR_INCOMPLETE = 0x1 << 7;
852 
853         /** @hide */
854         @AddedInOrBefore(majorVersion = 33)
855         public static final int OXYGEN_SENSOR_HEATER_AVAILABLE = 0x1 << 8;
856         /** @hide */
857         @AddedInOrBefore(majorVersion = 33)
858         public static final int OXYGEN_SENSOR_HEATER_INCOMPLETE = 0x1 << 9;
859 
860         /** @hide */
861         @AddedInOrBefore(majorVersion = 33)
862         public static final int OXYGEN_SENSOR_AVAILABLE = 0x1 << 10;
863         /** @hide */
864         @AddedInOrBefore(majorVersion = 33)
865         public static final int OXYGEN_SENSOR_INCOMPLETE = 0x1 << 11;
866 
867         /** @hide */
868         @AddedInOrBefore(majorVersion = 33)
869         public static final int AC_REFRIGERANT_AVAILABLE = 0x1 << 12;
870         /** @hide */
871         @AddedInOrBefore(majorVersion = 33)
872         public static final int AC_REFRIGERANT_INCOMPLETE = 0x1 << 13;
873 
874         /** @hide */
875         @AddedInOrBefore(majorVersion = 33)
876         public static final int SECONDARY_AIR_SYSTEM_AVAILABLE = 0x1 << 14;
877         /** @hide */
878         @AddedInOrBefore(majorVersion = 33)
879         public static final int SECONDARY_AIR_SYSTEM_INCOMPLETE = 0x1 << 15;
880 
881         /** @hide */
882         @AddedInOrBefore(majorVersion = 33)
883         public static final int EVAPORATIVE_SYSTEM_AVAILABLE = 0x1 << 16;
884         /** @hide */
885         @AddedInOrBefore(majorVersion = 33)
886         public static final int EVAPORATIVE_SYSTEM_INCOMPLETE = 0x1 << 17;
887 
888         /** @hide */
889         @AddedInOrBefore(majorVersion = 33)
890         public static final int HEATED_CATALYST_AVAILABLE = 0x1 << 18;
891         /** @hide */
892         @AddedInOrBefore(majorVersion = 33)
893         public static final int HEATED_CATALYST_INCOMPLETE = 0x1 << 19;
894 
895         /** @hide */
896         @AddedInOrBefore(majorVersion = 33)
897         public static final int CATALYST_AVAILABLE = 0x1 << 20;
898         /** @hide */
899         @AddedInOrBefore(majorVersion = 33)
900         public static final int CATALYST_INCOMPLETE = 0x1 << 21;
901 
902         static final IgnitionMonitor.Decoder EGR_DECODER =
903                 new IgnitionMonitor.Decoder(EGR_AVAILABLE, EGR_INCOMPLETE);
904 
905         static final IgnitionMonitor.Decoder OXYGEN_SENSOR_HEATER_DECODER =
906                 new IgnitionMonitor.Decoder(OXYGEN_SENSOR_HEATER_AVAILABLE,
907                         OXYGEN_SENSOR_HEATER_INCOMPLETE);
908 
909         static final IgnitionMonitor.Decoder OXYGEN_SENSOR_DECODER =
910                 new IgnitionMonitor.Decoder(OXYGEN_SENSOR_AVAILABLE, OXYGEN_SENSOR_INCOMPLETE);
911 
912         static final IgnitionMonitor.Decoder AC_REFRIGERANT_DECODER =
913                 new IgnitionMonitor.Decoder(AC_REFRIGERANT_AVAILABLE,
914                         AC_REFRIGERANT_INCOMPLETE);
915 
916         static final IgnitionMonitor.Decoder SECONDARY_AIR_SYSTEM_DECODER =
917                 new IgnitionMonitor.Decoder(SECONDARY_AIR_SYSTEM_AVAILABLE,
918                         SECONDARY_AIR_SYSTEM_INCOMPLETE);
919 
920         static final IgnitionMonitor.Decoder EVAPORATIVE_SYSTEM_DECODER =
921                 new IgnitionMonitor.Decoder(EVAPORATIVE_SYSTEM_AVAILABLE,
922                         EVAPORATIVE_SYSTEM_INCOMPLETE);
923 
924         static final IgnitionMonitor.Decoder HEATED_CATALYST_DECODER =
925                 new IgnitionMonitor.Decoder(HEATED_CATALYST_AVAILABLE,
926                         HEATED_CATALYST_INCOMPLETE);
927 
928         static final IgnitionMonitor.Decoder CATALYST_DECODER =
929                 new IgnitionMonitor.Decoder(CATALYST_AVAILABLE, CATALYST_INCOMPLETE);
930 
SparkIgnitionMonitors(int bitmask)931         SparkIgnitionMonitors(int bitmask) {
932             super(bitmask);
933             EGR = EGR_DECODER.fromValue(bitmask);
934             oxygenSensorHeater = OXYGEN_SENSOR_HEATER_DECODER.fromValue(bitmask);
935             oxygenSensor = OXYGEN_SENSOR_DECODER.fromValue(bitmask);
936             ACRefrigerant = AC_REFRIGERANT_DECODER.fromValue(bitmask);
937             secondaryAirSystem = SECONDARY_AIR_SYSTEM_DECODER.fromValue(bitmask);
938             evaporativeSystem = EVAPORATIVE_SYSTEM_DECODER.fromValue(bitmask);
939             heatedCatalyst = HEATED_CATALYST_DECODER.fromValue(bitmask);
940             catalyst = CATALYST_DECODER.fromValue(bitmask);
941         }
942     }
943 
944     /**
945      * Contains information about ignition monitors specific to compression vehicles.
946      */
947     public static final class CompressionIgnitionMonitors extends CommonIgnitionMonitors {
948         @AddedInOrBefore(majorVersion = 33)
949         public final IgnitionMonitor EGROrVVT;
950         @AddedInOrBefore(majorVersion = 33)
951         public final IgnitionMonitor PMFilter;
952         @AddedInOrBefore(majorVersion = 33)
953         public final IgnitionMonitor exhaustGasSensor;
954         @AddedInOrBefore(majorVersion = 33)
955         public final IgnitionMonitor boostPressure;
956         @AddedInOrBefore(majorVersion = 33)
957         public final IgnitionMonitor NOxSCR;
958         @AddedInOrBefore(majorVersion = 33)
959         public final IgnitionMonitor NMHCCatalyst;
960 
961         /** @hide */
962         @AddedInOrBefore(majorVersion = 33)
963         public static final int EGR_OR_VVT_AVAILABLE = 0x1 << 6;
964         /** @hide */
965         @AddedInOrBefore(majorVersion = 33)
966         public static final int EGR_OR_VVT_INCOMPLETE = 0x1 << 7;
967 
968         /** @hide */
969         @AddedInOrBefore(majorVersion = 33)
970         public static final int PM_FILTER_AVAILABLE = 0x1 << 8;
971         /** @hide */
972         @AddedInOrBefore(majorVersion = 33)
973         public static final int PM_FILTER_INCOMPLETE = 0x1 << 9;
974 
975         /** @hide */
976         @AddedInOrBefore(majorVersion = 33)
977         public static final int EXHAUST_GAS_SENSOR_AVAILABLE = 0x1 << 10;
978         /** @hide */
979         @AddedInOrBefore(majorVersion = 33)
980         public static final int EXHAUST_GAS_SENSOR_INCOMPLETE = 0x1 << 11;
981 
982         /** @hide */
983         @AddedInOrBefore(majorVersion = 33)
984         public static final int BOOST_PRESSURE_AVAILABLE = 0x1 << 12;
985         /** @hide */
986         @AddedInOrBefore(majorVersion = 33)
987         public static final int BOOST_PRESSURE_INCOMPLETE = 0x1 << 13;
988 
989         /** @hide */
990         @AddedInOrBefore(majorVersion = 33)
991         public static final int NOx_SCR_AVAILABLE = 0x1 << 14;
992         /** @hide */
993         @AddedInOrBefore(majorVersion = 33)
994         public static final int NOx_SCR_INCOMPLETE = 0x1 << 15;
995 
996         /** @hide */
997         @AddedInOrBefore(majorVersion = 33)
998         public static final int NMHC_CATALYST_AVAILABLE = 0x1 << 16;
999         /** @hide */
1000         @AddedInOrBefore(majorVersion = 33)
1001         public static final int NMHC_CATALYST_INCOMPLETE = 0x1 << 17;
1002 
1003         static final IgnitionMonitor.Decoder EGR_OR_VVT_DECODER =
1004                 new IgnitionMonitor.Decoder(EGR_OR_VVT_AVAILABLE, EGR_OR_VVT_INCOMPLETE);
1005 
1006         static final IgnitionMonitor.Decoder PM_FILTER_DECODER =
1007                 new IgnitionMonitor.Decoder(PM_FILTER_AVAILABLE, PM_FILTER_INCOMPLETE);
1008 
1009         static final IgnitionMonitor.Decoder EXHAUST_GAS_SENSOR_DECODER =
1010                 new IgnitionMonitor.Decoder(EXHAUST_GAS_SENSOR_AVAILABLE,
1011                         EXHAUST_GAS_SENSOR_INCOMPLETE);
1012 
1013         static final IgnitionMonitor.Decoder BOOST_PRESSURE_DECODER =
1014                 new IgnitionMonitor.Decoder(BOOST_PRESSURE_AVAILABLE,
1015                         BOOST_PRESSURE_INCOMPLETE);
1016 
1017         static final IgnitionMonitor.Decoder NOx_SCR_DECODER =
1018                 new IgnitionMonitor.Decoder(NOx_SCR_AVAILABLE, NOx_SCR_INCOMPLETE);
1019 
1020         static final IgnitionMonitor.Decoder NMHC_CATALYST_DECODER =
1021                 new IgnitionMonitor.Decoder(NMHC_CATALYST_AVAILABLE, NMHC_CATALYST_INCOMPLETE);
1022 
CompressionIgnitionMonitors(int bitmask)1023         CompressionIgnitionMonitors(int bitmask) {
1024             super(bitmask);
1025             EGROrVVT = EGR_OR_VVT_DECODER.fromValue(bitmask);
1026             PMFilter = PM_FILTER_DECODER.fromValue(bitmask);
1027             exhaustGasSensor = EXHAUST_GAS_SENSOR_DECODER.fromValue(bitmask);
1028             boostPressure = BOOST_PRESSURE_DECODER.fromValue(bitmask);
1029             NOxSCR = NOx_SCR_DECODER.fromValue(bitmask);
1030             NMHCCatalyst = NMHC_CATALYST_DECODER.fromValue(bitmask);
1031         }
1032     }
1033 
1034     /**
1035      * Returns the state of the fuel system, if present in this frame.
1036      * Returns null otherwise.
1037      */
1038     @AddedInOrBefore(majorVersion = 33)
getFuelSystemStatus()1039     public @Nullable @FuelSystemStatus.Status Integer getFuelSystemStatus() {
1040         return getSystemIntegerSensor(android.car.diagnostic.IntegerSensorIndex.FUEL_SYSTEM_STATUS);
1041     }
1042 
1043     /**
1044      * Returns the state of the secondary air system, if present in this frame.
1045      * Returns null otherwise.
1046      */
1047     @AddedInOrBefore(majorVersion = 33)
getSecondaryAirStatus()1048     public @Nullable @SecondaryAirStatus.Status Integer getSecondaryAirStatus() {
1049         return getSystemIntegerSensor(
1050             android.car.diagnostic.IntegerSensorIndex.COMMANDED_SECONDARY_AIR_STATUS);
1051     }
1052 
1053     /**
1054      * Returns data about the ignition monitors, if present in this frame.
1055      * Returns null otherwise.
1056      */
1057     @AddedInOrBefore(majorVersion = 33)
getIgnitionMonitors()1058     public @Nullable CommonIgnitionMonitors getIgnitionMonitors() {
1059         Integer ignitionMonitorsType =
1060                 getSystemIntegerSensor(
1061                     android.car.diagnostic.IntegerSensorIndex.IGNITION_MONITORS_SUPPORTED);
1062         Integer ignitionMonitorsBitmask =
1063                 getSystemIntegerSensor(
1064                     android.car.diagnostic.IntegerSensorIndex.IGNITION_SPECIFIC_MONITORS);
1065         if (null == ignitionMonitorsType) return null;
1066         if (null == ignitionMonitorsBitmask) return null;
1067         switch (ignitionMonitorsType) {
1068             case 0:
1069                 return new SparkIgnitionMonitors(ignitionMonitorsBitmask);
1070             case 1:
1071                 return new CompressionIgnitionMonitors(ignitionMonitorsBitmask);
1072             default:
1073                 return null;
1074         }
1075     }
1076 
1077     /**
1078      * Returns the fuel type, if present in this frame.
1079      * Returns null otherwise.
1080      */
1081     @AddedInOrBefore(majorVersion = 33)
getFuelType()1082     public @Nullable @FuelType.Type Integer getFuelType() {
1083         return getSystemIntegerSensor(android.car.diagnostic.IntegerSensorIndex.FUEL_TYPE);
1084     }
1085 }
1086