diff options
Diffstat (limited to 'src/imports/wifi')
-rw-r--r-- | src/imports/wifi/pluginmain.cpp | 31 | ||||
-rw-r--r-- | src/imports/wifi/qwifimanager.cpp | 339 | ||||
-rw-r--r-- | src/imports/wifi/qwifimanager.h | 20 | ||||
-rw-r--r-- | src/imports/wifi/qwifinetwork.cpp | 75 | ||||
-rw-r--r-- | src/imports/wifi/qwifinetwork.h | 8 | ||||
-rw-r--r-- | src/imports/wifi/qwifinetworklistmodel.cpp (renamed from src/imports/wifi/qwifinetworklist.cpp) | 93 | ||||
-rw-r--r-- | src/imports/wifi/qwifinetworklistmodel.h (renamed from src/imports/wifi/qwifinetworklist.h) | 13 | ||||
-rw-r--r-- | src/imports/wifi/wifi.pro | 4 |
8 files changed, 478 insertions, 105 deletions
diff --git a/src/imports/wifi/pluginmain.cpp b/src/imports/wifi/pluginmain.cpp index 3c560f9..fdf07e9 100644 --- a/src/imports/wifi/pluginmain.cpp +++ b/src/imports/wifi/pluginmain.cpp @@ -25,6 +25,35 @@ #include <hardware_legacy/wifi.h> +/*! + \qmltype Interface + \inqmlmodule Qt.labs.wifi + \ingroup wifi-qmltypes + \brief The Interface element provides the module API. + + This element cannot be directly created. It can only be accessed via a namespace import. + + \code + import Qt.labs.wifi 0.1 + import Qt.labs.wifi 0.1 as Wifi + + Component.onCompleted: { + if (Wifi.Interface.wifiSupported()) { + var component = Qt.createComponent("WifiMenu.qml") + } else { + print("WiFi functionality not available on this device.") + } + } + \endcode +*/ + +/*! + \qmlmethod bool Interface::wifiSupported() + + Returns true if the device is WiFi capable (provides a WiFi driver), otherwise returns false. +*/ + + class QWifiGlobal : public QObject { Q_OBJECT @@ -68,7 +97,7 @@ public: Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.wifi")); qmlRegisterType<QWifiManager>(uri, 0, 1, "WifiManager"); - qmlRegisterType<QWifiNetworkList>(); + qmlRegisterType<QWifiNetworkListModel>(); qmlRegisterSingletonType<QWifiGlobal>(uri, 0, 1, "Interface", global_object_wifi); } }; diff --git a/src/imports/wifi/qwifimanager.cpp b/src/imports/wifi/qwifimanager.cpp index 7d6683b..af6f5d3 100644 --- a/src/imports/wifi/qwifimanager.cpp +++ b/src/imports/wifi/qwifimanager.cpp @@ -32,6 +32,7 @@ static bool QT_WIFI_DEBUG = !qgetenv("QT_WIFI_DEBUG").isEmpty(); const QEvent::Type WIFI_SCAN_RESULTS = (QEvent::Type) (QEvent::User + 2001); const QEvent::Type WIFI_CONNECTED = (QEvent::Type) (QEvent::User + 2002); +const QEvent::Type WIFI_HANDSHAKE_FAILED = (QEvent::Type) (QEvent::User + 2003); /* * This function is borrowed from /system/core/libnetutils/dhcp_utils.c @@ -89,28 +90,30 @@ public: } void run() { - if (QT_WIFI_DEBUG) qDebug("EventReceiver thread is running"); + if (QT_WIFI_DEBUG) qDebug("WiFi event thread is running"); + QWifiManagerEvent *event = 0; char buffer[2048]; while (1) { int size = wifi_wait_for_event(m_if.constData(), buffer, sizeof(buffer) - 1); if (size > 0) { buffer[size] = 0; - - if (QT_WIFI_DEBUG) qDebug("EVENT: %s", buffer); - - char *event = &buffer[11]; - if (strstr(event, "SCAN-RESULTS")) { - if (m_manager->exitingEventThread()) + event = 0; + if (strstr(buffer, "SCAN-RESULTS")) { + if (m_manager->exitingEventThread()) { + if (QT_WIFI_DEBUG) qDebug() << "Exiting WiFi event thread"; return; - QWifiManagerEvent *e = new QWifiManagerEvent(WIFI_SCAN_RESULTS); - QCoreApplication::postEvent(m_manager, e); - } else if (strstr(event, "CONNECTED")) { - QWifiManagerEvent *e = new QWifiManagerEvent(WIFI_CONNECTED); - QCoreApplication::postEvent(m_manager, e); - } else if (strstr(event, "TERMINATING")) { + } + event = new QWifiManagerEvent(WIFI_SCAN_RESULTS); + } else if (strstr(buffer, "CONNECTED")) { + event = new QWifiManagerEvent(WIFI_CONNECTED); + } else if (strstr(buffer, "Handshake failed")) { + event = new QWifiManagerEvent(WIFI_HANDSHAKE_FAILED); + } else if (strstr(buffer, "TERMINATING")) { // stop monitoring for events when supplicant is terminating return; } + if (event) + QCoreApplication::postEvent(m_manager, event); } } } @@ -119,13 +122,236 @@ public: QByteArray m_if; }; +/*! + \qmlmodule Qt.labs.wifi 0.1 + \title WiFi Module + \ingroup qtee-qmlmodules + \brief Controlling wireless network interfaces. + + Provides QML types for controlling and accessing information about wireless network interfaces. + + The import command for adding these QML types is: + + \code + import Qt.labs.wifi 0.1 + \endcode + + If the module is imported into a namespace, some additional methods become available through the + \l Interface element. + + \code + import Qt.labs.wifi 0.1 as Wifi + \endcode + + \section1 QML Types +*/ + +/*! + + \qmltype WifiManager + \inqmlmodule Qt.labs.wifi + \ingroup wifi-qmltypes + \brief Provides information about the WiFi backend and available networks. + + This element is the main interface to the WiFi functionality. + + */ + +/*! + \qmlproperty enumeration WifiManager::networkState + + This property holds the current state of the network connection. + + \list + \li \e WifiManager.Disconnected - Not connected to any network + \li \e WifiManager.Authenticating - Verifying password with the network provider + \li \e WifiManager.HandshakeFailed - Incorrect password provided + \li \e WifiManager.ObtainingIPAddress - Requesting IP address from DHCP server + \li \e WifiManager.DhcpRequestFailed - Could not retrieve IP address + \li \e WifiManager.Connected - Ready to process network requests + \endlist +*/ + +/*! + \qmlproperty bool WifiManager::backendReady + + This property holds whether or not the backend has been successfully initialized. + + \code + WifiManager { + id: wifiManager + scanning: backendReady + } + + Button { + id: wifiOnOffButton + text: (wifiManager.backendReady) ? "Switch Off" : "Switch On" + onClicked: { + if (wifiManager.backendReady) { + wifiManager.stop() + } else { + wifiManager.start() + } + } + } + \endcode +*/ + +/*! + \qmlproperty bool WifiManager::scanning + + This property holds whether or not the backend is scanning for WiFi networks. To + preserve battery energy, stop scanning for networks once you are done with configuring a network. + + Before starting to scan for networks, you need to initialize the WiFi backend. + + \sa start +*/ + +/*! + \qmlproperty string WifiManager::connectedSSID + + This property holds the network name. +*/ + +/*! + \qmlproperty WifiNetworkListModel WifiManager::networks + + This property holds a list of networks that can be sensed by a device. Use the returned + model as data model in ListView, model is updated every 5 seconds. + + WifiNetworkListModel is a simple data model consisting of WifiNetwork objects, accessed with + the "network" data role. Instances of WifiNetwork cannot be created directly from the QML system. + + \code + WifiManager { + id: wifiManager + scanning: backendReady + Component.onCompleted: start() + } + + Component { + id: listDelegate + Rectangle { + id: delegateBackground + height: 60 + width: parent.width + color: "#5C5C5C" + border.color: "black" + border.width: 1 + + Text { + id: ssidLabel + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: 10 + font.pixelSize: 20 + font.bold: true + color: "#E6E6E6" + text: network.ssid + } + + Rectangle { + width: Math.max(100 + network.signalStrength, 0) / 100 * parent.width; + height: 20 + radius: 10 + antialiasing: true + anchors.margins: 20 + anchors.right: parent.right + anchors.top: parent.top + color: "#BF8888" + border.color: "#212126" + } + } + } + + + ListView { + id: networkView + anchors.fill: parent + model: wifiManager.networks + delegate: listDelegate + } + \endcode + +*/ + +/*! + \qmlmethod void WifiManager::start() + + Start an initialization of the WiFi backend. + + \sa stop + */ + +/*! + \qmlmethod void WifiManager::stop() + + Stop the WiFi backend and shut down all network functionality. + + \sa start + */ + +/*! + \qmlmethod void WifiManager::connect(WifiNetwork network, const string passphrase) + + Connect to network \a network and use passphrase \a passphrase for authentication. + + \sa disconnect, networkState + */ + +/*! + \qmlmethod void WifiManager::disconnect() + + Disconnect from currently connected network connection. + + \sa connect, networkState + */ + +/*! + \qmlsignal void WifiManager::scanningChanged(bool scanning) + + This signal is emitted when device starts or stops to scan for available wifi networks. + + \sa scanning + +*/ + +/*! + \qmlsignal void WifiManager::networkStateChanged(WifiNetwork network) + + This signal is emitted whenever changes in a network state occur. Network \a network is the + the currently active network connection. + + \sa networkState +*/ + +/*! + \qmlsignal void WifiManager::backendReadyChanged() + + This signal is emitted when backend has been successfully initialized or shut down. + + \sa start, stop +*/ + +/*! + \qmlsignal void WifiManager::connectedSSIDChanged(string ssid) + + This signal is emitted when the device has connected to or disconnected from a network. + \a ssid contains the name of the connected network, or an empty string if the network was disconnected. + + \sa connect, disconnect +*/ + QWifiManager::QWifiManager() - : m_networks(this) + : m_networkListModel(this) , m_eventThread(0) , m_scanTimer(0) , m_scanning(false) , m_daemonClientSocket(0) , m_exitingEventThread(false) + , m_startingUp(true) + , m_network(0) { char interface[PROPERTY_VALUE_MAX]; property_get(WIFI_INTERFACE, interface, NULL); @@ -143,15 +369,15 @@ QWifiManager::QWifiManager() qWarning() << "QWifiManager: failed to connect to qconnectivity socket"; } // check if backend has already been initialized - char backend_status[PROPERTY_VALUE_MAX]; - if (property_get(QT_WIFI_BACKEND, backend_status, NULL)) { - if (strcmp(backend_status, "running") == 0) { + char backendStatus[PROPERTY_VALUE_MAX]; + if (property_get(QT_WIFI_BACKEND, backendStatus, NULL)) { + if (strcmp(backendStatus, "running") == 0) { // let it re-connect, in most cases this will see that everything is working properly // and will do nothing. Special case is when process has crashed or was killed by a system // signal in previous execution, which results in broken connection to a supplicant, // connectToBackend will fix it.. connectToBackend(); - } else if (strcmp(backend_status, "stopped") == 0) { + } else if (strcmp(backendStatus, "stopped") == 0) { // same here, cleans up the state disconnectFromBackend(); } @@ -160,12 +386,7 @@ QWifiManager::QWifiManager() QWifiManager::~QWifiManager() { - // exit event thread if it is running - if (m_eventThread->isRunning()) { - m_exitingEventThread = true; - call("SCAN"); - m_eventThread->wait(); - } + exitEventThread(); delete m_eventThread; delete m_daemonClientSocket; } @@ -177,14 +398,12 @@ void QWifiManager::handleDhcpReply() receivedMessage = m_daemonClientSocket->readLine(m_daemonClientSocket->bytesAvailable()); if (QT_WIFI_DEBUG) qDebug() << "QWifiManager: reply from qconnectivity: " << receivedMessage; if (receivedMessage == "success") { - m_state = Connected; - emit networkStateChanged(); + updateNetworkState(Connected); emit connectedSSIDChanged(m_connectedSSID); // Store settings of a working wifi connection call("SAVE_CONFIG"); } else if (receivedMessage == "failed") { - m_state = DhcpRequestFailed; - emit networkStateChanged(); + updateNetworkState(DhcpRequestFailed); } else { qWarning() << "QWifiManager: unknown message: " << receivedMessage; } @@ -210,12 +429,16 @@ void QWifiManager::connectedToDaemon() void QWifiManager::start() { if (QT_WIFI_DEBUG) qDebug("QWifiManager: connecting to the backend"); + if (m_backendReady) + return; connectToBackend(); } void QWifiManager::stop() { if (QT_WIFI_DEBUG) qDebug("QWifiManager: shutting down"); + if (!m_backendReady) + return; disconnectFromBackend(); } @@ -244,15 +467,12 @@ void QWifiManager::connectToBackend() if (QT_WIFI_DEBUG) qDebug("QWifiManager: started successfully"); m_exitingEventThread = false; m_eventThread->start(); - handleConnected(); + call("SCAN"); } void QWifiManager::disconnectFromBackend() { - m_exitingEventThread = true; - call("SCAN"); - m_eventThread->wait(); - + exitEventThread(); if (wifi_stop_supplicant(0) < 0) qWarning("QWifiManager: failed to stop supplicant"); wifi_close_supplicant_connection(m_interface.constData()); @@ -261,9 +481,18 @@ void QWifiManager::disconnectFromBackend() emit backendReadyChanged(); } +void QWifiManager::exitEventThread() +{ + if (m_eventThread->isRunning()) { + m_exitingEventThread = true; + call("SCAN"); + m_eventThread->wait(); + } +} + void QWifiManager::setScanning(bool scanning) { - if (m_scanning == scanning) + if (!m_backendReady || m_scanning == scanning) return; m_scanning = scanning; @@ -299,15 +528,27 @@ bool QWifiManager::checkedCall(const char *command) const return call(command).trimmed().toUpper() == "OK"; } +void QWifiManager::updateNetworkState(NetworkState state) +{ + m_state = state; + if (m_network) + emit networkStateChanged(m_network); +} + bool QWifiManager::event(QEvent *e) { switch ((int) e->type()) { case WIFI_SCAN_RESULTS: - m_networks.parseScanResults(call("SCAN_RESULTS")); + m_networkListModel.parseScanResults(call("SCAN_RESULTS")); + if (m_startingUp) + handleConnected(); return true; case WIFI_CONNECTED: handleConnected(); break; + case WIFI_HANDSHAKE_FAILED: + updateNetworkState(HandshakeFailed); + break; case QEvent::Timer: { int tid = static_cast<QTimerEvent *>(e)->timerId(); if (tid == m_scanTimer) { @@ -323,10 +564,13 @@ bool QWifiManager::event(QEvent *e) void QWifiManager::connect(QWifiNetwork *network, const QString &passphrase) { + m_network = network; if (network->ssid() == m_connectedSSID) { - if (QT_WIFI_DEBUG) qDebug("QWifiManager::connect(), already connected to %s", network->ssid().constData()); + if (QT_WIFI_DEBUG) + qDebug("QWifiManager::connect(), already connected to %s", network->ssid().constData()); return; } + updateNetworkState(Authenticating); call("DISABLE_NETWORK all"); if (!m_connectedSSID.isEmpty()) { @@ -334,16 +578,13 @@ void QWifiManager::connect(QWifiNetwork *network, const QString &passphrase) emit connectedSSIDChanged(m_connectedSSID); } - m_state = ObtainingIPAddress; - emit networkStateChanged(); bool networkKnown = false; QByteArray id; QByteArray listResult = call("LIST_NETWORKS"); QList<QByteArray> lines = listResult.split('\n'); foreach (const QByteArray &line, lines) { if (line.contains(network->ssid())) { - int networkId = line.toInt(); - id = QByteArray::number(networkId); + id = line.split('\t').at(0); networkKnown = true; break; } @@ -351,7 +592,7 @@ void QWifiManager::connect(QWifiNetwork *network, const QString &passphrase) if (!networkKnown) { bool ok; - QByteArray id = call("ADD_NETWORK").trimmed(); + id = call("ADD_NETWORK").trimmed(); id.toInt(&ok); if (!ok) { qWarning("QWifiManager::connect(), failed to add network"); @@ -394,9 +635,8 @@ void QWifiManager::disconnect() call("DISCONNECT"); QByteArray req = m_interface; sendDhcpRequest(req.append(" disconnect")); - m_state = Disconnected; m_connectedSSID.clear(); - emit networkStateChanged(); + updateNetworkState(Disconnected); emit connectedSSIDChanged(m_connectedSSID); } @@ -404,7 +644,7 @@ void QWifiManager::handleConnected() { QList<QByteArray> lists = call("LIST_NETWORKS").split('\n'); QByteArray connectedNetwork; - for (int i=1; i<lists.size(); ++i) { + for (int i = 1; i < lists.size(); ++i) { if (lists.at(i).toUpper().contains("[CURRENT]")) { connectedNetwork = lists.at(i); break; @@ -413,8 +653,6 @@ void QWifiManager::handleConnected() if (connectedNetwork.isEmpty()) { if (QT_WIFI_DEBUG) qDebug("QWifiManager::handleConnected: not connected to a network..."); - m_state = Disconnected; - emit networkStateChanged(); return; } @@ -423,6 +661,15 @@ void QWifiManager::handleConnected() QList<QByteArray> info = connectedNetwork.split('\t'); m_connectedSSID = info.at(1); + if (m_startingUp) { + m_startingUp = false; + if (!m_network) { + int pos = 0; // unused + m_network = m_networkListModel.networkForSSID(info.at(1), &pos); + } + } + + updateNetworkState(ObtainingIPAddress); QByteArray req = m_interface; sendDhcpRequest(req.append(" connect")); } diff --git a/src/imports/wifi/qwifimanager.h b/src/imports/wifi/qwifimanager.h index 432f411..162190e 100644 --- a/src/imports/wifi/qwifimanager.h +++ b/src/imports/wifi/qwifimanager.h @@ -25,7 +25,7 @@ #include <cutils/properties.h> -#include "qwifinetworklist.h" +#include "qwifinetworklistmodel.h" class QWifiManagerEventThread; @@ -37,11 +37,13 @@ class QWifiManager : public QObject Q_PROPERTY(bool backendReady READ isbackendReady NOTIFY backendReadyChanged) Q_PROPERTY(bool scanning READ scanning WRITE setScanning NOTIFY scanningChanged) Q_PROPERTY(QString connectedSSID READ connectedSSID NOTIFY connectedSSIDChanged) - Q_PROPERTY(QWifiNetworkList *networks READ networks CONSTANT) + Q_PROPERTY(QWifiNetworkListModel *networks READ networks CONSTANT) public: enum NetworkState { Disconnected, + Authenticating, + HandshakeFailed, ObtainingIPAddress, DhcpRequestFailed, Connected @@ -50,7 +52,7 @@ public: QWifiManager(); ~QWifiManager(); - QWifiNetworkList *networks() { return &m_networks; } + QWifiNetworkListModel *networks() { return &m_networkListModel; } QString connectedSSID() const { return m_connectedSSID; } bool scanning() const { return m_scanning; } void setScanning(bool scanning); @@ -65,10 +67,10 @@ public slots: void disconnect(); signals: - void scanningChanged(bool arg); - void networkStateChanged(); + void scanningChanged(bool scanning); + void networkStateChanged(QWifiNetwork *network); void backendReadyChanged(); - void connectedSSIDChanged(const QString &); + void connectedSSIDChanged(const QString &ssid); protected: bool event(QEvent *); @@ -76,8 +78,10 @@ protected: void handleConnected(); void connectToBackend(); void disconnectFromBackend(); + void exitEventThread(); QByteArray call(const char *command) const; bool checkedCall(const char *command) const; + void updateNetworkState(NetworkState state); protected slots: void connectedToDaemon(); @@ -87,7 +91,7 @@ private: friend class QWifiManagerEventThread; QString m_connectedSSID; - QWifiNetworkList m_networks; + QWifiNetworkListModel m_networkListModel; QWifiManagerEventThread *m_eventThread; int m_scanTimer; @@ -99,6 +103,8 @@ private: QLocalSocket *m_daemonClientSocket; QByteArray m_request; bool m_exitingEventThread; + bool m_startingUp; + QWifiNetwork *m_network; }; #endif // QWIFIMANAGER_H diff --git a/src/imports/wifi/qwifinetwork.cpp b/src/imports/wifi/qwifinetwork.cpp index a159e59..d4c20ef 100644 --- a/src/imports/wifi/qwifinetwork.cpp +++ b/src/imports/wifi/qwifinetwork.cpp @@ -18,7 +18,73 @@ ****************************************************************************/ #include "qwifinetwork.h" -QWifiNetwork::QWifiNetwork() +/*! + \qmltype WifiNetwork + \inqmlmodule Qt.labs.wifi + \ingroup wifi-qmltypes + \brief Represents a single WiFi network access point. + + Instances of WifiNetwork cannot be created directly from the QML system, use + WifiManager::networks. +*/ + +/*! + \qmlproperty string WifiNetwork::bssid + + This property holds basic service set identification of a network, used to uniquely + identify BSS. + +*/ + +/*! + \qmlproperty string WifiNetwork::ssid + + This property holds a network name. The SSID is the informal (human) name of BSS. +*/ + +/*! + \qmlproperty int WifiNetwork::signalStrength + + This property holds the current strength of a WiFi signal, measured in dBm. New readings are + taken every 5 seconds. + + \sa signalStrengthChanged +*/ + +/*! + \qmlproperty bool WifiNetwork::supportsWPA + + This property holds whether network access point supports WPA security protocol. +*/ + +/*! + \qmlproperty bool WifiNetwork::supportsWPA2 + + This property holds whether network access point supports WPA2 security protocol. +*/ + +/*! + \qmlproperty bool WifiNetwork::supportsWEP + + This property holds whether network access point supports WEP security protocol. +*/ + +/*! + \qmlproperty bool WifiNetwork::supportsWPS + + This property holds whether network access point supports WPS security protocol. +*/ + +/*! + \qmlsignal void WifiNetwork::signalStrengthChanged(int strength) + + This signal is emitted whenever signal strength has changed comparing the the + previous reading, the new signal's strength is \a strength. + +*/ + +QWifiNetwork::QWifiNetwork() : + m_outOfRange(false) { } @@ -29,3 +95,10 @@ void QWifiNetwork::setSignalStrength(int strength) m_signalStrength = strength; emit signalStrengthChanged(m_signalStrength); } + +void QWifiNetwork::setOutOfRange(bool outOfRange) +{ + if (m_outOfRange == outOfRange) + return; + m_outOfRange = outOfRange; +} diff --git a/src/imports/wifi/qwifinetwork.h b/src/imports/wifi/qwifinetwork.h index 780fc87..5ecc6a3 100644 --- a/src/imports/wifi/qwifinetwork.h +++ b/src/imports/wifi/qwifinetwork.h @@ -22,8 +22,6 @@ #include <QtCore/QByteArray> #include <QtCore/QObject> -class QWifiManager; - class QWifiNetwork : public QObject { Q_OBJECT @@ -48,6 +46,9 @@ public: int signalStrength() const { return m_signalStrength; } void setSignalStrength(int strength); + void setOutOfRange(bool outOfRange); + bool outOfRange() { return m_outOfRange; } + QByteArray flags() const { return m_flags; } void setFlags(const QByteArray &f) { m_flags = f; } bool supportsWPA2() const { return m_flags.contains("WPA2"); } @@ -56,7 +57,7 @@ public: bool supportsWPS() const { return m_flags.contains("WPS"); } signals: - void signalStrengthChanged(int arg); + void signalStrengthChanged(int strength); private: QByteArray m_bssid; @@ -64,6 +65,7 @@ private: int m_signalStrength; QByteArray m_flags; + bool m_outOfRange; }; #endif // QWIFINETWORK_H diff --git a/src/imports/wifi/qwifinetworklist.cpp b/src/imports/wifi/qwifinetworklistmodel.cpp index 60fdc53..4fbf25f 100644 --- a/src/imports/wifi/qwifinetworklist.cpp +++ b/src/imports/wifi/qwifinetworklistmodel.cpp @@ -16,55 +16,47 @@ ** the contact form at http://qt.digia.com/ ** ****************************************************************************/ -#include "qwifinetworklist.h" +#include "qwifinetworklistmodel.h" #include <QtCore> -const int ID_BSSID = (Qt::ItemDataRole) (Qt::UserRole + 1); -const int ID_SSID = (Qt::ItemDataRole) (Qt::UserRole + 2); -const int ID_SIGNAL = (Qt::ItemDataRole) (Qt::UserRole + 3); -const int ID_WPA2 = (Qt::ItemDataRole) (Qt::UserRole + 4); -const int ID_WPA = (Qt::ItemDataRole) (Qt::UserRole + 5); -const int ID_NETWORK = (Qt::ItemDataRole) (Qt::UserRole + 6); +const int ID_NETWORK = (Qt::ItemDataRole) (Qt::UserRole + 1); -QWifiNetworkList::QWifiNetworkList(QWifiManager *manager) +QWifiNetworkListModel::QWifiNetworkListModel(QWifiManager *manager) : m_manager(manager) { } -QHash<int, QByteArray> QWifiNetworkList::roleNames() const +QWifiNetworkListModel::~QWifiNetworkListModel() +{ + qDeleteAll(m_networks); + qDeleteAll(m_outOfRangeNetworks); + m_networks.clear(); + m_outOfRangeNetworks.clear(); +} + +QHash<int, QByteArray> QWifiNetworkListModel::roleNames() const { QHash<int, QByteArray> names; - names.insert(ID_BSSID, "bssid"); - names.insert(ID_SSID, "ssid"); - names.insert(ID_SIGNAL, "strength"); - names.insert(ID_WPA2, "wpa2"); - names.insert(ID_WPA, "wpa"); names.insert(ID_NETWORK, "network"); return names; } -QVariant QWifiNetworkList::data(const QModelIndex &index, int role) const +QVariant QWifiNetworkListModel::data(const QModelIndex &index, int role) const { QWifiNetwork *n = m_networks.at(index.row()); - switch (role) { - case ID_BSSID: return n->bssid(); - case ID_SSID: return n->ssid(); - case ID_SIGNAL: return n->signalStrength(); - case ID_WPA2: return n->supportsWPA2(); - case ID_WPA: return n->supportsWPA(); - case ID_NETWORK: return QVariant::fromValue((QObject *) n); + case ID_NETWORK: return QVariant::fromValue((QObject *) n); } - qWarning("QWifiNetworkList::data(), undefined role: %d\n", role); + qWarning("QWifiNetworkListModel::data(), undefined role: %d\n", role); return QVariant(); } -QWifiNetwork *QWifiNetworkList::networkForSSID(const QByteArray &ssid, int *pos) +QWifiNetwork *QWifiNetworkListModel::networkForSSID(const QByteArray &ssid, int *pos) { - for (int i=0; i<m_networks.size(); ++i) { + for (int i = 0; i < m_networks.size(); ++i) { if (m_networks.at(i)->ssid() == ssid) { if (pos) *pos = i; @@ -74,21 +66,32 @@ QWifiNetwork *QWifiNetworkList::networkForSSID(const QByteArray &ssid, int *pos) return 0; } -void QWifiNetworkList::parseScanResults(const QByteArray &results) +QWifiNetwork *QWifiNetworkListModel::outOfRangeListContains(const QByteArray &ssid) { - QList<QByteArray> lines = results.split('\n'); + for (int i = 0; i < m_outOfRangeNetworks.length(); ++i) + if (m_outOfRangeNetworks.at(i)->ssid() == ssid) + return m_outOfRangeNetworks.takeAt(i); + return 0; +} +void QWifiNetworkListModel::parseScanResults(const QByteArray &results) +{ + QList<QByteArray> lines = results.split('\n'); QSet<QByteArray> sensibleNetworks; - for (int i=1; i<lines.size(); ++i) { + + for (int i = 1; i < lines.size(); ++i) { QList<QByteArray> info = lines.at(i).split('\t'); if (info.size() < 5 || info.at(4).isEmpty() || info.at(0).isEmpty()) continue; int pos = 0; - if (!sensibleNetworks.contains(info.at(4))) - sensibleNetworks.insert(info.at(4)); - QWifiNetwork *existingNetwork = networkForSSID(info.at(4), &pos); - if (!existingNetwork) { + sensibleNetworks.insert(info.at(4)); + QWifiNetwork *knownNetwork = networkForSSID(info.at(4), &pos); + if (!knownNetwork) + knownNetwork = outOfRangeListContains(info.at(4)); + + if (!knownNetwork) { QWifiNetwork *network = new QWifiNetwork(); + network->setOutOfRange(false); network->setBssid(info.at(0)); network->setFlags(info.at(3)); // signal strength is in dBm @@ -98,13 +101,23 @@ void QWifiNetworkList::parseScanResults(const QByteArray &results) m_networks << network; endInsertRows(); } else { + if (knownNetwork->outOfRange()) { + // known network has come back into a range + knownNetwork->setOutOfRange(false); + beginInsertRows(QModelIndex(), m_networks.size(), m_networks.size()); + m_networks << knownNetwork; + endInsertRows(); + pos = m_networks.length() - 1; + } // ssids are the same, compare bssids.. - if (existingNetwork->bssid() == info.at(0)) { + if (knownNetwork->bssid() == info.at(0)) { // same access point, simply update the signal strength - existingNetwork->setSignalStrength(info.at(2).toInt()); + knownNetwork->setSignalStrength(info.at(2).toInt()); + knownNetwork->setOutOfRange(false); dataChanged(createIndex(pos, 0), createIndex(pos, 0)); - } else if (existingNetwork->signalStrength() < info.at(2).toInt()) { + } else if (knownNetwork->signalStrength() < info.at(2).toInt()) { // replace with a stronger access point within the same network + m_networks.at(pos)->setOutOfRange(false); m_networks.at(pos)->setBssid(info.at(0)); m_networks.at(pos)->setFlags(info.at(3)); m_networks.at(pos)->setSignalStrength(info.at(2).toInt()); @@ -113,16 +126,16 @@ void QWifiNetworkList::parseScanResults(const QByteArray &results) } } } - // remove networks that have gone out of range - for (int i = 0; i < m_networks.size(); ++i) { + // remove out-of-range networks from the data model + for (int i = 0; i < m_networks.size();) { if (!sensibleNetworks.contains(m_networks.at(i)->ssid())) { beginRemoveRows(QModelIndex(), i, i); - delete m_networks.takeAt(i); + QWifiNetwork *n = m_networks.takeAt(i); + n->setOutOfRange(true); + m_outOfRangeNetworks.append(n); endRemoveRows(); } else { ++i; } } } - - diff --git a/src/imports/wifi/qwifinetworklist.h b/src/imports/wifi/qwifinetworklistmodel.h index 84e78fc..91ca231 100644 --- a/src/imports/wifi/qwifinetworklist.h +++ b/src/imports/wifi/qwifinetworklistmodel.h @@ -16,8 +16,8 @@ ** the contact form at http://qt.digia.com/ ** ****************************************************************************/ -#ifndef QWIFINETWORKLIST_H -#define QWIFINETWORKLIST_H +#ifndef QWIFINETWORKLISTMODEL_H +#define QWIFINETWORKLISTMODEL_H #include <QtCore/QAbstractListModel> #include <QtCore/QList> @@ -26,17 +26,19 @@ class QWifiManager; -class QWifiNetworkList : public QAbstractListModel +class QWifiNetworkListModel : public QAbstractListModel { Q_OBJECT public: - QWifiNetworkList(QWifiManager *manager); + QWifiNetworkListModel(QWifiManager *manager); + ~QWifiNetworkListModel(); void parseScanResults(const QByteArray &data); QWifiNetwork *networkForSSID(const QByteArray &ssid, int *pos); + QWifiNetwork *outOfRangeListContains(const QByteArray &ssid); int rowCount(const QModelIndex &) const { return m_networks.size(); } QVariant data(const QModelIndex &index, int role) const; @@ -46,6 +48,7 @@ public: private: QWifiManager *m_manager; QList<QWifiNetwork *> m_networks; + QList<QWifiNetwork *> m_outOfRangeNetworks; }; -#endif // QWIFINETWORKLIST_H +#endif // QWIFINETWORKLISTMODEL_H diff --git a/src/imports/wifi/wifi.pro b/src/imports/wifi/wifi.pro index 0231479..b920978 100644 --- a/src/imports/wifi/wifi.pro +++ b/src/imports/wifi/wifi.pro @@ -8,12 +8,12 @@ SOURCES += \ pluginmain.cpp \ qwifimanager.cpp \ qwifinetwork.cpp \ - qwifinetworklist.cpp + qwifinetworklistmodel.cpp HEADERS += \ qwifimanager.h \ qwifinetwork.h \ - qwifinetworklist.h + qwifinetworklistmodel.h LIBS += -lhardware_legacy -lcutils |