Skip to content

Commit

Permalink
[libqofono] Added a few synchronous (blocking) methods. JB#51589
Browse files Browse the repository at this point in the history
New public methods are:

    QOfonoManager::instance(bool)
    QOfonoModem::instance(const QString &, bool)
    QOfonoObject::getPropertiesSync()

And these are new constructors which may also block:

    QOfonoManager::QOfonoManager(bool, QObject *)
    QOfonoModem::QOfonoModem(const QString &, QObject *)

This makes libqofono easier to use in an environment which allows
blocking D-Bus calls (e.g. a command line app). More blocking
constructors and methods  may be added in the future when/if
those are needed.
  • Loading branch information
monich committed Nov 4, 2020
1 parent 4eec0c7 commit 5a60eb6
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 99 deletions.
120 changes: 88 additions & 32 deletions src/qofonomanager.cpp
Expand Up @@ -20,25 +20,73 @@
class QOfonoManager::Private
{
public:
typedef void (Private::*GetModems)(QOfonoManager *);

OfonoManager *ofonoManager;
QStringList modems;
bool available;

Private() : ofonoManager(NULL), available(false) {}
Private();

QString defaultModem();
void handleGetModemsReply(QOfonoManager* obj, ObjectPathPropertiesList reply);
void getModems(QOfonoManager *manager);
void setup(QOfonoManager *obj, GetModems getModems);
void connectToOfono(QOfonoManager *obj, GetModems getModems);
void handleGetModemsReply(QOfonoManager *obj, ObjectPathPropertiesList reply);
void getModems(QOfonoManager *obj);
void getModemsSync(QOfonoManager *obj);
};

QOfonoManager::Private::Private() :
ofonoManager(Q_NULLPTR),
available(false)
{
QOfonoDbusTypes::registerObjectPathProperties();
}

QString QOfonoManager::Private::defaultModem()
{
return modems.isEmpty() ? QString() : modems[0];
}

void QOfonoManager::Private::handleGetModemsReply(QOfonoManager* obj, ObjectPathPropertiesList reply)
void QOfonoManager::Private::setup(QOfonoManager *obj, GetModems getModems)
{
QDBusConnection bus(OFONO_BUS);
QDBusServiceWatcher *ofonoWatcher = new QDBusServiceWatcher(OFONO_SERVICE, bus,
QDBusServiceWatcher::WatchForRegistration |
QDBusServiceWatcher::WatchForUnregistration, obj);

obj->connect(ofonoWatcher, SIGNAL(serviceRegistered(QString)),
SLOT(connectToOfono(QString)));
obj->connect(ofonoWatcher, SIGNAL(serviceUnregistered(QString)),
SLOT(ofonoUnregistered(QString)));

if (bus.interface()->isServiceRegistered(OFONO_SERVICE)) {
connectToOfono(obj, getModems);
}
}

void QOfonoManager::Private::connectToOfono(QOfonoManager *obj, GetModems getModems)
{
if (!ofonoManager) {
OfonoManager *mgr = new OfonoManager(OFONO_SERVICE, "/", OFONO_BUS, obj);
if (mgr->isValid()) {
ofonoManager = mgr;
obj->connect(mgr,
SIGNAL(ModemAdded(QDBusObjectPath,QVariantMap)),
SLOT(onModemAdded(QDBusObjectPath,QVariantMap)));
obj->connect(mgr,
SIGNAL(ModemRemoved(QDBusObjectPath)),
SLOT(onModemRemoved(QDBusObjectPath)));
(this->*getModems)(obj);
} else {
delete mgr;
}
}
}

void QOfonoManager::Private::handleGetModemsReply(QOfonoManager *obj, ObjectPathPropertiesList reply)
{
bool wasAvailable = available;
const bool wasAvailable = available;
QString prevDefault = defaultModem();
QStringList newModems;
const int n = reply.count();
Expand Down Expand Up @@ -70,24 +118,31 @@ void QOfonoManager::Private::getModems(QOfonoManager *manager)
}
}

void QOfonoManager::Private::getModemsSync(QOfonoManager *obj)
{
if (ofonoManager) {
QDBusPendingReply<ObjectPathPropertiesList> reply = ofonoManager->GetModems();
reply.waitForFinished();
if (reply.isError()) {
qWarning() << reply.error();
} else {
handleGetModemsReply(obj, reply.value());
}
}
}

QOfonoManager::QOfonoManager(QObject *parent) :
QObject(parent),
d_ptr(new Private)
{
QOfonoDbusTypes::registerObjectPathProperties();
QDBusConnection bus(OFONO_BUS);
QDBusServiceWatcher *ofonoWatcher = new QDBusServiceWatcher(OFONO_SERVICE, bus,
QDBusServiceWatcher::WatchForRegistration |
QDBusServiceWatcher::WatchForUnregistration, this);

connect(ofonoWatcher, SIGNAL(serviceRegistered(QString)),
this, SLOT(connectToOfono(QString)));
connect(ofonoWatcher, SIGNAL(serviceUnregistered(QString)),
this, SLOT(ofonoUnregistered(QString)));
d_ptr->setup(this, &Private::getModems);
}

if (bus.interface()->isServiceRegistered(OFONO_SERVICE)) {
connectToOfono(QString());
}
QOfonoManager::QOfonoManager(bool mayBlock, QObject *parent) : // Since 1.0.101
QObject(parent),
d_ptr(new Private)
{
d_ptr->setup(this, mayBlock ? &Private::getModemsSync : &Private::getModems);
}

QOfonoManager::~QOfonoManager()
Expand All @@ -102,12 +157,8 @@ QStringList QOfonoManager::modems()

QStringList QOfonoManager::getModems()
{
if (d_ptr->ofonoManager && !d_ptr->available) {
QDBusPendingReply<ObjectPathPropertiesList> reply = d_ptr->ofonoManager->GetModems();
reply.waitForFinished();
if (!reply.isError()) {
d_ptr->handleGetModemsReply(this, reply.value());
}
if (!d_ptr->available) {
d_ptr->getModemsSync(this);
}
return d_ptr->modems;
}
Expand All @@ -124,12 +175,11 @@ bool QOfonoManager::available() const

bool QOfonoManager::isValid() const
{
// isValid() is essentially the same as available(), keeping it around for
// backward compatibility
// This is equivalent to available() for historical reasons
return d_ptr->available;
}

void QOfonoManager::onModemAdded(const QDBusObjectPath& path, const QVariantMap&)
void QOfonoManager::onModemAdded(const QDBusObjectPath &path, const QVariantMap&)
{
QString pathStr = path.path();
if (!d_ptr->modems.contains(pathStr)) {
Expand All @@ -145,7 +195,7 @@ void QOfonoManager::onModemAdded(const QDBusObjectPath& path, const QVariantMap&
}
}

void QOfonoManager::onModemRemoved(const QDBusObjectPath& path)
void QOfonoManager::onModemRemoved(const QDBusObjectPath &path)
{
QString pathStr = path.path();
QString prevDefault = defaultModem();
Expand All @@ -159,7 +209,7 @@ void QOfonoManager::onModemRemoved(const QDBusObjectPath& path)
}
}

void QOfonoManager::onGetModemsFinished(QDBusPendingCallWatcher* watcher)
void QOfonoManager::onGetModemsFinished(QDBusPendingCallWatcher *watcher)
{
QDBusPendingReply<ObjectPathPropertiesList> reply(*watcher);
watcher->deleteLater();
Expand All @@ -178,7 +228,7 @@ void QOfonoManager::onGetModemsFinished(QDBusPendingCallWatcher* watcher)
void QOfonoManager::connectToOfono(const QString &)
{
if (!d_ptr->ofonoManager) {
OfonoManager* mgr = new OfonoManager(OFONO_SERVICE, "/", OFONO_BUS, this);
OfonoManager *mgr = new OfonoManager(OFONO_SERVICE, "/", OFONO_BUS, this);
if (mgr->isValid()) {
d_ptr->ofonoManager = mgr;
connect(mgr,
Expand All @@ -202,7 +252,7 @@ void QOfonoManager::ofonoUnregistered(const QString &)
}
if (d_ptr->ofonoManager) {
delete d_ptr->ofonoManager;
d_ptr->ofonoManager = NULL;
d_ptr->ofonoManager = Q_NULLPTR;
if (!d_ptr->modems.isEmpty()) {
Q_FOREACH(QString modem, d_ptr->modems) {
Q_EMIT modemRemoved(modem);
Expand All @@ -215,12 +265,18 @@ void QOfonoManager::ofonoUnregistered(const QString &)
}

QSharedPointer<QOfonoManager> QOfonoManager::instance()
{
return instance(false); // Don't block
}

QSharedPointer<QOfonoManager> QOfonoManager::instance(bool mayBlock)
{
static QWeakPointer<QOfonoManager> sharedInstance;
QSharedPointer<QOfonoManager> mgr = sharedInstance;
if (mgr.isNull()) {
mgr = QSharedPointer<QOfonoManager>::create();
mgr = QSharedPointer<QOfonoManager>(new QOfonoManager(mayBlock), &QObject::deleteLater);
sharedInstance = mgr;
} else {
}
return mgr;
}
8 changes: 5 additions & 3 deletions src/qofonomanager.h
Expand Up @@ -32,7 +32,8 @@ class QOFONOSHARED_EXPORT QOfonoManager : public QObject
Q_PROPERTY(bool available READ available NOTIFY availableChanged)

public:
explicit QOfonoManager(QObject *parent = 0);
explicit QOfonoManager(QObject *parent = Q_NULLPTR);
QOfonoManager(bool mayBlock, QObject *parent = Q_NULLPTR); // Since 1.0.101
~QOfonoManager();

QStringList getModems(); // May block
Expand All @@ -42,15 +43,16 @@ class QOFONOSHARED_EXPORT QOfonoManager : public QObject
bool isValid() const;

static QSharedPointer<QOfonoManager> instance();
static QSharedPointer<QOfonoManager> instance(bool mayBlock); // Since 1.0.101

Q_SIGNALS: // SIGNALS
Q_SIGNALS:
void modemAdded(const QString &modem);
void modemRemoved(const QString &modem);
void availableChanged(bool available);
void modemsChanged(const QStringList &modems);
void defaultModemChanged(const QString &modem);

private slots:
private Q_SLOTS:
void onModemAdded(const QDBusObjectPath &path, const QVariantMap &var);
void onModemRemoved(const QDBusObjectPath &path);
void onGetModemsFinished(QDBusPendingCallWatcher*);
Expand Down
64 changes: 49 additions & 15 deletions src/qofonomodem.cpp
Expand Up @@ -47,21 +47,49 @@ class QOfonoModem::Private : public SUPER::ExtData

bool modemPathValid;
QSharedPointer<QOfonoManager> mgr;
Private() : modemPathValid(false), mgr(QOfonoManager::instance()) {}

Private(QSharedPointer<QOfonoManager> manager) : modemPathValid(false), mgr(manager) {}
void setup(QOfonoModem *modem);
bool isModemPathValid(const QString &path);
};

inline void QOfonoModem::Private::setup(QOfonoModem *modem)
{
connect(mgr.data(), SIGNAL(availableChanged(bool)), modem, SLOT(checkModemPathValidity()));
connect(mgr.data(), SIGNAL(modemsChanged(QStringList)), modem, SLOT(checkModemPathValidity()));
}

inline bool QOfonoModem::Private::isModemPathValid(const QString &path)
{
return !path.isEmpty() && mgr->isValid() && mgr->modems().contains(path);
}

#define DEFINE_PROPERTY(p) const QString QOfonoModem::Private::p(QLatin1String(#p));
MODEM_PROPERTIES(DEFINE_PROPERTY)

QOfonoModem::QOfonoModem(QObject *parent) :
SUPER(new Private, parent)
SUPER(new Private(QOfonoManager::instance(false)), parent)
{
QOfonoManager* mgr = privateData()->mgr.data();
connect(mgr, SIGNAL(availableChanged(bool)), SLOT(checkModemPathValidity()));
connect(mgr, SIGNAL(modemsChanged(QStringList)), SLOT(checkModemPathValidity()));
privateData()->setup(this);
checkModemPathValidity();
}

QOfonoModem::QOfonoModem(const QString &path, QObject *parent) : // Since 1.0.101
SUPER(new Private(QOfonoManager::instance(true)), path, parent)
{
Private* priv = privateData();
priv->setup(this);
priv->modemPathValid = priv->isModemPathValid(path);
if (priv->modemPathValid) {
resetDbusInterfaceSync();
}
if (!isValid()) {
// Try to repeat the call asynchronously if something went wrong.
// That may help in case if it was a timeout
queryProperties();
}
}

QOfonoModem::~QOfonoModem()
{
}
Expand Down Expand Up @@ -207,12 +235,24 @@ void QOfonoModem::propertyChanged(const QString &property, const QVariant &value
}

QSharedPointer<QOfonoModem> QOfonoModem::instance(const QString &modemPath)
{
return instance(modemPath, false);
}

QSharedPointer<QOfonoModem> QOfonoModem::instance(const QString &modemPath, bool mayBlock) // Since 1.0.101
{
QSharedPointer<QOfonoModem> modem = modemMap()->value(modemPath);
if (modem.isNull()) {
modem = QSharedPointer<QOfonoModem>::create();
modem = QSharedPointer<QOfonoModem>(mayBlock ? new QOfonoModem(modemPath) :
new QOfonoModem(), &QObject::deleteLater);
modem->fixObjectPath(modemPath);
modemMap()->insert(modemPath, QWeakPointer<QOfonoModem>(modem));
} else if (mayBlock && !modem->isValid()) {
// This may generate a second (synchronous) GetProperties call for
// the same object (if the first call was asynchronous and hasn't
// compeleted yet) but that should be a fairly rare case, not worth
// optimization.
modem->getPropertiesSync();
}
return modem;
}
Expand All @@ -222,22 +262,16 @@ bool QOfonoModem::isValid() const
return SUPER::isValid() && privateData()->modemPathValid;
}

QOfonoModem::Private* QOfonoModem::privateData() const
QOfonoModem::Private *QOfonoModem::privateData() const
{
return (Private*)SUPER::extData();
}

bool QOfonoModem::checkModemPathValidity()
{
ValidTracker valid(this);
bool modemPathValid;
Private* priv = privateData();
if (priv->mgr->isValid()) {
QString path = modemPath();
modemPathValid = !path.isEmpty() && priv->mgr->modems().contains(path);
} else {
modemPathValid = false;
}
Private *priv = privateData();
const bool modemPathValid = priv->isModemPathValid(modemPath());
if (priv->modemPathValid != modemPathValid) {
priv->modemPathValid = modemPathValid;
if (modemPathValid) {
Expand Down
18 changes: 10 additions & 8 deletions src/qofonomodem.h
@@ -1,7 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2013-2015 Jolla Ltd.
** Contact: lorn.potter@jollamobile.com
** Copyright (C) 2013-2020 Jolla Ltd.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
Expand Down Expand Up @@ -47,7 +46,8 @@ class QOFONOSHARED_EXPORT QOfonoModem : public QOfonoObject
Q_PROPERTY(QString modemPath READ modemPath WRITE setModemPath NOTIFY modemPathChanged)

public:
explicit QOfonoModem(QObject *parent = 0);
explicit QOfonoModem(QObject *parent = Q_NULLPTR);
QOfonoModem(const QString &path, QObject *parent = Q_NULLPTR); // Blocking (since 1.0.101)
~QOfonoModem();

QString modemPath() const;
Expand Down Expand Up @@ -75,10 +75,12 @@ class QOFONOSHARED_EXPORT QOfonoModem : public QOfonoObject
QStringList features() const;
QStringList interfaces() const;

bool isValid() const;
bool isValid() const Q_DECL_OVERRIDE;

// If you use this, remember to keep a QSharedPointer to it, otherwise it may be destroyed.
// The second one may block if the shared instance hasn't been initialized yet.
static QSharedPointer<QOfonoModem> instance(const QString &modemPath);
static QSharedPointer<QOfonoModem> instance(const QString &modemPath, bool mayBlock); // Since 1.0.101

Q_SIGNALS:
void poweredChanged(bool powered);
Expand All @@ -100,13 +102,13 @@ private Q_SLOTS:
bool checkModemPathValidity();

protected:
QDBusAbstractInterface *createDbusInterface(const QString &path);
void propertyChanged(const QString &key, const QVariant &value);
void objectPathChanged(const QString &path, const QVariantMap *properties);
QDBusAbstractInterface *createDbusInterface(const QString &path) Q_DECL_OVERRIDE;
void propertyChanged(const QString &key, const QVariant &value) Q_DECL_OVERRIDE;
void objectPathChanged(const QString &path, const QVariantMap *properties) Q_DECL_OVERRIDE;

private:
class Private;
Private* privateData() const;
Private *privateData() const;
};

#endif // QOFONOMODEM_H

0 comments on commit 5a60eb6

Please sign in to comment.