Expose pairing state for devices
Will allow to have information about whether we're pairing, mostly for better GUI. Pair-programmed with Albert Vaca
This commit is contained in:
parent
339ce7beea
commit
ea41d3786e
9 changed files with 99 additions and 25 deletions
|
@ -60,9 +60,11 @@ public:
|
||||||
virtual bool linkShouldBeKeptAlive() { return false; }
|
virtual bool linkShouldBeKeptAlive() { return false; }
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void receivedPackage(const NetworkPackage& np);
|
void pairingRequest(PairingHandler* handler);
|
||||||
|
void pairingRequestExpired(PairingHandler* handler);
|
||||||
void pairStatusChanged(DeviceLink::PairStatus status);
|
void pairStatusChanged(DeviceLink::PairStatus status);
|
||||||
void pairingError(const QString &error);
|
void pairingError(const QString &error);
|
||||||
|
void receivedPackage(const NetworkPackage& np);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QCA::PrivateKey mPrivateKey;
|
QCA::PrivateKey mPrivateKey;
|
||||||
|
|
|
@ -38,8 +38,6 @@ LanPairingHandler::LanPairingHandler(DeviceLink* deviceLink)
|
||||||
|
|
||||||
void LanPairingHandler::packageReceived(const NetworkPackage& np)
|
void LanPairingHandler::packageReceived(const NetworkPackage& np)
|
||||||
{
|
{
|
||||||
m_pairingTimeout.stop();
|
|
||||||
|
|
||||||
bool wantsPair = np.get<bool>(QStringLiteral("pair"));
|
bool wantsPair = np.get<bool>(QStringLiteral("pair"));
|
||||||
|
|
||||||
if (wantsPair) {
|
if (wantsPair) {
|
||||||
|
@ -57,7 +55,6 @@ void LanPairingHandler::packageReceived(const NetworkPackage& np)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Daemon::instance()->askPairingConfirmation(this);
|
|
||||||
setInternalPairStatus(RequestedByPeer);
|
setInternalPairStatus(RequestedByPeer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,14 +90,12 @@ bool LanPairingHandler::requestPairing()
|
||||||
const bool success = deviceLink()->sendPackage(np);
|
const bool success = deviceLink()->sendPackage(np);
|
||||||
if (success) {
|
if (success) {
|
||||||
setInternalPairStatus(Requested);
|
setInternalPairStatus(Requested);
|
||||||
m_pairingTimeout.start();
|
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LanPairingHandler::acceptPairing()
|
bool LanPairingHandler::acceptPairing()
|
||||||
{
|
{
|
||||||
m_pairingTimeout.stop(); // Just in case it is started
|
|
||||||
NetworkPackage np(PACKAGE_TYPE_PAIR, {{"pair", true}});
|
NetworkPackage np(PACKAGE_TYPE_PAIR, {{"pair", true}});
|
||||||
bool success = deviceLink()->sendPackage(np);
|
bool success = deviceLink()->sendPackage(np);
|
||||||
if (success) {
|
if (success) {
|
||||||
|
@ -132,6 +127,18 @@ void LanPairingHandler::pairingTimeout()
|
||||||
|
|
||||||
void LanPairingHandler::setInternalPairStatus(LanPairingHandler::InternalPairStatus status)
|
void LanPairingHandler::setInternalPairStatus(LanPairingHandler::InternalPairStatus status)
|
||||||
{
|
{
|
||||||
|
if (status == Requested || status == RequestedByPeer) {
|
||||||
|
m_pairingTimeout.start();
|
||||||
|
} else {
|
||||||
|
m_pairingTimeout.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_status == RequestedByPeer && (status == NotPaired || status == Paired)) {
|
||||||
|
Q_EMIT deviceLink()->pairingRequestExpired(this);
|
||||||
|
} else if (status == RequestedByPeer) {
|
||||||
|
Q_EMIT deviceLink()->pairingRequest(this);
|
||||||
|
}
|
||||||
|
|
||||||
m_status = status;
|
m_status = status;
|
||||||
if (status == Paired) {
|
if (status == Paired) {
|
||||||
deviceLink()->setPairStatus(DeviceLink::Paired);
|
deviceLink()->setPairStatus(DeviceLink::Paired);
|
||||||
|
|
|
@ -49,7 +49,7 @@ public:
|
||||||
|
|
||||||
virtual void packageReceived(const NetworkPackage& np) = 0;
|
virtual void packageReceived(const NetworkPackage& np) = 0;
|
||||||
virtual void unpair() = 0;
|
virtual void unpair() = 0;
|
||||||
virtual int pairingTimeoutMsec() const { return 30 * 1000; } // 30 seconds of timeout (default), subclasses that use different values should override
|
static int pairingTimeoutMsec() { return 30 * 1000; } // 30 seconds of timeout (default), subclasses that use different values should override
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
virtual bool requestPairing() = 0;
|
virtual bool requestPairing() = 0;
|
||||||
|
|
|
@ -70,11 +70,7 @@ Daemon::Daemon(QObject *parent, bool testMode)
|
||||||
//Read remebered paired devices
|
//Read remebered paired devices
|
||||||
const QStringList& list = KdeConnectConfig::instance()->trustedDevices();
|
const QStringList& list = KdeConnectConfig::instance()->trustedDevices();
|
||||||
Q_FOREACH (const QString& id, list) {
|
Q_FOREACH (const QString& id, list) {
|
||||||
Device* device = new Device(this, id);
|
addDevice(new Device(this, id));
|
||||||
connect(device, &Device::reachableChanged, this, &Daemon::onDeviceStatusChanged);
|
|
||||||
connect(device, &Device::trustedChanged, this, &Daemon::onDeviceStatusChanged);
|
|
||||||
d->mDevices[id] = device;
|
|
||||||
Q_EMIT deviceAdded(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Listen to new devices
|
//Listen to new devices
|
||||||
|
@ -185,11 +181,7 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink*
|
||||||
if (!isDiscoveringDevices() && !device->isTrusted() && !dl->linkShouldBeKeptAlive()) {
|
if (!isDiscoveringDevices() && !device->isTrusted() && !dl->linkShouldBeKeptAlive()) {
|
||||||
device->deleteLater();
|
device->deleteLater();
|
||||||
} else {
|
} else {
|
||||||
connect(device, &Device::reachableChanged, this, &Daemon::onDeviceStatusChanged);
|
addDevice(device);
|
||||||
connect(device, &Device::trustedChanged, this, &Daemon::onDeviceStatusChanged);
|
|
||||||
d->mDevices[id] = device;
|
|
||||||
|
|
||||||
Q_EMIT deviceAdded(id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,6 +242,28 @@ QString Daemon::deviceIdByName(const QString &name) const
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Daemon::addDevice(Device* device)
|
||||||
|
{
|
||||||
|
const QString id = device->id();
|
||||||
|
connect(device, &Device::reachableChanged, this, &Daemon::onDeviceStatusChanged);
|
||||||
|
connect(device, &Device::trustedChanged, this, &Daemon::onDeviceStatusChanged);
|
||||||
|
connect(device, &Device::pairingRequestsChanged, this, &Daemon::pairingRequestsChanged);
|
||||||
|
connect(device, &Device::pairingRequestsChanged, this, [this, device]() { askPairingConfirmation(device); } );
|
||||||
|
d->mDevices[id] = device;
|
||||||
|
|
||||||
|
Q_EMIT deviceAdded(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList Daemon::pairingRequests() const
|
||||||
|
{
|
||||||
|
QStringList ret;
|
||||||
|
for(Device* dev: d->mDevices) {
|
||||||
|
if (dev->hasPairingRequests())
|
||||||
|
ret += dev->id();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
Daemon::~Daemon()
|
Daemon::~Daemon()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ class KDECONNECTCORE_EXPORT Daemon
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.daemon")
|
Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.daemon")
|
||||||
Q_PROPERTY(bool isDiscoveringDevices READ isDiscoveringDevices)
|
Q_PROPERTY(bool isDiscoveringDevices READ isDiscoveringDevices)
|
||||||
|
Q_PROPERTY(QStringList pairingRequests READ pairingRequests NOTIFY pairingRequestsChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Daemon(QObject *parent, bool testMode = false);
|
explicit Daemon(QObject *parent, bool testMode = false);
|
||||||
|
@ -48,12 +49,14 @@ public:
|
||||||
|
|
||||||
QList<Device*> devicesList() const;
|
QList<Device*> devicesList() const;
|
||||||
|
|
||||||
virtual void askPairingConfirmation(PairingHandler *d) = 0;
|
virtual void askPairingConfirmation(Device *device) = 0;
|
||||||
virtual void reportError(const QString &title, const QString &description) = 0;
|
virtual void reportError(const QString &title, const QString &description) = 0;
|
||||||
virtual QNetworkAccessManager* networkAccessManager();
|
virtual QNetworkAccessManager* networkAccessManager();
|
||||||
|
|
||||||
Device* getDevice(const QString& deviceId);
|
Device* getDevice(const QString& deviceId);
|
||||||
|
|
||||||
|
QStringList pairingRequests() const;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
Q_SCRIPTABLE void acquireDiscoveryMode(const QString &id);
|
Q_SCRIPTABLE void acquireDiscoveryMode(const QString &id);
|
||||||
Q_SCRIPTABLE void releaseDiscoveryMode(const QString &id);
|
Q_SCRIPTABLE void releaseDiscoveryMode(const QString &id);
|
||||||
|
@ -74,12 +77,14 @@ Q_SIGNALS:
|
||||||
Q_SCRIPTABLE void deviceRemoved(const QString& id); //Note that paired devices will never be removed
|
Q_SCRIPTABLE void deviceRemoved(const QString& id); //Note that paired devices will never be removed
|
||||||
Q_SCRIPTABLE void deviceVisibilityChanged(const QString& id, bool isVisible);
|
Q_SCRIPTABLE void deviceVisibilityChanged(const QString& id, bool isVisible);
|
||||||
Q_SCRIPTABLE void announcedNameChanged(const QString &announcedName);
|
Q_SCRIPTABLE void announcedNameChanged(const QString &announcedName);
|
||||||
|
Q_SCRIPTABLE void pairingRequestsChanged();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* dl);
|
void onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* dl);
|
||||||
void onDeviceStatusChanged();
|
void onDeviceStatusChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void addDevice(Device* device);
|
||||||
bool isDiscoveringDevices() const;
|
bool isDiscoveringDevices() const;
|
||||||
void removeDevice(Device* d);
|
void removeDevice(Device* d);
|
||||||
void cleanDevices();
|
void cleanDevices();
|
||||||
|
|
|
@ -251,9 +251,45 @@ void Device::addLink(const NetworkPackage& identityPackage, DeviceLink* link)
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(link, &DeviceLink::pairStatusChanged, this, &Device::pairStatusChanged);
|
connect(link, &DeviceLink::pairStatusChanged, this, &Device::pairStatusChanged);
|
||||||
|
connect(link, &DeviceLink::pairingRequest, this, &Device::addPairingRequest);
|
||||||
|
connect(link, &DeviceLink::pairingRequestExpired, this, &Device::removePairingRequest);
|
||||||
connect(link, &DeviceLink::pairingError, this, &Device::pairingError);
|
connect(link, &DeviceLink::pairingError, this, &Device::pairingError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Device::addPairingRequest(PairingHandler* handler)
|
||||||
|
{
|
||||||
|
m_pairRequests.insert(handler);
|
||||||
|
Q_EMIT pairingRequestsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::removePairingRequest(PairingHandler* handler)
|
||||||
|
{
|
||||||
|
m_pairRequests.remove(handler);
|
||||||
|
Q_EMIT pairingRequestsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::acceptPairing()
|
||||||
|
{
|
||||||
|
if (m_pairRequests.isEmpty())
|
||||||
|
qWarning() << "no pair requests to accept!";
|
||||||
|
|
||||||
|
//copying because the pairing handler will be removed upon accept
|
||||||
|
const auto prCopy = m_pairRequests;
|
||||||
|
for (auto ph: prCopy)
|
||||||
|
ph->acceptPairing();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::rejectPairing()
|
||||||
|
{
|
||||||
|
if (m_pairRequests.isEmpty())
|
||||||
|
qWarning() << "no pair requests to reject!";
|
||||||
|
|
||||||
|
//copying because the pairing handler will be removed upon reject
|
||||||
|
const auto prCopy = m_pairRequests;
|
||||||
|
for (auto ph: prCopy)
|
||||||
|
ph->rejectPairing();
|
||||||
|
}
|
||||||
|
|
||||||
void Device::linkDestroyed(QObject* o)
|
void Device::linkDestroyed(QObject* o)
|
||||||
{
|
{
|
||||||
removeLink(static_cast<DeviceLink*>(o));
|
removeLink(static_cast<DeviceLink*>(o));
|
||||||
|
|
|
@ -44,6 +44,7 @@ class KDECONNECTCORE_EXPORT Device
|
||||||
Q_PROPERTY(bool isReachable READ isReachable NOTIFY reachableChanged)
|
Q_PROPERTY(bool isReachable READ isReachable NOTIFY reachableChanged)
|
||||||
Q_PROPERTY(bool isTrusted READ isTrusted NOTIFY trustedChanged)
|
Q_PROPERTY(bool isTrusted READ isTrusted NOTIFY trustedChanged)
|
||||||
Q_PROPERTY(QStringList supportedPlugins READ supportedPlugins NOTIFY pluginsChanged)
|
Q_PROPERTY(QStringList supportedPlugins READ supportedPlugins NOTIFY pluginsChanged)
|
||||||
|
Q_PROPERTY(bool hasPairingRequests READ hasPairingRequests NOTIFY pairingRequestsChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -102,6 +103,8 @@ public:
|
||||||
int protocolVersion() { return m_protocolVersion; }
|
int protocolVersion() { return m_protocolVersion; }
|
||||||
QStringList supportedPlugins() const { return m_supportedPlugins.toList(); }
|
QStringList supportedPlugins() const { return m_supportedPlugins.toList(); }
|
||||||
|
|
||||||
|
bool hasPairingRequests() const { return !m_pairRequests.isEmpty(); }
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
///sends a @p np package to the device
|
///sends a @p np package to the device
|
||||||
///virtual for testing purposes.
|
///virtual for testing purposes.
|
||||||
|
@ -113,10 +116,15 @@ public Q_SLOTS:
|
||||||
Q_SCRIPTABLE void unpair(); //from all links
|
Q_SCRIPTABLE void unpair(); //from all links
|
||||||
Q_SCRIPTABLE void reloadPlugins(); //from kconf
|
Q_SCRIPTABLE void reloadPlugins(); //from kconf
|
||||||
|
|
||||||
|
Q_SCRIPTABLE void acceptPairing();
|
||||||
|
Q_SCRIPTABLE void rejectPairing();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void privateReceivedPackage(const NetworkPackage& np);
|
void privateReceivedPackage(const NetworkPackage& np);
|
||||||
void linkDestroyed(QObject* o);
|
void linkDestroyed(QObject* o);
|
||||||
void pairStatusChanged(DeviceLink::PairStatus current);
|
void pairStatusChanged(DeviceLink::PairStatus current);
|
||||||
|
void addPairingRequest(PairingHandler* handler);
|
||||||
|
void removePairingRequest(PairingHandler* handler);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
Q_SCRIPTABLE void pluginsChanged();
|
Q_SCRIPTABLE void pluginsChanged();
|
||||||
|
@ -125,6 +133,8 @@ Q_SIGNALS:
|
||||||
Q_SCRIPTABLE void pairingError(const QString& error);
|
Q_SCRIPTABLE void pairingError(const QString& error);
|
||||||
Q_SCRIPTABLE void nameChanged(const QString& name);
|
Q_SCRIPTABLE void nameChanged(const QString& name);
|
||||||
|
|
||||||
|
void pairingRequestsChanged();
|
||||||
|
|
||||||
private: //Methods
|
private: //Methods
|
||||||
static DeviceType str2type(const QString &deviceType);
|
static DeviceType str2type(const QString &deviceType);
|
||||||
static QString type2str(DeviceType deviceType);
|
static QString type2str(DeviceType deviceType);
|
||||||
|
@ -144,6 +154,7 @@ private: //Fields (TODO: dPointer!)
|
||||||
//Capabilities stuff
|
//Capabilities stuff
|
||||||
QMultiMap<QString, KdeConnectPlugin*> m_pluginsByIncomingCapability;
|
QMultiMap<QString, KdeConnectPlugin*> m_pluginsByIncomingCapability;
|
||||||
QSet<QString> m_supportedPlugins;
|
QSet<QString> m_supportedPlugins;
|
||||||
|
QSet<PairingHandler*> m_pairRequests;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Device*)
|
Q_DECLARE_METATYPE(Device*)
|
||||||
|
|
|
@ -42,18 +42,17 @@ public:
|
||||||
, m_nam(Q_NULLPTR)
|
, m_nam(Q_NULLPTR)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void askPairingConfirmation(PairingHandler* d) override
|
void askPairingConfirmation(Device* device) override
|
||||||
{
|
{
|
||||||
KNotification* notification = new KNotification(QStringLiteral("pairingRequest"),
|
KNotification* notification = new KNotification(QStringLiteral("pairingRequest"),
|
||||||
KNotification::Persistent);
|
KNotification::Persistent);
|
||||||
notification->setIconName(QStringLiteral("dialog-information"));
|
notification->setIconName(QStringLiteral("dialog-information"));
|
||||||
notification->setComponentName(QStringLiteral("kdeconnect"));
|
notification->setComponentName(QStringLiteral("kdeconnect"));
|
||||||
notification->setText(i18n("Pairing request from %1", getDevice(d->deviceLink()->deviceId())->name()));
|
notification->setText(i18n("Pairing request from %1", device->name()));
|
||||||
notification->setActions(QStringList() << i18n("Accept") << i18n("Reject"));
|
notification->setActions(QStringList() << i18n("Accept") << i18n("Reject"));
|
||||||
connect(notification, &KNotification::ignored, d, &PairingHandler::rejectPairing);
|
// notification->setTimeout(PairingHandler::pairingTimeoutMsec());
|
||||||
connect(notification, &KNotification::action1Activated, d, &PairingHandler::acceptPairing);
|
connect(notification, &KNotification::action1Activated, device, &Device::acceptPairing);
|
||||||
connect(notification, &KNotification::action2Activated, d, &PairingHandler::rejectPairing);
|
connect(notification, &KNotification::action2Activated, device, &Device::rejectPairing);
|
||||||
QTimer::singleShot(d->pairingTimeoutMsec(), notification, &KNotification::close); // close after pairing timeout, assuming that the peer uses the same timeout value
|
|
||||||
notification->sendEvent();
|
notification->sendEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
qWarning() << "error:" << title << description;
|
qWarning() << "error:" << title << description;
|
||||||
}
|
}
|
||||||
|
|
||||||
void askPairingConfirmation(PairingHandler * d) override {
|
void askPairingConfirmation(Device * d) override {
|
||||||
d->acceptPairing();
|
d->acceptPairing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue