From 29d15fb7396bcd037cf1cda4b025fbf1d1705493 Mon Sep 17 00:00:00 2001 From: Jin Liu Date: Wed, 10 Jun 2026 17:27:26 +0800 Subject: [PATCH] bluetooth: try getting battery percentage from upower if missing from bluez Bluetooth widget / tab will now also query UPowerService for battery percentage if BluetoothService doesn't provide it. An example of this is the Playstation 5 controller. --- src/shell/bar/widget_factory.cpp | 3 ++- src/shell/bar/widgets/bluetooth_widget.cpp | 18 +++++++++++++--- src/shell/bar/widgets/bluetooth_widget.h | 5 ++++- src/shell/control_center/bluetooth_tab.cpp | 21 +++++++++++++------ src/shell/control_center/bluetooth_tab.h | 4 +++- .../control_center/control_center_panel.cpp | 2 +- 6 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/shell/bar/widget_factory.cpp b/src/shell/bar/widget_factory.cpp index 2675185c27..884de00b4d 100644 --- a/src/shell/bar/widget_factory.cpp +++ b/src/shell/bar/widget_factory.cpp @@ -198,7 +198,8 @@ std::unique_ptr WidgetFactory::create( if (type == "bluetooth") { const bool showLabel = wc != nullptr ? wc->getBool("show_label", false) : false; const bool hideWhenNoConnectedDevice = wc != nullptr ? wc->getBool("hide_when_no_connected_device", false) : false; - auto widget = std::make_unique(m_bluetooth, output, showLabel, hideWhenNoConnectedDevice); + auto widget = + std::make_unique(m_bluetooth, m_upower, output, showLabel, hideWhenNoConnectedDevice); widget->setContentScale(contentScale); return widget; } diff --git a/src/shell/bar/widgets/bluetooth_widget.cpp b/src/shell/bar/widgets/bluetooth_widget.cpp index dbe267a5bb..dd2e432f37 100644 --- a/src/shell/bar/widgets/bluetooth_widget.cpp +++ b/src/shell/bar/widgets/bluetooth_widget.cpp @@ -6,6 +6,7 @@ #include "ui/builders.h" #include "ui/palette.h" #include "ui/style.h" +#include "util/string_utils.h" #include #include @@ -45,9 +46,11 @@ namespace { } // namespace BluetoothWidget::BluetoothWidget( - BluetoothService* bluetooth, wl_output* /*output*/, bool showLabel, bool hideWhenNoConnectedDevice + BluetoothService* bluetooth, UPowerService* upower, wl_output* /*output*/, bool showLabel, + bool hideWhenNoConnectedDevice ) - : m_bluetooth(bluetooth), m_showLabel(showLabel), m_hideWhenNoConnectedDevice(hideWhenNoConnectedDevice) {} + : m_bluetooth(bluetooth), m_upower(upower), m_showLabel(showLabel), + m_hideWhenNoConnectedDevice(hideWhenNoConnectedDevice) {} void BluetoothWidget::create() { auto area = std::make_unique(); @@ -171,7 +174,16 @@ void BluetoothWidget::syncState(Renderer& renderer) { std::vector rows; for (const auto& d : devices) { if (d.connected) { - std::string value = d.hasBattery ? std::to_string(d.batteryPercent) + "%" : "Connected"; + bool hasBattery = d.hasBattery; + uint8_t batteryPercent = d.batteryPercent; + if (!hasBattery && m_upower != nullptr) { + auto* upowerDevice = m_upower->deviceForSelector(StringUtils::toLower(d.address)); + if (upowerDevice) { + hasBattery = true; + batteryPercent = static_cast(upowerDevice->state.percentage); + } + } + std::string value = hasBattery ? std::to_string(batteryPercent) + "%" : "Connected"; rows.push_back({d.alias, std::move(value)}); } } diff --git a/src/shell/bar/widgets/bluetooth_widget.h b/src/shell/bar/widgets/bluetooth_widget.h index a2d9a6d3d5..545b0f76d4 100644 --- a/src/shell/bar/widgets/bluetooth_widget.h +++ b/src/shell/bar/widgets/bluetooth_widget.h @@ -1,6 +1,7 @@ #pragma once #include "dbus/bluetooth/bluetooth_service.h" +#include "dbus/upower/upower_service.h" #include "shell/bar/widget.h" #include @@ -12,7 +13,8 @@ struct wl_output; class BluetoothWidget : public Widget { public: BluetoothWidget( - BluetoothService* bluetooth, wl_output* output, bool showLabel, bool hideWhenNoConnectedDevice = false + BluetoothService* bluetooth, UPowerService* upower, wl_output* output, bool showLabel, + bool hideWhenNoConnectedDevice = false ); void create() override; @@ -24,6 +26,7 @@ class BluetoothWidget : public Widget { void syncWidgetVisibility(bool showWidget); BluetoothService* m_bluetooth = nullptr; + UPowerService* m_upower = nullptr; bool m_showLabel = false; bool m_hideWhenNoConnectedDevice = false; Glyph* m_glyph = nullptr; diff --git a/src/shell/control_center/bluetooth_tab.cpp b/src/shell/control_center/bluetooth_tab.cpp index aa7025038e..7576688555 100644 --- a/src/shell/control_center/bluetooth_tab.cpp +++ b/src/shell/control_center/bluetooth_tab.cpp @@ -8,6 +8,7 @@ #include "ui/controls/collapsible.h" #include "ui/palette.h" #include "ui/style.h" +#include "util/string_utils.h" #include #include @@ -95,13 +96,15 @@ namespace { class BluetoothDeviceRow : public Collapsible { public: - BluetoothDeviceRow(BluetoothDeviceInfo device, BluetoothService* service, float scale) + BluetoothDeviceRow(BluetoothDeviceInfo device, BluetoothService* service, UPowerService* upower, float scale) : m_device(std::move(device)), m_service(service) { setScale(scale); setRadius(Style::scaledRadiusMd(scale)); setFill(colorSpecFromRole(ColorRole::Surface)); clearBorder(); + const auto bucket = bucketFor(m_device); + auto header = ui::row( {.align = FlexAlign::Center, .gap = Style::spaceSm * scale, @@ -131,8 +134,15 @@ namespace { metrics->addChild( makeMetricPill("battery", std::to_string(static_cast(m_device.batteryPercent)) + "%", scale) ); + } else if (upower != nullptr && bucket == DeviceBucket::Connected) { + auto* upowerDevice = upower->deviceForSelector(StringUtils::toLower(m_device.address)); + if (upowerDevice) { + metrics->addChild( + makeMetricPill("battery", std::to_string(static_cast(upowerDevice->state.percentage)) + "%", scale) + ); + } } - if (m_device.hasRssi && bucketFor(m_device) == DeviceBucket::Available) { + if (m_device.hasRssi && bucket == DeviceBucket::Available) { metrics->addChild( makeMetricPill("antenna-bars-5", std::to_string(signalPercentFromRssi(m_device.rssi)) + "%", scale) ); @@ -141,8 +151,6 @@ namespace { header->addChild(std::move(metrics)); } - const auto bucket = bucketFor(m_device); - if (m_device.connecting) { header->addChild( ui::spinner({ @@ -260,7 +268,8 @@ namespace { } // namespace -BluetoothTab::BluetoothTab(BluetoothService* service, BluetoothAgent* agent) : m_service(service), m_agent(agent) {} +BluetoothTab::BluetoothTab(BluetoothService* service, BluetoothAgent* agent, UPowerService* upower) + : m_service(service), m_agent(agent), m_upower(upower) {} BluetoothTab::~BluetoothTab() = default; @@ -795,7 +804,7 @@ void BluetoothTab::rebuildDeviceList(Renderer& renderer) { currentBucket = bucket; first = false; } - auto row = std::make_unique(device, m_service, scale); + auto row = std::make_unique(device, m_service, m_upower, scale); auto* rowPtr = row.get(); bucketCard->addChild(std::move(row)); rowPtr->startConnectingSpinner(); diff --git a/src/shell/control_center/bluetooth_tab.h b/src/shell/control_center/bluetooth_tab.h index 0ccb6909ab..94dd7a825b 100644 --- a/src/shell/control_center/bluetooth_tab.h +++ b/src/shell/control_center/bluetooth_tab.h @@ -2,6 +2,7 @@ #include "dbus/bluetooth/bluetooth_agent.h" #include "dbus/bluetooth/bluetooth_service.h" +#include "dbus/upower/upower_service.h" #include "shell/control_center/tab.h" #include @@ -17,7 +18,7 @@ class Toggle; class BluetoothTab : public Tab { public: - BluetoothTab(BluetoothService* service, BluetoothAgent* agent); + BluetoothTab(BluetoothService* service, BluetoothAgent* agent, UPowerService* upower); ~BluetoothTab() override; std::unique_ptr create() override; @@ -37,6 +38,7 @@ class BluetoothTab : public Tab { BluetoothService* m_service = nullptr; BluetoothAgent* m_agent = nullptr; + UPowerService* m_upower = nullptr; Flex* m_rootLayout = nullptr; diff --git a/src/shell/control_center/control_center_panel.cpp b/src/shell/control_center/control_center_panel.cpp index c14ed721b3..5e98c12851 100644 --- a/src/shell/control_center/control_center_panel.cpp +++ b/src/shell/control_center/control_center_panel.cpp @@ -68,7 +68,7 @@ ControlCenterPanel::ControlCenterPanel( m_tabs[tabIndex(TabId::Calendar)] = std::make_unique(config, calendar); m_tabs[tabIndex(TabId::Notifications)] = std::make_unique(notifications); m_tabs[tabIndex(TabId::Network)] = std::make_unique(network, networkSecrets); - m_tabs[tabIndex(TabId::Bluetooth)] = std::make_unique(bluetooth, bluetoothAgent); + m_tabs[tabIndex(TabId::Bluetooth)] = std::make_unique(bluetooth, bluetoothAgent, upower); m_tabs[tabIndex(TabId::Display)] = std::make_unique(brightness, config); m_tabs[tabIndex(TabId::System)] = std::make_unique(sysmon); m_tabs[tabIndex(TabId::ScreenTime)] = std::make_unique(screenTime);