summaryrefslogtreecommitdiffstats
blob: 86af0637a7f2f82159b6c1759d3025d0d1175ae5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.car.hardware;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * A CarSensorEvent object corresponds to a single sensor event coming from the car. The sensor
 * data is stored in a sensor-type specific format in the object's float and byte arrays.
 *
 * To aid unmarshalling the object's data arrays, this class provides static nested classes and
 * conversion methods, for example {@link EnvironmentData} and {@link #getEnvironmentData}. The
 * conversion methods each have an optional data parameter which, if not null, will be used and
 * returned. This parameter should be used to avoid unnecessary object churn whenever possible.
 * Additionally, calling a conversion method on a CarSensorEvent object with an inappropriate type
 * will result in an {@code UnsupportedOperationException} being thrown.
 */
public class CarSensorEvent implements Parcelable {

    /**
     *  GEAR_* represents meaning of intValues[0] for {@link CarSensorManager#SENSOR_TYPE_GEAR}
     *  sensor type.
     *  GEAR_NEUTRAL means transmission gear is in neutral state, and the car may be moving.
     */
    public static final int GEAR_NEUTRAL    = 0x0001;
    /**
     * intValues[0] from 1 to 99 represents transmission gear number for moving forward.
     * GEAR_FIRST is for gear number 1.
     */
    public static final int GEAR_FIRST      = 0x0010;
    /** Gear number 2. */
    public static final int GEAR_SECOND     = 0x0020;
    /** Gear number 3. */
    public static final int GEAR_THIRD      = 0x0040;
    /** Gear number 4. */
    public static final int GEAR_FOURTH     = 0x0080;
    /** Gear number 5. */
    public static final int GEAR_FIFTH      = 0x0100;
    /** Gear number 6. */
    public static final int GEAR_SIXTH      = 0x0200;
    /** Gear number 7. */
    public static final int GEAR_SEVENTH    = 0x0400;
    /** Gear number 8. */
    public static final int GEAR_EIGHTH     = 0x0800;
    /** Gear number 9. */
    public static final int GEAR_NINTH      = 0x1000;
    /** Gear number 10. */
    public static final int GEAR_TENTH      = 0x2000;
    /**
     * This is for transmission without specific gear number for moving forward like CVT. It tells
     * that car is in a transmission state to move it forward.
     */
    public static final int GEAR_DRIVE      = 0x0008;
    /** Gear in parking state */
    public static final int GEAR_PARK       = 0x0004;
    /** Gear in reverse */
    public static final int GEAR_REVERSE    = 0x0002;

    /**
     * Ignition state is unknown.
     *
     * The constants that starts with IGNITION_STATE_ represent values for
     * {@link CarSensorManager#SENSOR_TYPE_IGNITION_STATE} sensor.
     * */
    public static final int IGNITION_STATE_UNDEFINED = 0;
    /**
     * Steering wheel is locked.
     */
    public static final int IGNITION_STATE_LOCK = 1;
    /** Typically engine is off, but steering wheel is unlocked. */
    public static final int IGNITION_STATE_OFF = 2;
    /** Accessory is turned off, but engine is not running yet (for EV car is not ready to move). */
    public static final int IGNITION_STATE_ACC = 3;
    /** In this state engine typically is running (for EV, car is ready to move). */
    public static final int IGNITION_STATE_ON = 4;
    /** In this state engine is typically starting (cranking). */
    public static final int IGNITION_STATE_START = 5;

    /**
     * Index for {@link CarSensorManager#SENSOR_TYPE_ENVIRONMENT} in floatValues.
     * Temperature in Celsius degrees.
     */
    public static final int INDEX_ENVIRONMENT_TEMPERATURE = 0;
    /**
     * Index for {@link CarSensorManager#SENSOR_TYPE_ENVIRONMENT} in floatValues.
     * Pressure in kPa.
     */
    public static final int INDEX_ENVIRONMENT_PRESSURE = 1;
    /**
     * Index for {@link CarSensorManager#SENSOR_TYPE_WHEEL_TICK_DISTANCE} in longValues. RESET_COUNT
     * is incremented whenever the HAL detects that a sensor reset has occurred.  It represents to
     * the upper layer that the WHEEL_DISTANCE values will not be contiguous with other values
     * reported with a different RESET_COUNT.
     */
    public static final int INDEX_WHEEL_DISTANCE_RESET_COUNT = 0;
    public static final int INDEX_WHEEL_DISTANCE_FRONT_LEFT = 1;
    public static final int INDEX_WHEEL_DISTANCE_FRONT_RIGHT = 2;
    public static final int INDEX_WHEEL_DISTANCE_REAR_RIGHT = 3;
    public static final int INDEX_WHEEL_DISTANCE_REAR_LEFT = 4;

    private static final long MILLI_IN_NANOS = 1000000L;

    /** Sensor type for this event like {@link CarSensorManager#SENSOR_TYPE_CAR_SPEED}. */
    public int sensorType;

    /**
     * When this data was received from car. It is elapsed real-time of data reception from car in
     * nanoseconds since system boot.
     */
    public long timestamp;
    /**
     * array holding float type of sensor data. If the sensor has single value, only floatValues[0]
     * should be used. */
    public final float[] floatValues;
    /** array holding int type of sensor data */
    public final int[] intValues;
    /** array holding long int type of sensor data */
    public final long[] longValues;

    /** @hide */
    public CarSensorEvent(Parcel in) {
        sensorType = in.readInt();
        timestamp = in.readLong();
        int len = in.readInt();
        floatValues = new float[len];
        in.readFloatArray(floatValues);
        len = in.readInt();
        intValues = new int[len];
        in.readIntArray(intValues);
        // version 1 up to here
        len = in.readInt();
        longValues = new long[len];
        in.readLongArray(longValues);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(sensorType);
        dest.writeLong(timestamp);
        dest.writeInt(floatValues.length);
        dest.writeFloatArray(floatValues);
        dest.writeInt(intValues.length);
        dest.writeIntArray(intValues);
        dest.writeInt(longValues.length);
        dest.writeLongArray(longValues);
    }

    public static final Parcelable.Creator<CarSensorEvent> CREATOR
    = new Parcelable.Creator<CarSensorEvent>() {
        public CarSensorEvent createFromParcel(Parcel in) {
            return new CarSensorEvent(in);
        }

        public CarSensorEvent[] newArray(int size) {
            return new CarSensorEvent[size];
        }
    };

    /** @hide */
    public CarSensorEvent(int sensorType, long timestamp, int floatValueSize, int intValueSize,
                          int longValueSize) {
        this.sensorType = sensorType;
        this.timestamp = timestamp;
        floatValues = new float[floatValueSize];
        intValues = new int[intValueSize];
        longValues = new long[longValueSize];
    }

    /** @hide */
    CarSensorEvent(int sensorType, long timestamp, float[] floatValues, int[] intValues,
                   long[] longValues) {
        this.sensorType = sensorType;
        this.timestamp = timestamp;
        this.floatValues = floatValues;
        this.intValues = intValues;
        this.longValues = longValues;
    }

    private void checkType(int type) {
        if (sensorType == type) {
            return;
        }
        throw new UnsupportedOperationException(String.format(
                "Invalid sensor type: expected %d, got %d", type, sensorType));
    }

    public static class EnvironmentData {
        public long timestamp;
        /** If unsupported by the car, this value is NaN. */
        public float temperature;
        /** If unsupported by the car, this value is NaN. */
        public float pressure;

        /** @hide */
        private EnvironmentData() {};
    }

    /**
     * Convenience method for obtaining an {@link EnvironmentData} object from a CarSensorEvent
     * object with type {@link CarSensorManager#SENSOR_TYPE_ENVIRONMENT}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return an EnvironmentData object corresponding to the data contained in the CarSensorEvent.
     * @hide
     */
    public EnvironmentData getEnvironmentData(EnvironmentData data) {
        checkType(CarSensorManager.SENSOR_TYPE_ENVIRONMENT);
        if (data == null) {
            data = new EnvironmentData();
        }
        data.timestamp = timestamp;
        data.temperature = floatValues[INDEX_ENVIRONMENT_TEMPERATURE];
        data.pressure = floatValues[INDEX_ENVIRONMENT_PRESSURE];
        return data;
    }

    /** @hide */
    public static class NightData {
        public long timestamp;
        public boolean isNightMode;

        /** @hide */
        private NightData() {};
    }

    /**
     * Convenience method for obtaining a {@link NightData} object from a CarSensorEvent
     * object with type {@link CarSensorManager#SENSOR_TYPE_NIGHT}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a NightData object corresponding to the data contained in the CarSensorEvent.
     * @hide
     */
    public NightData getNightData(NightData data) {
        checkType(CarSensorManager.SENSOR_TYPE_NIGHT);
        if (data == null) {
            data = new NightData();
        }
        data.timestamp = timestamp;
        data.isNightMode = intValues[0] == 1;
        return data;
    }

    /** @hide */
    public static class GearData {
        public long timestamp;
        public int gear;

        /** @hide */
        private GearData() {};
    }

    /**
     * Convenience method for obtaining a {@link GearData} object from a CarSensorEvent
     * object with type {@link CarSensorManager#SENSOR_TYPE_GEAR}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a GearData object corresponding to the data contained in the CarSensorEvent.
     * @hide
     */
    public GearData getGearData(GearData data) {
        checkType(CarSensorManager.SENSOR_TYPE_GEAR);
        if (data == null) {
            data = new GearData();
        }
        data.timestamp = timestamp;
        data.gear = intValues[0];
        return data;
    }

    /** @hide */
    public static class ParkingBrakeData {
        public long timestamp;
        public boolean isEngaged;

        /** @hide */
        private ParkingBrakeData() {}
    }

    /**
     * Convenience method for obtaining a {@link ParkingBrakeData} object from a CarSensorEvent
     * object with type {@link CarSensorManager#SENSOR_TYPE_PARKING_BRAKE}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a ParkingBreakData object corresponding to the data contained in the CarSensorEvent.
     * @hide
     */
    public ParkingBrakeData getParkingBrakeData(ParkingBrakeData data) {
        checkType(CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
        if (data == null) {
            data = new ParkingBrakeData();
        }
        data.timestamp = timestamp;
        data.isEngaged = intValues[0] == 1;
        return data;
    }

    /** @hide */
    public static class FuelLevelData {
        public long timestamp;
        /** Fuel level in milliliters.  Negative values indicate this property is unsupported. */
        public float level;

        /** @hide */
        private FuelLevelData() {};
    }

    /**
     * Convenience method for obtaining a {@link FuelLevelData} object from a CarSensorEvent
     * object with type {@link CarSensorManager#SENSOR_TYPE_FUEL_LEVEL}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a FuelLevel object corresponding to the data contained in the CarSensorEvent.
     * @hide
     */
    public FuelLevelData getFuelLevelData(FuelLevelData data) {
        checkType(CarSensorManager.SENSOR_TYPE_FUEL_LEVEL);
        if (data == null) {
            data = new FuelLevelData();
        }
        data.timestamp = timestamp;
        if (floatValues == null) {
            data.level = -1.0f;
        } else {
            if (floatValues[0] < 0) {
                data.level = -1.0f;
            } else {
                data.level = floatValues[0];
            }
        }
        return data;
    }

    /** @hide */
    public static class OdometerData {
        public long timestamp;
        public float kms;

        /** @hide */
        private OdometerData() {};
    }

    /**
     * Convenience method for obtaining an {@link OdometerData} object from a CarSensorEvent
     * object with type {@link CarSensorManager#SENSOR_TYPE_ODOMETER}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return an OdometerData object corresponding to the data contained in the CarSensorEvent.
     * @hide
     */
    public OdometerData getOdometerData(OdometerData data) {
        checkType(CarSensorManager.SENSOR_TYPE_ODOMETER);
        if (data == null) {
            data = new OdometerData();
        }
        data.timestamp = timestamp;
        data.kms = floatValues[0];
        return data;
    }

    /** @hide */
    public static class RpmData {
        public long timestamp;
        public float rpm;

        /** @hide */
        private RpmData() {};
    }

    /**
     * Convenience method for obtaining a {@link RpmData} object from a CarSensorEvent
     * object with type {@link CarSensorManager#SENSOR_TYPE_RPM}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a RpmData object corresponding to the data contained in the CarSensorEvent.
     * @hide
     */
    public RpmData getRpmData(RpmData data) {
        checkType(CarSensorManager.SENSOR_TYPE_RPM);
        if (data == null) {
            data = new RpmData();
        }
        data.timestamp = timestamp;
        data.rpm = floatValues[0];
        return data;
    }

    /** @hide */
    public static class CarSpeedData {
        public long timestamp;
        public float carSpeed;

        /** @hide */
        private CarSpeedData() {};
    }

    /**
     * Convenience method for obtaining a {@link CarSpeedData} object from a CarSensorEvent
     * object with type {@link CarSensorManager#SENSOR_TYPE_CAR_SPEED}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a CarSpeedData object corresponding to the data contained in the CarSensorEvent.
     * @hide
     */
    public CarSpeedData getCarSpeedData(CarSpeedData data) {
        checkType(CarSensorManager.SENSOR_TYPE_CAR_SPEED);
        if (data == null) {
            data = new CarSpeedData();
        }
        data.timestamp = timestamp;
        data.carSpeed = floatValues[0];
        return data;
    }

    /** @hide */
    public static class CarWheelTickDistanceData {
        public long timestamp;
        public long sensorResetCount;
        public long frontLeftWheelDistanceMm;
        public long frontRightWheelDistanceMm;
        public long rearRightWheelDistanceMm;
        public long rearLeftWheelDistanceMm;

        /** @hide */
        private CarWheelTickDistanceData() {};
    }

    /**
     * Convenience method for obtaining a {@link CarWheelTickDistanceData} object from a
     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_WHEEL_TICK_DISTANCE}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return CarWheelTickDistanceData object corresponding to data contained in the CarSensorEvent
     * @hide
     */
    public CarWheelTickDistanceData getCarWheelTickDistanceData(CarWheelTickDistanceData data) {
        checkType(CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE);
        if (data == null) {
            data = new CarWheelTickDistanceData();
        }
        data.timestamp = timestamp;
        data.sensorResetCount = longValues[INDEX_WHEEL_DISTANCE_RESET_COUNT];
        data.frontLeftWheelDistanceMm = longValues[INDEX_WHEEL_DISTANCE_FRONT_LEFT];
        data.frontRightWheelDistanceMm = longValues[INDEX_WHEEL_DISTANCE_FRONT_RIGHT];
        data.rearRightWheelDistanceMm = longValues[INDEX_WHEEL_DISTANCE_REAR_RIGHT];
        data.rearLeftWheelDistanceMm = longValues[INDEX_WHEEL_DISTANCE_REAR_LEFT];
        return data;
    }

    /** @hide */
    public static class CarAbsActiveData {
        public long timestamp;
        public boolean absIsActive;

        /** @hide */
        private CarAbsActiveData() {};
    }

    /**
     * Convenience method for obtaining a {@link CarAbsActiveData} object from a CarSensorEvent
     * object with type {@link CarSensorManager#SENSOR_TYPE_ABS_ACTIVE}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a CarAbsActiveData object corresponding to data contained in the CarSensorEvent.
     * @hide
     */
    public CarAbsActiveData getCarAbsActiveData(CarAbsActiveData data) {
        checkType(CarSensorManager.SENSOR_TYPE_ABS_ACTIVE);
        if (data == null) {
            data = new CarAbsActiveData();
        }
        data.timestamp = timestamp;
        data.absIsActive = intValues[0] == 1;
        return data;
    }

    /** @hide */
    public static class CarTractionControlActiveData {
        public long timestamp;
        public boolean tractionControlIsActive;

        /** @hide */
        private CarTractionControlActiveData() {};
    }

    /**
     * Convenience method for obtaining a {@link CarTractionControlActiveData} object from a
     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_TRACTION_CONTROL_ACTIVE}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a CarTractionControlActiveData object corresponding to data contained in the
     *     CarSensorEvent.
     * @hide
     */
    public CarTractionControlActiveData getCarTractionControlActiveData(
            CarTractionControlActiveData data) {
        checkType(CarSensorManager.SENSOR_TYPE_TRACTION_CONTROL_ACTIVE);
        if (data == null) {
            data = new CarTractionControlActiveData();
        }
        data.timestamp = timestamp;
        data.tractionControlIsActive = intValues[0] == 1;
        return data;
    }

    /** @hide */
    public static class CarFuelDoorOpenData {
        public long timestamp;
        public boolean fuelDoorIsOpen;

        /** @hide */
        private CarFuelDoorOpenData() {};
    }

    /**
     * Convenience method for obtaining a {@link CarFuelDoorOpenData} object from a
     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_FUEL_DOOR_OPEN}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a CarFuelDoorOpenData object corresponding to data contained in the
     *     CarSensorEvent.
     * @hide
     */
    public CarFuelDoorOpenData getCarFuelDoorOpenData(
        CarFuelDoorOpenData data) {
        checkType(CarSensorManager.SENSOR_TYPE_FUEL_DOOR_OPEN);
        if (data == null) {
            data = new CarFuelDoorOpenData();
        }
        data.timestamp = timestamp;
        data.fuelDoorIsOpen = intValues[0] == 1;
        return data;
    }

    /** @hide */
    public static class CarEvBatteryLevelData {
        public long timestamp;
        /** Battery Level in Watt-hours */
        public float evBatteryLevel;

        /** @hide */
        private CarEvBatteryLevelData() {};
    }

    /**
     * Convenience method for obtaining a {@link CarEvBatteryLevelData} object from a
     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_BATTERY_LEVEL}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a CarEvBatteryLevelData object corresponding to data contained in the
     *     CarSensorEvent.
     * @hide
     */
    public CarEvBatteryLevelData getCarEvBatteryLevelData(
        CarEvBatteryLevelData data) {
        checkType(CarSensorManager.SENSOR_TYPE_EV_BATTERY_LEVEL);
        if (data == null) {
            data = new CarEvBatteryLevelData();
        }
        data.timestamp = timestamp;
        if (floatValues == null) {
            data.evBatteryLevel = -1.0f;
        } else {
            if (floatValues[0] < 0) {
                data.evBatteryLevel = -1.0f;
            } else {
                data.evBatteryLevel = floatValues[0];
            }
        }
        return data;
    }

    /** @hide */
    public static class CarEvChargePortOpenData {
        public long timestamp;
        public boolean evChargePortIsOpen;

        /** @hide */
        private CarEvChargePortOpenData() {};
    }

    /**
     * Convenience method for obtaining a {@link CarEvChargePortOpenData} object from a
     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_CHARGE_PORT_OPEN}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a CarEvChargePortOpenData object corresponding to data contained in the
     *     CarSensorEvent.
     * @hide
     */
    public CarEvChargePortOpenData getCarEvChargePortOpenData(
        CarEvChargePortOpenData data) {
        checkType(CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_OPEN);
        if (data == null) {
            data = new CarEvChargePortOpenData();
        }
        data.timestamp = timestamp;
        data.evChargePortIsOpen = intValues[0] == 1;
        return data;
    }

    /** @hide */
    public static class CarEvChargePortConnectedData {
        public long timestamp;
        public boolean evChargePortIsConnected;

        /** @hide */
        private CarEvChargePortConnectedData() {};
    }

    /**
     * Convenience method for obtaining a {@link CarEvChargePortConnectedData} object from a
     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a CarEvChargePortConnectedData object corresponding to data contained in the
     *     CarSensorEvent.
     * @hide
     */
    public CarEvChargePortConnectedData getCarEvChargePortConnectedData(
        CarEvChargePortConnectedData data) {
        checkType(CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED);
        if (data == null) {
            data = new CarEvChargePortConnectedData();
        }
        data.timestamp = timestamp;
        data.evChargePortIsConnected = intValues[0] == 1;
        return data;
    }

    /** @hide */
    public static class CarEvBatteryChargeRateData {
        public long timestamp;
        /** EV battery charging rate in mW.
         * Positive values indicates battery being charged.  Negative values indicate discharge */
        public float evChargeRate;

        /** @hide */
        private CarEvBatteryChargeRateData() {};
    }

    /**
     * Convenience method for obtaining a {@link CarEvBatteryChargeRateData} object from a
     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_EV_BATTERY_CHARGE_RATE}.
     *
     * @param data an optional output parameter which, if non-null, will be used by this method
     *     instead of a newly created object.
     * @return a CarEvBatteryChargeRateData object corresponding to data contained in the
     *     CarSensorEvent.
     * @hide
     */
    public CarEvBatteryChargeRateData getCarEvBatteryChargeRateData(
        CarEvBatteryChargeRateData data) {
        checkType(CarSensorManager.SENSOR_TYPE_EV_BATTERY_CHARGE_RATE);
        if (data == null) {
            data = new CarEvBatteryChargeRateData();
        }
        data.timestamp = timestamp;
        data.evChargeRate = floatValues[0];
        return data;
    }

    /** @hide */
    public static class CarEngineOilLevelData {
        public long timestamp;
        public int engineOilLevel;

        /** @hide */
        private CarEngineOilLevelData() {};
    }

    /**
     * Convenience method for obtaining a {@link CarEngineOilLevelData} object from a
     * CarSensorEvent object with type {@link CarSensorManager#SENSOR_TYPE_ENGINE_OIL_LEVEL}.
     *
     * @param data an optional output parameter, which, if non-null, will be used by this method
     *      instead of a newly created object.
     * @return a CarEngineOilLEvelData object corresponding to data contained in the CarSensorEvent.
     * @hide
     */
    public CarEngineOilLevelData getCarEngineOilLevelData(CarEngineOilLevelData data) {
        checkType(CarSensorManager.SENSOR_TYPE_ENGINE_OIL_LEVEL);
        if (data == null) {
            data = new CarEngineOilLevelData();
        }
        data.timestamp = timestamp;
        data.engineOilLevel = intValues[0];
        return data;
    }

    /** @hide */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getName() + "[");
        sb.append("type:" + Integer.toHexString(sensorType));
        if (floatValues != null && floatValues.length > 0) {
            sb.append(" float values:");
            for (float v: floatValues) {
                sb.append(" " + v);
            }
        }
        if (intValues != null && intValues.length > 0) {
            sb.append(" int values:");
            for (int v: intValues) {
                sb.append(" " + v);
            }
        }
        if (longValues != null && longValues.length > 0) {
            sb.append(" long values:");
            for (long v: longValues) {
                sb.append(" " + v);
            }
        }
        sb.append("]");
        return sb.toString();
    }
}