/*
* Copyright (C) 2021 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 androidx.health.services.client.data
import android.util.Log
import androidx.health.services.client.data.DataType.Companion.DISTANCE
import androidx.health.services.client.data.DataType.TimeType
import androidx.health.services.client.proto.DataProto
import androidx.health.services.client.proto.DataProto.DataType.TimeType.TIME_TYPE_INTERVAL
import androidx.health.services.client.proto.DataProto.DataType.TimeType.TIME_TYPE_SAMPLE
import androidx.health.services.client.proto.DataProto.DataType.TimeType.TIME_TYPE_UNKNOWN
import com.google.protobuf.ByteString
/**
* [DataType] that represents a granular, non-aggregated point in time. This will map to
* [IntervalDataPoint]s and [SampleDataPoint]s.
*/
class DeltaDataType<T : Any, D : DataPoint<T>>(
name: String,
timeType: TimeType,
valueClass: Class<T>
) : DataType<T, D>(name, timeType, valueClass, isAggregate = false)
/**
* [DataType] that represents aggregated data. This will map to [CumulativeDataPoint]s and
* [StatisticalDataPoint]s.
*/
class AggregateDataType<T : Number, D : DataPoint<T>>(
name: String,
timeType: TimeType,
valueClass: Class<T>,
) : DataType<T, D>(name, timeType, valueClass, isAggregate = true)
/**
* A data type is a representation of health data managed by Health Services.
*
* A [DataType] specifies the type of the values inside of a [DataPoint]. Health Services defines
* data types for instantaneous observations (Samples / [SampleDataPoint], e.g. heart rate) and data
* types for a change between readings (Intervals / [IntervalDataPoint], e.g. distance).
*
* Health services also allows specifying aggregated versions of many data types, which will allow
* the developer to get e.g. a running total of intervals ([CumulativeDataPoint]) or statistics like
* min/max/average on samples ([StatisticalDataPoint]).
*
* Note: the data type defines only the representation and format of the data, and not how it's
* being collected, the sensor being used, or the parameters of the collection. As an example,
* [DISTANCE] may come from GPS location if available, or steps if not available.
*/
@Suppress("ParcelCreator")
abstract class DataType<T : Any, D : DataPoint<T>>(
/** Returns the name of this [DataType], e.g. `"Steps"`. */
val name: String,
/** Returns the [TimeType] of this [DataType]. */
internal val timeType: TimeType,
/** Returns the underlying [Class] of this [DataType]. */
val valueClass: Class<T>,
/**
* Returns `true` if this will be represented by [StatisticalDataPoint] or
* [CumulativeDataPoint], otherwise `false`.
*/
internal val isAggregate: Boolean,
) {
/**
* Whether the [DataType] corresponds to a measurement spanning an interval, or a sample at a
* single point in time.
*/
public class TimeType private constructor(public val id: Int, public val name: String) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is TimeType) return false
if (id != other.id) return false
return true
}
override fun hashCode(): Int = id
override fun toString(): String = name
internal fun toProto(): DataProto.DataType.TimeType = when (this) {
INTERVAL -> TIME_TYPE_INTERVAL
SAMPLE -> TIME_TYPE_SAMPLE
else -> TIME_TYPE_UNKNOWN
}
companion object {
/** The [TimeType] is unknown or this library is too old to know about it. */
@JvmField
val UNKNOWN: TimeType = TimeType(0, "UNKNOWN")
/**
* TimeType that indicates the DataType has a value that represents an interval of time
* with a beginning and end. For example, number of steps taken over a span of time.
*/
@JvmField
val INTERVAL: TimeType = TimeType(1, "INTERVAL")
/**
* TimeType that indicates the DataType has a value that represents a single point in
* time. For example, heart rate reading at a specific time.
*/
@JvmField
val SAMPLE: TimeType = TimeType(2, "SAMPLE")
internal fun fromProto(proto: DataProto.DataType.TimeType): TimeType = when (proto) {
TIME_TYPE_INTERVAL -> INTERVAL
TIME_TYPE_SAMPLE -> SAMPLE
TIME_TYPE_UNKNOWN -> UNKNOWN
}
}
}
override fun toString(): String =
"DataType(" +
"name=$name," +
" timeType=$timeType," +
" class=${valueClass.simpleName}," +
" isAggregate=$isAggregate" + ")"
internal val proto: DataProto.DataType =
DataProto.DataType.newBuilder().setName(name).setTimeType(timeType.toProto())
.setFormat(classToValueFormat()).build()
internal fun toProtoFromValue(
value: T,
): DataProto.Value {
val builder = DataProto.Value.newBuilder()
when (valueClass.kotlin) {
Long::class -> builder.longVal = value as Long
Double::class -> builder.doubleVal = value as Double
Boolean::class -> builder.boolVal = value as Boolean
ByteArray::class -> builder.byteArrayVal = ByteString.copyFrom(value as ByteArray)
DoubleArray::class -> builder.doubleArrayVal = DataProto.Value.DoubleArray.newBuilder()
.addAllDoubleArray((value as DoubleArray).toList()).build()
LocationData::class -> (value as LocationData).addToValueProtoBuilder(builder)
else -> Log.w(TAG, "Unexpected value class ${valueClass.simpleName}")
}
return builder.build()
}
@Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST")
internal fun toValueFromProto(proto: DataProto.Value): T {
return when (valueClass.kotlin) {
Long::class -> proto.longVal
Double::class -> proto.doubleVal
Boolean::class -> proto.boolVal
ByteArray::class -> proto.byteArrayVal?.toByteArray()
DoubleArray::class -> proto.doubleArrayVal
LocationData::class -> LocationData.fromDataProtoValue(proto)
else -> throw UnsupportedOperationException("Cannot retrieve value for $valueClass")
} as T
}
private fun classToValueFormat(): Int {
return when (valueClass.kotlin) {
Double::class -> FORMAT_DOUBLE
Long::class -> FORMAT_LONG
Boolean::class -> FORMAT_BOOLEAN
DoubleArray::class -> FORMAT_DOUBLE_ARRAY
ByteArray::class -> FORMAT_BYTE_ARRAY
LocationData::class -> FORMAT_DOUBLE_ARRAY
else ->
throw UnsupportedOperationException("No IPC format available for class $valueClass")
}
}
companion object {
private const val TAG = "DataType"
private inline fun <reified T : Number> createIntervalDataType(
name: String
): DeltaDataType<T, IntervalDataPoint<T>> =
DeltaDataType(name, TimeType.INTERVAL, T::class.java)
private inline fun <reified T : Number> createSampleDataType(
name: String
): DeltaDataType<T, SampleDataPoint<T>> = DeltaDataType(
name, TimeType.SAMPLE, T::class.java
)
private inline fun <reified T : Number> createStatsDataType(
name: String
): AggregateDataType<T, StatisticalDataPoint<T>> =
AggregateDataType(name, TimeType.SAMPLE, T::class.java)
private inline fun <reified T : Number> createCumulativeDataType(
name: String
): AggregateDataType<T, CumulativeDataPoint<T>> =
AggregateDataType(name, TimeType.INTERVAL, T::class.java)
/**
* A measure of the gain in elevation since the last update expressed in meters. Elevation
* losses are not counted in this metric (so it will only be positive or 0).
*/
@JvmField
val ELEVATION_GAIN: DeltaDataType<Double, IntervalDataPoint<Double>> =
createIntervalDataType("Elevation Gain")
/**
* A measure of the total gain in elevation since the start of an active exercise expressed
* in meters. Elevation losses are not counted in this metric (so it will only be positive
* or 0).
*/
@JvmField
val ELEVATION_GAIN_TOTAL: AggregateDataType<Double, CumulativeDataPoint<Double>> =
createCumulativeDataType("Elevation Gain")
/**
* A measure of the loss in elevation since the last update expressed in meters. Elevation
* gains are not counted in this metric (so it will only be positive or 0).
*/
@JvmField
val ELEVATION_LOSS: DeltaDataType<Double, IntervalDataPoint<Double>> =
createIntervalDataType("Elevation Loss")
/**
* A measure of the total loss in elevation since the start of an active exercise expressed
* in meters. Elevation gains are not counted in this metric (so it will only be positive or
* 0).
*/
@JvmField
val ELEVATION_LOSS_TOTAL: AggregateDataType<Double, CumulativeDataPoint<Double>> =
createCumulativeDataType("Elevation Loss")
/** Absolute elevation at a specific point in time expressed in meters. */
@JvmField
val ABSOLUTE_ELEVATION: DeltaDataType<Double, SampleDataPoint<Double>> =
createSampleDataType("Absolute Elevation")
/**
* Statistical information about the absolute elevation over the course of the active
* exercise expressed in meters.
*/
@JvmField
val ABSOLUTE_ELEVATION_STATS: AggregateDataType<Double, StatisticalDataPoint<Double>> =
createStatsDataType("Absolute Elevation")
/** A distance delta between each reading expressed in meters. */
@JvmField
val DISTANCE: DeltaDataType<Double, IntervalDataPoint<Double>> =
createIntervalDataType("Distance")
/** Total distance since the start of the active exercise expressed in meters. */
@JvmField
val DISTANCE_TOTAL: AggregateDataType<Double, CumulativeDataPoint<Double>> =
createCumulativeDataType("Distance")
/** Distance traveled over declining ground between each reading expressed in meters. */
@JvmField
val DECLINE_DISTANCE: DeltaDataType<Double, IntervalDataPoint<Double>> =
createIntervalDataType("Decline Distance")
/**
* The total distance traveled over declining ground between each reading since the start of
* the active exercise expressed in meters.
*/
@JvmField
val DECLINE_DISTANCE_TOTAL: AggregateDataType<Double, CumulativeDataPoint<Double>> =
createCumulativeDataType("Decline Distance")
/**
* The amount of time the user spent traveling over declining ground since the last update,
* expressed in seconds.
*/
@JvmField
val DECLINE_DURATION: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Decline Duration")
/**
* Total duration the user spent traveling over declining ground since the start of the
* active exercise, expressed in seconds.
*/
@JvmField
val DECLINE_DURATION_TOTAL: AggregateDataType<Long, CumulativeDataPoint<Long>> =
createCumulativeDataType("Decline Duration")
/** The distance traveled over flat since the last update expressed in meters. */
@JvmField
val FLAT_GROUND_DISTANCE: DeltaDataType<Double, IntervalDataPoint<Double>> =
createIntervalDataType("Flat Ground Distance")
/**
* The total distance traveled over flat ground since the start of the active exercise
* expressed in meters.
*/
@JvmField
val FLAT_GROUND_DISTANCE_TOTAL: AggregateDataType<Double, CumulativeDataPoint<Double>> =
createCumulativeDataType("Flat Ground Distance")
/**
* The amount of time the user spent traveling over flat ground since the last update,
* expressed in seconds.
*/
@JvmField
val FLAT_GROUND_DURATION: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Flat Ground Duration")
/**
* The total duration the user spent traveling over flat ground since the start of the
* active exercise, expressed in seconds.
*/
@JvmField
val FLAT_GROUND_DURATION_TOTAL: AggregateDataType<Long, CumulativeDataPoint<Long>> =
createCumulativeDataType("Flat Ground Duration")
/**
* The number of golf shots taken since the last update, where a golf shot consists of
* swinging the club and hitting the ball. Expressed in seconds.
*/
@JvmField
val GOLF_SHOT_COUNT: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Golf Shot Count")
/**
* The total number of golf shots taken since the start of the current active exercise,
* where a golf shot consists swinging the club and hitting the ball. Expressed in seconds.
*/
@JvmField
val GOLF_SHOT_COUNT_TOTAL: AggregateDataType<Long, CumulativeDataPoint<Long>> =
createCumulativeDataType("Golf Shot Count")
/**
* The distance traveled over inclining ground since the last update expressed in meters.
*/
@JvmField
val INCLINE_DISTANCE: DeltaDataType<Double, IntervalDataPoint<Double>> =
createIntervalDataType("Incline Distance")
/**
* The total distance traveled over inclining since the start of the active exercise
* expressed in meters.
*/
@JvmField
val INCLINE_DISTANCE_TOTAL: AggregateDataType<Double, CumulativeDataPoint<Double>> =
createCumulativeDataType("Incline Distance")
/**
* The amount of time the user spent traveling over inclining ground since the last update,
* expressed in seconds.
*/
@JvmField
val INCLINE_DURATION: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Incline Duration")
/**
* Total amount of time the user spent traveling over inclining ground since the start of
* the active exercise, expressed in seconds.
*/
@JvmField
val INCLINE_DURATION_TOTAL: AggregateDataType<Long, CumulativeDataPoint<Long>> =
createCumulativeDataType("Incline Duration")
/**
* Number of floors climbed since the last update. Note that partial floors are supported,
* so this is represented as a [Double].
*/
@JvmField
val FLOORS: DeltaDataType<Double, IntervalDataPoint<Double>> =
createIntervalDataType("Floors")
/**
* Total number of floors climbed since the start of the active exercise. Note that partial
* floors are supported, so this is represented as a [Double].
*/
@JvmField
val FLOORS_TOTAL: AggregateDataType<Double, CumulativeDataPoint<Double>> =
createCumulativeDataType("Floors")
/**
* Current heart rate, in beats per minute.
*
* Accuracy for a [DataPoint] of type [DataType.HEART_RATE_BPM] is represented by
* [HeartRateAccuracy].
*/
@JvmField
val HEART_RATE_BPM: DeltaDataType<Double, SampleDataPoint<Double>> =
createSampleDataType("HeartRate")
/**
* Statistics on heart rate since the start of the current exercise, expressed in beats per
* minute.
*/
@JvmField
val HEART_RATE_BPM_STATS: AggregateDataType<Double, StatisticalDataPoint<Double>> =
createStatsDataType("HeartRate")
/**
* Latitude, longitude and optionally, altitude and bearing at a specific point in time.
*
* Accuracy for a [DataPoint] of type [LOCATION] is represented by [LocationAccuracy].
*/
@JvmField
val LOCATION: DeltaDataType<LocationData, SampleDataPoint<LocationData>> =
DeltaDataType("Location", TimeType.SAMPLE, LocationData::class.java)
/** Speed at a specific point in time, expressed as meters/second. */
@JvmField
val SPEED: DeltaDataType<Double, SampleDataPoint<Double>> =
createSampleDataType("Speed")
/**
* Statistics on speed since the start of the active exercise, expressed in meters/second.
*/
@JvmField
val SPEED_STATS: AggregateDataType<Double, StatisticalDataPoint<Double>> =
createStatsDataType("Speed")
/**
* Maximum rate of oxygen consumption measured at a specific point in time. Valid range
* `0f` - `100f`.
*/
@JvmField
val VO2_MAX: DeltaDataType<Double, SampleDataPoint<Double>> =
createSampleDataType("VO2 Max")
/**
* Statistics on maximum rate of oxygen consumption measured since the start of an exercise.
* Valid range `0f` - `100f`.
*/
@JvmField
val VO2_MAX_STATS: AggregateDataType<Double, StatisticalDataPoint<Double>> =
createStatsDataType("VO2 Max")
/** Number of steps taken since the last update. */
@JvmField
val STEPS: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Steps")
/** Total steps taken since the start of the active exercise. */
@JvmField
val STEPS_TOTAL: AggregateDataType<Long, CumulativeDataPoint<Long>> =
createCumulativeDataType("Steps")
/** Number of steps taken while walking since the last update. */
@JvmField
val WALKING_STEPS: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Walking Steps")
/**
* Total number of steps taken while walking since the start of the current active exercise.
*/
@JvmField
val WALKING_STEPS_TOTAL: AggregateDataType<Long, CumulativeDataPoint<Long>> =
createCumulativeDataType("Walking Steps")
/** Number of steps taken while running since the last update. */
@JvmField
val RUNNING_STEPS: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Running Steps")
/** Number of steps taken while running since the start of the current active exercise. */
@JvmField
val RUNNING_STEPS_TOTAL: AggregateDataType<Long, CumulativeDataPoint<Long>> =
createCumulativeDataType("Running Steps")
/** Step rate in steps/minute at a given point in time. */
@JvmField
val STEPS_PER_MINUTE: DeltaDataType<Long, SampleDataPoint<Long>> =
createSampleDataType("Step per minute")
/**
* Statistics on step rate in steps/minute since the beginning of the current active
* exercise.
*/
@JvmField
val STEPS_PER_MINUTE_STATS: AggregateDataType<Long, StatisticalDataPoint<Long>> =
createStatsDataType("Step per minute")
/** Number of swimming strokes taken since the last update. */
@JvmField
val SWIMMING_STROKES: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Swimming Strokes")
/**
* Total number of swimming strokes taken since the start of the current active exercise.
*/
@JvmField
val SWIMMING_STROKES_TOTAL: AggregateDataType<Long, CumulativeDataPoint<Long>> =
createCumulativeDataType("Swimming Strokes")
/** Number of calories burned (including basal rate and activity) since the last update. */
@JvmField
val CALORIES: DeltaDataType<Double, IntervalDataPoint<Double>> =
createIntervalDataType("Calories")
/**
* Total number of calories burned (including basal rate and activity) since the start of
* the current active exercise.
*/
@JvmField
val CALORIES_TOTAL: AggregateDataType<Double, CumulativeDataPoint<Double>> =
createCumulativeDataType("Calories")
/**
* Pace at a specific point in time. Will be 0 if the user stops moving, otherwise the value
* will be in milliseconds/kilometer.
*/
@JvmField
val PACE: DeltaDataType<Double, SampleDataPoint<Double>> =
createSampleDataType("Pace")
/**
* Statistics on pace since the start of the current exercise. A value of 0 indicates the
* user stopped moving, otherwise the value will be in milliseconds/kilometer.
*/
@JvmField
val PACE_STATS: AggregateDataType<Double, StatisticalDataPoint<Double>> =
createStatsDataType("Pace")
/**
* The number of seconds the user has been resting during an exercise since the last update.
*/
@JvmField
val RESTING_EXERCISE_DURATION: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Resting Exercise Duration")
/**
* The total number of seconds the user has been resting during the active exercise.
*/
@JvmField
val RESTING_EXERCISE_DURATION_TOTAL: AggregateDataType<Long, CumulativeDataPoint<Long>> =
createCumulativeDataType("Resting Exercise Duration")
/**
* The total time the Exercise was [ExerciseState.ACTIVE] in seconds.
*
* **_Note_: this [DataType] is only intended to be used in conjunction with exercise
* goals. [DataPoint]s will not be delivered for this [DataType]. If you want to query the
* active duration, you should use [ExerciseUpdate.activeDuration] which is available in
* every [ExerciseUpdate].**
*/
@JvmField
val ACTIVE_EXERCISE_DURATION_TOTAL: AggregateDataType<Long, CumulativeDataPoint<Long>> =
createCumulativeDataType("Active Exercise Duration")
/** Count of swimming laps since the start of the current active exercise. */
@JvmField
val SWIMMING_LAP_COUNT: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Swim Lap Count")
/** The number of repetitions of an exercise performed since the last update. */
@JvmField
val REP_COUNT: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Rep Count")
/**
* The number of repetitions of an exercise performed since the start of the current active
* exercise.
*/
@JvmField
val REP_COUNT_TOTAL: AggregateDataType<Long, CumulativeDataPoint<Long>> =
createCumulativeDataType("Rep Count")
/**
* The total step count over a day, where the previous day ends and a new day begins at
* 12:00 AM local time. Each [DataPoint] of this type will cover the interval from the start
* of day to now. In the event of time-zone shifts, the interval may be greater than 24hrs.
*/
@JvmField
val STEPS_DAILY: DeltaDataType<Long, IntervalDataPoint<Long>> =
createIntervalDataType("Daily Steps")
/**
* The total number floors climbed over a day, where the previous day ends and a new day
* begins at 12:00 AM local time. Each DataPoint of this type will cover the interval from
* the start of day to now. In the event of time-zone shifts, the interval may be greater
* than 24hrs.
*/
@JvmField
val FLOORS_DAILY: DeltaDataType<Double, IntervalDataPoint<Double>> =
createIntervalDataType("Daily Floors")
/**
* The total number of calories over a day (including both BMR and active calories), where
* the previous day ends and a new day begins at 12:00 AM local time. Each [DataPoint] of
* this type will cover the interval from the start of day to now. In the event of time-zone
* shifts, the interval might be greater than 24hrs.
*/
@JvmField
val CALORIES_DAILY: DeltaDataType<Double, IntervalDataPoint<Double>> =
createIntervalDataType("Daily Calories")
/**
* The total distance over a day, where the previous day ends and a new day begins at
* 12:00 AM local time. Each DataPoint of this type will cover the interval from the start
* of day to now. In the event of time-zone shifts, the interval may be greater than 24hrs.
*/
@JvmField
val DISTANCE_DAILY: DeltaDataType<Double, IntervalDataPoint<Double>> =
createIntervalDataType("Daily Distance")
internal val deltaDataTypes: Set<DeltaDataType<*, *>> = setOf(
ABSOLUTE_ELEVATION,
CALORIES,
CALORIES_DAILY,
DISTANCE_DAILY,
FLOORS_DAILY,
STEPS_DAILY,
DECLINE_DISTANCE,
DECLINE_DURATION,
DISTANCE,
ELEVATION_GAIN,
ELEVATION_LOSS,
FLAT_GROUND_DISTANCE,
FLAT_GROUND_DURATION,
FLOORS,
GOLF_SHOT_COUNT,
HEART_RATE_BPM,
INCLINE_DISTANCE,
INCLINE_DURATION,
LOCATION,
PACE,
REP_COUNT,
RESTING_EXERCISE_DURATION,
RUNNING_STEPS,
SPEED,
STEPS,
STEPS_PER_MINUTE,
SWIMMING_LAP_COUNT,
SWIMMING_STROKES,
VO2_MAX,
WALKING_STEPS,
)
internal val aggregateDataTypes: Set<AggregateDataType<*, *>> = setOf(
ABSOLUTE_ELEVATION_STATS,
ACTIVE_EXERCISE_DURATION_TOTAL,
CALORIES_TOTAL,
DECLINE_DISTANCE_TOTAL,
DECLINE_DURATION_TOTAL,
DISTANCE_TOTAL,
ELEVATION_GAIN_TOTAL,
ELEVATION_LOSS_TOTAL,
FLAT_GROUND_DISTANCE_TOTAL,
FLAT_GROUND_DURATION_TOTAL,
FLOORS_TOTAL,
GOLF_SHOT_COUNT_TOTAL,
HEART_RATE_BPM_STATS,
INCLINE_DISTANCE_TOTAL,
INCLINE_DURATION_TOTAL,
PACE_STATS,
REP_COUNT_TOTAL,
RESTING_EXERCISE_DURATION_TOTAL,
RUNNING_STEPS_TOTAL,
SPEED_STATS,
STEPS_PER_MINUTE_STATS,
STEPS_TOTAL,
SWIMMING_STROKES_TOTAL,
VO2_MAX_STATS,
WALKING_STEPS_TOTAL,
)
private val namesOfDeltasWithNoAggregate =
deltaDataTypes.map { it.name } subtract aggregateDataTypes.map { it.name }.toSet()
private val namesOfAggregatesWithNoDelta =
aggregateDataTypes.map { it.name } subtract deltaDataTypes.map { it.name }.toSet()
/** The format used for a [DataProto.Value] represented as a [Double]. */
internal const val FORMAT_DOUBLE: Int = 1
/** The format used for a [DataProto.Value] represented as an [Long]. */
internal const val FORMAT_LONG: Int = 2
/** The format used for a [DataProto.Value] represented as an [Boolean]. */
internal const val FORMAT_BOOLEAN: Int = 4
/** The format used for a [DataProto.Value] represented as a [DoubleArray]. */
internal const val FORMAT_DOUBLE_ARRAY: Int = 3
/** The format used for a [DataProto.Value] represented as a [ByteArray]. */
internal const val FORMAT_BYTE_ARRAY: Int = 5
@Suppress("UNCHECKED_CAST")
internal fun aggregateFromProto(
proto: DataProto.DataType
): AggregateDataType<out Number, out DataPoint<out Number>> =
aggregateDataTypes.firstOrNull { it.name == proto.name } ?: AggregateDataType(
proto.name,
TimeType.fromProto(proto.timeType),
protoDataTypeToClass(proto) as Class<Number>
)
internal fun deltaFromProto(
proto: DataProto.DataType
): DeltaDataType<out Any, out DataPoint<out Any>> =
deltaDataTypes.firstOrNull { it.name == proto.name } ?: DeltaDataType(
proto.name, TimeType.fromProto(proto.timeType), protoDataTypeToClass(proto)
)
internal fun deltaAndAggregateFromProto(
proto: DataProto.DataType
): List<DataType<out Any, out DataPoint<out Any>>> {
val list = mutableListOf<DataType<out Any, out DataPoint<out Any>>>()
if (!namesOfAggregatesWithNoDelta.contains(proto.name)) {
list += deltaFromProto(proto)
}
if (!namesOfDeltasWithNoAggregate.contains(proto.name)) {
list += aggregateFromProto(proto)
}
return list
}
private fun protoDataTypeToClass(proto: DataProto.DataType) = when (proto.format) {
FORMAT_DOUBLE -> Double::class.java
FORMAT_LONG -> Long::class.java
FORMAT_BOOLEAN -> Boolean::class.java
FORMAT_DOUBLE_ARRAY -> {
if (proto.name == LOCATION.name) LOCATION.valueClass
else DoubleArray::class.java
}
FORMAT_BYTE_ARRAY -> ByteArray::class.java
else -> Nothing::class.java
}
}
}