Skip to main content

android_ble/
error.rs

1//! Defines error types.
2
3use std::fmt::Debug;
4use std::num::NonZeroI32;
5
6use super::bindings::{android::bluetooth::BluetoothStatusCodes, java::lang::Throwable};
7use super::vm_context::jni_with_env;
8
9/// Internal error type, not compatible with `bluest::Error`.
10#[derive(Clone)]
11pub enum NativeError {
12    GattError(AttError),
13    BluetoothStatusCode(BluetoothStatusCode),
14    JavaError(java_spaghetti::Global<Throwable>),
15    JavaCastError,
16    JavaNullResult,
17    JavaCallReturnedFalse,
18}
19
20impl std::error::Error for NativeError {}
21
22impl std::fmt::Debug for NativeError {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        match self {
25            Self::GattError(att_err) => write!(f, "GattError({att_err:?})"),
26            Self::BluetoothStatusCode(code) => write!(f, "BluetoothStatusCode({code:?})"),
27            Self::JavaError(err) => jni_with_env(|env| {
28                let th = err.as_ref(env);
29                write!(f, "{th:?}")
30            }),
31            Self::JavaCastError => write!(f, "JavaCastError"),
32            Self::JavaNullResult => write!(f, "JavaNullResult"),
33            Self::JavaCallReturnedFalse => write!(f, "JavaCallReturnedFalse"),
34        }
35    }
36}
37
38impl std::fmt::Display for NativeError {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        match self {
41            Self::GattError(att_error) => write!(f, "GATT error: {att_error}"),
42            Self::BluetoothStatusCode(st) => write!(f, "{st}"),
43            Self::JavaError(err) => jni_with_env(|env| {
44                let th = err.as_ref(env);
45                write!(f, "Java Throwable: {th:?}")
46            }),
47            Self::JavaCastError => write!(f, "Java object cast failed"),
48            Self::JavaNullResult => write!(f, "Java call unexpectedly returned null"),
49            Self::JavaCallReturnedFalse => write!(f, "Java call unexpectedly returned false"),
50        }
51    }
52}
53
54impl From<java_spaghetti::Local<'_, Throwable>> for NativeError {
55    fn from(e: java_spaghetti::Local<'_, Throwable>) -> Self {
56        Self::JavaError(e.as_global())
57    }
58}
59
60impl From<AttError> for NativeError {
61    fn from(att_error: AttError) -> Self {
62        Self::GattError(att_error)
63    }
64}
65
66impl From<java_spaghetti::CastError> for NativeError {
67    fn from(_: java_spaghetti::CastError) -> Self {
68        Self::JavaCastError
69    }
70}
71
72impl From<java_spaghetti::Local<'_, Throwable>> for Error {
73    fn from(e: java_spaghetti::Local<'_, Throwable>) -> Self {
74        NativeError::from(e).into()
75    }
76}
77
78impl From<java_spaghetti::CastError> for Error {
79    fn from(e: java_spaghetti::CastError) -> Self {
80        NativeError::from(e).into()
81    }
82}
83
84impl From<AttError> for crate::Error {
85    fn from(e: AttError) -> Self {
86        NativeError::GattError(e).into()
87    }
88}
89
90impl From<ErrorKind> for Error {
91    fn from(kind: ErrorKind) -> Self {
92        Error {
93            kind,
94            source: None,
95            message: String::new(),
96        }
97    }
98}
99
100impl From<NativeError> for Error {
101    fn from(err: NativeError) -> Self {
102        use BluetoothStatusCode::*;
103        let kind = match &err {
104            NativeError::GattError(att_error) => ErrorKind::Protocol(*att_error),
105            NativeError::BluetoothStatusCode(code) => match code {
106                NotAllowed => ErrorKind::NotAuthorized,
107                NotEnabled => ErrorKind::AdapterUnavailable,
108                NotBonded => ErrorKind::NotAuthorized,
109                GattWriteNotAllowed => ErrorKind::NotAuthorized,
110                GattWriteBusy => ErrorKind::NotReady,
111                MissingBluetoothConnectPermission => ErrorKind::NotAuthorized,
112                ProfileServiceNotBound => ErrorKind::Other,
113                Unknown => ErrorKind::Other,
114                FeatureNotSupported => ErrorKind::NotSupported,
115                UnknownError(_) => ErrorKind::Other,
116            },
117            NativeError::JavaError(_)
118            | NativeError::JavaCastError
119            | NativeError::JavaNullResult
120            | NativeError::JavaCallReturnedFalse => ErrorKind::Internal,
121        };
122        let msg = err.to_string();
123        Error::new(kind, Some(err), msg)
124    }
125}
126
127/// See <https://developer.android.com/reference/android/bluetooth/BluetoothStatusCodes>.
128#[derive(Clone, Debug)]
129pub enum BluetoothStatusCode {
130    NotAllowed,
131    NotEnabled,
132    NotBonded,
133    GattWriteNotAllowed,
134    GattWriteBusy,
135    MissingBluetoothConnectPermission,
136    ProfileServiceNotBound,
137    Unknown,
138    FeatureNotSupported,
139    UnknownError(NonZeroI32),
140}
141
142impl std::fmt::Display for BluetoothStatusCode {
143    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144        let err_str = match self {
145            Self::NotAllowed =>
146                "Error code indicating that the API call was initiated by neither the system nor the active user.",
147            Self::NotEnabled =>
148                "Error code indicating that Bluetooth is not enabled.",
149            Self::NotBonded =>
150                "Error code indicating that the Bluetooth Device specified is not bonded.",
151            Self::GattWriteNotAllowed =>
152                "A GATT writeCharacteristic request is not permitted on the remote device.",
153            Self::GattWriteBusy =>
154                "A GATT writeCharacteristic request is not permitted on the remote device.",
155            Self::MissingBluetoothConnectPermission =>
156                "Error code indicating that the caller does not have the Manifest.permission.BLUETOOTH_CONNECT permission.",
157            Self::ProfileServiceNotBound =>
158                "Error code indicating that the profile service is not bound.",
159            Self::Unknown =>
160                "Indicates that an unknown error has occurred.",
161            Self::FeatureNotSupported =>
162                "Indicates that the feature is not supported.",
163            Self::UnknownError(code) => {
164                return f.write_str(&format!("Unknown Error with code {code}"));
165            }
166        };
167        f.write_str(err_str)
168    }
169}
170
171impl From<NonZeroI32> for BluetoothStatusCode {
172    fn from(code: NonZeroI32) -> Self {
173        let raw_code = code.get();
174        match raw_code {
175            BluetoothStatusCodes::ERROR_BLUETOOTH_NOT_ALLOWED => Self::NotAllowed,
176            BluetoothStatusCodes::ERROR_BLUETOOTH_NOT_ENABLED => Self::NotEnabled,
177            BluetoothStatusCodes::ERROR_DEVICE_NOT_BONDED => Self::NotBonded,
178            BluetoothStatusCodes::ERROR_GATT_WRITE_NOT_ALLOWED => Self::GattWriteNotAllowed,
179            BluetoothStatusCodes::ERROR_GATT_WRITE_REQUEST_BUSY => Self::GattWriteBusy,
180            BluetoothStatusCodes::ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION => {
181                Self::MissingBluetoothConnectPermission
182            }
183            BluetoothStatusCodes::ERROR_PROFILE_SERVICE_NOT_BOUND => Self::ProfileServiceNotBound,
184            BluetoothStatusCodes::ERROR_UNKNOWN => Self::Unknown,
185            BluetoothStatusCodes::FEATURE_NOT_SUPPORTED => Self::FeatureNotSupported,
186            _ => Self::UnknownError(code),
187        }
188    }
189}
190
191// NOTE: Code below is migrated from <https://docs.rs/bluest/0.6.9/src/bluest/error.rs.html>.
192
193/// The error type for Bluetooth operations.
194#[derive(Clone, Debug)]
195pub struct Error {
196    kind: ErrorKind,
197    source: Option<NativeError>,
198    message: String,
199}
200
201impl Error {
202    pub(crate) fn new<S: ToString>(
203        kind: ErrorKind,
204        source: Option<NativeError>,
205        message: S,
206    ) -> Self {
207        Error {
208            kind,
209            source,
210            message: message.to_string(),
211        }
212    }
213
214    /// Returns the corresponding [`ErrorKind`] for this error.
215    pub fn kind(&self) -> ErrorKind {
216        self.kind
217    }
218
219    /// Returns the message for this error.
220    pub fn message(&self) -> &str {
221        &self.message
222    }
223}
224
225impl std::fmt::Display for Error {
226    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227        match (self.message.is_empty(), &self.source) {
228            (true, None) => write!(f, "{}", &self.kind),
229            (false, None) => write!(f, "{}: {}", &self.kind, &self.message),
230            (_, Some(err)) => write!(f, "{}", err), // MODIFIED
231        }
232    }
233}
234
235impl std::error::Error for Error {
236    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
237        self.source.as_ref().map(|x| {
238            let x: &(dyn std::error::Error + 'static) = x;
239            x
240        })
241    }
242}
243
244/// A list of general categories of Bluetooth error.
245#[non_exhaustive]
246#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
247pub enum ErrorKind {
248    /// the Bluetooth adapter is not available
249    AdapterUnavailable,
250    /// the Bluetooth adapter is already scanning
251    AlreadyScanning,
252    /// connection failed
253    ConnectionFailed,
254    /// the Bluetooth device isn't connected
255    NotConnected,
256    /// the Bluetooth operation is unsupported
257    NotSupported,
258    /// permission denied
259    NotAuthorized,
260    /// not ready
261    NotReady,
262    /// not found
263    NotFound,
264    /// invalid paramter
265    InvalidParameter,
266    /// timed out
267    Timeout,
268    /// protocol error: {0}
269    Protocol(AttError),
270    /// an internal error has occured
271    Internal,
272    /// the service changed and is no longer valid
273    ServiceChanged,
274    /// error
275    Other,
276}
277
278impl std::fmt::Display for ErrorKind {
279    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
280        match self {
281            ErrorKind::AdapterUnavailable => f.write_str("the Bluetooth adapter is not available"),
282            ErrorKind::AlreadyScanning => f.write_str("the Bluetooth adapter is already scanning"),
283            ErrorKind::ConnectionFailed => f.write_str("connection failed"),
284            ErrorKind::NotConnected => f.write_str("the Bluetooth device isn't connected"),
285            ErrorKind::NotSupported => f.write_str("the Bluetooth operation is unsupported"),
286            ErrorKind::NotAuthorized => f.write_str("permission denied"),
287            ErrorKind::NotReady => f.write_str("not ready"),
288            ErrorKind::NotFound => f.write_str("not found"),
289            ErrorKind::InvalidParameter => f.write_str("invalid paramter"),
290            ErrorKind::Timeout => f.write_str("timed out"),
291            ErrorKind::Protocol(err) => write!(f, "protocol error: {err}"),
292            ErrorKind::Internal => f.write_str("an internal error has occured"),
293            ErrorKind::ServiceChanged => f.write_str("the service changed and is no longer valid"),
294            ErrorKind::Other => f.write_str("error"),
295        }
296    }
297}
298
299/// Bluetooth Attribute Protocol error. See the Bluetooth Core Specification, Vol 3, Part F, ยง3.4.1.1
300#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
301pub struct AttError(u8);
302
303impl AttError {
304    /// The operation completed successfully.
305    pub const SUCCESS: AttError = AttError(0x00);
306    /// The attribute handle given was not valid on this server.
307    pub const INVALID_HANDLE: AttError = AttError(0x01);
308    /// The attribute cannot be read.
309    pub const READ_NOT_PERMITTED: AttError = AttError(0x02);
310    /// The attribute cannot be written.
311    pub const WRITE_NOT_PERMITTED: AttError = AttError(0x03);
312    /// The attribute PDU was invalid.
313    pub const INVALID_PDU: AttError = AttError(0x04);
314    /// The attribute requires authentication before it can be read or written.
315    pub const INSUFFICIENT_AUTHENTICATION: AttError = AttError(0x05);
316    /// Attribute server does not support the request received from the client.
317    pub const REQUEST_NOT_SUPPORTED: AttError = AttError(0x06);
318    /// Offset specified was past the end of the attribute.
319    pub const INVALID_OFFSET: AttError = AttError(0x07);
320    /// The attribute requires authorization before it can be read or written.
321    pub const INSUFFICIENT_AUTHORIZATION: AttError = AttError(0x08);
322    /// Too many prepare writes have been queued.
323    pub const PREPARE_QUEUE_FULL: AttError = AttError(0x09);
324    /// No attribute found within the given attribute handle range.
325    pub const ATTRIBUTE_NOT_FOUND: AttError = AttError(0x0a);
326    /// The attribute cannot be read or written using the Read Blob Request.
327    pub const ATTRIBUTE_NOT_LONG: AttError = AttError(0x0b);
328    /// The Encryption Key Size used for encrypting this link is insufficient.
329    pub const INSUFFICIENT_ENCRYPTION_KEY_SIZE: AttError = AttError(0x0c);
330    /// The attribute value length is invalid for the operation.
331    pub const INVALID_ATTRIBUTE_VALUE_LENGTH: AttError = AttError(0x0d);
332    /// The attribute request that was requested has encountered an error that was unlikely, and therefore could not be completed as requested.
333    pub const UNLIKELY_ERROR: AttError = AttError(0x0e);
334    /// The attribute requires encryption before it can be read or written.
335    pub const INSUFFICIENT_ENCRYPTION: AttError = AttError(0x0f);
336    /// The attribute type is not a supported grouping attribute as defined by a higher layer specification.
337    pub const UNSUPPORTED_GROUP_TYPE: AttError = AttError(0x10);
338    /// Insufficient Resources to complete the request.
339    pub const INSUFFICIENT_RESOURCES: AttError = AttError(0x11);
340    /// The server requests the client to rediscover the database.
341    pub const DATABASE_OUT_OF_SYNC: AttError = AttError(0x12);
342    /// The attribute parameter value was not allowed.
343    pub const VALUE_NOT_ALLOWED: AttError = AttError(0x13);
344    /// Write Request Rejected
345    pub const WRITE_REQUEST_REJECTED: AttError = AttError(0xfc);
346    /// Client Characteristic Configuration Descriptor Improperly Configured
347    pub const CCCD_IMPROPERLY_CONFIGURED: AttError = AttError(0xfd);
348    /// Procedure Already in Progress
349    pub const PROCEDURE_ALREADY_IN_PROGRESS: AttError = AttError(0xfe);
350    /// Out of Range
351    pub const OUT_OF_RANGE: AttError = AttError(0xff);
352
353    /// Converts a [`u8`] value to an [`AttError`].
354    pub const fn from_u8(val: u8) -> Self {
355        AttError(val)
356    }
357
358    /// Converts an [`AttError`] to a [`u8`] value.
359    pub const fn as_u8(self) -> u8 {
360        self.0
361    }
362
363    /// Checks if the error code is in the application error range.
364    pub fn is_application(&self) -> bool {
365        (0x80..0xa0).contains(&self.0)
366    }
367
368    /// Checks if the error code is in the common profile and service range.
369    pub fn is_common_profile_or_service(&self) -> bool {
370        self.0 >= 0xe0
371    }
372}
373
374impl std::fmt::Display for AttError {
375    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
376        match *self {
377            AttError::SUCCESS => f.write_str("The operation completed successfully."),
378            AttError::INVALID_HANDLE => f.write_str("The attribute handle given was not valid on this server."),
379            AttError::READ_NOT_PERMITTED => f.write_str("The attribute cannot be read."),
380            AttError::WRITE_NOT_PERMITTED => f.write_str("The attribute cannot be written."),
381            AttError::INVALID_PDU => f.write_str("The attribute PDU was invalid."),
382            AttError::INSUFFICIENT_AUTHENTICATION => f.write_str("The attribute requires authentication before it can be read or written."),
383            AttError::REQUEST_NOT_SUPPORTED => f.write_str("Attribute server does not support the request received from the client."),
384            AttError::INVALID_OFFSET => f.write_str("Offset specified was past the end of the attribute."),
385            AttError::INSUFFICIENT_AUTHORIZATION => f.write_str("The attribute requires authorization before it can be read or written."),
386            AttError::PREPARE_QUEUE_FULL => f.write_str("Too many prepare writes have been queued."),
387            AttError::ATTRIBUTE_NOT_FOUND => f.write_str("No attribute found within the given attribute handle range."),
388            AttError::ATTRIBUTE_NOT_LONG => f.write_str("The attribute cannot be read or written using the Read Blob Request."),
389            AttError::INSUFFICIENT_ENCRYPTION_KEY_SIZE => f.write_str("The Encryption Key Size used for encrypting this link is insufficient."),
390            AttError::INVALID_ATTRIBUTE_VALUE_LENGTH => f.write_str("The attribute value length is invalid for the operation."),
391            AttError::UNLIKELY_ERROR => f.write_str("The attribute request that was requested has encountered an error that was unlikely, and therefore could not be completed as requested."),
392            AttError::INSUFFICIENT_ENCRYPTION => f.write_str("The attribute requires encryption before it can be read or written."),
393            AttError::UNSUPPORTED_GROUP_TYPE => f.write_str("The attribute type is not a supported grouping attribute as defined by a higher layer specification."),
394            AttError::INSUFFICIENT_RESOURCES => f.write_str("Insufficient Resources to complete the request."),
395            AttError::DATABASE_OUT_OF_SYNC => f.write_str("The server requests the client to rediscover the database."),
396            AttError::VALUE_NOT_ALLOWED => f.write_str("The attribute parameter value was not allowed."),
397            AttError::WRITE_REQUEST_REJECTED => f.write_str("Write Request Rejected"),
398            AttError::CCCD_IMPROPERLY_CONFIGURED => f.write_str("Client Characteristic Configuration Descriptor Improperly Configured"),
399            AttError::PROCEDURE_ALREADY_IN_PROGRESS => f.write_str("Procedure Already in Progress"),
400            AttError::OUT_OF_RANGE => f.write_str("Out of Range"),
401            _ => f.write_str(&format!("Unknown error 0x{:02x}", self.0)),
402        }
403    }
404}
405
406impl From<u8> for AttError {
407    fn from(number: u8) -> Self {
408        AttError(number)
409    }
410}
411
412impl From<AttError> for u8 {
413    fn from(val: AttError) -> Self {
414        val.0
415    }
416}