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,