Skip to main content

android_ble/
service.rs

1use std::sync::Arc;
2
3use super::bindings::android::bluetooth::BluetoothGattService;
4use super::characteristic::Characteristic;
5use super::gatt_tree::{CachedWeak, GattTree, ServiceInner};
6use super::util::OptionExt;
7use super::util::{JavaIterator, UuidExt};
8use super::vm_context::jni_with_env;
9use super::DeviceId;
10
11use crate::{Result, Uuid};
12
13/// A Bluetooth GATT service.
14#[derive(Debug, Clone)]
15pub struct Service {
16    dev_id: DeviceId,
17    service_id: Uuid,
18    inner: CachedWeak<ServiceInner>,
19}
20
21impl PartialEq for Service {
22    fn eq(&self, other: &Self) -> bool {
23        self.dev_id == other.dev_id && self.service_id == other.service_id
24    }
25}
26
27impl Eq for Service {}
28
29impl std::hash::Hash for Service {
30    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
31        self.dev_id.hash(state);
32        self.service_id.hash(state);
33    }
34}
35
36impl Service {
37    pub(crate) fn new(dev_id: DeviceId, service_id: Uuid) -> Self {
38        Self {
39            dev_id,
40            service_id,
41            inner: CachedWeak::new(),
42        }
43    }
44
45    /// The [Uuid] identifying the type of this GATT service.
46    pub fn uuid(&self) -> Uuid {
47        self.service_id
48    }
49
50    /// This method is kept for compatibility with `bluest`.
51    pub async fn uuid_async(&self) -> Result<Uuid> {
52        Ok(self.service_id)
53    }
54
55    /// Whether this is a primary service of the device.
56    pub async fn is_primary(&self) -> Result<bool> {
57        jni_with_env(|env| {
58            Ok(self.get_inner()?.service.as_ref(env).getType()?
59                == BluetoothGattService::SERVICE_TYPE_PRIMARY)
60        })
61    }
62
63    /// Returns all characteristics associated with this service.
64    ///
65    /// This method is kept for compatibility with `bluest`.
66    pub async fn discover_characteristics(&self) -> Result<Vec<Characteristic>> {
67        self.characteristics().await
68    }
69
70    /// Returns the characteristic(s) with the given [Uuid].
71    ///
72    /// This method is kept for compatibility with `bluest`.
73    pub async fn discover_characteristics_with_uuid(
74        &self,
75        uuid: Uuid,
76    ) -> Result<Vec<Characteristic>> {
77        Ok(self
78            .characteristics()
79            .await?
80            .into_iter()
81            .filter(|ch| ch.uuid() == uuid)
82            .collect())
83    }
84
85    /// Get previously discovered characteristics.
86    pub async fn characteristics(&self) -> Result<Vec<Characteristic>> {
87        Ok(self
88            .get_inner()?
89            .chars
90            .keys()
91            .map(|id| Characteristic::new(self.dev_id.clone(), self.service_id, *id))
92            .collect())
93    }
94
95    /// Returns the included services of this service.
96    ///
97    /// This method is kept for compatibility with `bluest`.
98    pub async fn discover_included_services(&self) -> Result<Vec<Service>> {
99        self.included_services().await
100    }
101
102    /// Returns the included service(s) with the given [Uuid].
103    pub async fn discover_included_services_with_uuid(&self, uuid: Uuid) -> Result<Vec<Service>> {
104        Ok(self
105            .included_services()
106            .await?
107            .into_iter()
108            .filter(|ch| ch.uuid() == uuid)
109            .collect())
110    }
111
112    /// Returns the included services of this service.
113    pub async fn included_services(&self) -> Result<Vec<Service>> {
114        jni_with_env(|env| {
115            let inner = self.get_inner()?;
116            let service = inner.service.as_ref(env);
117            let includes = service.getIncludedServices()?.non_null()?;
118            let vec = JavaIterator(includes.iterator()?.non_null()?)
119                .filter_map(|serv| {
120                    serv.cast::<BluetoothGattService>()
121                        .ok()
122                        .and_then(|serv| Uuid::from_java(serv.getUuid().ok()??.as_ref()).ok())
123                })
124                .map(|uuid| Service::new(self.dev_id.clone(), uuid))
125                .collect();
126            Ok(vec)
127        })
128    }
129
130    fn get_inner(&self) -> Result<Arc<ServiceInner>, crate::Error> {
131        self.inner.get_or_find(|| {
132            GattTree::find_service(&self.dev_id, self.service_id).ok_or_check_conn(&self.dev_id)
133        })
134    }
135}