• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! jni for uwb native stack
2 use jni::objects::{JObject, JValue};
3 use jni::sys::{
4     jarray, jboolean, jbyte, jbyteArray, jint, jintArray, jlong, jobject, jshort, jshortArray,
5     jsize,
6 };
7 use jni::JNIEnv;
8 use log::{error, info};
9 use num_traits::ToPrimitive;
10 use uwb_uci_packets::{
11     GetCapsInfoRspPacket, Packet, SessionGetAppConfigRspPacket, SessionSetAppConfigRspPacket,
12     StatusCode, UciResponseChild, UciResponsePacket, UciVendor_9_ResponseChild,
13     UciVendor_A_ResponseChild, UciVendor_B_ResponseChild, UciVendor_E_ResponseChild,
14     UciVendor_F_ResponseChild,
15 };
16 use uwb_uci_rust::error::UwbErr;
17 use uwb_uci_rust::event_manager::EventManagerImpl as EventManager;
18 use uwb_uci_rust::uci::{uci_hrcv::UciResponse, Dispatcher, DispatcherImpl, JNICommand};
19 
20 trait Context<'a> {
convert_byte_array(&self, array: jbyteArray) -> Result<Vec<u8>, jni::errors::Error>21     fn convert_byte_array(&self, array: jbyteArray) -> Result<Vec<u8>, jni::errors::Error>;
get_array_length(&self, array: jarray) -> Result<jsize, jni::errors::Error>22     fn get_array_length(&self, array: jarray) -> Result<jsize, jni::errors::Error>;
get_short_array_region( &self, array: jshortArray, start: jsize, buf: &mut [jshort], ) -> Result<(), jni::errors::Error>23     fn get_short_array_region(
24         &self,
25         array: jshortArray,
26         start: jsize,
27         buf: &mut [jshort],
28     ) -> Result<(), jni::errors::Error>;
get_int_array_region( &self, array: jintArray, start: jsize, buf: &mut [jint], ) -> Result<(), jni::errors::Error>29     fn get_int_array_region(
30         &self,
31         array: jintArray,
32         start: jsize,
33         buf: &mut [jint],
34     ) -> Result<(), jni::errors::Error>;
get_dispatcher(&self) -> Result<&'a mut dyn Dispatcher, UwbErr>35     fn get_dispatcher(&self) -> Result<&'a mut dyn Dispatcher, UwbErr>;
36 }
37 
38 struct JniContext<'a> {
39     env: JNIEnv<'a>,
40     obj: JObject<'a>,
41 }
42 
43 impl<'a> JniContext<'a> {
new(env: JNIEnv<'a>, obj: JObject<'a>) -> Self44     fn new(env: JNIEnv<'a>, obj: JObject<'a>) -> Self {
45         Self { env, obj }
46     }
47 }
48 
49 impl<'a> Context<'a> for JniContext<'a> {
convert_byte_array(&self, array: jbyteArray) -> Result<Vec<u8>, jni::errors::Error>50     fn convert_byte_array(&self, array: jbyteArray) -> Result<Vec<u8>, jni::errors::Error> {
51         self.env.convert_byte_array(array)
52     }
get_array_length(&self, array: jarray) -> Result<jsize, jni::errors::Error>53     fn get_array_length(&self, array: jarray) -> Result<jsize, jni::errors::Error> {
54         self.env.get_array_length(array)
55     }
get_short_array_region( &self, array: jshortArray, start: jsize, buf: &mut [jshort], ) -> Result<(), jni::errors::Error>56     fn get_short_array_region(
57         &self,
58         array: jshortArray,
59         start: jsize,
60         buf: &mut [jshort],
61     ) -> Result<(), jni::errors::Error> {
62         self.env.get_short_array_region(array, start, buf)
63     }
get_int_array_region( &self, array: jintArray, start: jsize, buf: &mut [jint], ) -> Result<(), jni::errors::Error>64     fn get_int_array_region(
65         &self,
66         array: jintArray,
67         start: jsize,
68         buf: &mut [jint],
69     ) -> Result<(), jni::errors::Error> {
70         self.env.get_int_array_region(array, start, buf)
71     }
get_dispatcher(&self) -> Result<&'a mut dyn Dispatcher, UwbErr>72     fn get_dispatcher(&self) -> Result<&'a mut dyn Dispatcher, UwbErr> {
73         let dispatcher_ptr_value = self.env.get_field(self.obj, "mDispatcherPointer", "J")?;
74         let dispatcher_ptr = dispatcher_ptr_value.j()?;
75         if dispatcher_ptr == 0i64 {
76             error!("The dispatcher is not initialized.");
77             return Err(UwbErr::NoneDispatcher);
78         }
79         // Safety: dispatcher pointer must not be a null pointer and it must point to a valid dispatcher object.
80         // This can be ensured because the dispatcher is created in an earlier stage and
81         // won't be deleted before calling doDeinitialize.
82         unsafe { Ok(&mut *(dispatcher_ptr as *mut DispatcherImpl)) }
83     }
84 }
85 
86 /// Initialize UWB
87 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeInit( _env: JNIEnv, _obj: JObject, ) -> jboolean88 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeInit(
89     _env: JNIEnv,
90     _obj: JObject,
91 ) -> jboolean {
92     logger::init(
93         logger::Config::default()
94             .with_tag_on_device("uwb")
95             .with_min_level(log::Level::Trace)
96             .with_filter("trace,jni=info"),
97     );
98     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeInit: enter");
99     true as jboolean
100 }
101 
102 /// Get max session number
103 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetMaxSessionNumber( _env: JNIEnv, _obj: JObject, ) -> jint104 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetMaxSessionNumber(
105     _env: JNIEnv,
106     _obj: JObject,
107 ) -> jint {
108     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetMaxSessionNumber: enter");
109     5
110 }
111 
112 /// Turn on UWB. initialize the GKI module and HAL module for UWB device.
113 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoInitialize( env: JNIEnv, obj: JObject, ) -> jboolean114 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoInitialize(
115     env: JNIEnv,
116     obj: JObject,
117 ) -> jboolean {
118     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoInitialize: enter");
119     boolean_result_helper(do_initialize(&JniContext::new(env, obj)), "DoInitialize")
120 }
121 
122 /// Turn off UWB. Deinitilize the GKI and HAL module, power of the UWB device.
123 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoDeinitialize( env: JNIEnv, obj: JObject, ) -> jboolean124 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoDeinitialize(
125     env: JNIEnv,
126     obj: JObject,
127 ) -> jboolean {
128     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoDeinitialize: enter");
129     boolean_result_helper(do_deinitialize(&JniContext::new(env, obj)), "DoDeinitialize")
130 }
131 
132 /// get nanos
133 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos( _env: JNIEnv, _obj: JObject, ) -> jlong134 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos(
135     _env: JNIEnv,
136     _obj: JObject,
137 ) -> jlong {
138     info!(
139         "Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos: enter"
140     );
141     0
142 }
143 
144 /// reset the device
145 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDeviceReset( env: JNIEnv, obj: JObject, reset_config: jbyte, ) -> jbyte146 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDeviceReset(
147     env: JNIEnv,
148     obj: JObject,
149     reset_config: jbyte,
150 ) -> jbyte {
151     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeDeviceReset: enter");
152     byte_result_helper(reset_device(&JniContext::new(env, obj), reset_config as u8), "ResetDevice")
153 }
154 
155 /// init the session
156 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionInit( env: JNIEnv, obj: JObject, session_id: jint, session_type: jbyte, ) -> jbyte157 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionInit(
158     env: JNIEnv,
159     obj: JObject,
160     session_id: jint,
161     session_type: jbyte,
162 ) -> jbyte {
163     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionInit: enter");
164     byte_result_helper(
165         session_init(&JniContext::new(env, obj), session_id as u32, session_type as u8),
166         "SessionInit",
167     )
168 }
169 
170 /// deinit the session
171 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDeInit( env: JNIEnv, obj: JObject, session_id: jint, ) -> jbyte172 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDeInit(
173     env: JNIEnv,
174     obj: JObject,
175     session_id: jint,
176 ) -> jbyte {
177     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDeInit: enter");
178     byte_result_helper(
179         session_deinit(&JniContext::new(env, obj), session_id as u32),
180         "SessionDeInit",
181     )
182 }
183 
184 /// get session count
185 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionCount( env: JNIEnv, obj: JObject, ) -> jbyte186 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionCount(
187     env: JNIEnv,
188     obj: JObject,
189 ) -> jbyte {
190     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionCount: enter");
191     match get_session_count(&JniContext::new(env, obj)) {
192         Ok(count) => count,
193         Err(e) => {
194             error!("GetSessionCount failed with {:?}", e);
195             -1
196         }
197     }
198 }
199 
200 ///  start the ranging
201 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStart( env: JNIEnv, obj: JObject, session_id: jint, ) -> jbyte202 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStart(
203     env: JNIEnv,
204     obj: JObject,
205     session_id: jint,
206 ) -> jbyte {
207     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStart: enter");
208     byte_result_helper(ranging_start(&JniContext::new(env, obj), session_id as u32), "RangingStart")
209 }
210 
211 /// stop the ranging
212 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStop( env: JNIEnv, obj: JObject, session_id: jint, ) -> jbyte213 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStop(
214     env: JNIEnv,
215     obj: JObject,
216     session_id: jint,
217 ) -> jbyte {
218     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStop: enter");
219     byte_result_helper(ranging_stop(&JniContext::new(env, obj), session_id as u32), "RangingStop")
220 }
221 
222 /// get the session state
223 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionState( env: JNIEnv, obj: JObject, session_id: jint, ) -> jbyte224 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionState(
225     env: JNIEnv,
226     obj: JObject,
227     session_id: jint,
228 ) -> jbyte {
229     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionState: enter");
230     match get_session_state(&JniContext::new(env, obj), session_id as u32) {
231         Ok(state) => state,
232         Err(e) => {
233             error!("GetSessionState failed with {:?}", e);
234             -1
235         }
236     }
237 }
238 
239 /// set app configurations
240 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetAppConfigurations( env: JNIEnv, obj: JObject, session_id: jint, no_of_params: jint, app_config_param_len: jint, app_config_params: jbyteArray, ) -> jbyteArray241 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetAppConfigurations(
242     env: JNIEnv,
243     obj: JObject,
244     session_id: jint,
245     no_of_params: jint,
246     app_config_param_len: jint,
247     app_config_params: jbyteArray,
248 ) -> jbyteArray {
249     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetAppConfigurations: enter");
250     match set_app_configurations(
251         &JniContext::new(env, obj),
252         session_id as u32,
253         no_of_params as u32,
254         app_config_param_len as u32,
255         app_config_params,
256     ) {
257         Ok(data) => {
258             let uwb_config_status_class =
259                 env.find_class("com/android/server/uwb/data/UwbConfigStatusData").unwrap();
260             let mut buf: Vec<u8> = Vec::new();
261             for iter in data.get_cfg_status() {
262                 buf.push(iter.cfg_id as u8);
263                 buf.push(iter.status as u8);
264             }
265             let cfg_jbytearray = env.byte_array_from_slice(&buf).unwrap();
266             let uwb_config_status_object = env.new_object(
267                 uwb_config_status_class,
268                 "(II[B)V",
269                 &[
270                     JValue::Int(data.get_status().to_i32().unwrap()),
271                     JValue::Int(data.get_cfg_status().len().to_i32().unwrap()),
272                     JValue::Object(JObject::from(cfg_jbytearray)),
273                 ],
274             );
275             *uwb_config_status_object.unwrap()
276         }
277         Err(e) => {
278             error!("SetAppConfig failed with: {:?}", e);
279             *JObject::null()
280         }
281     }
282 }
283 
284 /// get app configurations
285 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetAppConfigurations( env: JNIEnv, obj: JObject, session_id: jint, no_of_params: jint, app_config_param_len: jint, app_config_params: jbyteArray, ) -> jbyteArray286 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetAppConfigurations(
287     env: JNIEnv,
288     obj: JObject,
289     session_id: jint,
290     no_of_params: jint,
291     app_config_param_len: jint,
292     app_config_params: jbyteArray,
293 ) -> jbyteArray {
294     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetAppConfigurations: enter");
295     match get_app_configurations(
296         &JniContext::new(env, obj),
297         session_id as u32,
298         no_of_params as u32,
299         app_config_param_len as u32,
300         app_config_params,
301     ) {
302         Ok(data) => {
303             let uwb_tlv_info_class =
304                 env.find_class("com/android/server/uwb/data/UwbTlvData").unwrap();
305             let mut buf: Vec<u8> = Vec::new();
306             for tlv in data.get_tlvs() {
307                 buf.push(tlv.cfg_id as u8);
308                 buf.push(tlv.v.len() as u8);
309                 buf.extend(&tlv.v);
310             }
311             let tlv_jbytearray = env.byte_array_from_slice(&buf).unwrap();
312             let uwb_tlv_info_object = env.new_object(
313                 uwb_tlv_info_class,
314                 "(II[B)V",
315                 &[
316                     JValue::Int(data.get_status().to_i32().unwrap()),
317                     JValue::Int(data.get_tlvs().len().to_i32().unwrap()),
318                     JValue::Object(JObject::from(tlv_jbytearray)),
319                 ],
320             );
321             *uwb_tlv_info_object.unwrap()
322         }
323         Err(e) => {
324             error!("GetAppConfig failed with: {:?}", e);
325             *JObject::null()
326         }
327     }
328 }
329 
330 /// get capability info
331 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetCapsInfo( env: JNIEnv, obj: JObject, ) -> jbyteArray332 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetCapsInfo(
333     env: JNIEnv,
334     obj: JObject,
335 ) -> jbyteArray {
336     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetCapsInfo: enter");
337     match get_caps_info(&JniContext::new(env, obj)) {
338         Ok(data) => {
339             let uwb_tlv_info_class =
340                 env.find_class("com/android/server/uwb/data/UwbTlvData").unwrap();
341             let mut buf: Vec<u8> = Vec::new();
342             for tlv in data.get_tlvs() {
343                 buf.push(tlv.t as u8);
344                 buf.push(tlv.v.len() as u8);
345                 buf.extend(&tlv.v);
346             }
347             let tlv_jbytearray = env.byte_array_from_slice(&buf).unwrap();
348             let uwb_tlv_info_object = env.new_object(
349                 uwb_tlv_info_class,
350                 "(II[B)V",
351                 &[
352                     JValue::Int(data.get_status().to_i32().unwrap()),
353                     JValue::Int(data.get_tlvs().len().to_i32().unwrap()),
354                     JValue::Object(JObject::from(tlv_jbytearray)),
355                 ],
356             );
357             *uwb_tlv_info_object.unwrap()
358         }
359         Err(e) => {
360             error!("GetCapsInfo failed with: {:?}", e);
361             *JObject::null()
362         }
363     }
364 }
365 
366 /// update multicast list
367 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeControllerMulticastListUpdate( env: JNIEnv, obj: JObject, session_id: jint, action: jbyte, no_of_controlee: jbyte, addresses: jshortArray, sub_session_ids: jintArray, ) -> jbyte368 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeControllerMulticastListUpdate(
369     env: JNIEnv,
370     obj: JObject,
371     session_id: jint,
372     action: jbyte,
373     no_of_controlee: jbyte,
374     addresses: jshortArray,
375     sub_session_ids: jintArray,
376 ) -> jbyte {
377     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeControllerMulticastListUpdate: enter");
378     byte_result_helper(
379         multicast_list_update(
380             &JniContext::new(env, obj),
381             session_id as u32,
382             action as u8,
383             no_of_controlee as u8,
384             addresses,
385             sub_session_ids,
386         ),
387         "ControllerMulticastListUpdate",
388     )
389 }
390 
391 /// set country code
392 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetCountryCode( env: JNIEnv, obj: JObject, country_code: jbyteArray, ) -> jbyte393 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetCountryCode(
394     env: JNIEnv,
395     obj: JObject,
396     country_code: jbyteArray,
397 ) -> jbyte {
398     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetCountryCode: enter");
399     byte_result_helper(set_country_code(&JniContext::new(env, obj), country_code), "SetCountryCode")
400 }
401 
402 /// set country code
403 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSendRawVendorCmd( env: JNIEnv, obj: JObject, gid: jint, oid: jint, payload: jbyteArray, ) -> jobject404 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSendRawVendorCmd(
405     env: JNIEnv,
406     obj: JObject,
407     gid: jint,
408     oid: jint,
409     payload: jbyteArray,
410 ) -> jobject {
411     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeRawVendor: enter");
412     let uwb_vendor_uci_response_class =
413         env.find_class("com/android/server/uwb/data/UwbVendorUciResponse").unwrap();
414     match send_raw_vendor_cmd(
415         &JniContext::new(env, obj),
416         gid.try_into().expect("invalid gid"),
417         oid.try_into().expect("invalid oid"),
418         payload,
419     ) {
420         Ok((gid, oid, payload)) => *env
421             .new_object(
422                 uwb_vendor_uci_response_class,
423                 "(BII[B)V",
424                 &[
425                     JValue::Byte(StatusCode::UciStatusOk.to_i8().unwrap()),
426                     JValue::Int(gid.to_i32().unwrap()),
427                     JValue::Int(oid.to_i32().unwrap()),
428                     JValue::Object(JObject::from(
429                         env.byte_array_from_slice(payload.as_ref()).unwrap(),
430                     )),
431                 ],
432             )
433             .unwrap(),
434         Err(e) => {
435             error!("send raw uci cmd failed with: {:?}", e);
436             *env.new_object(
437                 uwb_vendor_uci_response_class,
438                 "(BII[B)V",
439                 &[
440                     JValue::Byte(StatusCode::UciStatusFailed.to_i8().unwrap()),
441                     JValue::Int(-1),
442                     JValue::Int(-1),
443                     JValue::Object(JObject::null()),
444                 ],
445             )
446             .unwrap()
447         }
448     }
449 }
450 
451 /// retrieve the UWB power stats
452 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetPowerStats( env: JNIEnv, obj: JObject, ) -> jobject453 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetPowerStats(
454     env: JNIEnv,
455     obj: JObject,
456 ) -> jobject {
457     info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetPowerStats: enter");
458     let uwb_power_stats_class =
459         env.find_class("com/android/server/uwb/info/UwbPowerStats").unwrap();
460     match get_power_stats(&JniContext::new(env, obj)) {
461         Ok(para) => {
462             let power_stats = env.new_object(uwb_power_stats_class, "(IIII)V", &para).unwrap();
463             *power_stats
464         }
465         Err(e) => {
466             error!("Get power stats failed with: {:?}", e);
467             *JObject::null()
468         }
469     }
470 }
471 
boolean_result_helper(result: Result<(), UwbErr>, function_name: &str) -> jboolean472 fn boolean_result_helper(result: Result<(), UwbErr>, function_name: &str) -> jboolean {
473     match result {
474         Ok(()) => true as jboolean,
475         Err(err) => {
476             error!("{} failed with: {:?}", function_name, err);
477             false as jboolean
478         }
479     }
480 }
481 
byte_result_helper(result: Result<(), UwbErr>, function_name: &str) -> jbyte482 fn byte_result_helper(result: Result<(), UwbErr>, function_name: &str) -> jbyte {
483     match result {
484         Ok(()) => StatusCode::UciStatusOk.to_i8().unwrap(),
485         Err(err) => {
486             error!("{} failed with: {:?}", function_name, err);
487             match err {
488                 UwbErr::StatusCode(status_code) => status_code
489                     .to_i8()
490                     .unwrap_or_else(|| StatusCode::UciStatusFailed.to_i8().unwrap()),
491                 _ => StatusCode::UciStatusFailed.to_i8().unwrap(),
492             }
493         }
494     }
495 }
496 
do_initialize<'a, T: Context<'a>>(context: &T) -> Result<(), UwbErr>497 fn do_initialize<'a, T: Context<'a>>(context: &T) -> Result<(), UwbErr> {
498     let dispatcher = context.get_dispatcher()?;
499     dispatcher.send_jni_command(JNICommand::Enable)?;
500     match uwa_get_device_info(dispatcher) {
501         Ok(res) => {
502             if let UciResponse::GetDeviceInfoRsp(device_info) = res {
503                 dispatcher.set_device_info(Some(device_info));
504             }
505         }
506         Err(e) => {
507             error!("GetDeviceInfo failed with: {:?}", e);
508             return Err(UwbErr::failed());
509         }
510     }
511     Ok(())
512 }
513 
do_deinitialize<'a, T: Context<'a>>(context: &T) -> Result<(), UwbErr>514 fn do_deinitialize<'a, T: Context<'a>>(context: &T) -> Result<(), UwbErr> {
515     let dispatcher = context.get_dispatcher()?;
516     dispatcher.send_jni_command(JNICommand::Disable(true))?;
517     dispatcher.wait_for_exit()?;
518     Ok(())
519 }
520 
521 // unused, but leaving this behind if we want to use it later.
522 #[allow(dead_code)]
get_specification_info<'a, T: Context<'a>>(context: &T) -> Result<[JValue<'a>; 16], UwbErr>523 fn get_specification_info<'a, T: Context<'a>>(context: &T) -> Result<[JValue<'a>; 16], UwbErr> {
524     let dispatcher = context.get_dispatcher()?;
525     match dispatcher.get_device_info() {
526         Some(data) => {
527             Ok([
528                 JValue::Int((data.get_uci_version() & 0xFF).into()),
529                 JValue::Int(((data.get_uci_version() >> 8) & 0xF).into()),
530                 JValue::Int(((data.get_uci_version() >> 12) & 0xF).into()),
531                 JValue::Int((data.get_mac_version() & 0xFF).into()),
532                 JValue::Int(((data.get_mac_version() >> 8) & 0xF).into()),
533                 JValue::Int(((data.get_mac_version() >> 12) & 0xF).into()),
534                 JValue::Int((data.get_phy_version() & 0xFF).into()),
535                 JValue::Int(((data.get_phy_version() >> 8) & 0xF).into()),
536                 JValue::Int(((data.get_phy_version() >> 12) & 0xF).into()),
537                 JValue::Int((data.get_uci_test_version() & 0xFF).into()),
538                 JValue::Int(((data.get_uci_test_version() >> 8) & 0xF).into()),
539                 JValue::Int(((data.get_uci_test_version() >> 12) & 0xF).into()),
540                 JValue::Int(1), // fira_major_version
541                 JValue::Int(0), // fira_minor_version
542                 JValue::Int(1), // ccc_major_version
543                 JValue::Int(0), // ccc_minor_version
544             ])
545         }
546         None => {
547             error!("Fail to get specification info.");
548             Err(UwbErr::failed())
549         }
550     }
551 }
552 
session_init<'a, T: Context<'a>>( context: &T, session_id: u32, session_type: u8, ) -> Result<(), UwbErr>553 fn session_init<'a, T: Context<'a>>(
554     context: &T,
555     session_id: u32,
556     session_type: u8,
557 ) -> Result<(), UwbErr> {
558     let dispatcher = context.get_dispatcher()?;
559     let res = match dispatcher
560         .block_on_jni_command(JNICommand::UciSessionInit(session_id, session_type))?
561     {
562         UciResponse::SessionInitRsp(data) => data,
563         _ => return Err(UwbErr::failed()),
564     };
565     status_code_to_res(res.get_status())
566 }
567 
session_deinit<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr>568 fn session_deinit<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr> {
569     let dispatcher = context.get_dispatcher()?;
570     let res = match dispatcher.block_on_jni_command(JNICommand::UciSessionDeinit(session_id))? {
571         UciResponse::SessionDeinitRsp(data) => data,
572         _ => return Err(UwbErr::failed()),
573     };
574     status_code_to_res(res.get_status())
575 }
576 
get_session_count<'a, T: Context<'a>>(context: &T) -> Result<jbyte, UwbErr>577 fn get_session_count<'a, T: Context<'a>>(context: &T) -> Result<jbyte, UwbErr> {
578     let dispatcher = context.get_dispatcher()?;
579     match dispatcher.block_on_jni_command(JNICommand::UciSessionGetCount)? {
580         UciResponse::SessionGetCountRsp(rsp) => match status_code_to_res(rsp.get_status()) {
581             Ok(()) => Ok(rsp.get_session_count() as jbyte),
582             Err(err) => Err(err),
583         },
584         _ => Err(UwbErr::failed()),
585     }
586 }
587 
ranging_start<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr>588 fn ranging_start<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr> {
589     let dispatcher = context.get_dispatcher()?;
590     let res = match dispatcher.block_on_jni_command(JNICommand::UciStartRange(session_id))? {
591         UciResponse::RangeStartRsp(data) => data,
592         _ => return Err(UwbErr::failed()),
593     };
594     status_code_to_res(res.get_status())
595 }
596 
ranging_stop<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr>597 fn ranging_stop<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr> {
598     let dispatcher = context.get_dispatcher()?;
599     let res = match dispatcher.block_on_jni_command(JNICommand::UciStopRange(session_id))? {
600         UciResponse::RangeStopRsp(data) => data,
601         _ => return Err(UwbErr::failed()),
602     };
603     status_code_to_res(res.get_status())
604 }
605 
get_session_state<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<jbyte, UwbErr>606 fn get_session_state<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<jbyte, UwbErr> {
607     let dispatcher = context.get_dispatcher()?;
608     match dispatcher.block_on_jni_command(JNICommand::UciGetSessionState(session_id))? {
609         UciResponse::SessionGetStateRsp(data) => Ok(data.get_session_state() as jbyte),
610         _ => Err(UwbErr::failed()),
611     }
612 }
613 
set_app_configurations<'a, T: Context<'a>>( context: &T, session_id: u32, no_of_params: u32, app_config_param_len: u32, app_config_params: jintArray, ) -> Result<SessionSetAppConfigRspPacket, UwbErr>614 fn set_app_configurations<'a, T: Context<'a>>(
615     context: &T,
616     session_id: u32,
617     no_of_params: u32,
618     app_config_param_len: u32,
619     app_config_params: jintArray,
620 ) -> Result<SessionSetAppConfigRspPacket, UwbErr> {
621     let app_configs = context.convert_byte_array(app_config_params)?;
622     let dispatcher = context.get_dispatcher()?;
623     match dispatcher.block_on_jni_command(JNICommand::UciSetAppConfig {
624         session_id,
625         no_of_params,
626         app_config_param_len,
627         app_configs,
628     })? {
629         UciResponse::SessionSetAppConfigRsp(data) => Ok(data),
630         _ => Err(UwbErr::failed()),
631     }
632 }
633 
get_app_configurations<'a, T: Context<'a>>( context: &T, session_id: u32, no_of_params: u32, app_config_param_len: u32, app_config_params: jintArray, ) -> Result<SessionGetAppConfigRspPacket, UwbErr>634 fn get_app_configurations<'a, T: Context<'a>>(
635     context: &T,
636     session_id: u32,
637     no_of_params: u32,
638     app_config_param_len: u32,
639     app_config_params: jintArray,
640 ) -> Result<SessionGetAppConfigRspPacket, UwbErr> {
641     let app_configs = context.convert_byte_array(app_config_params)?;
642     let dispatcher = context.get_dispatcher()?;
643     match dispatcher.block_on_jni_command(JNICommand::UciGetAppConfig {
644         session_id,
645         no_of_params,
646         app_config_param_len,
647         app_configs,
648     })? {
649         UciResponse::SessionGetAppConfigRsp(data) => Ok(data),
650         _ => Err(UwbErr::failed()),
651     }
652 }
653 
get_caps_info<'a, T: Context<'a>>(context: &T) -> Result<GetCapsInfoRspPacket, UwbErr>654 fn get_caps_info<'a, T: Context<'a>>(context: &T) -> Result<GetCapsInfoRspPacket, UwbErr> {
655     let dispatcher = context.get_dispatcher()?;
656     match dispatcher.block_on_jni_command(JNICommand::UciGetCapsInfo)? {
657         UciResponse::GetCapsInfoRsp(data) => Ok(data),
658         _ => Err(UwbErr::failed()),
659     }
660 }
661 
multicast_list_update<'a, T: Context<'a>>( context: &T, session_id: u32, action: u8, no_of_controlee: u8, addresses: jshortArray, sub_session_ids: jintArray, ) -> Result<(), UwbErr>662 fn multicast_list_update<'a, T: Context<'a>>(
663     context: &T,
664     session_id: u32,
665     action: u8,
666     no_of_controlee: u8,
667     addresses: jshortArray,
668     sub_session_ids: jintArray,
669 ) -> Result<(), UwbErr> {
670     let mut address_list = vec![0i16; context.get_array_length(addresses)?.try_into().unwrap()];
671     context.get_short_array_region(addresses, 0, &mut address_list)?;
672     let mut sub_session_id_list =
673         vec![0i32; context.get_array_length(sub_session_ids)?.try_into().unwrap()];
674     context.get_int_array_region(sub_session_ids, 0, &mut sub_session_id_list)?;
675     let dispatcher = context.get_dispatcher()?;
676     let res = match dispatcher.block_on_jni_command(JNICommand::UciSessionUpdateMulticastList {
677         session_id,
678         action,
679         no_of_controlee,
680         address_list: address_list.to_vec(),
681         sub_session_id_list: sub_session_id_list.to_vec(),
682     })? {
683         UciResponse::SessionUpdateControllerMulticastListRsp(data) => data,
684         _ => return Err(UwbErr::failed()),
685     };
686     status_code_to_res(res.get_status())
687 }
688 
set_country_code<'a, T: Context<'a>>( context: &T, country_code: jbyteArray, ) -> Result<(), UwbErr>689 fn set_country_code<'a, T: Context<'a>>(
690     context: &T,
691     country_code: jbyteArray,
692 ) -> Result<(), UwbErr> {
693     let code = context.convert_byte_array(country_code)?;
694     if code.len() != 2 {
695         return Err(UwbErr::failed());
696     }
697     let dispatcher = context.get_dispatcher()?;
698     let res = match dispatcher.block_on_jni_command(JNICommand::UciSetCountryCode { code })? {
699         UciResponse::AndroidSetCountryCodeRsp(data) => data,
700         _ => return Err(UwbErr::failed()),
701     };
702     status_code_to_res(res.get_status())
703 }
704 
get_vendor_uci_payload(data: UciResponsePacket) -> Result<Vec<u8>, UwbErr>705 fn get_vendor_uci_payload(data: UciResponsePacket) -> Result<Vec<u8>, UwbErr> {
706     match data.specialize() {
707         UciResponseChild::UciVendor_9_Response(evt) => match evt.specialize() {
708             UciVendor_9_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
709             UciVendor_9_ResponseChild::None => Ok(Vec::new()),
710         },
711         UciResponseChild::UciVendor_A_Response(evt) => match evt.specialize() {
712             UciVendor_A_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
713             UciVendor_A_ResponseChild::None => Ok(Vec::new()),
714         },
715         UciResponseChild::UciVendor_B_Response(evt) => match evt.specialize() {
716             UciVendor_B_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
717             UciVendor_B_ResponseChild::None => Ok(Vec::new()),
718         },
719         UciResponseChild::UciVendor_E_Response(evt) => match evt.specialize() {
720             UciVendor_E_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
721             UciVendor_E_ResponseChild::None => Ok(Vec::new()),
722         },
723         UciResponseChild::UciVendor_F_Response(evt) => match evt.specialize() {
724             UciVendor_F_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
725             UciVendor_F_ResponseChild::None => Ok(Vec::new()),
726         },
727         _ => {
728             error!("Invalid vendor response with gid {:?}", data.get_group_id());
729             Err(UwbErr::Specialize(data.to_vec()))
730         }
731     }
732 }
733 
send_raw_vendor_cmd<'a, T: Context<'a>>( context: &T, gid: u32, oid: u32, payload: jbyteArray, ) -> Result<(i32, i32, Vec<u8>), UwbErr>734 fn send_raw_vendor_cmd<'a, T: Context<'a>>(
735     context: &T,
736     gid: u32,
737     oid: u32,
738     payload: jbyteArray,
739 ) -> Result<(i32, i32, Vec<u8>), UwbErr> {
740     let payload = context.convert_byte_array(payload)?;
741     let dispatcher = context.get_dispatcher()?;
742     match dispatcher.block_on_jni_command(JNICommand::UciRawVendorCmd { gid, oid, payload })? {
743         UciResponse::RawVendorRsp(response) => Ok((
744             response.get_group_id().to_i32().unwrap(),
745             response.get_opcode().to_i32().unwrap(),
746             get_vendor_uci_payload(response)?,
747         )),
748         _ => Err(UwbErr::failed()),
749     }
750 }
751 
status_code_to_res(status_code: StatusCode) -> Result<(), UwbErr>752 fn status_code_to_res(status_code: StatusCode) -> Result<(), UwbErr> {
753     match status_code {
754         StatusCode::UciStatusOk => Ok(()),
755         _ => Err(UwbErr::StatusCode(status_code)),
756     }
757 }
758 
759 /// create a dispatcher instance
760 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherNew( env: JNIEnv, obj: JObject, ) -> jlong761 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherNew(
762     env: JNIEnv,
763     obj: JObject,
764 ) -> jlong {
765     let eventmanager = match EventManager::new(env, obj) {
766         Ok(evtmgr) => evtmgr,
767         Err(err) => {
768             error!("Fail to create event manager{:?}", err);
769             return *JObject::null() as jlong;
770         }
771     };
772     match DispatcherImpl::new(eventmanager) {
773         Ok(dispatcher) => Box::into_raw(Box::new(dispatcher)) as jlong,
774         Err(err) => {
775             error!("Fail to create dispatcher {:?}", err);
776             *JObject::null() as jlong
777         }
778     }
779 }
780 
781 /// destroy the dispatcher instance
782 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherDestroy( env: JNIEnv, obj: JObject, )783 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherDestroy(
784     env: JNIEnv,
785     obj: JObject,
786 ) {
787     let dispatcher_ptr_value = match env.get_field(obj, "mDispatcherPointer", "J") {
788         Ok(value) => value,
789         Err(err) => {
790             error!("Failed to get the pointer with: {:?}", err);
791             return;
792         }
793     };
794     let dispatcher_ptr = match dispatcher_ptr_value.j() {
795         Ok(value) => value,
796         Err(err) => {
797             error!("Failed to get the pointer with: {:?}", err);
798             return;
799         }
800     };
801     // Safety: dispatcher pointer must not be a null pointer and must point to a valid dispatcher object.
802     // This can be ensured because the dispatcher is created in an earlier stage and
803     // won't be deleted before calling this destroy function.
804     // This function will early return if the instance is already destroyed.
805     let _boxed_dispatcher = unsafe { Box::from_raw(dispatcher_ptr as *mut DispatcherImpl) };
806     info!("The dispatcher successfully destroyed.");
807 }
808 
get_power_stats<'a, T: Context<'a>>(context: &T) -> Result<[JValue<'a>; 4], UwbErr>809 fn get_power_stats<'a, T: Context<'a>>(context: &T) -> Result<[JValue<'a>; 4], UwbErr> {
810     let dispatcher = context.get_dispatcher()?;
811     match dispatcher.block_on_jni_command(JNICommand::UciGetPowerStats)? {
812         UciResponse::AndroidGetPowerStatsRsp(data) => Ok([
813             JValue::Int(data.get_stats().idle_time_ms as i32),
814             JValue::Int(data.get_stats().tx_time_ms as i32),
815             JValue::Int(data.get_stats().rx_time_ms as i32),
816             JValue::Int(data.get_stats().total_wake_count as i32),
817         ]),
818         _ => Err(UwbErr::failed()),
819     }
820 }
821 
uwa_get_device_info(dispatcher: &dyn Dispatcher) -> Result<UciResponse, UwbErr>822 fn uwa_get_device_info(dispatcher: &dyn Dispatcher) -> Result<UciResponse, UwbErr> {
823     let res = dispatcher.block_on_jni_command(JNICommand::UciGetDeviceInfo)?;
824     Ok(res)
825 }
826 
reset_device<'a, T: Context<'a>>(context: &T, reset_config: u8) -> Result<(), UwbErr>827 fn reset_device<'a, T: Context<'a>>(context: &T, reset_config: u8) -> Result<(), UwbErr> {
828     let dispatcher = context.get_dispatcher()?;
829     let res = match dispatcher.block_on_jni_command(JNICommand::UciDeviceReset { reset_config })? {
830         UciResponse::DeviceResetRsp(data) => data,
831         _ => return Err(UwbErr::failed()),
832     };
833     status_code_to_res(res.get_status())
834 }
835 
836 #[cfg(test)]
837 mod mock_context;
838 #[cfg(test)]
839 mod mock_dispatcher;
840 
841 #[cfg(test)]
842 mod tests {
843     use super::*;
844 
845     use crate::mock_context::MockContext;
846     use crate::mock_dispatcher::MockDispatcher;
847 
848     #[test]
test_boolean_result_helper()849     fn test_boolean_result_helper() {
850         assert_eq!(true as jboolean, boolean_result_helper(Ok(()), "Foo"));
851         assert_eq!(false as jboolean, boolean_result_helper(Err(UwbErr::Undefined), "Foo"));
852     }
853 
854     #[test]
test_byte_result_helper()855     fn test_byte_result_helper() {
856         assert_eq!(StatusCode::UciStatusOk.to_i8().unwrap(), byte_result_helper(Ok(()), "Foo"));
857         assert_eq!(
858             StatusCode::UciStatusFailed.to_i8().unwrap(),
859             byte_result_helper(Err(UwbErr::Undefined), "Foo")
860         );
861         assert_eq!(
862             StatusCode::UciStatusRejected.to_i8().unwrap(),
863             byte_result_helper(Err(UwbErr::StatusCode(StatusCode::UciStatusRejected)), "Foo")
864         );
865     }
866 
867     #[test]
test_do_initialize()868     fn test_do_initialize() {
869         let packet = uwb_uci_packets::GetDeviceInfoRspBuilder {
870             status: StatusCode::UciStatusOk,
871             uci_version: 0,
872             mac_version: 0,
873             phy_version: 0,
874             uci_test_version: 0,
875             vendor_spec_info: vec![],
876         }
877         .build();
878 
879         let mut dispatcher = MockDispatcher::new();
880         dispatcher.expect_send_jni_command(JNICommand::Enable, Ok(()));
881         dispatcher.expect_block_on_jni_command(
882             JNICommand::UciGetDeviceInfo,
883             Ok(UciResponse::GetDeviceInfoRsp(packet.clone())),
884         );
885         let mut context = MockContext::new(dispatcher);
886 
887         let result = do_initialize(&context);
888         let device_info = context.get_mock_dispatcher().get_device_info().clone();
889         assert!(result.is_ok());
890         assert_eq!(device_info.unwrap().to_vec(), packet.to_vec());
891     }
892 
893     #[test]
test_do_deinitialize()894     fn test_do_deinitialize() {
895         let mut dispatcher = MockDispatcher::new();
896         dispatcher.expect_send_jni_command(JNICommand::Disable(true), Ok(()));
897         dispatcher.expect_wait_for_exit(Ok(()));
898         let context = MockContext::new(dispatcher);
899 
900         let result = do_deinitialize(&context);
901         assert!(result.is_ok());
902     }
903 
904     #[test]
test_get_specification_info()905     fn test_get_specification_info() {
906         let packet = uwb_uci_packets::GetDeviceInfoRspBuilder {
907             status: StatusCode::UciStatusOk,
908             uci_version: 0x1234,
909             mac_version: 0x5678,
910             phy_version: 0x9ABC,
911             uci_test_version: 0x1357,
912             vendor_spec_info: vec![],
913         }
914         .build();
915         let expected_array = [
916             0x34, 0x2, 0x1, // uci_version
917             0x78, 0x6, 0x5, // mac_version.
918             0xBC, 0xA, 0x9, // phy_version.
919             0x57, 0x3, 0x1, // uci_test_version.
920             1,   // fira_major_version
921             0,   // fira_minor_version
922             1,   // ccc_major_version
923             0,   // ccc_minor_version
924         ];
925 
926         let mut dispatcher = MockDispatcher::new();
927         dispatcher.set_device_info(Some(packet));
928         let context = MockContext::new(dispatcher);
929 
930         let results = get_specification_info(&context).unwrap();
931         for (idx, result) in results.iter().enumerate() {
932             assert_eq!(TryInto::<jint>::try_into(*result).unwrap(), expected_array[idx]);
933         }
934     }
935 
936     #[test]
test_session_init()937     fn test_session_init() {
938         let session_id = 1234;
939         let session_type = 5;
940         let packet =
941             uwb_uci_packets::SessionInitRspBuilder { status: StatusCode::UciStatusOk }.build();
942 
943         let mut dispatcher = MockDispatcher::new();
944         dispatcher.expect_block_on_jni_command(
945             JNICommand::UciSessionInit(session_id, session_type),
946             Ok(UciResponse::SessionInitRsp(packet)),
947         );
948         let context = MockContext::new(dispatcher);
949 
950         let result = session_init(&context, session_id, session_type);
951         assert!(result.is_ok());
952     }
953 
954     #[test]
test_session_deinit()955     fn test_session_deinit() {
956         let session_id = 1234;
957         let packet =
958             uwb_uci_packets::SessionDeinitRspBuilder { status: StatusCode::UciStatusOk }.build();
959 
960         let mut dispatcher = MockDispatcher::new();
961         dispatcher.expect_block_on_jni_command(
962             JNICommand::UciSessionDeinit(session_id),
963             Ok(UciResponse::SessionDeinitRsp(packet)),
964         );
965         let context = MockContext::new(dispatcher);
966 
967         let result = session_deinit(&context, session_id);
968         assert!(result.is_ok());
969     }
970 
971     #[test]
test_get_session_count()972     fn test_get_session_count() {
973         let session_count = 7;
974         let packet = uwb_uci_packets::SessionGetCountRspBuilder {
975             status: StatusCode::UciStatusOk,
976             session_count,
977         }
978         .build();
979 
980         let mut dispatcher = MockDispatcher::new();
981         dispatcher.expect_block_on_jni_command(
982             JNICommand::UciSessionGetCount,
983             Ok(UciResponse::SessionGetCountRsp(packet)),
984         );
985         let context = MockContext::new(dispatcher);
986 
987         let result = get_session_count(&context).unwrap();
988         assert_eq!(result, session_count as jbyte);
989     }
990 
991     #[test]
test_ranging_start()992     fn test_ranging_start() {
993         let session_id = 1234;
994         let packet =
995             uwb_uci_packets::RangeStartRspBuilder { status: StatusCode::UciStatusOk }.build();
996 
997         let mut dispatcher = MockDispatcher::new();
998         dispatcher.expect_block_on_jni_command(
999             JNICommand::UciStartRange(session_id),
1000             Ok(UciResponse::RangeStartRsp(packet)),
1001         );
1002         let context = MockContext::new(dispatcher);
1003 
1004         let result = ranging_start(&context, session_id);
1005         assert!(result.is_ok());
1006     }
1007 
1008     #[test]
test_ranging_stop()1009     fn test_ranging_stop() {
1010         let session_id = 1234;
1011         let packet =
1012             uwb_uci_packets::RangeStopRspBuilder { status: StatusCode::UciStatusOk }.build();
1013 
1014         let mut dispatcher = MockDispatcher::new();
1015         dispatcher.expect_block_on_jni_command(
1016             JNICommand::UciStopRange(session_id),
1017             Ok(UciResponse::RangeStopRsp(packet)),
1018         );
1019         let context = MockContext::new(dispatcher);
1020 
1021         let result = ranging_stop(&context, session_id);
1022         assert!(result.is_ok());
1023     }
1024 
1025     #[test]
test_get_session_state()1026     fn test_get_session_state() {
1027         let session_id = 1234;
1028         let session_state = uwb_uci_packets::SessionState::SessionStateActive;
1029         let packet = uwb_uci_packets::SessionGetStateRspBuilder {
1030             status: StatusCode::UciStatusOk,
1031             session_state,
1032         }
1033         .build();
1034 
1035         let mut dispatcher = MockDispatcher::new();
1036         dispatcher.expect_block_on_jni_command(
1037             JNICommand::UciGetSessionState(session_id),
1038             Ok(UciResponse::SessionGetStateRsp(packet)),
1039         );
1040         let context = MockContext::new(dispatcher);
1041 
1042         let result = get_session_state(&context, session_id).unwrap();
1043         assert_eq!(result, session_state as jbyte);
1044     }
1045 
1046     #[test]
test_set_app_configurations()1047     fn test_set_app_configurations() {
1048         let session_id = 1234;
1049         let no_of_params = 3;
1050         let app_config_param_len = 5;
1051         let app_configs = vec![1, 2, 3, 4, 5];
1052         let fake_app_config_params = std::ptr::null_mut();
1053         let packet = uwb_uci_packets::SessionSetAppConfigRspBuilder {
1054             status: StatusCode::UciStatusOk,
1055             cfg_status: vec![],
1056         }
1057         .build();
1058 
1059         let mut dispatcher = MockDispatcher::new();
1060         dispatcher.expect_block_on_jni_command(
1061             JNICommand::UciSetAppConfig {
1062                 session_id,
1063                 no_of_params,
1064                 app_config_param_len,
1065                 app_configs: app_configs.clone(),
1066             },
1067             Ok(UciResponse::SessionSetAppConfigRsp(packet.clone())),
1068         );
1069         let mut context = MockContext::new(dispatcher);
1070         context.expect_convert_byte_array(fake_app_config_params, Ok(app_configs));
1071 
1072         let result = set_app_configurations(
1073             &context,
1074             session_id,
1075             no_of_params,
1076             app_config_param_len,
1077             fake_app_config_params,
1078         )
1079         .unwrap();
1080         assert_eq!(result.to_vec(), packet.to_vec());
1081     }
1082 
1083     #[test]
test_get_app_configurations()1084     fn test_get_app_configurations() {
1085         let session_id = 1234;
1086         let no_of_params = 3;
1087         let app_config_param_len = 5;
1088         let app_configs = vec![1, 2, 3, 4, 5];
1089         let fake_app_config_params = std::ptr::null_mut();
1090         let packet = uwb_uci_packets::SessionGetAppConfigRspBuilder {
1091             status: StatusCode::UciStatusOk,
1092             tlvs: vec![],
1093         }
1094         .build();
1095 
1096         let mut dispatcher = MockDispatcher::new();
1097         dispatcher.expect_block_on_jni_command(
1098             JNICommand::UciGetAppConfig {
1099                 session_id,
1100                 no_of_params,
1101                 app_config_param_len,
1102                 app_configs: app_configs.clone(),
1103             },
1104             Ok(UciResponse::SessionGetAppConfigRsp(packet.clone())),
1105         );
1106         let mut context = MockContext::new(dispatcher);
1107         context.expect_convert_byte_array(fake_app_config_params, Ok(app_configs));
1108 
1109         let result = get_app_configurations(
1110             &context,
1111             session_id,
1112             no_of_params,
1113             app_config_param_len,
1114             fake_app_config_params,
1115         )
1116         .unwrap();
1117         assert_eq!(result.to_vec(), packet.to_vec());
1118     }
1119 
1120     #[test]
test_get_caps_info()1121     fn test_get_caps_info() {
1122         let packet = uwb_uci_packets::GetCapsInfoRspBuilder {
1123             status: StatusCode::UciStatusOk,
1124             tlvs: vec![],
1125         }
1126         .build();
1127 
1128         let mut dispatcher = MockDispatcher::new();
1129         dispatcher.expect_block_on_jni_command(
1130             JNICommand::UciGetCapsInfo,
1131             Ok(UciResponse::GetCapsInfoRsp(packet.clone())),
1132         );
1133         let context = MockContext::new(dispatcher);
1134 
1135         let result = get_caps_info(&context).unwrap();
1136         assert_eq!(result.to_vec(), packet.to_vec());
1137     }
1138 
1139     #[test]
test_multicast_list_update()1140     fn test_multicast_list_update() {
1141         let session_id = 1234;
1142         let action = 3;
1143         let no_of_controlee = 5;
1144         let fake_addresses = std::ptr::null_mut();
1145         let address_list = Box::new([1, 3, 5, 7, 9]);
1146         let fake_sub_session_ids = std::ptr::null_mut();
1147         let sub_session_id_list = Box::new([2, 4, 6, 8, 10]);
1148         let packet = uwb_uci_packets::SessionUpdateControllerMulticastListRspBuilder {
1149             status: StatusCode::UciStatusOk,
1150         }
1151         .build();
1152 
1153         let mut dispatcher = MockDispatcher::new();
1154         dispatcher.expect_block_on_jni_command(
1155             JNICommand::UciSessionUpdateMulticastList {
1156                 session_id,
1157                 action,
1158                 no_of_controlee,
1159                 address_list: address_list.to_vec(),
1160                 sub_session_id_list: sub_session_id_list.to_vec(),
1161             },
1162             Ok(UciResponse::SessionUpdateControllerMulticastListRsp(packet)),
1163         );
1164         let mut context = MockContext::new(dispatcher);
1165         context.expect_get_array_length(fake_addresses, Ok(address_list.len() as jsize));
1166         context.expect_get_short_array_region(fake_addresses, 0, Ok(address_list));
1167         context
1168             .expect_get_array_length(fake_sub_session_ids, Ok(sub_session_id_list.len() as jsize));
1169         context.expect_get_int_array_region(fake_sub_session_ids, 0, Ok(sub_session_id_list));
1170 
1171         let result = multicast_list_update(
1172             &context,
1173             session_id,
1174             action,
1175             no_of_controlee,
1176             fake_addresses,
1177             fake_sub_session_ids,
1178         );
1179         assert!(result.is_ok());
1180     }
1181 
1182     #[test]
test_set_country_code()1183     fn test_set_country_code() {
1184         let fake_country_code = std::ptr::null_mut();
1185         let country_code = "US".as_bytes().to_vec();
1186         let packet =
1187             uwb_uci_packets::AndroidSetCountryCodeRspBuilder { status: StatusCode::UciStatusOk }
1188                 .build();
1189 
1190         let mut dispatcher = MockDispatcher::new();
1191         dispatcher.expect_block_on_jni_command(
1192             JNICommand::UciSetCountryCode { code: country_code.clone() },
1193             Ok(UciResponse::AndroidSetCountryCodeRsp(packet)),
1194         );
1195         let mut context = MockContext::new(dispatcher);
1196         context.expect_convert_byte_array(fake_country_code, Ok(country_code));
1197 
1198         let result = set_country_code(&context, fake_country_code);
1199         assert!(result.is_ok());
1200     }
1201 
1202     #[test]
test_send_raw_vendor_cmd()1203     fn test_send_raw_vendor_cmd() {
1204         let gid = 2;
1205         let oid = 4;
1206         let opcode = 6;
1207         let fake_payload = std::ptr::null_mut();
1208         let payload = vec![1, 2, 4, 8];
1209         let response = vec![3, 6, 9];
1210         let packet = uwb_uci_packets::UciVendor_9_ResponseBuilder {
1211             opcode,
1212             payload: Some(response.clone().into()),
1213         }
1214         .build()
1215         .into();
1216 
1217         let mut dispatcher = MockDispatcher::new();
1218         dispatcher.expect_block_on_jni_command(
1219             JNICommand::UciRawVendorCmd { gid, oid, payload: payload.clone() },
1220             Ok(UciResponse::RawVendorRsp(packet)),
1221         );
1222         let mut context = MockContext::new(dispatcher);
1223         context.expect_convert_byte_array(fake_payload, Ok(payload));
1224 
1225         let result = send_raw_vendor_cmd(&context, gid, oid, fake_payload).unwrap();
1226         assert_eq!(result.0, uwb_uci_packets::GroupId::VendorReserved9 as i32);
1227         assert_eq!(result.1, opcode as i32);
1228         assert_eq!(result.2, response);
1229     }
1230 
1231     #[test]
test_get_power_stats()1232     fn test_get_power_stats() {
1233         let idle_time_ms = 5;
1234         let tx_time_ms = 4;
1235         let rx_time_ms = 3;
1236         let total_wake_count = 2;
1237         let packet = uwb_uci_packets::AndroidGetPowerStatsRspBuilder {
1238             stats: uwb_uci_packets::PowerStats {
1239                 status: StatusCode::UciStatusOk,
1240                 idle_time_ms,
1241                 tx_time_ms,
1242                 rx_time_ms,
1243                 total_wake_count,
1244             },
1245         }
1246         .build();
1247 
1248         let mut dispatcher = MockDispatcher::new();
1249         dispatcher.expect_block_on_jni_command(
1250             JNICommand::UciGetPowerStats,
1251             Ok(UciResponse::AndroidGetPowerStatsRsp(packet)),
1252         );
1253         let context = MockContext::new(dispatcher);
1254 
1255         let result = get_power_stats(&context).unwrap();
1256         assert_eq!(TryInto::<jint>::try_into(result[0]).unwrap(), idle_time_ms as jint);
1257         assert_eq!(TryInto::<jint>::try_into(result[1]).unwrap(), tx_time_ms as jint);
1258         assert_eq!(TryInto::<jint>::try_into(result[2]).unwrap(), rx_time_ms as jint);
1259         assert_eq!(TryInto::<jint>::try_into(result[3]).unwrap(), total_wake_count as jint);
1260     }
1261 
1262     #[test]
test_reset_device()1263     fn test_reset_device() {
1264         let reset_config = uwb_uci_packets::ResetConfig::UwbsReset as u8;
1265         let packet =
1266             uwb_uci_packets::DeviceResetRspBuilder { status: StatusCode::UciStatusOk }.build();
1267 
1268         let mut dispatcher = MockDispatcher::new();
1269         dispatcher.expect_block_on_jni_command(
1270             JNICommand::UciDeviceReset { reset_config },
1271             Ok(UciResponse::DeviceResetRsp(packet)),
1272         );
1273         let context = MockContext::new(dispatcher);
1274 
1275         let result = reset_device(&context, reset_config);
1276         assert!(result.is_ok());
1277     }
1278 }
1279