Merge branch 'kate/wip/expose-charge-type' into 'master'

Expose and set up the system charge strategy

Closes #275

See merge request upower/upower!289
This commit is contained in:
Kate Hsuan 2026-01-23 15:39:40 +08:00
commit e577c5ff28
12 changed files with 720 additions and 101 deletions

View file

@ -153,6 +153,185 @@ method return sender=:1.386 -> dest=:1.477 reply_serial=2
</doc:doc>
</method>
<!-- ************************************************************ -->
<method name="GetSupportedChargeStrategies">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="strategies" direction="out" type="as">
<doc:doc><doc:summary>
The supported charge strategies for the power device.
<doc:list>
<doc:item>
<doc:term>Unknown</doc:term>
<doc:definition>
The battery charging behavior is unknown or not supported.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>N/A</doc:term>
<doc:definition>
The battery charging behavior is not supported
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Trickle</doc:term>
<doc:definition>
The battery charges slowly.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Fast</doc:term>
<doc:definition>
Quickly charge the battery using fast-charge technology
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Standard</doc:term>
<doc:definition>
Fully charge the battery with a moderate rate.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Adaptive</doc:term>
<doc:definition>
The battery charges at a rate that adapts to the battery's capacity which the system firmware controls.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Custom</doc:term>
<doc:definition>
The battery charges at a rate that is set by the user.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Long Life</doc:term>
<doc:definition>
The charger reduces its charging rate in order to prolong the battery health.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Bypass</doc:term>
<doc:definition>
Bypass the charge path around the integrated charger. A external charger is used instead to manage the charging
</doc:definition>
</doc:item>
</doc:list>
</doc:summary></doc:doc>
</arg>
<doc:doc>
<doc:description>
<doc:para>
Get the supported charge strategies for the power device. The supported
charge strategies are reported by the system firmware if they are available.
</doc:para>
</doc:description>
</doc:doc>
</method>
<!-- ************************************************************ -->
<method name="SetChargeStrategy">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="strategies" direction="in" type="s">
<doc:doc><doc:summary>
Set the charging strategy for the battery device.
<doc:list>
<doc:item>
<doc:term>Unknown</doc:term>
<doc:definition>
The battery charging behavior is unknown or not supported.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>N/A</doc:term>
<doc:definition>
The battery charging behavior is not supported
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Trickle</doc:term>
<doc:definition>
The battery charges slowly.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Fast</doc:term>
<doc:definition>
Quickly charge the battery using fast-charge technology
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Standard</doc:term>
<doc:definition>
Fully charge the battery with a moderate rate.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Adaptive</doc:term>
<doc:definition>
The battery charges at a rate that adapts to the battery's capacity which the system firmware controls.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Custom</doc:term>
<doc:definition>
The battery charges at a rate that is set by the user.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Long Life</doc:term>
<doc:definition>
The charger reduces its charging rate in order to prolong the battery health.
</doc:definition>
</doc:item>
</doc:list>
<doc:list>
<doc:item>
<doc:term>Bypass</doc:term>
<doc:definition>
Bypass the charge path around the integrated charger. A external charger is used instead to manage the charging
</doc:definition>
</doc:item>
</doc:list>
</doc:summary></doc:doc>
</arg>
<doc:doc>
<doc:description>
<doc:para>
Set the charging strategy against the supported charge strategies. The supported charging strategies can be found by invoking the GetSupportedChargeStrategies method.
</doc:para>
</doc:description>
</doc:doc>
</method>
<!-- ************************************************************ -->
<method name="GetHistory">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
@ -921,6 +1100,80 @@ method return sender=:1.386 -> dest=:1.477 reply_serial=2
</doc:description>
</doc:doc>
</property>
<property name="ChargeStrategy" type="u" access="read">
<doc:doc>
<doc:description>
<doc:para>The charging algorithm is used for a battery.</doc:para>
<doc:list>
<doc:item>
<doc:term>1</doc:term><doc:definition>Unknown. The battery charging behavior is unknown or not supported.</doc:definition>
</doc:item>
<doc:item>
<doc:term>2</doc:term><doc:definition>N/A. The battery charging behavior is not supported.</doc:definition>
</doc:item>
<doc:item>
<doc:term>4</doc:term><doc:definition>Trickle. The battery charges slowly.</doc:definition>
</doc:item>
<doc:item>
<doc:term>8</doc:term><doc:definition>Fast. Quickly charge the battery using fast-charge technology</doc:definition>
</doc:item>
<doc:item>
<doc:term>16</doc:term><doc:definition>Standard. Fully charge the battery with a moderate rate.</doc:definition>
</doc:item>
<doc:item>
<doc:term>32</doc:term><doc:definition>Adaptive. The battery charges at a rate that adapts to the battery's capacity which the system firmware controls.</doc:definition>
</doc:item>
<doc:item>
<doc:term>64</doc:term><doc:definition>Custom. The battery charges at a rate that is set by the user.</doc:definition>
</doc:item>
<doc:item>
<doc:term>128</doc:term><doc:definition>Long-life. The charger reduces its charging rate in order to prolong the battery health</doc:definition>
</doc:item>
<doc:item>
<doc:term>256</doc:term><doc:definition>Bypass. Bypass the charge path around the integrated charger. A external charger is used instead to manage the charging</doc:definition>
</doc:item>
</doc:list>
</doc:description>
</doc:doc>
</property>
<property name="ChargeStrategiesSupported" type="u" access="read">
<doc:doc>
<doc:description>
<doc:para>The supported charge strategies for the battery in bit mask format.</doc:para>
<doc:list>
<doc:item>
<doc:term>Bit 0</doc:term><doc:definition>Unknown. The battery charging behavior is unknown or not supported.</doc:definition>
</doc:item>
<doc:item>
<doc:term>Bit 1</doc:term><doc:definition>N/A. The battery charging behavior is not supported.</doc:definition>
</doc:item>
<doc:item>
<doc:term>Bit 2</doc:term><doc:definition>Trickle. The battery charges slowly.</doc:definition>
</doc:item>
<doc:item>
<doc:term>Bit 3</doc:term><doc:definition>Fast. Quickly charge the battery using fast-charge technology</doc:definition>
</doc:item>
<doc:item>
<doc:term>Bit 4</doc:term><doc:definition>Standard. Fully charge the battery with a moderate rate.</doc:definition>
</doc:item>
<doc:item>
<doc:term>Bit 5</doc:term><doc:definition>Adaptive. The battery charges at a rate that adapts to the battery's capacity which the system firmware controls.</doc:definition>
</doc:item>
<doc:item>
<doc:term>Bit 6</doc:term><doc:definition>Custom. The battery charges at a rate that is set by the user.</doc:definition>
</doc:item>
<doc:item>
<doc:term>Bit 7</doc:term><doc:definition>Long-life. The charger reduces its charging rate in order to prolong the battery health</doc:definition>
</doc:item>
<doc:item>
<doc:term>Bit 8</doc:term><doc:definition>Bypass. Bypass the charge path around the integrated charger. A external charger is used instead to manage the charging</doc:definition>
</doc:item>
</doc:list>
<doc:para>Examples:</doc:para>
<doc:para>If the system supports standard and long-life charge strategies, the value is 144.</doc:para>
</doc:description>
</doc:doc>
</property>
<property name="VoltageMinDesign" type="d" access="read">
<doc:doc>
<doc:description>

View file

@ -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)));

View file

@ -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 <hpa@redhat.com>
*/
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;
}

View file

@ -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

View file

@ -29,4 +29,12 @@ file are instantly applied.
</defaults>
</action>
<action id="org.freedesktop.UPower.set-charge-strategy">
<description>Change the battery charging strategy</description>
<message>Authentication is required to set battery charging strategy.</message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
</policyconfig>

View file

@ -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"""

View file

@ -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",

View file

@ -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);
}

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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,