1use 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#[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#[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#[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 pub fn kind(&self) -> ErrorKind {
216 self.kind
217 }
218
219 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), }
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#[non_exhaustive]
246#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
247pub enum ErrorKind {
248 AdapterUnavailable,
250 AlreadyScanning,
252 ConnectionFailed,
254 NotConnected,
256 NotSupported,
258 NotAuthorized,
260 NotReady,
262 NotFound,
264 InvalidParameter,
266 Timeout,
268 Protocol(AttError),
270 Internal,
272 ServiceChanged,
274 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#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
301pub struct AttError(u8);
302
303impl AttError {
304 pub const SUCCESS: AttError = AttError(0x00);
306 pub const INVALID_HANDLE: AttError = AttError(0x01);
308 pub const READ_NOT_PERMITTED: AttError = AttError(0x02);
310 pub const WRITE_NOT_PERMITTED: AttError = AttError(0x03);
312 pub const INVALID_PDU: AttError = AttError(0x04);
314 pub const INSUFFICIENT_AUTHENTICATION: AttError = AttError(0x05);
316 pub const REQUEST_NOT_SUPPORTED: AttError = AttError(0x06);
318 pub const INVALID_OFFSET: AttError = AttError(0x07);
320 pub const INSUFFICIENT_AUTHORIZATION: AttError = AttError(0x08);
322 pub const PREPARE_QUEUE_FULL: AttError = AttError(0x09);
324 pub const ATTRIBUTE_NOT_FOUND: AttError = AttError(0x0a);
326 pub const ATTRIBUTE_NOT_LONG: AttError = AttError(0x0b);
328 pub const INSUFFICIENT_ENCRYPTION_KEY_SIZE: AttError = AttError(0x0c);
330 pub const INVALID_ATTRIBUTE_VALUE_LENGTH: AttError = AttError(0x0d);
332 pub const UNLIKELY_ERROR: AttError = AttError(0x0e);
334 pub const INSUFFICIENT_ENCRYPTION: AttError = AttError(0x0f);
336 pub const UNSUPPORTED_GROUP_TYPE: AttError = AttError(0x10);
338 pub const INSUFFICIENT_RESOURCES: AttError = AttError(0x11);
340 pub const DATABASE_OUT_OF_SYNC: AttError = AttError(0x12);
342 pub const VALUE_NOT_ALLOWED: AttError = AttError(0x13);
344 pub const WRITE_REQUEST_REJECTED: AttError = AttError(0xfc);
346 pub const CCCD_IMPROPERLY_CONFIGURED: AttError = AttError(0xfd);
348 pub const PROCEDURE_ALREADY_IN_PROGRESS: AttError = AttError(0xfe);
350 pub const OUT_OF_RANGE: AttError = AttError(0xff);
352
353 pub const fn from_u8(val: u8) -> Self {
355 AttError(val)
356 }
357
358 pub const fn as_u8(self) -> u8 {
360 self.0
361 }
362
363 pub fn is_application(&self) -> bool {
365 (0x80..0xa0).contains(&self.0)
366 }
367
368 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}