From f7ca11b202e442e759cca86a70d9c6d027e82e76 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 11 Oct 2013 08:38:51 -0500 Subject: if /dev/rfkill doesn't exist or isn't writable, then try to handle bluetooth toggles simply by toggling bluez Adapters' Powered property --- src/bluetooth.vala | 49 ++++----------------- src/bluez.vala | 121 +++++++++++++++++++++++++++++++++++++++++++++------- src/desktop.vala | 6 +-- src/killswitch.vala | 7 +++ src/phone.vala | 2 +- src/profile.vala | 13 +++--- 6 files changed, 128 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/bluetooth.vala b/src/bluetooth.vala index 100bdf2..b268701 100644 --- a/src/bluetooth.vala +++ b/src/bluetooth.vala @@ -27,22 +27,19 @@ public interface Bluetooth: Object This work as a proxy for "does this hardware support bluetooth?" */ public abstract bool supported { get; protected set; } - /* True if there are any bluetooth adapters powered up on the system. - In short, whether or not this system's bluetooth is "on". */ - public abstract bool powered { get; protected set; } + /* True if bluetooth's enabled on this system. + Bluetooth can be soft-blocked by software and hard-blocked physically, + eg by a laptop's network killswitch */ + public abstract bool enabled { get; protected set; } + + /* Try to enable/disable bluetooth. This can fail if it's overridden + by the system, eg by a laptop's network killswitch */ + public abstract void try_set_enabled (bool b); /* True if our system can be seen by other bluetooth devices */ public abstract bool discoverable { get; protected set; } public abstract void try_set_discoverable (bool discoverable); - /* True if bluetooth's blocked. This can be soft-blocked by software and - * hard-blocked physically, eg by a laptop's network killswitch */ - public abstract bool blocked { get; protected set; } - - /* Try to block/unblock bluetooth. This can fail if it's overridden - by the system, eg by a laptop's network killswitch */ - public abstract void try_set_blocked (bool b); - /* Get a list of the Device structs that we know about */ public abstract List get_devices (); @@ -53,33 +50,3 @@ public interface Bluetooth: Object The device_key argument comes from the Device struct */ public abstract void set_device_connected (uint device_key, bool connected); } - - - -/** - * Base class for Bluetooth objects that use a killswitch to implement - * the 'discoverable' property. - */ -public abstract class KillswitchBluetooth: Object, Bluetooth -{ - private KillSwitch killswitch; - - public KillswitchBluetooth (KillSwitch killswitch) - { - // always sync our 'blocked' property with the one in killswitch - this.killswitch = killswitch; - blocked = killswitch.blocked; - killswitch.notify["blocked"].connect (() => blocked = killswitch.blocked ); - } - - public bool supported { get; protected set; default = false; } - public bool powered { get; protected set; default = false; } - public bool discoverable { get; protected set; default = false; } - public bool blocked { get; protected set; default = true; } - public void try_set_blocked (bool b) { killswitch.try_set_blocked (b); } - - // empty implementations - public abstract void try_set_discoverable (bool b); - public abstract List get_devices (); - public abstract void set_device_connected (uint device_key, bool connected); -} diff --git a/src/bluez.vala b/src/bluez.vala index 8c8c1b6..82f34f4 100644 --- a/src/bluez.vala +++ b/src/bluez.vala @@ -22,12 +22,25 @@ /** * Bluetooth implementaion which uses org.bluez on DBus */ -public class Bluez: KillswitchBluetooth +public class Bluez: Bluetooth, Object { uint next_device_id = 1; org.bluez.Manager manager; org.bluez.Adapter default_adapter; + private bool _powered = false; + + private bool powered { + get { return _powered; } + set { _powered = value; update_enabled(); } + } + + private KillSwitch killswitch = null; + + private string adapter_path = null; + + private DBusConnection bus = null; + /* maps an org.bluez.Device's object_path to the org.bluez.Device proxy */ HashTable path_to_proxy; @@ -42,42 +55,85 @@ public class Bluez: KillswitchBluetooth public Bluez (KillSwitch killswitch) { - base (killswitch); + try + { + bus = Bus.get_sync (BusType.SYSTEM); + } + catch (Error e) + { + critical (@"$(e.message)"); + } - string adapter_path = null; + if (killswitch.is_valid()) + { + this.killswitch = killswitch; + killswitch.notify["blocked"].connect (() => update_enabled()); + update_enabled (); + } id_to_path = new HashTable (direct_hash, direct_equal); id_to_device = new HashTable (direct_hash, direct_equal); path_to_id = new HashTable (str_hash, str_equal); path_to_proxy = new HashTable (str_hash, str_equal); + reset_manager (); + } + + private void reset_manager () + { + string new_adapter_path = null; try { - manager = Bus.get_proxy_sync (BusType.SYSTEM, "org.bluez", "/"); + manager = bus.get_proxy_sync ("org.bluez", "/"); - // get the current default adapter & watch for future default adapters - adapter_path = manager.default_adapter (); + // if the default adapter changes, update our connections manager.default_adapter_changed.connect ((object_path) => on_default_adapter_changed (object_path)); + + // if the current adapter disappears, call clear_adapter() + manager.adapter_removed.connect ((object_path) => { + if (object_path == adapter_path) + clear_adapter (); + }); + + // get the current default adapter & watch for future default adapters + new_adapter_path = manager.default_adapter (); } catch (Error e) { critical (@"$(e.message)"); } - on_default_adapter_changed (adapter_path); + on_default_adapter_changed (new_adapter_path); } - private void on_default_adapter_changed (string? object_path) + private void clear_adapter () { - supported = object_path != null; + if (adapter_path != null) + debug (@"clearing adapter; was using $adapter_path"); + + path_to_proxy.remove_all (); + path_to_id.remove_all (); + id_to_path.remove_all (); + id_to_device.remove_all (); + + default_adapter = null; + adapter_path = null; + + discoverable = false; + powered = false; + } + + void on_default_adapter_changed (string? object_path) + { + clear_adapter (); if (object_path != null) try { - debug (@"using default adapter at $object_path"); + adapter_path = object_path; default_adapter = Bus.get_proxy_sync (BusType.SYSTEM, "org.bluez", - object_path); + adapter_path); default_adapter.property_changed.connect (() => on_default_adapter_properties_changed ()); @@ -104,6 +160,8 @@ public class Bluez: KillswitchBluetooth on_default_adapter_properties_changed (); } + /* When the default adapter's properties change, + update our own properties "powered" and "discoverable" */ private void on_default_adapter_properties_changed () { bool is_discoverable = false; @@ -217,7 +275,6 @@ public class Bluez: KillswitchBluetooth private void device_connect_on_interface (DBusProxy proxy, string interface_name) { - var bus = proxy.get_connection (); var object_path = proxy.get_object_path (); debug (@"trying to connect to $object_path: $(interface_name)"); @@ -359,11 +416,21 @@ public class Bluez: KillswitchBluetooth devices_changed (); } + /* update the 'enabled' property by looking at the killswitch state + and the 'powered' property state */ + void update_enabled () + { + var blocked = (killswitch != null) && killswitch.blocked; + debug (@"in upate_enabled, powered is $powered, blocked is $blocked"); + enabled = powered && !blocked; + } + + //// //// Public API //// - public override void set_device_connected (uint id, bool connected) + public void set_device_connected (uint id, bool connected) { var device = id_to_device.lookup (id); var path = id_to_path.lookup (id); @@ -380,7 +447,7 @@ public class Bluez: KillswitchBluetooth } } - public override void try_set_discoverable (bool b) + public void try_set_discoverable (bool b) { if (discoverable != b) try { @@ -392,8 +459,32 @@ public class Bluez: KillswitchBluetooth } } - public override List get_devices () + public List get_devices () { return id_to_device.get_values(); } + + public bool supported { get; protected set; default = false; } + public bool discoverable { get; protected set; default = false; } + public bool enabled { get; protected set; default = false; } + + public void try_set_enabled (bool b) + { + if (killswitch != null) + { + debug (@"setting killswitch blocked to $(!b)"); + killswitch.try_set_blocked (!b); + } + + if (default_adapter != null) try + { + debug (@"setting bluez Adapter's Powered property to $b"); + default_adapter.set_property ("Powered", new Variant.boolean (b)); + powered = b; + } + catch (Error e) + { + critical (@"$(e.message)"); + } + } } diff --git a/src/desktop.vala b/src/desktop.vala index 7c99a45..a30935a 100644 --- a/src/desktop.vala +++ b/src/desktop.vala @@ -82,7 +82,7 @@ class Desktop: Profile void update_visibility () { - visible = bluetooth.powered && !bluetooth.blocked && settings.get_boolean("visible"); + visible = bluetooth.enabled && settings.get_boolean("visible"); } /// @@ -229,10 +229,6 @@ class Desktop: Profile bluetooth.notify["discoverable"].connect (() => action.set_state (bluetooth.discoverable)); - action.set_enabled (bluetooth.powered); - bluetooth.notify["powered"].connect (() - => action.set_enabled (bluetooth.powered)); - return action; } diff --git a/src/killswitch.vala b/src/killswitch.vala index 08ee0cc..167d189 100644 --- a/src/killswitch.vala +++ b/src/killswitch.vala @@ -26,6 +26,8 @@ */ public interface KillSwitch: Object { + public abstract bool is_valid (); + public abstract bool blocked { get; protected set; } /* Try to block/unblock bluetooth. @@ -109,6 +111,11 @@ public class RfKillSwitch: KillSwitch, Object } } + public bool is_valid () + { + return fd != -1; + } + private bool on_channel_event (IOChannel source, IOCondition condition) { read_event (); diff --git a/src/phone.vala b/src/phone.vala index 18c698c..2b0b96b 100644 --- a/src/phone.vala +++ b/src/phone.vala @@ -53,7 +53,7 @@ class Phone: Profile void update_visibility () { - visible = bluetooth.powered && !bluetooth.blocked; + visible = bluetooth.enabled; } /// diff --git a/src/profile.vala b/src/profile.vala index c32e46b..584af56 100644 --- a/src/profile.vala +++ b/src/profile.vala @@ -123,16 +123,16 @@ class Profile: Object { var action = new SimpleAction.stateful ("bluetooth-enabled", null, - !bluetooth.blocked); + bluetooth.enabled); action.activate.connect (() => action.change_state (!action.get_state().get_boolean())); action.change_state.connect ((action, requestedValue) - => bluetooth.try_set_blocked (!requestedValue.get_boolean())); + => bluetooth.try_set_enabled (requestedValue.get_boolean())); - bluetooth.notify["blocked"].connect (() - => action.set_state (!bluetooth.blocked)); + bluetooth.notify["enabled"].connect (() + => action.set_state (bluetooth.enabled)); return action; } @@ -144,12 +144,9 @@ class Profile: Object protected Variant action_state_for_root () { - var blocked = bluetooth.blocked; - var powered = bluetooth.powered; - string a11y; string icon_name; - if (powered && !blocked) + if (bluetooth.enabled) { a11y = "Bluetooth (on)"; icon_name = "bluetooth-active"; -- cgit v1.2.3