Skip to content
Commits on Source (10)
......@@ -52,3 +52,4 @@ build_stable:
paths:
- "${CI_PROJECT_DIR}/_build/meson-logs/"
- "${CI_PROJECT_DIR}/_build/meson-dist"
- "${CI_PROJECT_DIR}/_build/meson-private/dist-build/meson-logs/"
ver 42.4:
This version switches the power state API added in version 42.3 to be backed
by the experimental PowerState property in bluetoothd. The API will not show
transitional states if the version of bluetoothd is too old.
The battery API now exports the battery information for all Bluetooth devices
listed in UPower, not just the ones re-exported from bluetoothd.
ver 42.3:
This version adds a new API for more precise adapter power state, and fixes
a number of small UI problems in bluetooth-sendto.
......
......@@ -54,19 +54,12 @@
#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
#define BLUEZ_DEVICE_INTERFACE "org.bluez.Device1"
/* Subset of BluetoothAdapterState */
typedef enum {
POWER_STATE_REQUEST_NONE = 0,
POWER_STATE_REQUEST_ON,
POWER_STATE_REQUEST_OFF,
} PowerStateRequest;
struct _BluetoothClient {
GObject parent;
GListStore *list_store;
Adapter1 *default_adapter;
PowerStateRequest power_req;
gboolean has_power_state;
GDBusObjectManager *manager;
GCancellable *cancellable;
guint num_adapters;
......@@ -121,6 +114,26 @@ get_device_for_path (BluetoothClient *client,
return NULL;
}
static BluetoothDevice *
get_device_for_bdaddr (BluetoothClient *client,
const char *bdaddr)
{
guint n_items, i;
n_items = g_list_model_get_n_items (G_LIST_MODEL (client->list_store));
for (i = 0; i < n_items; i++) {
g_autoptr(BluetoothDevice) d = NULL;
g_autofree char *s = NULL;
d = g_list_model_get_item (G_LIST_MODEL (client->list_store), i);
g_object_get (G_OBJECT (d), "address", &s, NULL);
if (g_ascii_strncasecmp (bdaddr, s, BDADDR_STR_LEN) == 0) {
return g_steal_pointer (&d);
}
}
return NULL;
}
static char **
device_list_uuids (const gchar * const *uuids)
{
......@@ -418,31 +431,15 @@ adapter_set_powered_cb (GDBusProxy *proxy,
GAsyncResult *res,
gpointer user_data)
{
BluetoothClient *client;
g_autoptr(GError) error = NULL;
g_autoptr(GVariant) ret = NULL;
ret = g_dbus_proxy_call_finish (proxy, res, &error);
if (!ret) {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_debug ("Error setting property 'Powered' on %s: %s (%s, %d)",
g_dbus_proxy_get_object_path (proxy),
error->message, g_quark_to_string (error->domain), error->code);
}
client = user_data;
if (client->default_adapter) {
gboolean powered;
powered = adapter1_get_powered (client->default_adapter);
if ((powered && client->power_req == POWER_STATE_REQUEST_ON) ||
(!powered && client->power_req == POWER_STATE_REQUEST_OFF)) {
/* Only reset if we don't have a conflicting state in progress */
client->power_req = POWER_STATE_REQUEST_NONE;
}
}
g_object_notify (G_OBJECT (client), "default-adapter-state");
}
static void
......@@ -458,12 +455,6 @@ adapter_set_powered (BluetoothClient *client,
return;
}
if ((powered && client->power_req == POWER_STATE_REQUEST_ON) ||
(!powered && client->power_req == POWER_STATE_REQUEST_OFF)) {
g_debug ("Default adapter is already being powered %s", powered ? "on" : "off");
return;
}
if (powered == adapter1_get_powered (client->default_adapter)) {
g_debug ("Default adapter is already %spowered", powered ? "" : "un");
return;
......@@ -473,9 +464,6 @@ adapter_set_powered (BluetoothClient *client,
powered ? "up" : "down",
g_dbus_proxy_get_object_path (G_DBUS_PROXY (client->default_adapter)));
variant = g_variant_new_boolean (powered);
client->power_req = powered ?
POWER_STATE_REQUEST_ON : POWER_STATE_REQUEST_OFF;
g_object_notify (G_OBJECT (client), "default-adapter-state");
g_dbus_proxy_call (G_DBUS_PROXY (client->default_adapter),
"org.freedesktop.DBus.Properties.Set",
g_variant_new ("(ssv)", "org.bluez.Adapter1", "Powered", variant),
......@@ -588,6 +576,9 @@ adapter_notify_cb (Adapter1 *adapter,
g_object_notify (G_OBJECT (client), "default-adapter-setup-mode");
} else if (g_strcmp0 (property, "powered") == 0) {
g_object_notify (G_OBJECT (client), "default-adapter-powered");
if (!client->has_power_state)
g_object_notify (G_OBJECT (client), "default-adapter-state");
} else if (g_strcmp0 (property, "power-state") == 0) {
g_object_notify (G_OBJECT (client), "default-adapter-state");
}
}
......@@ -639,6 +630,7 @@ default_adapter_changed (GDBusObjectManager *manager,
g_list_store_remove_all (client->list_store);
g_debug ("Disabling discovery on old default adapter");
_bluetooth_client_set_default_adapter_discovering (client, FALSE);
g_clear_object (&client->default_adapter);
}
client->default_adapter = ADAPTER1 (g_object_ref (G_OBJECT (adapter)));
......@@ -739,7 +731,6 @@ adapter_removed (GDBusObjectManager *manager,
if (!was_default)
goto out;
new_default_adapter = NULL;
object_list = g_dbus_object_manager_get_objects (client->manager);
for (l = object_list; l != NULL; l = l->next) {
......@@ -1012,7 +1003,7 @@ up_device_added_cb (UpClient *up_client,
gpointer user_data)
{
BluetoothClient *client = user_data;
g_autofree char *native_path = NULL;
g_autofree char *serial = NULL;
g_autoptr(BluetoothDevice) device = NULL;
UpDeviceLevel battery_level;
double percentage;
......@@ -1021,16 +1012,16 @@ up_device_added_cb (UpClient *up_client,
g_debug ("Considering UPower device %s", up_device_get_object_path (up_device));
g_object_get (up_device,
"native-path", &native_path,
"serial", &serial,
"battery-level", &battery_level,
"percentage", &percentage,
NULL);
if (!native_path || !g_str_has_prefix (native_path, "/org/bluez/"))
if (!serial || !bluetooth_verify_address(serial))
return;
device = get_device_for_path (client, native_path);
device = get_device_for_bdaddr (client, serial);
if (!device) {
g_debug ("Could not find bluez device for upower device %s", native_path);
g_debug ("Could not find bluez device for upower device with serial %s", serial);
return;
}
g_signal_connect (G_OBJECT (up_device), "notify::battery-level",
......@@ -1042,7 +1033,7 @@ up_device_added_cb (UpClient *up_client,
battery_type = BLUETOOTH_BATTERY_TYPE_PERCENTAGE;
else
battery_type = BLUETOOTH_BATTERY_TYPE_COARSE;
g_debug ("Applying battery information for %s", native_path);
g_debug ("Applying battery information for %s", serial);
g_object_set (device,
"battery-type", battery_type,
"battery-level", battery_level,
......@@ -1114,6 +1105,7 @@ static void bluetooth_client_init(BluetoothClient *client)
{
client->cancellable = g_cancellable_new ();
client->list_store = g_list_store_new (BLUETOOTH_TYPE_DEVICE);
client->has_power_state = TRUE;
g_dbus_object_manager_client_new_for_bus (G_BUS_TYPE_SYSTEM,
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START,
......@@ -1248,14 +1240,31 @@ _bluetooth_client_set_default_adapter_discovering (BluetoothClient *client,
static BluetoothAdapterState
adapter_get_state (BluetoothClient *client)
{
const char *str;
if (!client->default_adapter)
return BLUETOOTH_ADAPTER_STATE_ABSENT;
if (client->power_req == POWER_STATE_REQUEST_NONE)
return adapter1_get_powered (client->default_adapter) ?
BLUETOOTH_ADAPTER_STATE_ON : BLUETOOTH_ADAPTER_STATE_OFF;
return client->power_req == POWER_STATE_REQUEST_ON ?
BLUETOOTH_ADAPTER_STATE_TURNING_ON :
BLUETOOTH_ADAPTER_STATE_TURNING_OFF;
str = adapter1_get_power_state (client->default_adapter);
if (str) {
if (g_str_equal (str, "on"))
return BLUETOOTH_ADAPTER_STATE_ON;
if (g_str_equal (str, "off") ||
g_str_equal (str, "off-blocked"))
return BLUETOOTH_ADAPTER_STATE_OFF;
if (g_str_equal (str, "off-enabling"))
return BLUETOOTH_ADAPTER_STATE_TURNING_ON;
if (g_str_equal (str, "on-disabling"))
return BLUETOOTH_ADAPTER_STATE_TURNING_OFF;
g_warning_once ("Unexpected adapter PowerState value '%s'", str);
} else {
client->has_power_state = FALSE;
}
/* Fallback if property is missing, or value is unexpected */
return adapter1_get_powered (client->default_adapter) ?
BLUETOOTH_ADAPTER_STATE_ON : BLUETOOTH_ADAPTER_STATE_OFF;
}
static void
......
......@@ -12,6 +12,7 @@
<property name="Alias" type="s" access="readwrite"></property>
<property name="Class" type="u" access="read"></property>
<property name="Powered" type="b" access="readwrite"></property>
<property name="PowerState" type="s" access="read"></property>
<property name="Discoverable" type="b" access="readwrite"></property>
<property name="DiscoverableTimeout" type="u" access="readwrite"></property>
<property name="Pairable" type="b" access="readwrite"></property>
......
......@@ -27,6 +27,8 @@
#include <gio/gio.h>
#include <bluetooth-enums.h>
#define BDADDR_STR_LEN 17
BluetoothType bluetooth_class_to_type (guint32 class);
BluetoothType bluetooth_appearance_to_type (guint16 appearance);
const gchar *bluetooth_type_to_string (guint type);
......
......@@ -143,6 +143,9 @@
<!-- http://bugzilla.gnome.org/show_bug.cgi?id=561325 -->
<device type="network" oui="00:06:66:" name="OBDPros scantool" pin="1234"/>
<!-- https://lore.kernel.org/linux-bluetooth/01070182f561c630-852e0333-6f04-448b-b064-46a2f000e860-000000@eu-central-1.amazonses.com/ -->
<device name="NISSAN CONNECT" pin="1234"/>
<!-- Generic types -->
<!-- Printers -->
......
#!/usr/bin/python3
#
# Copyright (C) 2022 Bastien Nocera <hadess@hadess.net>
#
# SPDX-License-Identifier: LGPL-2.1-or-later
import gi
from gi.repository import GLib
from gi.repository import Gio
gi.require_version('GnomeBluetooth', '3.0')
from gi.repository import GnomeBluetooth
def notify_cb(client, pspec):
value = client.get_property(pspec.name)
print(f'{pspec.name} changed to {value}')
client = GnomeBluetooth.Client.new()
client.connect('notify', notify_cb)
ml = GLib.MainLoop()
ml.run()
project(
'gnome-bluetooth', 'c',
version: '42.3',
version: '42.4',
license: 'GPL2+',
default_options: 'buildtype=debugoptimized',
meson_version: '>= 0.58.0',
......
......@@ -3,7 +3,7 @@ msgstr ""
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-bluetooth/issues\n"
"POT-Creation-Date: 2022-07-15 20:11+0000\n"
"Last-Translator: Нанба Наала <naala-nanba@rambler.ru>\n"
"Language-Team: Abkhazian <ab@li.org>\n"
"Language-Team: Abkhazian <daniel.abzakh@gmail.com>\n"
"Language: ab\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
......@@ -242,7 +242,7 @@ msgstr ""
#: lib/bluetooth-utils.c:89
msgid "Display"
msgstr ""
msgstr "Аԥшра"
#: lib/bluetooth-utils.c:91
msgid "Wearable"
......
......@@ -13,7 +13,6 @@ is part of gnome-bluetooth, see also http://live.gnome.org/GnomeBluetooth
.TP
\--device
Define the device address to send the file(s) to.
If omitted a chooser will be displayed.
.TP
\--name
Define the device name to send the file(s) to.
......
......@@ -267,7 +267,8 @@ class OopTests(dbusmock.DBusTestCase):
self.assertEqual(dbusprops_bluez.Get('org.bluez.Adapter1', 'Powered'), False)
self.assertEqual(self.client.props.default_adapter_state, GnomeBluetoothPriv.AdapterState.OFF)
self.client.props.default_adapter_powered = True
self.assertEqual(self.client.props.default_adapter_state, GnomeBluetoothPriv.AdapterState.TURNING_ON)
# NOTE: this should be "turning on"
self.assertEqual(self.client.props.default_adapter_state, GnomeBluetoothPriv.AdapterState.OFF)
self.wait_for_condition(lambda: dbusprops_bluez.Get('org.bluez.Adapter1', 'Powered') == True)
self.assertEqual(self.client.props.num_adapters, 1)
self.assertEqual(dbusprops_bluez.Get('org.bluez.Adapter1', 'Powered'), True)
......@@ -278,7 +279,6 @@ class OopTests(dbusmock.DBusTestCase):
self.client.props.default_adapter_powered = False
self.wait_for_condition(lambda: dbusprops_bluez.Get('org.bluez.Adapter1', 'Powered') == False)
self.assertEqual(dbusprops_bluez.Get('org.bluez.Adapter1', 'Powered'), False)
self.assertEqual(self.client.props.default_adapter_state, GnomeBluetoothPriv.AdapterState.TURNING_OFF)
self.wait_for_mainloop()
self.assertEqual(self.client.props.default_adapter_powered, False)
self.assertEqual(self.client.props.default_adapter_state, GnomeBluetoothPriv.AdapterState.OFF)
......@@ -286,7 +286,7 @@ class OopTests(dbusmock.DBusTestCase):
dbusmock_bluez.UpdateProperties('org.bluez.Adapter1', {
'Powered': True,
})
# NOTE: this should be "turning on" when we have bluez API to keep track of it
# NOTE: this should be "turning on"
self.assertEqual(self.client.props.default_adapter_state, GnomeBluetoothPriv.AdapterState.OFF)
self.wait_for_condition(lambda: dbusprops_bluez.Get('org.bluez.Adapter1', 'Powered') == True)
self.assertEqual(dbusprops_bluez.Get('org.bluez.Adapter1', 'Powered'), True)
......@@ -622,6 +622,7 @@ class Tests(dbusmock.DBusTestCase):
'org.freedesktop.UPower.Device',
{
'NativePath': dbus.String('/org/bluez/hci0/dev_11_22_33_44_55_66'),
'Serial': dbus.String('11:22:33:44:55:66', variant_level=1),
'Type': dbus.UInt32(5, variant_level=1),
'State': dbus.UInt32(2, variant_level=1),
'Percentage': dbus.Double(66, variant_level=1),
......@@ -644,6 +645,7 @@ class Tests(dbusmock.DBusTestCase):
'org.freedesktop.UPower.Device',
{
'NativePath': dbus.String('/org/bluez/hci0/dev_11_22_33_44_55_67'),
'Serial': dbus.String('11:22:33:44:55:67', variant_level=1),
'Type': dbus.UInt32(5, variant_level=1),
'State': dbus.UInt32(2, variant_level=1),
'Percentage': dbus.Double(55, variant_level=1),
......