diff --git a/dbus/org.freedesktop.UPower.Device.xml b/dbus/org.freedesktop.UPower.Device.xml
index cbeccd2..7072885 100644
--- a/dbus/org.freedesktop.UPower.Device.xml
+++ b/dbus/org.freedesktop.UPower.Device.xml
@@ -153,6 +153,185 @@ method return sender=:1.386 -> dest=:1.477 reply_serial=2
+
+
+
+
+
+ The supported charge strategies for the power device.
+
+
+ Unknown
+
+ The battery charging behavior is unknown or not supported.
+
+
+
+
+
+ N/A
+
+ The battery charging behavior is not supported
+
+
+
+
+
+ Trickle
+
+ The battery charges slowly.
+
+
+
+
+
+ Fast
+
+ Quickly charge the battery using fast-charge technology
+
+
+
+
+
+ Standard
+
+ Fully charge the battery with a moderate rate.
+
+
+
+
+
+ Adaptive
+
+ The battery charges at a rate that adapts to the battery's capacity which the system firmware controls.
+
+
+
+
+
+ Custom
+
+ The battery charges at a rate that is set by the user.
+
+
+
+
+
+ Long Life
+
+ The charger reduces its charging rate in order to prolong the battery health.
+
+
+
+
+
+ Bypass
+
+ Bypass the charge path around the integrated charger. A external charger is used instead to manage the charging
+
+
+
+
+
+
+
+
+ Get the supported charge strategies for the power device. The supported
+ charge strategies are reported by the system firmware if they are available.
+
+
+
+
+
+
+
+
+
+
+ Set the charging strategy for the battery device.
+
+
+ Unknown
+
+ The battery charging behavior is unknown or not supported.
+
+
+
+
+
+ N/A
+
+ The battery charging behavior is not supported
+
+
+
+
+
+ Trickle
+
+ The battery charges slowly.
+
+
+
+
+
+ Fast
+
+ Quickly charge the battery using fast-charge technology
+
+
+
+
+
+ Standard
+
+ Fully charge the battery with a moderate rate.
+
+
+
+
+
+ Adaptive
+
+ The battery charges at a rate that adapts to the battery's capacity which the system firmware controls.
+
+
+
+
+
+ Custom
+
+ The battery charges at a rate that is set by the user.
+
+
+
+
+
+ Long Life
+
+ The charger reduces its charging rate in order to prolong the battery health.
+
+
+
+
+
+ Bypass
+
+ Bypass the charge path around the integrated charger. A external charger is used instead to manage the charging
+
+
+
+
+
+
+
+
+ Set the charging strategy against the supported charge strategies. The supported charging strategies can be found by invoking the GetSupportedChargeStrategies method.
+
+
+
+
+
@@ -921,6 +1100,80 @@ method return sender=:1.386 -> dest=:1.477 reply_serial=2
+
+
+
+ The charging algorithm is used for a battery.
+
+
+ 1Unknown. The battery charging behavior is unknown or not supported.
+
+
+ 2N/A. The battery charging behavior is not supported.
+
+
+ 4Trickle. The battery charges slowly.
+
+
+ 8Fast. Quickly charge the battery using fast-charge technology
+
+
+ 16Standard. Fully charge the battery with a moderate rate.
+
+
+ 32Adaptive. The battery charges at a rate that adapts to the battery's capacity which the system firmware controls.
+
+
+ 64Custom. The battery charges at a rate that is set by the user.
+
+
+ 128Long-life. The charger reduces its charging rate in order to prolong the battery health
+
+
+ 256Bypass. Bypass the charge path around the integrated charger. A external charger is used instead to manage the charging
+
+
+
+
+
+
+
+
+ The supported charge strategies for the battery in bit mask format.
+
+
+ Bit 0Unknown. The battery charging behavior is unknown or not supported.
+
+
+ Bit 1N/A. The battery charging behavior is not supported.
+
+
+ Bit 2Trickle. The battery charges slowly.
+
+
+ Bit 3Fast. Quickly charge the battery using fast-charge technology
+
+
+ Bit 4Standard. Fully charge the battery with a moderate rate.
+
+
+ Bit 5Adaptive. The battery charges at a rate that adapts to the battery's capacity which the system firmware controls.
+
+
+ Bit 6Custom. The battery charges at a rate that is set by the user.
+
+
+ Bit 7Long-life. The charger reduces its charging rate in order to prolong the battery health
+
+
+ Bit 8Bypass. Bypass the charge path around the integrated charger. A external charger is used instead to manage the charging
+
+
+ Examples:
+ If the system supports standard and long-life charge strategies, the value is 144.
+
+
+
diff --git a/libupower-glib/up-device.c b/libupower-glib/up-device.c
index 1773f1d..7eeae72 100644
--- a/libupower-glib/up-device.c
+++ b/libupower-glib/up-device.c
@@ -420,6 +420,8 @@ up_device_to_text (UpDevice *device)
g_string_append_printf (string, " charge-threshold-enabled: %s\n", up_device_bool_to_string (up_exported_device_get_charge_threshold_enabled (priv->proxy_device)));
if (up_exported_device_get_charge_threshold_supported (priv->proxy_device))
g_string_append_printf (string, " charge-threshold-supported: %s\n", up_device_bool_to_string (up_exported_device_get_charge_threshold_supported (priv->proxy_device)));
+ if (up_exported_device_get_charge_strategy (priv->proxy_device) != UP_DEVICE_CHARGE_STRATEGIES_UNKNOWN)
+ g_string_append_printf (string, " charge-strategy: %s\n", up_device_charge_strategy_to_str (up_exported_device_get_charge_strategy (priv->proxy_device)));
}
if (kind == UP_DEVICE_KIND_LINE_POWER)
g_string_append_printf (string, " online: %s\n", up_device_bool_to_string (up_exported_device_get_online (priv->proxy_device)));
diff --git a/libupower-glib/up-types.c b/libupower-glib/up-types.c
index 23954d6..2d3f6c1 100644
--- a/libupower-glib/up-types.c
+++ b/libupower-glib/up-types.c
@@ -371,3 +371,81 @@ up_device_level_from_string (const gchar *level)
return UP_DEVICE_LEVEL_FULL;
return UP_DEVICE_LEVEL_UNKNOWN;
}
+
+/**
+ * up_device_charge_strategy_to_str:
+ *
+ * Converts a #UpDeviceChargeStrategies to a string.
+ *
+ * Return value: identifier string
+ *
+ * Since: 1.91.1
+ **/
+const gchar *
+up_device_charge_strategy_to_str (UpDeviceChargeStrategies strategy)
+{
+ if (strategy == UP_DEVICE_CHARGE_STRATEGIES_UNKNOWN)
+ return "Unknown";
+ if (strategy == UP_DEVICE_CHARGE_STRATEGIES_NA)
+ return "N/A";
+ if (strategy == UP_DEVICE_CHARGE_STRATEGIES_TRICKLE)
+ return "Trickle";
+ if (strategy == UP_DEVICE_CHARGE_STRATEGIES_FAST)
+ return "Fast";
+ if (strategy == UP_DEVICE_CHARGE_STRATEGIES_STANDARD)
+ return "Standard";
+ if (strategy == UP_DEVICE_CHARGE_STRATEGIES_ADAPTIVE)
+ return "Adaptive";
+ if (strategy == UP_DEVICE_CHARGE_STRATEGIES_CUSTOM)
+ return "Custom";
+ if (strategy == UP_DEVICE_CHARGE_STRATEGIES_LONG_LIFE)
+ return "Long Life";
+ if (strategy == UP_DEVICE_CHARGE_STRATEGIES_BYPASS)
+ return "Bypass";
+
+ /* invalid type */
+ return "Unknown";
+}
+
+/**
+ * up_device_battery_charge_strategy_from_string:
+ *
+ * Converts a string to #UpDeviceChargeStrategies.
+ *
+ * Return value: enumerated value
+ *
+ * Since: 1.91.1
+ **/
+UpDeviceChargeStrategies
+up_device_battery_charge_strategy_from_string (const gchar *strategy)
+{
+ if (strategy == NULL)
+ return UP_DEVICE_CHARGE_STRATEGIES_UNKNOWN;
+
+ /* Codes are suggested by Claude AI
+ *
+ * co-worked-with: Cursor and Claude AI
+ * Reviewed-by: Kate Hsuan
+ */
+ if (g_str_equal (strategy, "Unknown"))
+ return UP_DEVICE_CHARGE_STRATEGIES_UNKNOWN;
+ if (g_str_equal (strategy, "N/A"))
+ return UP_DEVICE_CHARGE_STRATEGIES_NA;
+ if (g_str_equal (strategy, "Trickle"))
+ return UP_DEVICE_CHARGE_STRATEGIES_TRICKLE;
+ if (g_str_equal (strategy, "Fast"))
+ return UP_DEVICE_CHARGE_STRATEGIES_FAST;
+ if (g_str_equal (strategy, "Standard"))
+ return UP_DEVICE_CHARGE_STRATEGIES_STANDARD;
+ if (g_str_equal (strategy, "Adaptive"))
+ return UP_DEVICE_CHARGE_STRATEGIES_ADAPTIVE;
+ if (g_str_equal (strategy, "Custom"))
+ return UP_DEVICE_CHARGE_STRATEGIES_CUSTOM;
+ if (g_str_equal (strategy, "Long Life"))
+ return UP_DEVICE_CHARGE_STRATEGIES_LONG_LIFE;
+ if (g_str_equal (strategy, "Bypass"))
+ return UP_DEVICE_CHARGE_STRATEGIES_BYPASS;
+
+ /* invalid type */
+ return UP_DEVICE_CHARGE_STRATEGIES_LAST;
+}
diff --git a/libupower-glib/up-types.h b/libupower-glib/up-types.h
index d44c94e..dfef411 100644
--- a/libupower-glib/up-types.h
+++ b/libupower-glib/up-types.h
@@ -127,14 +127,35 @@ typedef enum {
UP_DEVICE_LEVEL_LAST
} UpDeviceLevel;
-const gchar *up_device_kind_to_string (UpDeviceKind type_enum);
-const gchar *up_device_state_to_string (UpDeviceState state_enum);
-const gchar *up_device_technology_to_string (UpDeviceTechnology technology_enum);
-const gchar *up_device_level_to_string (UpDeviceLevel level_enum);
-UpDeviceKind up_device_kind_from_string (const gchar *type);
-UpDeviceState up_device_state_from_string (const gchar *state);
-UpDeviceTechnology up_device_technology_from_string (const gchar *technology);
-UpDeviceLevel up_device_level_from_string (const gchar *level);
+/**
+ * UpDeviceChargeTypes:
+ *
+ * Select the charging algorithm to use for a battery.
+ **/
+typedef enum {
+ UP_DEVICE_CHARGE_STRATEGIES_0,
+ UP_DEVICE_CHARGE_STRATEGIES_UNKNOWN = 1 << 0,
+ UP_DEVICE_CHARGE_STRATEGIES_NA = 1 << 1,
+ UP_DEVICE_CHARGE_STRATEGIES_TRICKLE = 1 << 2,
+ UP_DEVICE_CHARGE_STRATEGIES_FAST = 1 << 3,
+ UP_DEVICE_CHARGE_STRATEGIES_STANDARD = 1 << 4,
+ UP_DEVICE_CHARGE_STRATEGIES_ADAPTIVE = 1 << 5,
+ UP_DEVICE_CHARGE_STRATEGIES_CUSTOM = 1 << 6,
+ UP_DEVICE_CHARGE_STRATEGIES_LONG_LIFE = 1 << 7,
+ UP_DEVICE_CHARGE_STRATEGIES_BYPASS = 1 << 8,
+ UP_DEVICE_CHARGE_STRATEGIES_LAST,
+} UpDeviceChargeStrategies;
+
+const gchar *up_device_kind_to_string (UpDeviceKind type_enum);
+const gchar *up_device_state_to_string (UpDeviceState state_enum);
+const gchar *up_device_technology_to_string (UpDeviceTechnology technology_enum);
+const gchar *up_device_level_to_string (UpDeviceLevel level_enum);
+const gchar *up_device_charge_strategy_to_str (UpDeviceChargeStrategies charge_type_enum);
+UpDeviceChargeStrategies up_device_battery_charge_strategy_from_string (const gchar *strategy);
+UpDeviceKind up_device_kind_from_string (const gchar *type);
+UpDeviceState up_device_state_from_string (const gchar *state);
+UpDeviceTechnology up_device_technology_from_string (const gchar *technology);
+UpDeviceLevel up_device_level_from_string (const gchar *level);
G_END_DECLS
diff --git a/policy/org.freedesktop.upower.policy.in b/policy/org.freedesktop.upower.policy.in
index b1d02b2..58da2d3 100644
--- a/policy/org.freedesktop.upower.policy.in
+++ b/policy/org.freedesktop.upower.policy.in
@@ -29,4 +29,12 @@ file are instantly applied.
+
+ Change the battery charging strategy
+ Authentication is required to set battery charging strategy.
+
+ no
+ yes
+
+
diff --git a/src/linux/integration-test.py b/src/linux/integration-test.py
index cd3cb74..f4e2b34 100755
--- a/src/linux/integration-test.py
+++ b/src/linux/integration-test.py
@@ -353,6 +353,32 @@ class Tests(dbusmock.DBusTestCase):
None,
)
+ def get_charge_strategies(self, device):
+ return self.dbus.call_sync(
+ UP,
+ device,
+ "org.freedesktop.UPower.Device",
+ "GetSupportedChargeStrategies",
+ None,
+ None,
+ Gio.DBusCallFlags.NO_AUTO_START,
+ -1,
+ None,
+ ).unpack()[0]
+
+ def set_charge_strategy(self, device, strategy):
+ self.dbus.call_sync(
+ UP,
+ device,
+ "org.freedesktop.UPower.Device",
+ "SetChargeStrategy",
+ GLib.Variant("(s)", (strategy,)),
+ None,
+ Gio.DBusCallFlags.NO_AUTO_START,
+ -1,
+ None,
+ )
+
def get_kbd_backlight_brightness(self, kbd_backlight):
return self.dbus.call_sync(
UP,
@@ -2871,6 +2897,113 @@ class Tests(dbusmock.DBusTestCase):
self.stop_daemon()
+ def test_battery_charge_strategy_supported(self):
+ """Battery with charge_strategy supported"""
+
+ bat0 = self.testbed.add_device(
+ "power_supply",
+ "BAT1",
+ None,
+ [
+ "type",
+ "Battery",
+ "present",
+ "1",
+ "status",
+ "unknown",
+ "energy_full",
+ "60000000",
+ "energy_full_design",
+ "80000000",
+ "energy_now",
+ "48000000",
+ "voltage_now",
+ "12000000",
+ "charge_control_start_threshold",
+ "0",
+ "charge_control_end_threshold",
+ "100",
+ "charge_types",
+ "Standard [Long_Life] Fast Adaptive",
+ ],
+ [],
+ )
+
+ self.start_daemon()
+ devs = self.proxy.EnumerateDevices()
+ self.assertEqual(len(devs), 1)
+ bat0_up = devs[0]
+
+ self.assertEqual(
+ self.get_dbus_dev_property(bat0_up, "ChargeStrategy"), 128 # Long Life
+ )
+
+ self.assertEqual(
+ self.get_dbus_dev_property(bat0_up, "ChargeStrategiesSupported"),
+ 184, # 16 + 128 + 8 + 32
+ )
+
+ supported_strategies = self.get_charge_strategies(bat0_up)
+ self.assertEqual(
+ supported_strategies,
+ ["Fast", "Standard", "Adaptive", "Long Life"],
+ )
+ self.stop_daemon()
+
+ def test_set_battery_charge_strategy(self):
+ """Set battery charge strategy"""
+
+ if not self.polkit:
+ self.start_polkitd({})
+ self.polkit_obj.SetAllowed(["org.freedesktop.UPower.set-charge-strategy"])
+
+ bat0 = self.testbed.add_device(
+ "power_supply",
+ "BAT1",
+ None,
+ [
+ "type",
+ "Battery",
+ "present",
+ "1",
+ "status",
+ "unknown",
+ "energy_full",
+ "60000000",
+ "energy_full_design",
+ "80000000",
+ "energy_now",
+ "48000000",
+ "voltage_now",
+ "12000000",
+ "charge_control_start_threshold",
+ "0",
+ "charge_control_end_threshold",
+ "100",
+ "charge_types",
+ "Standard [Long_Life] Fast Adaptive",
+ ],
+ [],
+ )
+
+ self.start_daemon()
+ devs = self.proxy.EnumerateDevices()
+ self.assertEqual(len(devs), 1)
+ bat0_up = devs[0]
+
+ self.assertEqual(
+ self.get_dbus_dev_property(bat0_up, "ChargeStrategy"), 128 # Long Life
+ )
+
+ self.set_charge_strategy(bat0_up, "Fast")
+ # it is a hack for umockdev, the configured value should be "[Fast]" but
+ # umockdev writes "Fast"
+ battery_name = bat0_up.split("_")[-1]
+ with open(f"/sys/class/power_supply/{battery_name}/charge_types") as fp:
+ self.assertEqual(fp.read(), "Fast")
+
+ self.stop_daemon()
+
def test_battery_zero_power_draw(self):
"""Battery with zero power draw, e.g. in a dual-battery system"""
diff --git a/src/linux/up-device-supply-battery.c b/src/linux/up-device-supply-battery.c
index 9d395f2..de3d5c0 100644
--- a/src/linux/up-device-supply-battery.c
+++ b/src/linux/up-device-supply-battery.c
@@ -45,20 +45,6 @@ enum {
PROP_IGNORE_SYSTEM_PERCENTAGE
};
-typedef enum {
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_0,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_UNKNOWN = 1 << 0,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_NA = 1 << 1,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_TRICKLE = 1 << 2,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_FAST = 1 << 3,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_STANDARD = 1 << 4,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_ADAPTIVE = 1 << 5,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_CUSTOM = 1 << 6,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_LONG_LIFE = 1 << 7,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_BYPASS = 1 << 8,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPE_LAST,
-} UpDeviceSupplyBatteryChargeTypes;
-
typedef enum {
UP_DEVICE_SUPPLY_BATTERY_CHARGE_THRESHOLD_SETTINGS_0,
UP_DEVICE_SUPPLY_BATTERY_CHARGE_THRESHOLD_SETTINGS_CHARGE_CONTROL_START_THRESHOLD = 1 << 0,
@@ -76,7 +62,7 @@ struct _UpDeviceSupplyBattery
guint energy_old_first;
gdouble rate_old;
guint supported_charge_types;
- UpDeviceSupplyBatteryChargeTypes charge_type;
+ UpDeviceChargeStrategies charge_types;
UpDeviceSupplyBatteryChargeThresholdSettings charge_threshold_settings;
gboolean charge_threshold_by_charge_type;
gboolean shown_invalid_voltage_warning;
@@ -234,88 +220,80 @@ remove_brackets (const gchar *type)
return g_string_free (washed_type, FALSE);
}
-static UpDeviceSupplyBatteryChargeTypes
+static UpDeviceChargeStrategies
up_device_battery_charge_type_str_to_enum (const gchar *type)
{
if (type == NULL)
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPE_LAST;
+ return UP_DEVICE_CHARGE_STRATEGIES_LAST;
if (!g_strcmp0 ("Unknown", type))
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_UNKNOWN;
- else if (!g_strcmp0 ("N/A", type))
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_NA;
- else if (!g_strcmp0 ("Trickle", type))
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_TRICKLE;
- else if (!g_strcmp0 ("Fast", type))
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_FAST;
- else if (!g_strcmp0 ("Standard", type))
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_STANDARD;
- else if (!g_strcmp0 ("Adaptive", type))
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_ADAPTIVE;
- else if (!g_strcmp0 ("Custom", type))
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_CUSTOM;
- else if (!g_strcmp0 ("Long_Life", type))
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_LONG_LIFE;
- else if (!g_strcmp0 ("Bypass", type))
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_BYPASS;
+ return UP_DEVICE_CHARGE_STRATEGIES_UNKNOWN;
+ if (!g_strcmp0 ("N/A", type))
+ return UP_DEVICE_CHARGE_STRATEGIES_NA;
+ if (!g_strcmp0 ("Trickle", type))
+ return UP_DEVICE_CHARGE_STRATEGIES_TRICKLE;
+ if (!g_strcmp0 ("Fast", type))
+ return UP_DEVICE_CHARGE_STRATEGIES_FAST;
+ if (!g_strcmp0 ("Standard", type))
+ return UP_DEVICE_CHARGE_STRATEGIES_STANDARD;
+ if (!g_strcmp0 ("Adaptive", type))
+ return UP_DEVICE_CHARGE_STRATEGIES_ADAPTIVE;
+ if (!g_strcmp0 ("Custom", type))
+ return UP_DEVICE_CHARGE_STRATEGIES_CUSTOM;
+ if (!g_strcmp0 ("Long_Life", type))
+ return UP_DEVICE_CHARGE_STRATEGIES_LONG_LIFE;
+ if (!g_strcmp0 ("Bypass", type))
+ return UP_DEVICE_CHARGE_STRATEGIES_BYPASS;
/* invalid type */
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPE_LAST;
+ return UP_DEVICE_CHARGE_STRATEGIES_LAST;
}
-static gchar *
-up_device_battery_charge_type_enum_to_str (UpDeviceSupplyBatteryChargeTypes types)
-{
- if (types == UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_UNKNOWN)
- return g_strdup ("Unknown");
-
- if (types == UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_NA)
- return g_strdup ("N/A");
-
- if (types == UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_TRICKLE)
- return g_strdup ("Trickle");
-
- if (types == UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_FAST)
- return g_strdup ("Fast");
-
- if (types == UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_STANDARD)
- return g_strdup ("Standard");
-
- if (types == UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_ADAPTIVE)
- return g_strdup ("Adaptive");
-
- if (types == UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_CUSTOM)
- return g_strdup ("Custom");
-
- if (types == UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_LONG_LIFE)
- return g_strdup ("Long_Life");
-
- if (types == UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_BYPASS)
- return g_strdup ("Bypass");
+static gchar*
+up_device_battery_charge_type_to_string (UpDeviceChargeStrategies charge_type) {
+ if (charge_type == UP_DEVICE_CHARGE_STRATEGIES_UNKNOWN)
+ return "Unknown";
+ if (charge_type == UP_DEVICE_CHARGE_STRATEGIES_NA)
+ return "N/A";
+ if (charge_type == UP_DEVICE_CHARGE_STRATEGIES_TRICKLE)
+ return "Trickle";
+ if (charge_type == UP_DEVICE_CHARGE_STRATEGIES_FAST)
+ return "Fast";
+ if (charge_type == UP_DEVICE_CHARGE_STRATEGIES_STANDARD)
+ return "Standard";
+ if (charge_type == UP_DEVICE_CHARGE_STRATEGIES_ADAPTIVE)
+ return "Adaptive";
+ if (charge_type == UP_DEVICE_CHARGE_STRATEGIES_CUSTOM)
+ return "Custom";
+ if (charge_type == UP_DEVICE_CHARGE_STRATEGIES_LONG_LIFE)
+ return "Long_Life";
+ if (charge_type == UP_DEVICE_CHARGE_STRATEGIES_BYPASS)
+ return "Bypass";
/* invalid type */
- return g_strdup ("Unknown");
+ return "Unknown";
}
-static UpDeviceSupplyBatteryChargeTypes
+
+static UpDeviceChargeStrategies
up_device_battery_charge_find_available_charge_types_for_charging (UpDevice *device) {
UpDeviceSupplyBattery *self = UP_DEVICE_SUPPLY_BATTERY (device);
- UpDeviceSupplyBatteryChargeTypes charge_types = self->supported_charge_types;
+ UpDeviceChargeStrategies charge_types = self->supported_charge_types;
- if (charge_types & UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_FAST)
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_FAST;
+ if (charge_types & UP_DEVICE_CHARGE_STRATEGIES_FAST)
+ return UP_DEVICE_CHARGE_STRATEGIES_FAST;
- if (charge_types & UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_STANDARD)
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_STANDARD;
+ if (charge_types & UP_DEVICE_CHARGE_STRATEGIES_STANDARD)
+ return UP_DEVICE_CHARGE_STRATEGIES_STANDARD;
- if (charge_types & UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_ADAPTIVE)
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_ADAPTIVE;
+ if (charge_types & UP_DEVICE_CHARGE_STRATEGIES_ADAPTIVE)
+ return UP_DEVICE_CHARGE_STRATEGIES_ADAPTIVE;
- return UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPE_LAST;
+ return UP_DEVICE_CHARGE_STRATEGIES_LAST;
}
static void
-up_device_battery_get_supported_charge_types (UpDevice *device, UpBatteryInfo *info)
+up_device_battery_get_supported_charge_types (UpDevice *device, UpBatteryInfo *info, UpBatteryValues *values)
{
UpDeviceSupplyBattery *self = UP_DEVICE_SUPPLY_BATTERY (device);
GUdevDevice *native;
@@ -325,7 +303,7 @@ up_device_battery_get_supported_charge_types (UpDevice *device, UpBatteryInfo *i
native = G_UDEV_DEVICE (up_device_get_native (device));
- charge_type_str = g_udev_device_get_sysfs_attr (native, "charge_types");
+ charge_type_str = g_udev_device_get_sysfs_attr_uncached (native, "charge_types");
if (charge_type_str == NULL)
return;
@@ -336,13 +314,16 @@ up_device_battery_get_supported_charge_types (UpDevice *device, UpBatteryInfo *i
for (int i = 0; i < g_strv_length(types); i++) {
if (g_utf8_strchr (types[i], 1, '[') != NULL) {
tmp_type = remove_brackets (types[i]);
- self->charge_type = up_device_battery_charge_type_str_to_enum (tmp_type);
+ self->charge_types = up_device_battery_charge_type_str_to_enum (tmp_type);
+ values->charge_strategy = self->charge_types;
} else {
tmp_type = g_strdup (types[i]);
}
self->supported_charge_types |= up_device_battery_charge_type_str_to_enum (tmp_type);
g_free (tmp_type);
}
+
+ info->charge_strategies_supported = self->supported_charge_types;
}
/**
@@ -368,10 +349,10 @@ up_device_supply_battery_is_charge_threshold_by_charge_type (UpDevice *device) {
g_udev_device_has_sysfs_attr (native, "charge_control_end_threshold"))
return FALSE;
- if (self->supported_charge_types & UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_LONG_LIFE) {
- if (self->supported_charge_types & (UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_STANDARD |
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_ADAPTIVE |
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_FAST)) {
+ if (self->supported_charge_types & UP_DEVICE_CHARGE_STRATEGIES_LONG_LIFE) {
+ if (self->supported_charge_types & (UP_DEVICE_CHARGE_STRATEGIES_STANDARD |
+ UP_DEVICE_CHARGE_STRATEGIES_ADAPTIVE |
+ UP_DEVICE_CHARGE_STRATEGIES_FAST)) {
g_debug ("charge_control_start_threshold and charge_control_end_threshold are not found but the supported charge_types Long_lift, Standard or Adaptive was found. Assuming charging threshold is supported");
return TRUE;
}
@@ -447,7 +428,7 @@ up_device_supply_battery_refresh (UpDevice *device,
}
/* refresh the changes of charge_types */
- up_device_battery_get_supported_charge_types (device, &info);
+ up_device_battery_get_supported_charge_types (device, &info, &values);
/* Test charge_types attribute, if "Long_Life", "Standard", "Adaptive" or "Fast" are found,
* then set charge_control_supported to TRUE.
@@ -628,7 +609,7 @@ up_device_supply_device_path (GUdevDevice *device)
static gboolean
up_device_supply_battery_is_charge_type_exist (UpDevice *device, const gchar *charge_type) {
UpDeviceSupplyBattery *self = UP_DEVICE_SUPPLY_BATTERY (device);
- UpDeviceSupplyBatteryChargeTypes type;
+ UpDeviceChargeStrategies type;
type = up_device_battery_charge_type_str_to_enum (charge_type);
@@ -640,16 +621,16 @@ up_device_supply_battery_is_charge_type_exist (UpDevice *device, const gchar *ch
static gboolean
up_device_supply_battery_set_battery_charge_types (UpDevice *device,
- UpDeviceSupplyBatteryChargeTypes charge_type,
+ UpDeviceChargeStrategies charge_type,
GError **error) {
GUdevDevice *native;
- g_autofree gchar *charge_type_str = NULL;
+ const gchar *charge_type_str = NULL;
g_autofree gchar *native_path = NULL;
g_autofree gchar *type_filename = NULL;
native = G_UDEV_DEVICE (up_device_get_native (device));
- charge_type_str = up_device_battery_charge_type_enum_to_str (charge_type);
+ charge_type_str = up_device_battery_charge_type_to_string (charge_type);
/* return, if the attribute "charge_types" is not found */
if (!g_udev_device_has_sysfs_attr (native, "charge_types"))
@@ -683,7 +664,7 @@ up_device_supply_battery_set_battery_charge_thresholds(UpDevice *device, guint s
g_autofree gchar *end_filename = NULL;
g_autoptr (GString) start_str = g_string_new (NULL);
g_autoptr (GString) end_str = g_string_new (NULL);
- UpDeviceSupplyBatteryChargeTypes charge_type_enum;
+ UpDeviceChargeStrategies charge_type_enum;
native = G_UDEV_DEVICE (up_device_get_native (device));
native_path = up_device_supply_device_path (native);
@@ -701,7 +682,7 @@ up_device_supply_battery_set_battery_charge_thresholds(UpDevice *device, guint s
NULL);
} else {
up_device_supply_battery_set_battery_charge_types (device,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_LONG_LIFE,
+ UP_DEVICE_CHARGE_STRATEGIES_LONG_LIFE,
NULL);
}
@@ -740,7 +721,7 @@ up_device_supply_battery_set_battery_charge_thresholds(UpDevice *device, guint s
} else {
/* for the Dell laptops, the charge_types has to be set to "Custom" to enable the charging threshold */
up_device_supply_battery_set_battery_charge_types (device,
- UP_DEVICE_SUPPLY_BATTERY_CHARGE_TYPES_CUSTOM,
+ UP_DEVICE_CHARGE_STRATEGIES_CUSTOM,
NULL);
}
@@ -759,6 +740,7 @@ up_device_supply_battery_class_init (UpDeviceSupplyBatteryClass *klass)
device_class->coldplug = up_device_supply_coldplug;
device_class->refresh = up_device_supply_battery_refresh;
battery_class->set_battery_charge_thresholds = up_device_supply_battery_set_battery_charge_thresholds;
+ battery_class->set_battery_charge_strategy = up_device_supply_battery_set_battery_charge_types;
g_object_class_install_property (object_class, PROP_IGNORE_SYSTEM_PERCENTAGE,
g_param_spec_boolean ("ignore-system-percentage",
diff --git a/src/linux/up-device-supply.c b/src/linux/up-device-supply.c
index ae4e696..93d2d5a 100644
--- a/src/linux/up-device-supply.c
+++ b/src/linux/up-device-supply.c
@@ -111,6 +111,7 @@ up_device_supply_reset_values (UpDeviceSupply *supply)
"charge-end-threshold", 100,
"charge-threshold-enabled", FALSE,
"charge-threshold-supported", FALSE,
+ "charge-strategy", UP_DEVICE_CHARGE_STRATEGIES_UNKNOWN,
NULL);
}
diff --git a/src/up-device-battery.c b/src/up-device-battery.c
index 0e51aab..6bc4b4b 100644
--- a/src/up-device-battery.c
+++ b/src/up-device-battery.c
@@ -392,6 +392,7 @@ up_device_battery_report (UpDeviceBattery *self,
"time-to-empty", time_to_empty,
"time-to-full", time_to_full,
"capacity-level", values->capacity_level,
+ "charge-strategy", values->charge_strategy,
/* XXX: Move "update-time" updates elsewhere? */
"update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC,
NULL);
@@ -538,6 +539,7 @@ up_device_battery_update_info (UpDeviceBattery *self, UpBatteryInfo *info)
"charge-threshold-enabled", charge_threshold_enabled,
"charge-threshold-supported", info->charge_control_supported,
"charge-threshold-settings-supported", info->charge_threshold_settings,
+ "charge-strategies-supported", info->charge_strategies_supported,
"voltage-min-design", info->voltage_min_design,
"voltage-max-design", info->voltage_max_design,
NULL);
@@ -617,6 +619,8 @@ up_device_battery_update_info (UpDeviceBattery *self, UpBatteryInfo *info)
"charge-threshold-enabled", FALSE,
"charge-threshold-supported", FALSE,
"charge-threshold-settings-supported", 0,
+ "charge-strategy", UP_DEVICE_CHARGE_STRATEGIES_UNKNOWN,
+ "charge-strategies-supported", 0,
"voltage-min-design", (gdouble) 0.0,
"voltage-max-design", (gdouble) 0.0,
"capacity-level", NULL,
@@ -665,7 +669,7 @@ up_device_battery_set_charge_threshold (UpExportedDevice *skeleton,
return FALSE;
}
- if (!up_device_polkit_is_allowed (device, invocation)) {
+ if (!up_device_polkit_is_allowed (device, invocation, "org.freedesktop.UPower.enable-charging-limit")) {
g_dbus_method_invocation_return_error (invocation,
UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
"Operation is not allowed.");
@@ -699,6 +703,8 @@ up_device_battery_set_charge_threshold (UpExportedDevice *skeleton,
else
ret = up_device_battery_set_charge_thresholds (self, 0, 100, &error);
+ up_device_refresh_internal (device, UP_REFRESH_EVENT);
+
if (!ret) {
g_dbus_method_invocation_return_error (invocation,
UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
@@ -715,6 +721,127 @@ up_device_battery_set_charge_threshold (UpExportedDevice *skeleton,
return TRUE;
}
+/**
+ * up_device_battery_get_supported_charge_strategies:
+ **/
+ static gboolean
+ up_device_battery_get_supported_charge_strategies (UpExportedDevice *skeleton,
+ GDBusMethodInvocation *invocation,
+ UpDeviceBattery *self)
+{
+ UpDeviceChargeStrategies charge_strategies_supported;
+ g_autoptr (GStrvBuilder) strv_builder = g_strv_builder_new ();
+ g_auto (GStrv) array = g_strv_builder_end (strv_builder);
+ UpDevice *device = UP_DEVICE (self);
+
+ if (device == NULL) {
+ g_dbus_method_invocation_return_error (invocation,
+ UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
+ "Error on getting device");
+ return FALSE;
+ }
+
+ g_object_get (self,
+ "charge-strategies-supported", &charge_strategies_supported,
+ NULL);
+
+ if (charge_strategies_supported & UP_DEVICE_CHARGE_STRATEGIES_UNKNOWN)
+ g_strv_builder_add (strv_builder,
+ up_device_charge_strategy_to_str (UP_DEVICE_CHARGE_STRATEGIES_UNKNOWN));
+ if (charge_strategies_supported & UP_DEVICE_CHARGE_STRATEGIES_NA)
+ g_strv_builder_add (strv_builder,
+ up_device_charge_strategy_to_str (UP_DEVICE_CHARGE_STRATEGIES_NA));
+ if (charge_strategies_supported & UP_DEVICE_CHARGE_STRATEGIES_TRICKLE)
+ g_strv_builder_add (strv_builder,
+ up_device_charge_strategy_to_str (UP_DEVICE_CHARGE_STRATEGIES_TRICKLE));
+ if (charge_strategies_supported & UP_DEVICE_CHARGE_STRATEGIES_FAST)
+ g_strv_builder_add (strv_builder,
+ up_device_charge_strategy_to_str (UP_DEVICE_CHARGE_STRATEGIES_FAST));
+ if (charge_strategies_supported & UP_DEVICE_CHARGE_STRATEGIES_STANDARD)
+ g_strv_builder_add (strv_builder,
+ up_device_charge_strategy_to_str (UP_DEVICE_CHARGE_STRATEGIES_STANDARD));
+ if (charge_strategies_supported & UP_DEVICE_CHARGE_STRATEGIES_ADAPTIVE)
+ g_strv_builder_add (strv_builder,
+ up_device_charge_strategy_to_str (UP_DEVICE_CHARGE_STRATEGIES_ADAPTIVE));
+ if (charge_strategies_supported & UP_DEVICE_CHARGE_STRATEGIES_CUSTOM)
+ g_strv_builder_add (strv_builder,
+ up_device_charge_strategy_to_str (UP_DEVICE_CHARGE_STRATEGIES_CUSTOM));
+ if (charge_strategies_supported & UP_DEVICE_CHARGE_STRATEGIES_LONG_LIFE)
+ g_strv_builder_add (strv_builder,
+ up_device_charge_strategy_to_str (UP_DEVICE_CHARGE_STRATEGIES_LONG_LIFE));
+ if (charge_strategies_supported & UP_DEVICE_CHARGE_STRATEGIES_BYPASS)
+ g_strv_builder_add (strv_builder,
+ up_device_charge_strategy_to_str (UP_DEVICE_CHARGE_STRATEGIES_BYPASS));
+ if (charge_strategies_supported == 0)
+ g_strv_builder_add (strv_builder, "Unknown");
+
+ array = g_strv_builder_end (strv_builder);
+
+ up_exported_device_complete_get_supported_charge_strategies (skeleton, invocation, (const gchar * const*) array);
+
+ return TRUE;
+}
+
+/**
+ * up_device_battery_set_charge_strategy:
+ **/
+static gboolean
+up_device_battery_set_charge_strategy (UpExportedDevice *skeleton,
+ GDBusMethodInvocation *invocation,
+ const gchar *strategy,
+ UpDeviceBattery *self)
+{
+ gboolean ret = FALSE;
+ UpDeviceChargeStrategies charge_strategy = 0;
+ UpDeviceChargeStrategies charge_strategies_supported = 0;
+ UpDevice *device = UP_DEVICE (self);
+ UpDeviceBatteryClass *klass = UP_DEVICE_BATTERY_GET_CLASS (self);
+ g_autoptr (GError) error = NULL;
+
+ if (device == NULL) {
+ g_dbus_method_invocation_return_error (invocation,
+ UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
+ "Error on getting device");
+ return FALSE;
+ }
+
+ if (!up_device_polkit_is_allowed (device, invocation, "org.freedesktop.UPower.set-charge-strategy")) {
+ g_dbus_method_invocation_return_error (invocation,
+ UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
+ "Operation is not allowed.");
+ return TRUE;
+ }
+
+ charge_strategy = up_device_battery_charge_strategy_from_string (strategy);
+
+ g_object_get (self,
+ "charge-strategies-supported",
+ &charge_strategies_supported,
+ NULL);
+
+ if (charge_strategy == UP_DEVICE_CHARGE_STRATEGIES_LAST ||
+ !(charge_strategies_supported & charge_strategy)) {
+ g_dbus_method_invocation_return_error (invocation,
+ UP_DAEMON_ERROR, UP_DAEMON_ERROR_NOT_SUPPORTED,
+ "invalid charging strategy: %s", strategy ? strategy : "NULL");
+ return TRUE;
+ }
+
+ ret = klass->set_battery_charge_strategy (device, charge_strategy, &error);
+ if (!ret) {
+ g_dbus_method_invocation_return_error (invocation,
+ UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
+ "failed on setting charging strategy: %s", error->message);
+ return TRUE;
+ }
+
+ up_device_refresh_internal (device, UP_REFRESH_EVENT);
+
+ up_exported_device_complete_set_charge_strategy (skeleton, invocation);
+
+ return TRUE;
+}
+
static void
up_device_battery_init (UpDeviceBattery *self)
{
@@ -726,6 +853,12 @@ up_device_battery_init (UpDeviceBattery *self)
g_signal_connect (self, "handle-enable-charge-threshold",
G_CALLBACK (up_device_battery_set_charge_threshold), self);
+
+ g_signal_connect (self, "handle-get-supported-charge-strategies",
+ G_CALLBACK (up_device_battery_get_supported_charge_strategies), self);
+
+ g_signal_connect (self, "handle-set-charge-strategy",
+ G_CALLBACK (up_device_battery_set_charge_strategy), self);
}
static void
diff --git a/src/up-device-battery.h b/src/up-device-battery.h
index dd74510..2a829f7 100644
--- a/src/up-device-battery.h
+++ b/src/up-device-battery.h
@@ -38,6 +38,9 @@ struct _UpDeviceBatteryClass
guint start,
guint end,
GError **error);
+ gboolean (* set_battery_charge_strategy) (UpDevice *device,
+ UpDeviceChargeStrategies strategy,
+ GError **error);
};
typedef enum {
@@ -65,6 +68,7 @@ typedef struct {
gdouble voltage;
gdouble temperature;
gchar *capacity_level;
+ UpDeviceChargeStrategies charge_strategy;
} UpBatteryValues;
typedef struct {
@@ -99,6 +103,7 @@ typedef struct {
guint charge_control_start_threshold;
guint charge_control_end_threshold;
guint charge_threshold_settings;
+ UpDeviceChargeStrategies charge_strategies_supported;
} UpBatteryInfo;
diff --git a/src/up-device.c b/src/up-device.c
index 2a5ff1a..7deafd8 100644
--- a/src/up-device.c
+++ b/src/up-device.c
@@ -407,12 +407,14 @@ up_device_get_daemon (UpDevice *device)
* up_device_polkit_is_allowed
**/
gboolean
-up_device_polkit_is_allowed (UpDevice *device, GDBusMethodInvocation *invocation)
+up_device_polkit_is_allowed (UpDevice *device, GDBusMethodInvocation *invocation, const gchar *action_id)
{
UpDevicePrivate *priv = up_device_get_instance_private (device);
+ g_return_val_if_fail (UP_IS_DEVICE (device), FALSE);
+ g_return_val_if_fail (action_id != NULL, FALSE);
if (!up_daemon_polkit_is_allowed (priv->daemon,
- "org.freedesktop.UPower.enable-charging-limit",
+ action_id,
invocation))
return FALSE;
diff --git a/src/up-device.h b/src/up-device.h
index 5e6ad61..1828ce0 100644
--- a/src/up-device.h
+++ b/src/up-device.h
@@ -69,7 +69,8 @@ gboolean up_device_get_online (UpDevice *device,
gboolean *online);
const gchar *up_device_get_state_dir_override (UpDevice *device);
gboolean up_device_polkit_is_allowed (UpDevice *device,
- GDBusMethodInvocation *invocation);
+ GDBusMethodInvocation *invocation,
+ const gchar *action_id);
void up_device_sibling_discovered (UpDevice *device,
GObject *sibling);
gboolean up_device_refresh_internal (UpDevice *device,