Skip to main content

android_ble/
descriptor.rs

1use std::sync::Arc;
2
3use java_spaghetti::ByteArray;
4
5use super::error::ErrorKind;
6use super::gatt_tree::{CachedWeak, DescriptorInner, GattTree};
7use super::jni::{ByteArrayExt, Monitor};
8use super::util::{BoolExt, IntExt, OptionExt};
9use super::vm_context::{android_api_level, jni_with_env};
10use super::{DeviceId, Result, Uuid};
11
12/// A Bluetooth GATT descriptor.
13#[derive(Debug, Clone)]
14pub struct Descriptor {
15    dev_id: DeviceId,
16    service_id: Uuid,
17    char_id: Uuid,
18    desc_id: Uuid,
19    inner: CachedWeak<DescriptorInner>,
20}
21
22impl PartialEq for Descriptor {
23    fn eq(&self, other: &Self) -> bool {
24        self.dev_id == other.dev_id
25            && self.service_id == other.service_id
26            && self.char_id == other.char_id
27            && self.desc_id == other.desc_id
28    }
29}
30
31impl Eq for Descriptor {}
32
33impl Descriptor {
34    pub(crate) fn new(dev_id: DeviceId, service_id: Uuid, char_id: Uuid, desc_id: Uuid) -> Self {
35        Self {
36            dev_id,
37            service_id,
38            char_id,
39            desc_id,
40            inner: CachedWeak::new(),
41        }
42    }
43
44    /// The [Uuid] identifying the type of this GATT descriptor.
45    pub fn uuid(&self) -> Uuid {
46        self.desc_id
47    }
48
49    /// This method is kept for compatibility with `bluest`.
50    pub async fn uuid_async(&self) -> Result<Uuid> {
51        Ok(self.desc_id)
52    }
53
54    /// The cached value of this descriptor. Returns an error if the value has not yet been read.
55    pub async fn value(&self) -> Result<Vec<u8>> {
56        self.get_inner()?
57            .read
58            .last_value()
59            .ok_or(crate::Error::new(
60                ErrorKind::NotReady,
61                None,
62                "please call `Descriptor::read` at first",
63            ))?
64    }
65
66    // NOTE: the sequence of gaining read lock and write lock should be the same
67    // in `read` and `write` methods, otherwise deadlock may occur.
68
69    /// Read the value of this descriptor from the device.
70    pub async fn read(&self) -> Result<Vec<u8>> {
71        let conn = GattTree::check_connection(&self.dev_id)?;
72        let inner = self.get_inner()?;
73        let read_lock = inner.read.lock().await;
74        let _write_lock = inner.write.lock().await;
75        jni_with_env(|env| {
76            let gatt = &conn.gatt.as_ref(env);
77            let gatt = Monitor::new(gatt);
78            gatt.readDescriptor(inner.desc.as_ref(env))
79                .map_err(|e| e.into())
80                .and_then(|b| b.non_false())
81        })?;
82        drop((conn, inner));
83        read_lock
84            .wait_unlock()
85            .await
86            .ok_or_check_conn(&self.dev_id)?
87    }
88
89    /// Write the `value` to this descriptor on the device.
90    pub async fn write(&self, value: &[u8]) -> Result<()> {
91        let conn = GattTree::check_connection(&self.dev_id)?;
92        let inner = self.get_inner()?;
93        let _read_lock = inner.read.lock().await;
94        let write_lock = inner.write.lock().await;
95        jni_with_env(|env| {
96            let gatt = conn.gatt.as_ref(env);
97            let gatt = Monitor::new(&gatt);
98            let desc = inner.desc.as_ref(env);
99            let array = ByteArray::from_slice(env, value);
100            if android_api_level() >= 33 {
101                gatt.writeDescriptor_BluetoothGattDescriptor_byte_array(desc, array)?
102                    .check_status_code()
103            } else {
104                #[allow(deprecated)]
105                desc.setValue(array)?;
106                #[allow(deprecated)]
107                gatt.writeDescriptor_BluetoothGattDescriptor(desc)
108                    .map_err(|e| e.into())
109                    .and_then(|b| b.non_false())
110            }
111        })?;
112        drop((conn, inner));
113        write_lock
114            .wait_unlock()
115            .await
116            .ok_or_check_conn(&self.dev_id)?
117    }
118
119    fn get_inner(&self) -> Result<Arc<DescriptorInner>, crate::Error> {
120        self.inner.get_or_find(|| {
121            GattTree::find_descriptor(&self.dev_id, self.service_id, self.char_id, self.desc_id)
122                .ok_or_check_conn(&self.dev_id)
123        })
124    }
125}