use crate::{Location, LocationError, Timestamp};
const FILETIME_UNIX_DIFF: i64 = 11_644_473_600;
const E_ACCESSDENIED: windows::core::HRESULT =
windows::core::HRESULT(0x8007_0005_u32.cast_signed());
pub async fn get_location() -> Result<Location, LocationError> {
use windows::Devices::Geolocation::Geolocator;
let map_err = |e: windows::core::Error| {
if e.code() == E_ACCESSDENIED {
LocationError::PermissionDenied
} else {
LocationError::Platform(e.to_string())
}
};
let geolocator = Geolocator::new().map_err(map_err)?;
let position = geolocator
.GetGeopositionAsync()
.map_err(map_err)?
.await
.map_err(map_err)?;
let coord = position.Coordinate().map_err(map_err)?;
let point = coord.Point().map_err(map_err)?;
let pos = point.Position().map_err(map_err)?;
let filetime = coord.Timestamp().map_err(map_err)?.UniversalTime;
let unix_100ns = i128::from(filetime) - i128::from(FILETIME_UNIX_DIFF) * 10_000_000;
let timestamp = Timestamp::from_nanosecond(unix_100ns * 100)
.map_err(|e| LocationError::Platform(e.to_string()))?;
let mut location = Location::from_degrees(pos.Latitude, pos.Longitude, timestamp)?;
if let Ok(accuracy) = coord.Accuracy() {
location = location.with_horizontal_accuracy(accuracy);
}
if let Ok(reference) = coord.AltitudeAccuracy()
&& let Ok(vertical_accuracy) = reference.Value()
{
location = location
.with_altitude(pos.Altitude)
.with_vertical_accuracy(vertical_accuracy);
}
Ok(location)
}