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#[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 pub fn uuid(&self) -> Uuid {
47 self.service_id
48 }
49
50 pub async fn uuid_async(&self) -> Result<Uuid> {
52 Ok(self.service_id)
53 }
54
55 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 pub async fn discover_characteristics(&self) -> Result<Vec<Characteristic>> {
67 self.characteristics().await
68 }
69
70 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 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 pub async fn discover_included_services(&self) -> Result<Vec<Service>> {
99 self.included_services().await
100 }
101
102 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 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}