diff --git a/ffi/src/springboardservices.rs b/ffi/src/springboardservices.rs index a56709f..7f1cade 100644 --- a/ffi/src/springboardservices.rs +++ b/ffi/src/springboardservices.rs @@ -7,6 +7,7 @@ use idevice::{ IdeviceError, IdeviceService, provider::IdeviceProvider, springboardservices::SpringBoardServicesClient, }; +use plist_ffi::plist_t; use crate::{ IdeviceFfiError, IdeviceHandle, ffi_err, provider::IdeviceProviderHandle, run_sync, @@ -263,6 +264,43 @@ pub unsafe extern "C" fn springboard_services_get_interface_orientation( } } +/// Gets the home screen icon layout metrics +/// +/// # Arguments +/// * `client` - A valid SpringBoardServicesClient handle +/// * `res` - On success, will point to a plist dictionary node containing the metrics +/// +/// # Returns +/// An IdeviceFfiError on error, null on success +/// +/// # Safety +/// `client` must be a valid pointer to a handle allocated by this library +/// `res` must be a valid, non-null pointer +#[unsafe(no_mangle)] +pub unsafe extern "C" fn springboard_services_get_homescreen_icon_metrics( + client: *mut SpringBoardServicesClientHandle, + res: *mut plist_t, +) -> *mut IdeviceFfiError { + if client.is_null() || res.is_null() { + tracing::error!("Invalid arguments: {client:?}, {res:?}"); + return ffi_err!(IdeviceError::FfiInvalidArg); + } + let client = unsafe { &mut *client }; + + let output = run_sync(async { client.0.get_homescreen_icon_metrics().await }); + + match output { + Ok(metrics) => { + unsafe { + *res = + plist_ffi::PlistWrapper::new_node(plist::Value::Dictionary(metrics)).into_ptr(); + } + null_mut() + } + Err(e) => ffi_err!(e), + } +} + /// Frees an SpringBoardServicesClient handle /// /// # Arguments diff --git a/idevice/src/services/springboardservices.rs b/idevice/src/services/springboardservices.rs index 3e89004..1fb98d7 100644 --- a/idevice/src/services/springboardservices.rs +++ b/idevice/src/services/springboardservices.rs @@ -325,4 +325,31 @@ impl SpringBoardServicesClient { Ok(orientation) } + + /// Gets the home screen icon layout metrics + /// + /// Returns icon spacing, size, and positioning information + /// + /// # Returns + /// A `plist::Dictionary` containing the icon layout metrics + /// + /// # Errors + /// Returns `IdeviceError` if: + /// - Communication fails + /// - The response is malformed + /// + /// # Example + /// ```rust + /// let metrics = client.get_homescreen_icon_metrics().await?; + /// println!("{:?}", metrics); + /// ``` + pub async fn get_homescreen_icon_metrics(&mut self) -> Result { + let req = crate::plist!({ + "command": "getHomeScreenIconMetrics", + }); + self.idevice.send_plist(req).await?; + + let res = self.idevice.read_plist().await?; + Ok(res) + } } diff --git a/tools/src/springboardservices.rs b/tools/src/springboardservices.rs index 1165b6a..d4efbf4 100644 --- a/tools/src/springboardservices.rs +++ b/tools/src/springboardservices.rs @@ -49,6 +49,10 @@ pub fn register() -> JkCommand { "get_interface_orientation", JkCommand::new().help("Gets the device's current screen orientation"), ) + .with_subcommand( + "get_homescreen_icon_metrics", + JkCommand::new().help("Gets home screen icon layout metrics"), + ) .subcommand_required(true) } @@ -113,6 +117,14 @@ pub async fn main(arguments: &CollectedArguments, provider: Box { + let metrics = sbc + .get_homescreen_icon_metrics() + .await + .expect("Failed to get homescreen icon metrics"); + let metrics_value = plist::Value::Dictionary(metrics); + println!("{}", pretty_print_plist(&metrics_value)); + } _ => unreachable!(), } }