LocationData.kt
/*
* Copyright 2022 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.annotation.FloatRange
import androidx.health.services.client.proto.DataProto
/** Data representing one location point with direction. */
public class LocationData(
/** Latitude of location. Range from -90.0 to = 90.0. */
@FloatRange(from = -90.0, to = 90.0) public val latitude: Double,
/** Longitude of location. Range from -180.0 to = 180.0. */
@FloatRange(from = -180.0, to = 180.0) public val longitude: Double,
/** Altitude of location in meters or [ALTITUDE_UNAVAILABLE] if not available. */
public val altitude: Double = ALTITUDE_UNAVAILABLE,
/** Bearing in degrees within the range of [0.0 (inclusive), 360.0(exclusive)] or
* [BEARING_UNAVAILABLE] if not available.
*/
public val bearing: Double = BEARING_UNAVAILABLE,
) {
init {
if (latitude !in -90.0..90.0) {
Log.w(TAG, "latitude value $latitude is out of range")
}
if (longitude !in -180.0..180.0) {
Log.w(TAG, "longitude value $longitude is out of range")
}
if (bearing < -1.0 || bearing >= 360.0) {
Log.w(TAG, "bearing value $bearing is out of range")
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is LocationData) return false
if (latitude != other.latitude) return false
if (longitude != other.longitude) return false
if (altitude != other.altitude) return false
if (bearing != other.bearing) return false
return true
}
override fun hashCode(): Int {
var result = latitude.hashCode()
result = 31 * result + longitude.hashCode()
result = 31 * result + altitude.hashCode()
result = 31 * result + bearing.hashCode()
return result
}
override fun toString(): String =
"LocationData(" +
"latitude=$latitude," +
" longitude=$longitude," +
" altitude=$altitude," +
" bearing=$bearing" +
")"
internal fun addToValueProtoBuilder(proto: DataProto.Value.Builder) {
val doubleArrayBuilder = DataProto.Value.DoubleArray.newBuilder().apply {
addDoubleArray(latitude)
addDoubleArray(longitude)
addDoubleArray(altitude)
addDoubleArray(bearing)
}
proto.setDoubleArrayVal(doubleArrayBuilder)
}
internal companion object {
private const val TAG = "LocationData"
/**
* When using [DataType.LOCATION], the value is represented as [DoubleArray]. The [Double]
* value at this index represents the latitude.
*/
private const val LATITUDE_INDEX: Int = 0
/**
* When using [DataType.LOCATION], the value is represented as [DoubleArray]. The [Double]
* value at this index represents the longitude.
*/
private const val LONGITUDE_INDEX: Int = 1
/**
* When using [DataType.LOCATION], the value is represented as [DoubleArray]. The [Double]
* value at this index represents the altitude. This value will default to
* [ALTITUDE_UNAVAILABLE] if it is not available.
*/
private const val ALTITUDE_INDEX: Int = 2
/**
* When using [DataType.LOCATION], the value is represented as [DoubleArray]. The [Double]
* value at this index represents the bearing. The value will be within the range of
* 0.0 to 360.0 and default to [BEARING_UNAVAILABLE] if it is not available.
*/
private const val BEARING_INDEX: Int = 3
/** When using [DataType.LOCATION], the default value if altitude value is not available. */
public const val ALTITUDE_UNAVAILABLE: Double = Double.NaN
/** When using [DataType.LOCATION], the default value if bearing value is not available. */
public const val BEARING_UNAVAILABLE: Double = Double.NaN
internal fun fromDataProtoValue(proto: DataProto.Value): LocationData {
require(proto.hasDoubleArrayVal())
val latitude = proto.doubleArrayVal.getDoubleArray(LATITUDE_INDEX)
val longitude = proto.doubleArrayVal.getDoubleArray(LONGITUDE_INDEX)
val altitude = if (proto.doubleArrayVal.doubleArrayCount > ALTITUDE_INDEX) {
proto.doubleArrayVal.getDoubleArray(ALTITUDE_INDEX)
} else {
ALTITUDE_UNAVAILABLE
}
var bearing = if (proto.doubleArrayVal.doubleArrayCount > BEARING_INDEX) {
proto.doubleArrayVal.getDoubleArray(BEARING_INDEX)
} else {
BEARING_UNAVAILABLE
}
return LocationData(
latitude = latitude,
longitude = longitude,
altitude = altitude,
bearing = bearing
)
}
}
}