bluetooth/
adapter.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use std::error::Error;
6use std::sync::Arc;
7
8#[cfg(all(target_os = "android", feature = "native-bluetooth"))]
9use blurdroid::bluetooth_adapter::Adapter as BluetoothAdapterAndroid;
10#[cfg(all(target_os = "android", feature = "native-bluetooth"))]
11use blurdroid::bluetooth_device::Device as BluetoothDeviceAndroid;
12#[cfg(all(target_os = "android", feature = "native-bluetooth"))]
13use blurdroid::bluetooth_discovery_session::DiscoverySession as BluetoothDiscoverySessionAndroid;
14#[cfg(all(target_os = "macos", feature = "native-bluetooth"))]
15use blurmac::BluetoothAdapter as BluetoothAdapterMac;
16#[cfg(all(target_os = "macos", feature = "native-bluetooth"))]
17use blurmac::BluetoothDevice as BluetoothDeviceMac;
18#[cfg(all(target_os = "macos", feature = "native-bluetooth"))]
19use blurmac::BluetoothDiscoverySession as BluetoothDiscoverySessionMac;
20#[cfg(feature = "bluetooth-test")]
21use blurmock::fake_adapter::FakeBluetoothAdapter;
22#[cfg(feature = "bluetooth-test")]
23use blurmock::fake_device::FakeBluetoothDevice;
24#[cfg(feature = "bluetooth-test")]
25use blurmock::fake_discovery_session::FakeBluetoothDiscoverySession;
26#[cfg(all(target_os = "linux", feature = "native-bluetooth"))]
27use blurz::bluetooth_adapter::BluetoothAdapter as BluetoothAdapterBluez;
28#[cfg(all(target_os = "linux", feature = "native-bluetooth"))]
29use blurz::bluetooth_device::BluetoothDevice as BluetoothDeviceBluez;
30#[cfg(all(target_os = "linux", feature = "native-bluetooth"))]
31use blurz::bluetooth_discovery_session::BluetoothDiscoverySession as BluetoothDiscoverySessionBluez;
32
33use super::bluetooth::{BluetoothDevice, BluetoothDiscoverySession};
34#[cfg(not(any(
35    all(target_os = "linux", feature = "native-bluetooth"),
36    all(target_os = "android", feature = "native-bluetooth"),
37    all(target_os = "macos", feature = "native-bluetooth")
38)))]
39use super::empty::BluetoothDevice as BluetoothDeviceEmpty;
40#[cfg(not(any(
41    all(target_os = "linux", feature = "native-bluetooth"),
42    all(target_os = "android", feature = "native-bluetooth"),
43    all(target_os = "macos", feature = "native-bluetooth")
44)))]
45use super::empty::BluetoothDiscoverySession as BluetoothDiscoverySessionEmpty;
46#[cfg(not(any(
47    all(target_os = "linux", feature = "native-bluetooth"),
48    all(target_os = "android", feature = "native-bluetooth"),
49    all(target_os = "macos", feature = "native-bluetooth")
50)))]
51use super::empty::EmptyAdapter as BluetoothAdapterEmpty;
52use super::macros::get_inner_and_call;
53#[cfg(feature = "bluetooth-test")]
54use super::macros::get_inner_and_call_test_func;
55
56#[derive(Clone, Debug)]
57pub enum BluetoothAdapter {
58    #[cfg(all(target_os = "linux", feature = "native-bluetooth"))]
59    Bluez(Arc<BluetoothAdapterBluez>),
60    #[cfg(all(target_os = "android", feature = "native-bluetooth"))]
61    Android(Arc<BluetoothAdapterAndroid>),
62    #[cfg(all(target_os = "macos", feature = "native-bluetooth"))]
63    Mac(Arc<BluetoothAdapterMac>),
64    #[cfg(not(any(
65        all(target_os = "linux", feature = "native-bluetooth"),
66        all(target_os = "android", feature = "native-bluetooth"),
67        all(target_os = "macos", feature = "native-bluetooth")
68    )))]
69    Empty(Arc<BluetoothAdapterEmpty>),
70    #[cfg(feature = "bluetooth-test")]
71    Mock(Arc<FakeBluetoothAdapter>),
72}
73
74impl BluetoothAdapter {
75    #[cfg(all(target_os = "linux", feature = "native-bluetooth"))]
76    pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
77        let bluez_adapter = BluetoothAdapterBluez::init()?;
78        Ok(Self::Bluez(Arc::new(bluez_adapter)))
79    }
80
81    #[cfg(all(target_os = "android", feature = "native-bluetooth"))]
82    pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
83        let blurdroid_adapter = BluetoothAdapterAndroid::get_adapter()?;
84        Ok(Self::Android(Arc::new(blurdroid_adapter)))
85    }
86
87    #[cfg(all(target_os = "macos", feature = "native-bluetooth"))]
88    pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
89        let mac_adapter = BluetoothAdapterMac::init()?;
90        Ok(Self::Mac(Arc::new(mac_adapter)))
91    }
92
93    #[cfg(not(any(
94        all(target_os = "linux", feature = "native-bluetooth"),
95        all(target_os = "android", feature = "native-bluetooth"),
96        all(target_os = "macos", feature = "native-bluetooth")
97    )))]
98    pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
99        let adapter = BluetoothAdapterEmpty::init()?;
100        Ok(Self::Empty(Arc::new(adapter)))
101    }
102
103    #[cfg(feature = "bluetooth-test")]
104    pub fn new_mock() -> Result<BluetoothAdapter, Box<dyn Error>> {
105        Ok(Self::Mock(FakeBluetoothAdapter::new_empty()))
106    }
107
108    pub fn get_id(&self) -> String {
109        get_inner_and_call!(self, BluetoothAdapter, get_id)
110    }
111
112    pub fn get_devices(&self) -> Result<Vec<BluetoothDevice>, Box<dyn Error>> {
113        match self {
114            #[cfg(all(target_os = "linux", feature = "native-bluetooth"))]
115            BluetoothAdapter::Bluez(inner) => {
116                let device_list = inner.get_device_list()?;
117                Ok(device_list
118                    .into_iter()
119                    .map(|device| BluetoothDevice::Bluez(BluetoothDeviceBluez::new(device).into()))
120                    .collect())
121            },
122            #[cfg(all(target_os = "android", feature = "native-bluetooth"))]
123            BluetoothAdapter::Android(inner) => {
124                let device_list = inner.get_device_list()?;
125                Ok(device_list
126                    .into_iter()
127                    .map(|device| {
128                        BluetoothDevice::Android(BluetoothDeviceAndroid::new_empty(
129                            self.0.clone(),
130                            device,
131                        ))
132                    })
133                    .collect())
134            },
135            #[cfg(all(target_os = "macos", feature = "native-bluetooth"))]
136            BluetoothAdapter::Mac(inner) => {
137                let device_list = inner.get_device_list()?;
138                Ok(device_list
139                    .into_iter()
140                    .map(|device| {
141                        BluetoothDevice::Mac(Arc::new(BluetoothDeviceMac::new(
142                            inner.clone(),
143                            device,
144                        )))
145                    })
146                    .collect())
147            },
148            #[cfg(not(any(
149                all(target_os = "linux", feature = "native-bluetooth"),
150                all(target_os = "android", feature = "native-bluetooth"),
151                all(target_os = "macos", feature = "native-bluetooth")
152            )))]
153            BluetoothAdapter::Empty(inner) => {
154                let device_list = inner.get_device_list()?;
155                Ok(device_list
156                    .into_iter()
157                    .map(|device| {
158                        BluetoothDevice::Empty(Arc::new(BluetoothDeviceEmpty::new(device)))
159                    })
160                    .collect())
161            },
162            #[cfg(feature = "bluetooth-test")]
163            BluetoothAdapter::Mock(inner) => {
164                let device_list = inner.get_device_list()?;
165                Ok(device_list
166                    .into_iter()
167                    .map(|device| {
168                        BluetoothDevice::Mock(FakeBluetoothDevice::new_empty(inner.clone(), device))
169                    })
170                    .collect())
171            },
172        }
173    }
174
175    pub fn get_device(&self, address: String) -> Result<Option<BluetoothDevice>, Box<dyn Error>> {
176        let devices = self.get_devices()?;
177        for device in devices {
178            if device.get_address()? == address {
179                return Ok(Some(device));
180            }
181        }
182        Ok(None)
183    }
184
185    pub fn create_mock_device(&self, _device: String) -> Result<BluetoothDevice, Box<dyn Error>> {
186        match self {
187            #[cfg(feature = "bluetooth-test")]
188            BluetoothAdapter::Mock(inner) => Ok(BluetoothDevice::Mock(
189                FakeBluetoothDevice::new_empty(inner.clone(), _device),
190            )),
191            _ => Err(Box::from(
192                "Error! Test functions are not supported on real devices!",
193            )),
194        }
195    }
196
197    pub fn create_discovery_session(&self) -> Result<BluetoothDiscoverySession, Box<dyn Error>> {
198        let discovery_session = match self {
199            #[cfg(all(target_os = "linux", feature = "native-bluetooth"))]
200            #[allow(clippy::arc_with_non_send_sync)] // Problem with underlying library
201            BluetoothAdapter::Bluez(inner) => BluetoothDiscoverySession::Bluez(Arc::new(
202                BluetoothDiscoverySessionBluez::create_session(inner.get_id())?,
203            )),
204            #[cfg(all(target_os = "android", feature = "native-bluetooth"))]
205            BluetoothAdapter::Android(inner) => BluetoothDiscoverySession::Android(Arc::new(
206                BluetoothDiscoverySessionAndroid::create_session(inner.clone())?,
207            )),
208            #[cfg(all(target_os = "macos", feature = "native-bluetooth"))]
209            BluetoothAdapter::Mac(_) => {
210                BluetoothDiscoverySession::Mac(Arc::new(BluetoothDiscoverySessionMac {}))
211            },
212            #[cfg(not(any(
213                all(target_os = "linux", feature = "native-bluetooth"),
214                all(target_os = "android", feature = "native-bluetooth"),
215                all(target_os = "macos", feature = "native-bluetooth")
216            )))]
217            BluetoothAdapter::Empty(_) => {
218                BluetoothDiscoverySession::Empty(Arc::new(BluetoothDiscoverySessionEmpty {}))
219            },
220            #[cfg(feature = "bluetooth-test")]
221            BluetoothAdapter::Mock(inner) => BluetoothDiscoverySession::Mock(Arc::new(
222                FakeBluetoothDiscoverySession::create_session(inner.clone())?,
223            )),
224        };
225        Ok(discovery_session)
226    }
227
228    pub fn get_address(&self) -> Result<String, Box<dyn Error>> {
229        get_inner_and_call!(self, BluetoothAdapter, get_address)
230    }
231
232    pub fn get_name(&self) -> Result<String, Box<dyn Error>> {
233        get_inner_and_call!(self, BluetoothAdapter, get_name)
234    }
235
236    pub fn get_alias(&self) -> Result<String, Box<dyn Error>> {
237        get_inner_and_call!(self, BluetoothAdapter, get_alias)
238    }
239
240    pub fn get_class(&self) -> Result<u32, Box<dyn Error>> {
241        get_inner_and_call!(self, BluetoothAdapter, get_class)
242    }
243
244    pub fn is_powered(&self) -> Result<bool, Box<dyn Error>> {
245        get_inner_and_call!(self, BluetoothAdapter, is_powered)
246    }
247
248    pub fn is_discoverable(&self) -> Result<bool, Box<dyn Error>> {
249        get_inner_and_call!(self, BluetoothAdapter, is_discoverable)
250    }
251
252    pub fn is_pairable(&self) -> Result<bool, Box<dyn Error>> {
253        get_inner_and_call!(self, BluetoothAdapter, is_pairable)
254    }
255
256    pub fn get_pairable_timeout(&self) -> Result<u32, Box<dyn Error>> {
257        get_inner_and_call!(self, BluetoothAdapter, get_pairable_timeout)
258    }
259
260    pub fn get_discoverable_timeout(&self) -> Result<u32, Box<dyn Error>> {
261        get_inner_and_call!(self, BluetoothAdapter, get_discoverable_timeout)
262    }
263
264    pub fn is_discovering(&self) -> Result<bool, Box<dyn Error>> {
265        get_inner_and_call!(self, BluetoothAdapter, is_discovering)
266    }
267
268    pub fn get_uuids(&self) -> Result<Vec<String>, Box<dyn Error>> {
269        get_inner_and_call!(self, BluetoothAdapter, get_uuids)
270    }
271
272    pub fn get_vendor_id_source(&self) -> Result<String, Box<dyn Error>> {
273        get_inner_and_call!(self, BluetoothAdapter, get_vendor_id_source)
274    }
275
276    pub fn get_vendor_id(&self) -> Result<u32, Box<dyn Error>> {
277        get_inner_and_call!(self, BluetoothAdapter, get_vendor_id)
278    }
279
280    pub fn get_product_id(&self) -> Result<u32, Box<dyn Error>> {
281        get_inner_and_call!(self, BluetoothAdapter, get_product_id)
282    }
283
284    pub fn get_device_id(&self) -> Result<u32, Box<dyn Error>> {
285        get_inner_and_call!(self, BluetoothAdapter, get_device_id)
286    }
287
288    pub fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<dyn Error>> {
289        get_inner_and_call!(self, BluetoothAdapter, get_modalias)
290    }
291
292    #[cfg(feature = "bluetooth-test")]
293    pub fn set_id(&self, id: String) -> Result<(), Box<dyn Error>> {
294        match self {
295            #[cfg(feature = "bluetooth-test")]
296            BluetoothAdapter::Mock(inner) => {
297                inner.set_id(id);
298                Ok(())
299            },
300            _ => Err(Box::from(
301                "Error! Test functions are not supported on real devices!",
302            )),
303        }
304    }
305
306    #[cfg(feature = "bluetooth-test")]
307    pub fn set_address(&self, address: String) -> Result<(), Box<dyn Error>> {
308        get_inner_and_call_test_func!(self, BluetoothAdapter, set_address, address)
309    }
310
311    #[cfg(feature = "bluetooth-test")]
312    pub fn set_name(&self, name: String) -> Result<(), Box<dyn Error>> {
313        get_inner_and_call_test_func!(self, BluetoothAdapter, set_name, name)
314    }
315
316    #[cfg(feature = "bluetooth-test")]
317    pub fn set_alias(&self, alias: String) -> Result<(), Box<dyn Error>> {
318        get_inner_and_call_test_func!(self, BluetoothAdapter, set_alias, alias)
319    }
320
321    #[cfg(feature = "bluetooth-test")]
322    pub fn set_class(&self, class: u32) -> Result<(), Box<dyn Error>> {
323        get_inner_and_call_test_func!(self, BluetoothAdapter, set_class, class)
324    }
325
326    #[cfg(feature = "bluetooth-test")]
327    pub fn set_powered(&self, powered: bool) -> Result<(), Box<dyn Error>> {
328        get_inner_and_call_test_func!(self, BluetoothAdapter, set_powered, powered)
329    }
330
331    #[cfg(feature = "bluetooth-test")]
332    pub fn is_present(&self) -> Result<bool, Box<dyn Error>> {
333        get_inner_and_call_test_func!(self, BluetoothAdapter, is_present)
334    }
335
336    #[cfg(feature = "bluetooth-test")]
337    pub fn set_present(&self, present: bool) -> Result<(), Box<dyn Error>> {
338        get_inner_and_call_test_func!(self, BluetoothAdapter, set_present, present)
339    }
340
341    #[cfg(feature = "bluetooth-test")]
342    pub fn set_discoverable(&self, discoverable: bool) -> Result<(), Box<dyn Error>> {
343        get_inner_and_call_test_func!(self, BluetoothAdapter, set_discoverable, discoverable)
344    }
345
346    #[cfg(feature = "bluetooth-test")]
347    pub fn set_pairable(&self, pairable: bool) -> Result<(), Box<dyn Error>> {
348        get_inner_and_call_test_func!(self, BluetoothAdapter, set_pairable, pairable)
349    }
350
351    #[cfg(feature = "bluetooth-test")]
352    pub fn set_pairable_timeout(&self, timeout: u32) -> Result<(), Box<dyn Error>> {
353        get_inner_and_call_test_func!(self, BluetoothAdapter, set_pairable_timeout, timeout)
354    }
355
356    #[cfg(feature = "bluetooth-test")]
357    pub fn set_can_start_discovery(&self, can_start_discovery: bool) -> Result<(), Box<dyn Error>> {
358        get_inner_and_call_test_func!(
359            self,
360            BluetoothAdapter,
361            set_can_start_discovery,
362            can_start_discovery
363        )
364    }
365
366    #[cfg(feature = "bluetooth-test")]
367    pub fn set_discoverable_timeout(&self, timeout: u32) -> Result<(), Box<dyn Error>> {
368        get_inner_and_call_test_func!(self, BluetoothAdapter, set_discoverable_timeout, timeout)
369    }
370
371    #[cfg(feature = "bluetooth-test")]
372    pub fn set_discovering(&self, discovering: bool) -> Result<(), Box<dyn Error>> {
373        get_inner_and_call_test_func!(self, BluetoothAdapter, set_discovering, discovering)
374    }
375
376    #[cfg(feature = "bluetooth-test")]
377    pub fn set_can_stop_discovery(&self, can_stop_discovery: bool) -> Result<(), Box<dyn Error>> {
378        get_inner_and_call_test_func!(
379            self,
380            BluetoothAdapter,
381            set_can_stop_discovery,
382            can_stop_discovery
383        )
384    }
385
386    #[cfg(feature = "bluetooth-test")]
387    pub fn set_uuids(&self, uuids: Vec<String>) -> Result<(), Box<dyn Error>> {
388        get_inner_and_call_test_func!(self, BluetoothAdapter, set_uuids, uuids)
389    }
390
391    #[cfg(feature = "bluetooth-test")]
392    pub fn set_modalias(&self, modalias: String) -> Result<(), Box<dyn Error>> {
393        get_inner_and_call_test_func!(self, BluetoothAdapter, set_modalias, modalias)
394    }
395
396    #[cfg(feature = "bluetooth-test")]
397    pub fn get_ad_datas(&self) -> Result<Vec<String>, Box<dyn Error>> {
398        get_inner_and_call_test_func!(self, BluetoothAdapter, get_ad_datas)
399    }
400
401    #[cfg(feature = "bluetooth-test")]
402    pub fn set_ad_datas(&self, ad_datas: Vec<String>) -> Result<(), Box<dyn Error>> {
403        get_inner_and_call_test_func!(self, BluetoothAdapter, set_ad_datas, ad_datas)
404    }
405}