summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Branson <andrew.branson@cern.ch>2016-02-14 00:35:55 +0100
committerAndrew Branson <andrew.branson@cern.ch>2016-02-14 00:35:55 +0100
commit9df90e731612efe1cd9a69ae114f566c464e3e3a (patch)
tree19f1bbeb9baa1c0582290de5d45ce47c9c30d8fa
parent0d5ae0b50811736713bda642489d038759883589 (diff)
Revived old Bluez4 code from r50.
-rw-r--r--rockworkd/libpebble/bluez/bluezclient.cpp87
-rw-r--r--rockworkd/libpebble/bluez/bluezclient.h11
-rw-r--r--rockworkd/libpebble/bluez/device.cpp498
-rw-r--r--rockworkd/libpebble/bluez/device.h172
-rw-r--r--rockworkd/pebblemanager.cpp6
5 files changed, 759 insertions, 15 deletions
diff --git a/rockworkd/libpebble/bluez/bluezclient.cpp b/rockworkd/libpebble/bluez/bluezclient.cpp
index 8cdf848..313c540 100644
--- a/rockworkd/libpebble/bluez/bluezclient.cpp
+++ b/rockworkd/libpebble/bluez/bluezclient.cpp
@@ -1,5 +1,6 @@
#include "bluezclient.h"
#include "dbus-shared.h"
+#include "device.h"
#include <QDBusConnection>
#include <QDBusReply>
@@ -26,32 +27,84 @@ BluezClient::BluezClient(QObject *parent):
InterfaceList ifaces = objectList.value(path);
if (ifaces.contains(BLUEZ_DEVICE_IFACE)) {
QString candidatePath = path.path();
+ qDebug() << "have device" << candidatePath;
auto properties = ifaces.value(BLUEZ_DEVICE_IFACE);
addDevice(path, properties);
}
}
+
+ if (m_devices.isEmpty()) {
+ // Try with bluez 4
+ QDBusConnection system = QDBusConnection::systemBus();
+
+ QDBusReply<QList<QDBusObjectPath> > listAdaptersReply = system.call(
+ QDBusMessage::createMethodCall("org.bluez", "/", "org.bluez.Manager",
+ "ListAdapters"));
+ if (!listAdaptersReply.isValid()) {
+ qWarning() << listAdaptersReply.error().message();
+ return;
+ }
+
+ QList<QDBusObjectPath> adapters = listAdaptersReply.value();
+
+ if (adapters.isEmpty()) {
+ qWarning() << "No BT adapters found";
+ return;
+ }
+
+ QDBusReply<QVariantMap> adapterPropertiesReply = system.call(
+ QDBusMessage::createMethodCall("org.bluez", adapters[0].path(), "org.bluez.Adapter",
+ "GetProperties"));
+ if (!adapterPropertiesReply.isValid()) {
+ qWarning() << adapterPropertiesReply.error().message();
+ return;
+ }
+
+ QList<QDBusObjectPath> devices;
+ adapterPropertiesReply.value()["Devices"].value<QDBusArgument>() >> devices;
+
+ foreach (QDBusObjectPath path, devices) {
+ QDBusReply<QVariantMap> devicePropertiesReply = system.call(
+ QDBusMessage::createMethodCall("org.bluez", path.path(), "org.bluez.Device",
+ "GetProperties"));
+ if (!devicePropertiesReply.isValid()) {
+ qCritical() << devicePropertiesReply.error().message();
+ continue;
+ }
+
+ const QVariantMap &dict = devicePropertiesReply.value();
+
+ QString name = dict["Name"].toString();
+ if (name.startsWith("Pebble") && !name.startsWith("Pebble Time LE") && !name.startsWith("Pebble-LE")) {
+ qDebug() << "Found Pebble:" << name;
+ addDevice(path, dict);
+ }
+ }
+ }
}
}
-QList<Device> BluezClient::pairedPebbles() const
+QList<BluezDevice> BluezClient::pairedPebbles() const
{
- QList<Device> ret;
- if (m_bluezManager.isValid()) {
- foreach (const Device &dev, m_devices) {
- ret << dev;
- }
+ QList<BluezDevice> ret;
+
+ foreach (const BluezDevice &dev, m_devices) {
+ ret << dev;
}
+
return ret;
+
}
void BluezClient::addDevice(const QDBusObjectPath &path, const QVariantMap &properties)
{
QString address = properties.value("Address").toString();
QString name = properties.value("Name").toString();
+ qDebug() << "Adding device" << address << name;
if (name.startsWith("Pebble") && !name.startsWith("Pebble Time LE") && !name.startsWith("Pebble-LE") && !m_devices.contains(address)) {
qDebug() << "Found new Pebble:" << address << name;
- Device device;
+ BluezDevice device;
device.address = QBluetoothAddress(address);
device.name = name;
device.path = path.path();
@@ -70,6 +123,26 @@ void BluezClient::slotInterfacesAdded(const QDBusObjectPath &path, InterfaceList
}
}
+void BluezClient::slotDevicePairingDone(bool success)
+{
+ qDebug() << "pairing done" << success;
+ if (!success) {
+ return;
+ }
+
+ Device *device = static_cast<Device*>(sender());
+ device->deleteLater();
+
+ if (!m_devices.contains(device->getAddress())) {
+ BluezDevice bluezDevice;
+ bluezDevice.address = QBluetoothAddress(device->getAddress());
+ bluezDevice.name = device->getName();
+ bluezDevice.path = device->getPath();
+ m_devices.insert(device->getAddress(), bluezDevice);
+ emit devicesChanged();
+ }
+}
+
void BluezClient::slotInterfacesRemoved(const QDBusObjectPath &path, const QStringList &ifaces)
{
qDebug() << "interfaces removed" << path.path() << ifaces;
diff --git a/rockworkd/libpebble/bluez/bluezclient.h b/rockworkd/libpebble/bluez/bluezclient.h
index f8e5749..cbe7c0f 100644
--- a/rockworkd/libpebble/bluez/bluezclient.h
+++ b/rockworkd/libpebble/bluez/bluezclient.h
@@ -11,7 +11,7 @@
#include "bluez_adapter1.h"
#include "bluez_agentmanager1.h"
-class Device {
+class BluezDevice {
public:
QBluetoothAddress address;
QString name;
@@ -26,14 +26,15 @@ public:
BluezClient(QObject *parent = 0);
- QList<Device> pairedPebbles() const;
+ QList<BluezDevice> pairedPebbles() const;
private slots:
void addDevice(const QDBusObjectPath &path, const QVariantMap &properties);
void slotInterfacesAdded(const QDBusObjectPath&path, InterfaceList ifaces);
- void slotInterfacesRemoved(const QDBusObjectPath&path, const QStringList &ifaces);
-
+ void slotDevicePairingDone(bool success);
+ void slotInterfacesRemoved(const QDBusObjectPath&path, const QStringList &ifaces);
+
signals:
void devicesChanged();
@@ -45,7 +46,7 @@ private:
FreeDesktopProperties *m_bluezAdapterProperties = nullptr;
- QHash<QString, Device> m_devices;
+ QHash<QString, BluezDevice> m_devices;
};
#endif // BLUEZCLIENT_H
diff --git a/rockworkd/libpebble/bluez/device.cpp b/rockworkd/libpebble/bluez/device.cpp
new file mode 100644
index 0000000..9a0e9c3
--- /dev/null
+++ b/rockworkd/libpebble/bluez/device.cpp
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2013-2015 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include "device.h"
+
+#include <QDBusReply>
+#include <QDebug> // qWarning()
+#include <QThread>
+#include <QTimer>
+
+#include "dbus-shared.h"
+
+Device::Device(const QString &path, QDBusConnection &bus) :
+ m_strength(Device::None)
+{
+ initDevice(path, bus);
+}
+
+void Device::initDevice(const QString &path, QDBusConnection &bus)
+{
+ /* whenever any of the properties changes,
+ trigger the catch-all deviceChanged() signal */
+ QObject::connect(this, SIGNAL(nameChanged()), this, SIGNAL(deviceChanged()));
+ QObject::connect(this, SIGNAL(iconNameChanged()), this, SIGNAL(deviceChanged()));
+ QObject::connect(this, SIGNAL(addressChanged()), this, SIGNAL(deviceChanged()));
+ QObject::connect(this, SIGNAL(pairedChanged()), this, SIGNAL(deviceChanged()));
+ QObject::connect(this, SIGNAL(trustedChanged()), this, SIGNAL(deviceChanged()));
+ QObject::connect(this, SIGNAL(typeChanged()), this, SIGNAL(deviceChanged()));
+ QObject::connect(this, SIGNAL(connectionChanged()), this, SIGNAL(deviceChanged()));
+ QObject::connect(this, SIGNAL(strengthChanged()), this, SIGNAL(deviceChanged()));
+
+ m_bluezDevice.reset(new BluezDevice1(BLUEZ_SERVICE, path, bus));
+ /* Give our calls a bit more time than the default 25 seconds to
+ * complete whatever they are doing. In some situations (e.g. with
+ * specific devices) the default doesn't seem to be enough to. */
+ m_bluezDevice->setTimeout(60 * 1000 /* 60 seconds */);
+
+ m_bluezDeviceProperties.reset(new FreeDesktopProperties(BLUEZ_SERVICE, path, bus));
+
+ QObject::connect(m_bluezDeviceProperties.data(), SIGNAL(PropertiesChanged(const QString&, const QVariantMap&, const QStringList&)),
+ this, SLOT(slotPropertiesChanged(const QString&, const QVariantMap&, const QStringList&)));
+
+ Q_EMIT(pathChanged());
+
+ watchCall(m_bluezDeviceProperties->GetAll(BLUEZ_DEVICE_IFACE), [=](QDBusPendingCallWatcher *watcher) {
+ QDBusPendingReply<QVariantMap> reply = *watcher;
+
+ if (reply.isError()) {
+ qWarning() << "Failed to retrieve properties for device" << m_bluezDevice->path();
+ watcher->deleteLater();
+ return;
+ }
+
+ auto properties = reply.argumentAt<0>();
+ setProperties(properties);
+
+ watcher->deleteLater();
+ });
+}
+
+void Device::slotPropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
+ const QStringList &invalidatedProperties)
+{
+ Q_UNUSED(invalidatedProperties);
+
+ if (interface != BLUEZ_DEVICE_IFACE)
+ return;
+
+ setProperties(changedProperties);
+}
+
+void Device::setProperties(const QMap<QString,QVariant> &properties)
+{
+ QMapIterator<QString,QVariant> it(properties);
+ while (it.hasNext()) {
+ it.next();
+ updateProperty(it.key(), it.value());
+ }
+}
+
+void Device::setConnectAfterPairing(bool value)
+{
+ if (m_connectAfterPairing == value)
+ return;
+
+ m_connectAfterPairing = value;
+}
+
+void Device::disconnect()
+{
+ setConnection(Device::Disconnecting);
+
+ QDBusPendingCall call = m_bluezDevice->Disconnect();
+
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
+ QDBusPendingReply<void> reply = *watcher;
+
+ if (reply.isError()) {
+ qWarning() << "Could not disconnect device:"
+ << reply.error().message();
+
+ // Make sure we switch the connection indicator back to
+ // a sane state
+ updateConnection();
+ }
+
+ watcher->deleteLater();
+ });
+}
+
+void Device::connectAfterPairing()
+{
+ if (!m_connectAfterPairing)
+ return;
+
+ connect();
+}
+
+void Device::pair()
+{
+ if (m_paired) {
+ // If we are already paired we just have to make sure we
+ // trigger the connection process if we have to
+ connectAfterPairing();
+ return;
+ }
+
+ setConnection(Device::Connecting);
+
+ m_isPairing = true;
+
+ auto call = m_bluezDevice->asyncCall("Pair");
+
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
+ QDBusPendingReply<void> reply = *watcher;
+ bool success = true;
+
+ if (reply.isError()) {
+ qWarning() << "Failed to pair with device:"
+ << reply.error().message();
+ updateConnection();
+ success = false;
+ }
+
+ m_isPairing = false;
+
+ Q_EMIT(pairingDone(success));
+
+ watcher->deleteLater();
+ });
+}
+
+void Device::cancelPairing()
+{
+ if (!m_isPairing)
+ return;
+
+ auto call = m_bluezDevice->asyncCall("CancelPairing");
+
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
+ QDBusPendingReply<void> reply = *watcher;
+
+ if (reply.isError()) {
+ qWarning() << "Failed to cancel pairing attempt with device:"
+ << reply.error().message();
+ updateConnection();
+ } else {
+ // Only mark us a not pairing when call succeeded
+ m_isPairing = false;
+ }
+
+ watcher->deleteLater();
+ });
+}
+
+void Device::connect()
+{
+ // If we have just paired then the device switched to connected = true for
+ // a short moment as BlueZ opened up a RFCOMM channel to perform SDP. If
+ // we should connect with the device on specific profiles now we go ahead
+ // here even if we're marked as connected as this still doesn't mean we're
+ // connected on any profile. Calling org.bluez.Device1.Connect multiple
+ // times doesn't hurt an will not fail.
+ if (m_isConnected && !m_connectAfterPairing)
+ return;
+
+ setConnection(Device::Connecting);
+
+ QDBusPendingCall call = m_bluezDevice->asyncCall("Connect");
+
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
+ QDBusPendingReply<void> reply = *watcher;
+
+ if (reply.isError()) {
+ qWarning() << "Could not connect device:"
+ << reply.error().message();
+ } else {
+ makeTrusted(true);
+ }
+
+ // Regardless if the Connected property has changed or not we update
+ // the connection state here as the connection process is over now
+ // and we should have received any state change already at this
+ // point.
+ updateConnection();
+
+ watcher->deleteLater();
+ });
+}
+
+void Device::slotMakeTrustedDone(QDBusPendingCallWatcher *call)
+{
+ QDBusPendingReply<void> reply = *call;
+
+ if (reply.isError()) {
+ qWarning() << "Could not mark device as trusted:"
+ << reply.error().message();
+ }
+
+ call->deleteLater();
+}
+
+void Device::makeTrusted(bool trusted)
+{
+ auto call = m_bluezDeviceProperties->Set(BLUEZ_DEVICE_IFACE, "Trusted", QDBusVariant(trusted));
+
+ auto watcher = new QDBusPendingCallWatcher(call, this);
+ QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ this, SLOT(slotMakeTrustedDone(QDBusPendingCallWatcher*)));
+}
+
+void Device::setName(const QString &name)
+{
+ if (m_name != name) {
+ m_name = name;
+ Q_EMIT(nameChanged());
+ }
+}
+
+void Device::setIconName(const QString &iconName)
+{
+ if (m_iconName != iconName) {
+ m_iconName = iconName;
+ Q_EMIT(iconNameChanged());
+ }
+}
+
+void Device::setAddress(const QString &address)
+{
+ if (m_address != address) {
+ m_address = address;
+ Q_EMIT(addressChanged());
+ }
+}
+
+void Device::setType(Type type)
+{
+ if (m_type != type) {
+ m_type = type;
+ Q_EMIT(typeChanged());
+ updateIcon();
+ }
+}
+
+void Device::setPaired(bool paired)
+{
+ if (m_paired != paired) {
+ m_paired = paired;
+ Q_EMIT(pairedChanged());
+ }
+}
+
+void Device::setTrusted(bool trusted)
+{
+ if (m_trusted != trusted) {
+ m_trusted = trusted;
+ Q_EMIT(trustedChanged());
+ }
+}
+
+void Device::setConnection(Connection connection)
+{
+ if (m_connection != connection) {
+ m_connection = connection;
+ Q_EMIT(connectionChanged());
+ }
+}
+
+void Device::updateIcon()
+{
+ /* bluez-provided icon is unreliable? In testing I'm getting
+ an "audio-card" icon from bluez for my NoiseHush N700 headset.
+ Try to guess the icon from the device type,
+ and use the bluez-provided icon as a fallback */
+
+ const auto type = getType();
+
+ switch (type) {
+ case Type::Headset:
+ setIconName("image://theme/audio-headset-symbolic");
+ break;
+ case Type::Headphones:
+ setIconName("image://theme/audio-headphones-symbolic");
+ break;
+ case Type::Carkit:
+ setIconName("image://theme/audio-carkit-symbolic");
+ break;
+ case Type::Speakers:
+ case Type::OtherAudio:
+ setIconName("image://theme/audio-speakers-symbolic");
+ break;
+ case Type::Mouse:
+ setIconName("image://theme/input-mouse-symbolic");
+ break;
+ case Type::Keyboard:
+ setIconName("image://theme/input-keyboard-symbolic");
+ break;
+ case Type::Cellular:
+ setIconName("image://theme/phone-cellular-symbolic");
+ break;
+ case Type::Smartphone:
+ setIconName("image://theme/phone-smartphone-symbolic");
+ break;
+ case Type::Phone:
+ setIconName("image://theme/phone-uncategorized-symbolic");
+ break;
+ case Type::Computer:
+ setIconName("image://theme/computer-symbolic");
+ break;
+ default:
+ setIconName(QString("image://theme/%1").arg(m_fallbackIconName));
+ }
+}
+
+void Device::updateConnection()
+{
+ Connection c;
+
+ c = m_isConnected ? Connection::Connected : Connection::Disconnected;
+
+ setConnection(c);
+}
+
+void Device::updateProperty(const QString &key, const QVariant &value)
+{
+ if (key == "Name") {
+ setName(value.toString());
+ } else if (key == "Address") {
+ setAddress(value.toString());
+ } else if (key == "Connected") {
+ m_isConnected = value.toBool();
+ updateConnection();
+ } else if (key == "Class") {
+ setType(getTypeFromClass(value.toUInt()));
+ } else if (key == "Paired") {
+ setPaired(value.toBool());
+
+ if (m_paired && m_connectAfterPairing) {
+ connectAfterPairing();
+ return;
+ }
+
+ updateConnection();
+ } else if (key == "Trusted") {
+ setTrusted(value.toBool());
+ } else if (key == "Icon") {
+ m_fallbackIconName = value.toString();
+ updateIcon ();
+ } else if (key == "RSSI") {
+ m_strength = getStrengthFromRssi(value.toInt());
+ Q_EMIT(strengthChanged());
+ }
+}
+
+/* Determine the Type from the bits in the Class of Device (CoD) field.
+ https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband */
+Device::Type Device::getTypeFromClass (quint32 c)
+{
+ switch ((c & 0x1f00) >> 8) {
+ case 0x01:
+ return Type::Computer;
+
+ case 0x02:
+ switch ((c & 0xfc) >> 2) {
+ case 0x01:
+ return Type::Cellular;
+ case 0x03:
+ return Type::Smartphone;
+ case 0x04:
+ return Type::Modem;
+ default:
+ return Type::Phone;
+ }
+ break;
+
+ case 0x03:
+ return Type::Network;
+
+ case 0x04:
+ switch ((c & 0xfc) >> 2) {
+ case 0x01:
+ case 0x02:
+ return Type::Headset;
+
+ case 0x05:
+ return Type::Speakers;
+
+ case 0x06:
+ return Type::Headphones;
+
+ case 0x08:
+ return Type::Carkit;
+
+ case 0x0b: // vcr
+ case 0x0c: // video camera
+ case 0x0d: // camcorder
+ return Type::Video;
+
+ default:
+ return Type::OtherAudio;
+ }
+ break;
+
+ case 0x05:
+ switch ((c & 0xc0) >> 6) {
+ case 0x00:
+ switch ((c & 0x1e) >> 2) {
+ case 0x01:
+ case 0x02:
+ return Type::Joypad;
+ }
+ break;
+
+ case 0x01:
+ return Type::Keyboard;
+
+ case 0x02:
+ switch ((c & 0x1e) >> 2) {
+ case 0x05:
+ return Type::Tablet;
+ default:
+ return Type::Mouse;
+ }
+ }
+ break;
+
+ case 0x06:
+ if ((c & 0x80) != 0)
+ return Type::Printer;
+ if ((c & 0x20) != 0)
+ return Type::Camera;
+ break;
+
+ case 0x07:
+ if ((c & 0x4) != 0)
+ return Type::Watch;
+ break;
+ }
+
+ return Type::Other;
+}
+
+Device::Strength Device::getStrengthFromRssi(int rssi)
+{
+ /* Modelled similar to what Mac OS X does.
+ * See http://www.cnet.com/how-to/how-to-check-bluetooth-connection-strength-in-os-x/ */
+
+ if (rssi >= -60)
+ return Excellent;
+ else if (rssi < -60 && rssi >= -70)
+ return Good;
+ else if (rssi < -70 && rssi >= -90)
+ return Fair;
+ else if (rssi < -90)
+ return Poor;
+
+ return None;
+}
diff --git a/rockworkd/libpebble/bluez/device.h b/rockworkd/libpebble/bluez/device.h
new file mode 100644
index 0000000..bcc044b
--- /dev/null
+++ b/rockworkd/libpebble/bluez/device.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2013-2015 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef USS_BLUETOOTH_DEVICE_H
+#define USS_BLUETOOTH_DEVICE_H
+
+#include <QDBusConnection>
+#include <QDBusInterface>
+#include <QDBusPendingCallWatcher>
+#include <QSharedPointer>
+#include <QString>
+
+#include "freedesktop_properties.h"
+#include "bluez_device1.h"
+
+struct Device: QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString path
+ READ getPath
+ NOTIFY pathChanged)
+
+ Q_PROPERTY(QString name
+ READ getName
+ NOTIFY nameChanged)
+
+ Q_PROPERTY(QString iconName
+ READ getIconName
+ NOTIFY iconNameChanged)
+
+ Q_PROPERTY(QString address
+ READ getAddress
+ NOTIFY addressChanged)
+
+ Q_PROPERTY(Type type
+ READ getType
+ NOTIFY typeChanged)
+
+ Q_PROPERTY(bool paired
+ READ isPaired
+ NOTIFY pairedChanged)
+
+ Q_PROPERTY(bool trusted
+ READ isTrusted
+ WRITE makeTrusted
+ NOTIFY trustedChanged)
+
+ Q_PROPERTY(Connection connection
+ READ getConnection
+ NOTIFY connectionChanged)
+
+ Q_PROPERTY(Strength strength
+ READ getStrength
+ NOTIFY strengthChanged)
+
+public:
+
+ enum Type { Other, Computer, Cellular, Smartphone, Phone, Modem, Network,
+ Headset, Speakers, Headphones, Video, OtherAudio, Joypad,
+ Keypad, Keyboard, Tablet, Mouse, Printer, Camera, Carkit, Watch };
+
+ enum Strength { None, Poor, Fair, Good, Excellent };
+
+ enum Connection { Disconnected=1, Connecting=2,
+ Connected=4, Disconnecting=8 };
+
+ Q_ENUMS(Type Strength Connection)
+
+ Q_DECLARE_FLAGS(Connections, Connection)
+
+Q_SIGNALS:
+ void pathChanged();
+ void nameChanged();
+ void iconNameChanged();
+ void addressChanged();
+ void typeChanged();
+ void pairedChanged();
+ void trustedChanged();
+ void connectionChanged();
+ void strengthChanged();
+ void deviceChanged(); // catchall for any change
+ void pairingDone(bool success);
+
+public:
+ const QString& getName() const { return m_name; }
+ const QString& getAddress() const { return m_address; }
+ const QString& getIconName() const { return m_iconName; }
+ Type getType() const { return m_type; }
+ bool isPaired() const { return m_paired; }
+ bool isTrusted() const { return m_trusted; }
+ Connection getConnection() const { return m_connection; }
+ Strength getStrength() const { return m_strength; }
+ QString getPath() const { return m_bluezDevice ? m_bluezDevice->path() : QString(); }
+
+ private:
+ QString m_name;
+ QString m_state;
+ QString m_address;
+ QString m_iconName;
+ QString m_fallbackIconName;
+ Type m_type = Type::Other;
+ bool m_paired = false;
+ bool m_trusted = false;
+ Connection m_connection = Connection::Disconnected;
+ Strength m_strength = Strength::None;
+ bool m_isConnected = false;
+ bool m_connectAfterPairing = false;
+ QScopedPointer<BluezDevice1> m_bluezDevice;
+ QScopedPointer<FreeDesktopProperties> m_bluezDeviceProperties;
+ bool m_isPairing = false;
+
+ protected:
+ void setName(const QString &name);
+ void setIconName(const QString &name);
+ void setAddress(const QString &address);
+ void setType(Type type);
+ void setPaired(bool paired);
+ void setTrusted(bool trusted);
+ void setConnection(Connection connection);
+ void setStrength(Strength strength);
+ void updateIcon();
+ void updateConnection();
+
+ public:
+ Device() {}
+ Device(const QString &path, QDBusConnection &bus);
+ ~Device() {}
+ bool isValid() const { return getType() != Type::Other; }
+ void pair();
+ Q_INVOKABLE void cancelPairing();
+ void connect();
+ void makeTrusted(bool trusted);
+ void disconnect();
+ void setProperties(const QMap<QString,QVariant> &properties);
+ void setConnectAfterPairing(bool value);
+
+ private Q_SLOTS:
+ void slotPropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
+ const QStringList &invalidatedProperties);
+ void slotMakeTrustedDone(QDBusPendingCallWatcher *call);
+
+ private:
+ void initDevice(const QString &path, QDBusConnection &bus);
+ void updateProperties(QSharedPointer<QDBusInterface>);
+ void updateProperty(const QString &key, const QVariant &value);
+ static Type getTypeFromClass(quint32 bluetoothClass);
+ Device::Strength getStrengthFromRssi(int rssi);
+ void connectAfterPairing();
+};
+
+Q_DECLARE_METATYPE(Device*)
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Device::Connections)
+
+#endif // USS_BLUETOOTH_DEVICE_H
diff --git a/rockworkd/pebblemanager.cpp b/rockworkd/pebblemanager.cpp
index a119812..842dff0 100644
--- a/rockworkd/pebblemanager.cpp
+++ b/rockworkd/pebblemanager.cpp
@@ -26,8 +26,8 @@ QList<Pebble *> PebbleManager::pebbles() const
void PebbleManager::loadPebbles()
{
- QList<Device> pairedPebbles = m_bluezClient->pairedPebbles();
- foreach (const Device &device, pairedPebbles) {
+ QList<BluezDevice> pairedPebbles = m_bluezClient->pairedPebbles();
+ foreach (const BluezDevice &device, pairedPebbles) {
qDebug() << "loading pebble" << device.address.toString();
Pebble *pebble = get(device.address);
if (!pebble) {
@@ -46,7 +46,7 @@ void PebbleManager::loadPebbles()
QList<Pebble*> pebblesToRemove;
foreach (Pebble *pebble, m_pebbles) {
bool found = false;
- foreach (const Device &dev, pairedPebbles) {
+ foreach (const BluezDevice &dev, pairedPebbles) {
if (dev.address == pebble->address()) {
found = true;
break;