From 43aa783433862d61de450541d8a8a4b29d3d4a8f Mon Sep 17 00:00:00 2001 From: uncor3 Date: Fri, 26 Sep 2025 17:27:03 +0000 Subject: [PATCH] refactor DeviceInfoWidget - Adds battery widget and real-time battery monitoring - Creates custom battery widget component for visual battery status display - Integrates comprehensive battery information including charging state, current level, connection type (USB/USB-C), and power consumption - Implements automatic battery status updates every 30 seconds to keep information current during device connection - Refactors battery data retrieval into separate service function for better code organization and reusability - Enhances device info header with charging status, power consumption, and connection type indicators alongside visual battery widget --- src/batterywidget.cpp | 133 +++++++++++++++++++++++ src/batterywidget.h | 35 ++++++ src/core/services/get_battery_info.cpp | 43 ++++++++ src/core/services/init_device.cpp | 143 +++++++++++-------------- src/deviceinfowidget.cpp | 106 +++++++++++++++++- src/deviceinfowidget.h | 11 +- src/iDescriptor.h | 63 ++++++++++- 7 files changed, 447 insertions(+), 87 deletions(-) create mode 100644 src/batterywidget.cpp create mode 100644 src/batterywidget.h create mode 100644 src/core/services/get_battery_info.cpp diff --git a/src/batterywidget.cpp b/src/batterywidget.cpp new file mode 100644 index 0000000..533334d --- /dev/null +++ b/src/batterywidget.cpp @@ -0,0 +1,133 @@ +// https://github.com/p-dobrzynski-dev/QtCustomWidgets/blob/master/batterywidget.cpp +#include "batterywidget.h" + +#include +#include +#include +#include +#include + +BatteryWidget::BatteryWidget(float value, bool isCharging, QWidget *parent) + : QWidget(parent), m_value(value), m_isCharging(isCharging) +{ + setMinimumSize(50, 40); + setMaximumSize(60, 40); +} + +void BatteryWidget::resizeEvent(QResizeEvent *) +{ + widgetFrame = this->rect(); + + widgetFrame.setSize(QSize(widgetFrame.width(), widgetFrame.height() / 2)); + widgetFrame.moveTop(widgetFrame.center().y()); + + float scaleValue = 0.95; + QSizeF mainBatteryFrameSize = + QSizeF(widgetFrame.width() * scaleValue, widgetFrame.height()); + mainBatteryFrame.setSize(mainBatteryFrameSize); + + mainBatteryFrame.moveTopLeft(widgetFrame.topLeft()); + + QSizeF tipBatteryFrameSize = + QSizeF(widgetFrame.width() / 3, widgetFrame.height() / 2); + tipBatteryFrame.setSize(tipBatteryFrameSize); + + QPointF tipBatteryFramePoint = + QPointF(widgetFrame.topRight().x() - tipBatteryFrameSize.width(), + widgetFrame.topRight().y() + tipBatteryFrameSize.height() / 2); + tipBatteryFrame.moveTopLeft(tipBatteryFramePoint); + + float batteryLevelOffset = mainBatteryFrame.height() / 20; + QSizeF batteryLevelFrameSize = + QSizeF(mainBatteryFrame.width() - 2 * batteryLevelOffset, + mainBatteryFrame.height() - 2 * batteryLevelOffset); + batteryLevelFrame.setSize(batteryLevelFrameSize); + + QPointF batteryFramePoint = + QPointF(mainBatteryFrame.topLeft().x() + batteryLevelOffset, + mainBatteryFrame.topLeft().y() + batteryLevelOffset); + batteryLevelFrame.moveTopLeft(batteryFramePoint); +} + +void BatteryWidget::setValue(float newValue) +{ + m_value = newValue; + this->update(); +} + +float BatteryWidget::getValue() const { return m_value; } + +void BatteryWidget::setChargingState(bool state) +{ + m_isCharging = state; + this->update(); + this->repaint(); +} + +void BatteryWidget::updateContext(bool isCharging, float newValue) +{ + m_isCharging = isCharging; + m_value = newValue; + this->update(); + this->repaint(); +} + +bool BatteryWidget::getChargingState() { return m_isCharging; } + +void BatteryWidget::paintEvent(QPaintEvent *) +{ + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + QPen pen = QPen(Qt::red); + QBrush brush = QBrush(Qt::white); + + painter.setPen(pen); + // Drawing battery frame + + float widgetCorner = widgetFrame.height() / 15; + + QPainterPath FramePath; + FramePath.setFillRule(Qt::WindingFill); + FramePath.addRoundedRect(mainBatteryFrame, widgetCorner, widgetCorner); + FramePath.addRoundedRect(tipBatteryFrame, widgetCorner, widgetCorner); + FramePath = FramePath.simplified(); + + pen.setColor(Qt::gray); + pen.setWidth(widgetFrame.width() / 75); + painter.setPen(pen); + painter.drawPath(FramePath); + + painter.setBrush(QBrush(QColor("#44bd32"))); + painter.setPen(Qt::NoPen); + QRectF batteryLevelRect = QRectF(); + QSize batterySizeRect = + QSize(batteryLevelFrame.width() * m_value / m_maxValue, + batteryLevelFrame.height()); + batteryLevelRect.setSize(batterySizeRect); + batteryLevelRect.moveTo(batteryLevelFrame.topLeft()); + painter.drawRoundedRect(batteryLevelRect, widgetCorner, widgetCorner); + + pen.setColor(Qt::white); + painter.setPen(pen); + QFont textFont = QFont(); + textFont.setPixelSize(widgetFrame.height() / 2); + painter.setFont(textFont); + QFontMetrics fm(textFont); + QString percentageLevelString = QString("%1%").arg(m_value); + float textWidth = fm.horizontalAdvance(percentageLevelString); + float textHeight = fm.height(); + + QPointF textPosition = QPointF(widgetFrame.center().x() - textWidth / 2, + widgetFrame.center().y() + textHeight / 3); + painter.drawText(textPosition, percentageLevelString); + + float chargerSize = widgetFrame.height() / 2; + + // if (isCharging) { + // QPixmap pixmap(":/img/charge.png"); + // painter.drawPixmap(widgetFrame.center().x() - chargerSize * 1.5, + // widgetFrame.top() + chargerSize / 2, chargerSize, + // chargerSize, pixmap); + // } +} \ No newline at end of file diff --git a/src/batterywidget.h b/src/batterywidget.h new file mode 100644 index 0000000..fd68d2d --- /dev/null +++ b/src/batterywidget.h @@ -0,0 +1,35 @@ +#ifndef BATTERYWIDGET_H +#define BATTERYWIDGET_H + +#include + +class BatteryWidget : public QWidget +{ + Q_OBJECT +public: + BatteryWidget(float value, bool isCharging, QWidget *parent); + bool getChargingState(); + void setChargingState(bool state); + void updateContext(bool isCharging, float newValue); + + // New methods for value management + void setValue(float newValue); + float getValue() const; + +private: + QRectF widgetFrame; + QRectF mainBatteryFrame; + QRectF tipBatteryFrame; + QRectF batteryLevelFrame; + + bool m_isCharging = false; + + float m_value = 0.0f; + float m_minValue = 0.0f; + float m_maxValue = 100.0f; + + void resizeEvent(QResizeEvent *event) override; + void paintEvent(QPaintEvent *event) override; +}; + +#endif // BATTERYWIDGET_H diff --git a/src/core/services/get_battery_info.cpp b/src/core/services/get_battery_info.cpp new file mode 100644 index 0000000..987980b --- /dev/null +++ b/src/core/services/get_battery_info.cpp @@ -0,0 +1,43 @@ +#include "../../iDescriptor.h" +#include "plist/plist.h" +#include +#include +#include + +void get_battery_info(std::string productType, idevice_t idevice, + bool is_iphone, plist_t &diagnostics) +{ + diagnostics_relay_client_t diagnostics_client = nullptr; + try { + + if (diagnostics_relay_client_start_service(idevice, &diagnostics_client, + nullptr) != + DIAGNOSTICS_RELAY_E_SUCCESS) { + qDebug() << "Failed to start diagnostics relay service."; + return; + } + + bool newerThaniPhone8 = + is_product_type_newer(productType, std::string("iPhone8,1")); + + const char *batteryQuery = + is_iphone + ? newerThaniPhone8 ? "AppleSmartBattery" : "AppleARMPMUCharger" + : "AppleARMPMUCharger"; + + if (diagnostics_relay_query_ioregistry_entry( + diagnostics_client, nullptr, batteryQuery, &diagnostics) != + DIAGNOSTICS_RELAY_E_SUCCESS && + !diagnostics) { + + qDebug() + << "Failed to query diagnostics relay for AppleARMPMUCharger."; + if (diagnostics_client) + diagnostics_relay_client_free(diagnostics_client); + } + } catch (const std::exception &e) { + if (diagnostics_client) + diagnostics_relay_client_free(diagnostics_client); + qDebug() << "Exception in get_battery_info: " << e.what(); + } +} \ No newline at end of file diff --git a/src/core/services/init_device.cpp b/src/core/services/init_device.cpp index 8a293c3..9c1bc07 100644 --- a/src/core/services/init_device.cpp +++ b/src/core/services/init_device.cpp @@ -36,8 +36,8 @@ std::string safeGetXML(const char *key, pugi::xml_node dict) // TODO: return tyype DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, - afc_client_t &afcClient, plist_t &diagnostics, - DeviceInfo &d) + afc_client_t &afcClient, + IDescriptorInitDeviceResult &result) { pugi::xml_node dict = doc.child("plist").child("dict"); auto safeGet = [&](const char *key) -> std::string { @@ -67,7 +67,7 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, } return false; }; - + DeviceInfo &d = result.deviceInfo; d.deviceName = safeGet("DeviceName"); d.deviceClass = safeGet("DeviceClass"); d.deviceColor = safeGet("DeviceColor"); @@ -115,38 +115,71 @@ DeviceInfo fullDeviceInfo(const pugi::xml_document &doc, DeviceInfo::ActivationState::Unactivated; // Default value } // TODO:RegionInfo: LL/A - d.productType = parse_product_type(safeGet("ProductType")); + std::string rawProductType = safeGet("ProductType"); + d.productType = parse_product_type(rawProductType); + d.rawProductType = rawProductType; d.jailbroken = detect_jailbroken(afcClient); + d.is_iPhone = safeGet("DeviceClass") == "iPhone"; - uint64_t cycleCount; - plist_get_uint_val( - PlistNavigator(diagnostics)["IORegistry"]["BatteryData"]["CycleCount"], - &cycleCount); + /*BatteryInfo*/ + plist_t diagnostics = nullptr; + get_battery_info(rawProductType, result.device, d.is_iPhone, diagnostics); + if (!diagnostics) { + qDebug() << "Failed to get diagnostics plist."; + return d; + } - char *batterySerialNumber = nullptr; - plist_get_string_val( + plist_print(diagnostics); + uint64_t cycleCount = + PlistNavigator(diagnostics)["IORegistry"]["BatteryData"]["CycleCount"] + .getUInt(); + + std::string batterySerialNumber = PlistNavigator( - diagnostics)["IORegistry"]["BatteryData"]["BatterySerialNumber"], - &batterySerialNumber); - - uint64_t designCapacity = 0; - plist_get_uint_val( + diagnostics)["IORegistry"]["BatteryData"]["BatterySerialNumber"] + .getString(); + uint64_t designCapacity = PlistNavigator( - diagnostics)["IORegistry"]["BatteryData"]["DesignCapacity"], - &designCapacity); + diagnostics)["IORegistry"]["BatteryData"]["DesignCapacity"] + .getUInt(); - uint64_t absoluteCapacity = 0; - plist_get_uint_val( - PlistNavigator(diagnostics)["IORegistry"]["AbsoluteCapacity"], - &absoluteCapacity); + uint64_t appleRawCurrentCapacity = + PlistNavigator(diagnostics)["IORegistry"]["AppleRawCurrentCapacity"] + .getUInt(); d.batteryInfo.health = - QString::number((absoluteCapacity * 100) / designCapacity) + "%"; + QString::number((appleRawCurrentCapacity * 100) / designCapacity) + "%"; d.batteryInfo.cycleCount = cycleCount; - d.batteryInfo.serialNumber = batterySerialNumber + d.batteryInfo.serialNumber = !batterySerialNumber.empty() ? batterySerialNumber : "Error retrieving serial number"; + d.batteryInfo.isCharging = + PlistNavigator(diagnostics)["IORegistry"]["IsCharging"].getBool(); + + d.batteryInfo.fullyCharged = + PlistNavigator(diagnostics)["IORegistry"]["FullyCharged"].getBool(); + + d.batteryInfo.currentBatteryLevel = + PlistNavigator(diagnostics)["IORegistry"]["CurrentCapacity"].getUInt(); + + d.batteryInfo.usbConnectionType = + PlistNavigator( + diagnostics)["IORegistry"]["AdapterDetails"]["Description"] + .getString() == "usb type-c" + ? BatteryInfo::ConnectionType::USB_TYPEC + : BatteryInfo::ConnectionType::USB; + + d.batteryInfo.adapterVoltage = + PlistNavigator(diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0] + ["AdapterVoltage"] + .getUInt(); + + d.batteryInfo.watts = + PlistNavigator( + diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0]["Watts"] + .getUInt(); + plist_free(diagnostics); diagnostics = nullptr; @@ -167,7 +200,6 @@ IDescriptorInitDeviceResult init_idescriptor_device(const char *udid) // LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING = -19, lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR; lockdownd_service_descriptor_t lockdownService = nullptr; - diagnostics_relay_client_t diagnostics_client = nullptr; afc_client_t afcClient = nullptr; try { idevice_error_t ret = idevice_new_with_options(&result.device, udid, @@ -211,13 +243,6 @@ IDescriptorInitDeviceResult init_idescriptor_device(const char *udid) return result; } - if (diagnostics_relay_client_start_service( - result.device, &diagnostics_client, nullptr) != - DIAGNOSTICS_RELAY_E_SUCCESS) { - qDebug() << "Failed to start diagnostics relay service."; - return result; - } - pugi::xml_document infoXml; get_device_info_xml(udid, 0, 0, infoXml, client, result.device); @@ -232,62 +257,20 @@ IDescriptorInitDeviceResult init_idescriptor_device(const char *udid) return result; } - plist_t diagnostics = nullptr; std::string productType = safeGetXML("ProductType", infoXml.child("plist").child("dict")); - bool is_iphone = - safeGetXML("DeviceClass", infoXml.child("plist").child("dict")) == - "iPhone"; - if (is_iphone) { - - qDebug() << "iPhone is newer than iPhone 8 ?" - << is_product_type_newer(productType, - std::string("iPhone10,1")); - } - - const char *batteryQuery = - is_iphone - ? is_product_type_newer(productType, std::string("iPhone8,1")) - ? "AppleSmartBattery" - : "AppleARMPMUCharger" - : "AppleARMPMUCharger"; - // TODO: iPhone 8 and above should query AppleSmartBattery - // TODO: try catch here - - if (diagnostics_relay_query_ioregistry_entry( - diagnostics_client, nullptr, batteryQuery, &diagnostics) != - DIAGNOSTICS_RELAY_E_SUCCESS && - !diagnostics) { - - qDebug() - << "Failed to query diagnostics relay for AppleARMPMUCharger."; - // Clean up resources before returning - // if (afcClient) - // afc_client_free(afcClient); - if (lockdownService) - lockdownd_service_descriptor_free(lockdownService); - if (client) - lockdownd_client_free(client); - if (diagnostics_client) - diagnostics_relay_client_free(diagnostics_client); - return result; - } - // if (result.device) idevice_free(result.device); - fullDeviceInfo(infoXml, afcClient, diagnostics, result.deviceInfo); + fullDeviceInfo(infoXml, afcClient, result); result.afcClient = afcClient; result.success = true; - // TODO: cleanup needed ? - // if (afcClient) - // afc_client_free(afcClient); - // if (lockdownService) - // lockdownd_service_descriptor_free(lockdownService); - // if (client) - // lockdownd_client_free(client); - // if (diagnostics_client) - // diagnostics_relay_client_free(diagnostics_client); + + if (lockdownService) + lockdownd_service_descriptor_free(lockdownService); + if (client) + lockdownd_client_free(client); + return result; } catch (const std::exception &e) { diff --git a/src/deviceinfowidget.cpp b/src/deviceinfowidget.cpp index 636862d..1fbdfed 100644 --- a/src/deviceinfowidget.cpp +++ b/src/deviceinfowidget.cpp @@ -1,4 +1,5 @@ #include "deviceinfowidget.h" +#include "batterywidget.h" #include "diskusagewidget.h" #include "fileexplorerwidget.h" #include "iDescriptor.h" @@ -16,6 +17,7 @@ #include #include #include +#include #include // A custom QGraphicsView that keeps the content fitted with aspect ratio on @@ -39,7 +41,7 @@ protected: }; DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) - : QWidget(parent), device(device) + : QWidget(parent), m_device(device) { // Main layout with horizontal orientation QHBoxLayout *mainLayout = new QHBoxLayout(this); @@ -74,15 +76,49 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) // Header QWidget *headerWidget = new QWidget(); + headerWidget->setObjectName("headerWidget"); + headerWidget->setStyleSheet("QWidget#headerWidget { " + " border: 1px solid #ccc; " + " border-radius: 6px; " + "}"); + QHBoxLayout *headerLayout = new QHBoxLayout(headerWidget); - // headerLayout->setContentsMargins(0, 0, 0, 0); - // headerLayout->setSpacing(10); + headerLayout->setContentsMargins(10, 10, 10, 10); + headerLayout->setSpacing(15); QLabel *devProductType = new QLabel(QString::fromStdString(device->deviceInfo.productType)); devProductType->setStyleSheet("font-size: 1rem; font-weight: bold;"); + QLabel *diskCapacityLabel = new QLabel( + QString::number(device->deviceInfo.diskInfo.totalDiskCapacity / + (1000 * 1000 * 1000)) + + " GB"); + m_chargingStatusLabel = + new QLabel(device->deviceInfo.batteryInfo.isCharging ? "Charging" + : "Not Charging"); + m_chargingStatusLabel->setStyleSheet("font-size: 1rem;"); + + m_chargingWattsLabel = + new QLabel(QString::number(device->deviceInfo.batteryInfo.watts) + "W"); + + m_cableTypeLabel = + new QLabel(device->deviceInfo.batteryInfo.usbConnectionType == + BatteryInfo::ConnectionType::USB + ? "USB" + : "USB-C"); + + m_batteryWidget = + new BatteryWidget(device->deviceInfo.batteryInfo.currentBatteryLevel, + device->deviceInfo.batteryInfo.isCharging, this); + headerLayout->addWidget(devProductType); + headerLayout->addWidget(diskCapacityLabel); + headerLayout->addWidget(m_chargingStatusLabel); + headerLayout->addWidget(m_batteryWidget); + headerLayout->addWidget(m_chargingWattsLabel); + headerLayout->addWidget(m_cableTypeLabel); + infoLayout->addWidget(headerWidget); // add spacer infoLayout->addSpacerItem( @@ -102,6 +138,7 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) gridLayout->setColumnStretch(1, 1); // Allow value column to stretch gridLayout->setColumnStretch( 3, 1); // Allow value column for right side to stretch + gridLayout->setContentsMargins(17, 17, 17, 17); gridWidget->setLayout(gridLayout); QList> infoItems; @@ -229,6 +266,11 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) rightSideLayout->addWidget(new DiskUsageWidget(device, this)); rightSideLayout->setAlignment(Qt::AlignCenter); mainLayout->addLayout(rightSideLayout, 2); // Stretch factor 2 + + m_updateTimer = new QTimer(this); + connect(m_updateTimer, &QTimer::timeout, this, + &DeviceInfoWidget::updateBatteryInfo); + m_updateTimer->start(30000); // Update every 30 seconds } void DeviceInfoWidget::onBatteryMoreClicked() @@ -237,9 +279,9 @@ void DeviceInfoWidget::onBatteryMoreClicked() msgBox.setWindowTitle("Battery Details"); QString details = "Battery Cycle Count: " + - QString::number(device->deviceInfo.batteryInfo.cycleCount) + "\n" + + QString::number(m_device->deviceInfo.batteryInfo.cycleCount) + "\n" + "Battery Serial Number: " + - QString::fromStdString(device->deviceInfo.batteryInfo.serialNumber); + QString::fromStdString(m_device->deviceInfo.batteryInfo.serialNumber); msgBox.setText(details); msgBox.exec(); } @@ -265,4 +307,58 @@ QPixmap DeviceInfoWidget::getDeviceIcon(const std::string &productType) } return icon; +} + +void DeviceInfoWidget::updateBatteryInfo() +{ + qDebug() << "Updating battery info..."; + plist_t diagnostics = nullptr; + get_battery_info(m_device->deviceInfo.rawProductType, m_device->device, + m_device->deviceInfo.is_iPhone, diagnostics); + + if (!diagnostics) { + qDebug() << "Failed to get diagnostics plist."; + return; + } + /*DATA*/ + DeviceInfo &d = m_device->deviceInfo; + + d.batteryInfo.isCharging = + PlistNavigator(diagnostics)["IORegistry"]["IsCharging"].getBool(); + + d.batteryInfo.fullyCharged = + PlistNavigator(diagnostics)["IORegistry"]["FullyCharged"].getBool(); + + d.batteryInfo.currentBatteryLevel = + PlistNavigator(diagnostics)["IORegistry"]["CurrentCapacity"].getUInt(); + + d.batteryInfo.usbConnectionType = + PlistNavigator( + diagnostics)["IORegistry"]["AdapterDetails"]["Description"] + .getString() == "usb type-c" + ? BatteryInfo::ConnectionType::USB_TYPEC + : BatteryInfo::ConnectionType::USB; + + d.batteryInfo.adapterVoltage = + PlistNavigator(diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0] + ["AdapterVoltage"] + .getUInt(); + + d.batteryInfo.watts = + PlistNavigator( + diagnostics)["IORegistry"]["AppleRawAdapterDetails"][0]["Watts"] + .getUInt(); + + /*UI*/ + + m_chargingStatusLabel->setText(d.batteryInfo.isCharging ? "Charging" + : "Not Charging"); + m_chargingWattsLabel->setText(QString::number(d.batteryInfo.watts) + "W"); + m_cableTypeLabel->setText(d.batteryInfo.usbConnectionType == + BatteryInfo::ConnectionType::USB + ? "USB" + : "USB-C"); + + m_batteryWidget->updateContext(d.batteryInfo.isCharging, + d.batteryInfo.currentBatteryLevel); } \ No newline at end of file diff --git a/src/deviceinfowidget.h b/src/deviceinfowidget.h index f917e65..9b7a19b 100644 --- a/src/deviceinfowidget.h +++ b/src/deviceinfowidget.h @@ -1,6 +1,9 @@ #ifndef DEVICEINFOWIDGET_H #define DEVICEINFOWIDGET_H +#include "batterywidget.h" #include "iDescriptor.h" +#include +#include #include class DeviceInfoWidget : public QWidget @@ -15,7 +18,13 @@ private slots: private: QPixmap getDeviceIcon(const std::string &productType); - iDescriptorDevice *device; + iDescriptorDevice *m_device; + QTimer *m_updateTimer; + void updateBatteryInfo(); + QLabel *m_chargingStatusLabel; + QLabel *m_chargingWattsLabel; + QLabel *m_cableTypeLabel; + BatteryWidget *m_batteryWidget; }; #endif // DEVICEINFOWIDGET_H diff --git a/src/iDescriptor.h b/src/iDescriptor.h index 95233f3..283b0ce 100644 --- a/src/iDescriptor.h +++ b/src/iDescriptor.h @@ -29,6 +29,15 @@ struct BatteryInfo { // uint64_t maxCapacity; // uint64_t fullChargeCapacity; std::string serialNumber; + bool isCharging; + bool fullyCharged; + uint64_t currentBatteryLevel; + enum class ConnectionType { + USB, + USB_TYPEC, + } usbConnectionType; + uint64_t adapterVoltage; // in mV + uint64_t watts; }; //! IOS 12 @@ -59,6 +68,7 @@ struct DeviceInfo { } activationState; std::string activationStateAcknowledged; std::string productType; + std::string rawProductType; bool jailbroken; std::string basebandActivationTicketVersion; std::string basebandCertId; @@ -120,6 +130,7 @@ struct DeviceInfo { bool productionDevice; BatteryInfo batteryInfo; DiskInfo diskInfo; + bool is_iPhone; }; struct iDescriptorDevice { @@ -132,6 +143,7 @@ struct iDescriptorDevice { clients are not long lived, so do not assume this will be valid */ afc_client_t afcClient; + bool is_iPhone; }; struct IDescriptorInitDeviceResult { @@ -248,6 +260,7 @@ private: public: PlistNavigator(plist_t node) : current_node(node) {} + // Existing dictionary key access PlistNavigator operator[](const char *key) { if (!current_node || plist_get_node_type(current_node) != PLIST_DICT) { @@ -257,8 +270,53 @@ public: return PlistNavigator(next); } + // Add array index access + PlistNavigator operator[](int index) + { + if (!current_node || plist_get_node_type(current_node) != PLIST_ARRAY) { + return PlistNavigator(nullptr); + } + if (index < 0 || + index >= static_cast(plist_array_get_size(current_node))) { + return PlistNavigator(nullptr); + } + plist_t next = plist_array_get_item(current_node, index); + return PlistNavigator(next); + } + operator plist_t() const { return current_node; } bool valid() const { return current_node != nullptr; } + + // Your existing helper methods + bool getBool() const + { + if (!current_node) + return false; + uint8_t value = false; + plist_get_bool_val(current_node, &value); + return value; + } + + uint64_t getUInt() const + { + if (!current_node) + return 0; + uint64_t value = 0; + plist_get_uint_val(current_node, &value); + return value; + } + + std::string getString() const + { + if (!current_node) + return ""; + char *value = nullptr; + plist_get_string_val(current_node, &value); + std::string result = value ? value : ""; + if (value) + free(value); + return result; + } }; afc_error_t safe_afc_read_directory(afc_client_t afcClient, idevice_t device, @@ -376,4 +434,7 @@ bool query_mobile_gestalt(iDescriptorDevice *id_device, const QStringList &keys, uint32_t &xml_size, char *&xml_data); ; -std::string safeGetXML(const char *key, pugi::xml_node dict); \ No newline at end of file +std::string safeGetXML(const char *key, pugi::xml_node dict); + +void get_battery_info(std::string productType, idevice_t idevice, + bool is_iphone, plist_t &diagnostics); \ No newline at end of file