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