diff options
author | Ville Voutilainen <ville.voutilainen@qt.io> | 2018-04-18 18:54:33 +0300 |
---|---|---|
committer | Ville Voutilainen <ville.voutilainen@qt.io> | 2018-04-20 12:02:10 +0000 |
commit | f6730013c51c6b8d1da6df4eae5c774e34bcbc4d (patch) | |
tree | 80dfb0f5563c02e636839c7f5b765244bdd1c455 | |
parent | 8f3dfc1e6364fbd1aaf62d2c0aba0e4d6ac1742f (diff) |
Add support for wi-fi networks with hidden SSID
Task-number: QTBUG-62661
Change-Id: I664a1dbc3f30509bbabb669dfb479f71e885bdd6
Reviewed-by: Teemu Holappa <teemu.holappa@qt.io>
14 files changed, 295 insertions, 11 deletions
diff --git a/src/networksettings/connman/qnetworksettingsmanager_p.cpp b/src/networksettings/connman/qnetworksettingsmanager_p.cpp index a136237..e2b0281 100644 --- a/src/networksettings/connman/qnetworksettingsmanager_p.cpp +++ b/src/networksettings/connman/qnetworksettingsmanager_p.cpp @@ -44,6 +44,7 @@ QNetworkSettingsManagerPrivate::QNetworkSettingsManagerPrivate(QNetworkSettingsM , m_serviceFilter(Q_NULLPTR) , m_manager(Q_NULLPTR) , m_agent(Q_NULLPTR) + , m_currentWifiConnection(Q_NULLPTR) { qDBusRegisterMetaType<ConnmanMapStruct>(); qDBusRegisterMetaType<ConnmanMapStructList>(); @@ -89,6 +90,40 @@ void QNetworkSettingsManagerPrivate::requestInput(const QString& service, const m_agent->showUserCredentialsInput(); } +void QNetworkSettingsManagerPrivate::connectBySsid(const QString &name) +{ + m_unnamedServicesForSsidConnection = m_unnamedServices; + tryNextConnection(); + m_currentSsid = name; +} + +void QNetworkSettingsManagerPrivate::clearConnectionState() +{ + m_unnamedServicesForSsidConnection.clear(); + m_currentSsid.clear(); +} + +void QNetworkSettingsManagerPrivate::tryNextConnection() +{ + Q_Q(QNetworkSettingsManager); + QNetworkSettingsService* service = nullptr; + if (!m_currentSsid.isEmpty()) { + service = m_serviceModel->getByName(m_currentSsid); + m_currentSsid.clear(); + } + if (!service) { + if (!m_unnamedServicesForSsidConnection.isEmpty()) { + service = *m_unnamedServicesForSsidConnection.begin(); + m_unnamedServicesForSsidConnection.erase(m_unnamedServicesForSsidConnection.begin()); + } else { + q->clearConnectionState(); + } + } + if (service) { + service->doConnectService(); + } +} + void QNetworkSettingsManagerPrivate::getServicesFinished(QDBusPendingCallWatcher *watcher) { Q_Q(QNetworkSettingsManager); @@ -132,6 +167,11 @@ void QNetworkSettingsManagerPrivate::onServicesChanged(ConnmanMapStructList chan { foreach (QDBusObjectPath path, removed) { m_serviceModel->removeService(path.path()); + auto serviceIter = m_unnamedServices.find(path.path()); + if (serviceIter != m_unnamedServices.end()) { + serviceIter.value()->deleteLater(); + m_unnamedServices.erase(serviceIter); + } } QStringList newServices; @@ -158,6 +198,14 @@ void QNetworkSettingsManagerPrivate::handleNewService(const QString &servicePath QNetworkSettingsService *service = new QNetworkSettingsService(servicePath, this); + connect(service, &QNetworkSettingsService::connectionStateCleared, + q, &QNetworkSettingsManager::clearConnectionState); + + connect(service, &QNetworkSettingsService::serviceConnected, + q, &QNetworkSettingsManager::setCurrentWifiConnection); + connect(service, &QNetworkSettingsService::serviceDisconnected, + q, &QNetworkSettingsManager::clearCurrentWifiConnection); + if (service->name().length() > 0 && service->type() != QNetworkSettingsType::Unknown) { m_serviceModel->append(service); emit q->servicesChanged(); @@ -182,8 +230,15 @@ void QNetworkSettingsManagerPrivate::serviceReady() Q_Q(QNetworkSettingsManager); QNetworkSettingsService* service = qobject_cast<QNetworkSettingsService*>(sender()); + + if (service->type() != QNetworkSettingsType::Unknown + && service->type() == QNetworkSettingsType::Wifi) { + m_unnamedServices.insert(service->id(), service); + } + if (service->name().length() > 0 && service->type() != QNetworkSettingsType::Unknown) { service->disconnect(this); + m_unnamedServices.remove(service->id()); m_serviceModel->append(service); emit q->servicesChanged(); if (service->type() == QNetworkSettingsType::Wired) { diff --git a/src/networksettings/connman/qnetworksettingsmanager_p.h b/src/networksettings/connman/qnetworksettingsmanager_p.h index 579d857..b889379 100644 --- a/src/networksettings/connman/qnetworksettingsmanager_p.h +++ b/src/networksettings/connman/qnetworksettingsmanager_p.h @@ -42,6 +42,7 @@ #include <QObject> #include <QtDBus> +#include <QMap> #include "connmancommon.h" #include "qnetworksettingsmanager.h" #include "qnetworksettingsinterfacemodel.h" @@ -66,7 +67,11 @@ public: QNetworkSettingsInterfaceModel* interfaceModel() {return &m_interfaceModel;} QNetworkSettingsServiceModel* serviceModel() const {return m_serviceModel;} QNetworkSettingsServiceFilter* serviceFilter() const {return m_serviceFilter;} - + void connectBySsid(const QString &name); + void clearConnectionState(); + void tryNextConnection(); + void setCurrentWifiConnection(QNetworkSettingsService *connection) {m_currentWifiConnection = connection;} + QNetworkSettingsService* currentWifiConnection() const {return m_currentWifiConnection;} public slots: void getServicesFinished(QDBusPendingCallWatcher *watcher); void getTechnologiesFinished(QDBusPendingCallWatcher *watcher); @@ -78,10 +83,14 @@ private: protected: QNetworkSettingsInterfaceModel m_interfaceModel; QNetworkSettingsServiceModel *m_serviceModel; + QMap<QString, QNetworkSettingsService*> m_unnamedServices; + QMap<QString, QNetworkSettingsService*> m_unnamedServicesForSsidConnection; QNetworkSettingsServiceFilter *m_serviceFilter; private: NetConnmanManagerInterface *m_manager; QNetworkSettingsUserAgent *m_agent; + QString m_currentSsid; + QNetworkSettingsService *m_currentWifiConnection; }; QT_END_NAMESPACE diff --git a/src/networksettings/connman/qnetworksettingsservice_p.cpp b/src/networksettings/connman/qnetworksettingsservice_p.cpp index 6538cc1..3ac8a67 100644 --- a/src/networksettings/connman/qnetworksettingsservice_p.cpp +++ b/src/networksettings/connman/qnetworksettingsservice_p.cpp @@ -397,8 +397,14 @@ void QNetworkSettingsServicePrivate::updateProperty(const QString& key, const QV } else if (key == PropertyState) { QString value = qdbus_cast<QString>(val); + QNetworkSettingsState oldState; + oldState.setState(m_state.state()); value >> m_state; emit q->stateChanged(); + if (m_state.state() == QNetworkSettingsState::Ready && m_type.type() == QNetworkSettingsType::Wifi) + emit q->serviceConnected(q); + if (m_state.state() == QNetworkSettingsState::Disconnect && m_type.type() == QNetworkSettingsType::Wifi) + emit q->serviceDisconnected(q); } else if (key == PropertyName) { m_name = qdbus_cast<QString>(val); @@ -408,6 +414,10 @@ void QNetworkSettingsServicePrivate::updateProperty(const QString& key, const QV QString value = qdbus_cast<QString>(val); value >> m_type; emit q->typeChanged(); + if (m_state.state() == QNetworkSettingsState::Ready && m_type.type() == QNetworkSettingsType::Wifi) + emit q->serviceConnected(q); + if (m_state.state() == QNetworkSettingsState::Disconnect && m_type.type() == QNetworkSettingsType::Wifi) + emit q->serviceDisconnected(q); } else if (key == PropertyStrength) { m_wifiConfig.setSignalStrength(val.toInt()); diff --git a/src/networksettings/connman/qnetworksettingsuseragent_p.cpp b/src/networksettings/connman/qnetworksettingsuseragent_p.cpp index dd7fa5f..8cb1bac 100644 --- a/src/networksettings/connman/qnetworksettingsuseragent_p.cpp +++ b/src/networksettings/connman/qnetworksettingsuseragent_p.cpp @@ -61,7 +61,10 @@ void QNetworkSettingsUserAgentPrivate::ReportError(const QDBusObjectPath &path, Q_Q(QNetworkSettingsUserAgent); Q_UNUSED(path); Q_UNUSED(param); - emit q->error(); + if (!m_ssid.isEmpty()) + q->requestNextConnection(); + else + emit q->error(); } void QNetworkSettingsUserAgentPrivate::registerAgent() @@ -74,12 +77,27 @@ QVariantMap QNetworkSettingsUserAgentPrivate::RequestInput(const QDBusObjectPath { Q_Q(QNetworkSettingsUserAgent); Q_UNUSED(path); - Q_UNUSED(params); - msg.setDelayedReply(true); - m_reply = msg.createReply(); - m_pendingReply = true; - emit q->showUserCredentialsInput(); - return QVariantMap(); + QVariant name = params[PropertyName]; + if (!name.isValid()) { + m_ssid.clear(); + } + QVariantMap response; + QVariant passPhrase = params[PropertyPassphrase]; + if (name.isValid() && !m_ssid.isEmpty()) { + response[PropertyName] = m_ssid; + } + if (passPhrase.isValid()) { + if (!m_passphrase.isEmpty()) { + response[PropertyPassphrase] = m_passphrase; + } else { + msg.setDelayedReply(true); + m_reply = msg.createReply(); + m_pendingReply = true; + emit q->showUserCredentialsInput(); + return QVariantMap(); + } + } + return response; } void QNetworkSettingsUserAgentPrivate::setPassphrase(const QString& passphrase) @@ -87,10 +105,26 @@ void QNetworkSettingsUserAgentPrivate::setPassphrase(const QString& passphrase) m_passphrase = passphrase; if (m_pendingReply) { QVariantMap response; + if (!m_ssid.isEmpty()) { + response[PropertyName] = m_ssid; + } response[PropertyPassphrase] = m_passphrase; m_reply << response; m_pendingReply = false; QDBusConnection::systemBus().send(m_reply); } } + +void QNetworkSettingsUserAgentPrivate::setSsidAndPassphrase(const QString &ssid, const QString &passphrase) +{ + m_ssid = ssid; + m_passphrase = passphrase; +} + +void QNetworkSettingsUserAgentPrivate::clearConnectionState() +{ + m_passphrase.clear(); + m_ssid.clear(); +} + QT_END_NAMESPACE diff --git a/src/networksettings/connman/qnetworksettingsuseragent_p.h b/src/networksettings/connman/qnetworksettingsuseragent_p.h index 6433918..80aa164 100644 --- a/src/networksettings/connman/qnetworksettingsuseragent_p.h +++ b/src/networksettings/connman/qnetworksettingsuseragent_p.h @@ -65,6 +65,8 @@ public: QString passphrase() const {return m_passphrase;} void cancel(); void release(); + void setSsidAndPassphrase(const QString &ssid, const QString &passphrase); + void clearConnectionState(); public Q_SLOTS: // Dbus methods void ReportError(const QDBusObjectPath &path, const QString ¶m); QVariantMap RequestInput(const QDBusObjectPath &path, const QVariantMap ¶ms, @@ -75,6 +77,7 @@ private: QDBusMessage m_reply; bool m_pendingReply; QString m_passphrase; + QString m_ssid; }; QT_END_NAMESPACE diff --git a/src/networksettings/qnetworksettingsmanager.cpp b/src/networksettings/qnetworksettingsmanager.cpp index dafc0b1..9938c7c 100644 --- a/src/networksettings/qnetworksettingsmanager.cpp +++ b/src/networksettings/qnetworksettingsmanager.cpp @@ -31,6 +31,7 @@ #include "qnetworksettingsservicemodel.h" #include "qnetworksettingsinterfacemodel.h" #include "qnetworksettingsmanager_p.h" +#include "qnetworksettingsuseragent.h" #include <QStringListModel> QT_BEGIN_NAMESPACE @@ -65,10 +66,61 @@ QNetworkSettingsService* QNetworkSettingsManager::service(const QString& name, c return NULL; } +void QNetworkSettingsManager::connectBySsid(const QString &name, const QString &passphrase) +{ + Q_D(QNetworkSettingsManager); + QNetworkSettingsUserAgent* agent = userAgent(); + if (agent) + agent->setSsidAndPassphrase(name, passphrase); + d->connectBySsid(name); +} + +void QNetworkSettingsManager::clearConnectionState() +{ + Q_D(QNetworkSettingsManager); + d->clearConnectionState(); + QNetworkSettingsUserAgent* agent = userAgent(); + if (agent) + agent->clearConnectionState(); +} + +void QNetworkSettingsManager::tryNextConnection() +{ + Q_D(QNetworkSettingsManager); + d->tryNextConnection(); +} + +void QNetworkSettingsManager::clearCurrentWifiConnection(QNetworkSettingsService* service) +{ + Q_D(QNetworkSettingsManager); + QNetworkSettingsService *currentService = d->currentWifiConnection(); + if (service == currentService) { + d->setCurrentWifiConnection(nullptr); + emit currentWifiConnectionChanged(); + } +} + +void QNetworkSettingsManager::setCurrentWifiConnection(QNetworkSettingsService* service) +{ + Q_D(QNetworkSettingsManager); + QNetworkSettingsService *currentService = d->currentWifiConnection(); + d->setCurrentWifiConnection(service); + if (service != currentService) + emit currentWifiConnectionChanged(); +} + +QNetworkSettingsService* QNetworkSettingsManager::currentWifiConnection() +{ + Q_D(QNetworkSettingsManager); + return d->currentWifiConnection(); +} + void QNetworkSettingsManager::setUserAgent(QNetworkSettingsUserAgent *agent) { Q_D(QNetworkSettingsManager); d->setUserAgent(agent); + connect(agent, &QNetworkSettingsUserAgent::requestNextConnection, + this, &QNetworkSettingsManager::tryNextConnection); } QNetworkSettingsUserAgent* QNetworkSettingsManager::userAgent() diff --git a/src/networksettings/qnetworksettingsmanager.h b/src/networksettings/qnetworksettingsmanager.h index 7e7cfad..fcf7414 100644 --- a/src/networksettings/qnetworksettingsmanager.h +++ b/src/networksettings/qnetworksettingsmanager.h @@ -49,6 +49,7 @@ class Q_DECL_EXPORT QNetworkSettingsManager : public QObject Q_PROPERTY(QNetworkSettingsServiceFilter* services READ services NOTIFY servicesChanged) Q_PROPERTY(QNetworkSettingsInterfaceModel* interfaces READ interfaces NOTIFY interfacesChanged) Q_PROPERTY(QNetworkSettingsUserAgent* userAgent READ userAgent CONSTANT) + Q_PROPERTY(QNetworkSettingsService* currentWifiConnection READ currentWifiConnection NOTIFY currentWifiConnectionChanged) public: explicit QNetworkSettingsManager(QObject* parent = Q_NULLPTR); @@ -58,11 +59,17 @@ public: QNetworkSettingsUserAgent* userAgent(); Q_INVOKABLE QNetworkSettingsService* service(const QString& name, const int type); + Q_INVOKABLE void connectBySsid(const QString& name, const QString &passphrase); + void clearConnectionState(); + void tryNextConnection(); + void clearCurrentWifiConnection(QNetworkSettingsService* service); + void setCurrentWifiConnection(QNetworkSettingsService* service); + QNetworkSettingsService* currentWifiConnection(); Q_SIGNALS: void servicesChanged(); void interfacesChanged(); - + void currentWifiConnectionChanged(); protected: QNetworkSettingsManagerPrivate *d_ptr; diff --git a/src/networksettings/qnetworksettingsservice.cpp b/src/networksettings/qnetworksettingsservice.cpp index 0c142b2..d3ea020 100644 --- a/src/networksettings/qnetworksettingsservice.cpp +++ b/src/networksettings/qnetworksettingsservice.cpp @@ -322,6 +322,12 @@ void QNetworkSettingsService::setupNetworkSettingsProxy() */ void QNetworkSettingsService::connectService() { + emit connectionStateCleared(); + doConnectService(); +} + +void QNetworkSettingsService::doConnectService() +{ Q_D(QNetworkSettingsService); d->connectService(); } diff --git a/src/networksettings/qnetworksettingsservice.h b/src/networksettings/qnetworksettingsservice.h index 72d75ef..d6962dd 100644 --- a/src/networksettings/qnetworksettingsservice.h +++ b/src/networksettings/qnetworksettingsservice.h @@ -74,6 +74,7 @@ public: Q_INVOKABLE void setupNetworkSettingsProxy(); //Wireless config Q_INVOKABLE void connectService(); + void doConnectService(); Q_INVOKABLE void disconnectService(); Q_INVOKABLE void removeService(); Q_SIGNALS: @@ -87,6 +88,9 @@ Q_SIGNALS: void nameserversChanged(); void wirelessChanged(); void showCrendentialInput(); + void connectionStateCleared(); + void serviceConnected(QNetworkSettingsService* service); + void serviceDisconnected(QNetworkSettingsService* service); protected: QNetworkSettingsServicePrivate *d_ptr; diff --git a/src/networksettings/qnetworksettingsservicemodel.cpp b/src/networksettings/qnetworksettingsservicemodel.cpp index 9c0b93d..8e21f8e 100644 --- a/src/networksettings/qnetworksettingsservicemodel.cpp +++ b/src/networksettings/qnetworksettingsservicemodel.cpp @@ -162,6 +162,18 @@ void QNetworkSettingsServiceModel::updated(int row) dataChanged(createIndex(row, 0), createIndex(row, 0)); } +QNetworkSettingsService* QNetworkSettingsServiceModel::getByName(const QString& name) +{ + QNetworkSettingsService* ret = nullptr; + foreach (QNetworkSettingsService* item, m_items) { + if (item->name() == name) { + ret = item; + break; + } + } + return ret; +} + QList<QNetworkSettingsService*> QNetworkSettingsServiceModel::getModel() { return m_items; diff --git a/src/networksettings/qnetworksettingsservicemodel.h b/src/networksettings/qnetworksettingsservicemodel.h index 91f3b6d..8c34e89 100644 --- a/src/networksettings/qnetworksettingsservicemodel.h +++ b/src/networksettings/qnetworksettingsservicemodel.h @@ -52,6 +52,7 @@ public: void remove(int row); bool removeService(const QString &id); void updated(int row); + QNetworkSettingsService* getByName(const QString& name); QList<QNetworkSettingsService*> getModel(); enum Roles { diff --git a/src/networksettings/qnetworksettingsuseragent.cpp b/src/networksettings/qnetworksettingsuseragent.cpp index 8740cf4..cdf1e45 100644 --- a/src/networksettings/qnetworksettingsuseragent.cpp +++ b/src/networksettings/qnetworksettingsuseragent.cpp @@ -55,4 +55,16 @@ QString QNetworkSettingsUserAgent::passphrase() const return d->passphrase(); } +void QNetworkSettingsUserAgent::setSsidAndPassphrase(const QString &ssid, const QString &passphrase) +{ + Q_D(QNetworkSettingsUserAgent); + d->setSsidAndPassphrase(ssid, passphrase); +} + +void QNetworkSettingsUserAgent::clearConnectionState() +{ + Q_D(QNetworkSettingsUserAgent); + d->clearConnectionState(); +} + QT_END_NAMESPACE diff --git a/src/networksettings/qnetworksettingsuseragent.h b/src/networksettings/qnetworksettingsuseragent.h index 2f6cf12..7b76c15 100644 --- a/src/networksettings/qnetworksettingsuseragent.h +++ b/src/networksettings/qnetworksettingsuseragent.h @@ -43,11 +43,14 @@ public: Q_INVOKABLE void setPassphrase(const QString &passphrase); Q_INVOKABLE void cancelInput(); QString passphrase() const; + void setSsidAndPassphrase(const QString &ssid, const QString &passphrase); + void clearConnectionState(); Q_SIGNALS: void showUserCredentialsInput(); void error(); void ready(bool cancel); + void requestNextConnection(); private: QNetworkSettingsUserAgentPrivate *d_ptr; diff --git a/src/settingsui/network/WifiSettings.qml b/src/settingsui/network/WifiSettings.qml index 8bb8ee2..790e043 100644 --- a/src/settingsui/network/WifiSettings.qml +++ b/src/settingsui/network/WifiSettings.qml @@ -212,19 +212,95 @@ Item { } } } + Button { + id: manualConnect + visible: true + text: qsTr("Connect manually") + onClicked: { + visible = false + connectBySsidView.visible = true + } + } + GroupBox { + id: connectBySsidView + title: qsTr("Connect by an SSID") + visible: false + Layout.fillWidth: true + ColumnLayout { + width: parent.width + + RowLayout { + spacing: 10 + width: parent.width + + Label { + text: qsTr("SSID:") + horizontalAlignment: Text.AlignRight + Layout.preferredWidth: root.width * 0.382 + Layout.alignment: Qt.AlignVCenter + } + TextField { + id: ssid + text: "" + inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhPreferLowercase + Layout.alignment: Qt.AlignVCenter + Layout.fillWidth: true + } + } + RowLayout { + spacing: 10 + width: parent.width + Label { + text: qsTr("Passphrase:") + horizontalAlignment: Text.AlignRight + Layout.preferredWidth: root.width * 0.382 + Layout.alignment: Qt.AlignVCenter + } + TextField { + id: passphrase2 + text: "" + echoMode: TextInput.Password + inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase | Qt.ImhPreferLowercase | Qt.ImhSensitiveData + Layout.alignment: Qt.AlignVCenter + Layout.fillWidth: true + } + } + RowLayout { + spacing: 10 + + Button { + text: qsTr("Connect") + onClicked: { + NetworkSettingsManager.connectBySsid(ssid.text, passphrase2.text) + connectBySsidView.visible = false + manualConnect.visible = true + } + } + Button { + text: qsTr("Cancel") + onClicked: { + connectBySsidView.visible = false + manualConnect.visible = true + } + } + } + } + } ColumnLayout { spacing: parent.spacing width: parent.width visible: selectedInterface.state === NetworkSettingsState.Online || selectedInterface.state === NetworkSettingsState.Ready Label { - text: qsTr("IP Address: ") + NetworkSettingsManager.services.itemFromRow(networkSelection.currentIndex).ipv4.address + text: qsTr("IP Address: ") + (NetworkSettingsManager.currentWifiConnection ? NetworkSettingsManager.currentWifiConnection.ipv4.address : "") } Button { id: disconnect text: qsTr("Disconnect") onClicked: { - NetworkSettingsManager.services.itemFromRow(networkSelection.currentIndex).disconnectService(); + if (NetworkSettingsManager.currentWifiConnection) { + NetworkSettingsManager.currentWifiConnection.disconnectService(); + } networkSelection.currentIndex = -1; root.connecting = false } |