Skip to main content

fission_shell_winit/
geolocation.rs

1use fission_core::{
2    GeolocationError, GeolocationPermission, GeolocationPermissionRequest, GeolocationPosition,
3    GeolocationPositionRequest, GET_CURRENT_POSITION, GET_GEOLOCATION_PERMISSION,
4    REQUEST_GEOLOCATION_PERMISSION,
5};
6use fission_shell::async_host::AsyncRegistry;
7use std::sync::Arc;
8
9/// Host-side geolocation provider used by shell capability registration.
10pub trait GeolocationHost: Send + Sync + 'static {
11    /// Returns the current location permission state without showing a prompt.
12    fn permission(&self) -> Result<GeolocationPermission, GeolocationError>;
13    /// Requests location permission with precision and background preferences.
14    fn request_permission(
15        &self,
16        request: GeolocationPermissionRequest,
17    ) -> Result<GeolocationPermission, GeolocationError>;
18    /// Returns the current position according to accuracy, timeout, and cache rules.
19    fn current_position(
20        &self,
21        request: GeolocationPositionRequest,
22    ) -> Result<GeolocationPosition, GeolocationError>;
23}
24
25#[derive(Debug, Default)]
26pub struct UnsupportedGeolocationHost;
27
28impl GeolocationHost for UnsupportedGeolocationHost {
29    fn permission(&self) -> Result<GeolocationPermission, GeolocationError> {
30        Ok(GeolocationPermission::Unsupported)
31    }
32
33    fn request_permission(
34        &self,
35        _request: GeolocationPermissionRequest,
36    ) -> Result<GeolocationPermission, GeolocationError> {
37        Ok(GeolocationPermission::Unsupported)
38    }
39
40    fn current_position(
41        &self,
42        _request: GeolocationPositionRequest,
43    ) -> Result<GeolocationPosition, GeolocationError> {
44        Err(GeolocationError::unsupported("current_position"))
45    }
46}
47
48#[derive(Debug, Clone)]
49pub struct MemoryGeolocationHost {
50    position: GeolocationPosition,
51}
52
53impl MemoryGeolocationHost {
54    pub fn new(position: GeolocationPosition) -> Self {
55        Self { position }
56    }
57}
58
59impl Default for MemoryGeolocationHost {
60    fn default() -> Self {
61        Self {
62            position: GeolocationPosition {
63                latitude: 51.5074,
64                longitude: -0.1278,
65                altitude_meters: None,
66                accuracy_meters: 10.0,
67                altitude_accuracy_meters: None,
68                heading_degrees: None,
69                speed_mps: None,
70                timestamp_unix_ms: 1_774_000_000_000,
71            },
72        }
73    }
74}
75
76impl GeolocationHost for MemoryGeolocationHost {
77    fn permission(&self) -> Result<GeolocationPermission, GeolocationError> {
78        Ok(GeolocationPermission::Granted)
79    }
80
81    fn request_permission(
82        &self,
83        _request: GeolocationPermissionRequest,
84    ) -> Result<GeolocationPermission, GeolocationError> {
85        Ok(GeolocationPermission::Granted)
86    }
87
88    fn current_position(
89        &self,
90        _request: GeolocationPositionRequest,
91    ) -> Result<GeolocationPosition, GeolocationError> {
92        Ok(self.position.clone())
93    }
94}
95
96pub(crate) fn register_geolocation_capabilities(
97    async_registry: &mut AsyncRegistry,
98    host: Arc<dyn GeolocationHost>,
99) {
100    let permission_host = host.clone();
101    async_registry.register_operation_capability(GET_GEOLOCATION_PERMISSION, move |(), _| {
102        let host = permission_host.clone();
103        async move { host.permission() }
104    });
105
106    let request_host = host.clone();
107    async_registry.register_operation_capability(
108        REQUEST_GEOLOCATION_PERMISSION,
109        move |request, _| {
110            let host = request_host.clone();
111            async move { host.request_permission(request) }
112        },
113    );
114
115    async_registry.register_operation_capability(GET_CURRENT_POSITION, move |request, _| {
116        let host = host.clone();
117        async move { host.current_position(request) }
118    });
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    #[test]
126    fn unsupported_host_reports_unsupported() {
127        let host = UnsupportedGeolocationHost;
128        assert_eq!(
129            host.permission().unwrap(),
130            GeolocationPermission::Unsupported
131        );
132        assert!(host
133            .current_position(GeolocationPositionRequest::default())
134            .is_err());
135    }
136
137    #[test]
138    fn memory_host_returns_position() {
139        let host = MemoryGeolocationHost::default();
140        assert_eq!(host.permission().unwrap(), GeolocationPermission::Granted);
141        assert_eq!(
142            host.current_position(GeolocationPositionRequest::default())
143                .unwrap()
144                .latitude,
145            51.5074
146        );
147    }
148}