diff --git a/connd/com.jollamobile.Connectiond.xml b/connd/com.jollamobile.Connectiond.xml index 82dd574..b356e57 100644 --- a/connd/com.jollamobile.Connectiond.xml +++ b/connd/com.jollamobile.Connectiond.xml @@ -28,6 +28,9 @@ + + + @@ -39,5 +42,11 @@ + + + + + + diff --git a/connd/qconnectionagent.cpp b/connd/qconnectionagent.cpp index 898fc0c..af00be2 100644 --- a/connd/qconnectionagent.cpp +++ b/connd/qconnectionagent.cpp @@ -234,18 +234,35 @@ void QConnectionAgent::serviceStateChanged(const QString &state) if (state == "disconnect") { ua->sendConnectReply("Clear"); } -// if (state == "failure") { + if (state == "failure") { + if (delayedTethering && service->type() == "cellular" && tetheringWifiTech->tethering()) { + Q_EMIT tetheringFinished(false); + } // serviceInProgress.clear(); // // service->requestDisconnect(); -// } + } + if (delayedTethering && service->type() == "wifi" && state == "association") { + service->requestDisconnect(); + } if (state == "online") { Q_EMIT connectionState(state, service->type()); - } + if (service->type() == "wifi" && delayedTethering) { + netman->getTechnology(service->type())->setTethering(true); + } + if (service->type() == "cellular" && delayedTethering) { + if (!tetheringWifiTech->tethering()) { + tetheringWifiTech->setTethering(true); + } + } + } //auto migrate if (state == "idle") { - } else { + if (service->type() == "wifi" && delayedTethering) { + netman->getTechnology(service->type())->setTethering(true); + } + } else { updateServicesMap(); } currentNetworkState = state; @@ -358,10 +375,26 @@ void QConnectionAgent::networkStateChanged(const QString &state) if ((state == "online" && netman->defaultRoute()->type() == "cellular") || (state == "idle")) { + + if (tetheringWifiTech && tetheringWifiTech->powered() + && !tetheringWifiTech->tethering()) + tetheringWifiTech->scan(); // on gprs, scan wifi every scanTimeoutInterval minutes if (scanTimeoutInterval != 0) scanTimer->start(scanTimeoutInterval * 60 * 1000); } + + if (delayedTethering && state == "online") { + + if (tetheringWifiTech->tethering()) { + if (netman->defaultRoute()->type() == "cellular") { + delayedTethering = false; + Q_EMIT tetheringFinished(true); + } + } else { + tetheringWifiTech->setTethering(true); + } + } } bool QConnectionAgent::askRoaming() const @@ -457,10 +490,13 @@ void QConnectionAgent::technologyPowerChanged(bool powered) { NetworkTechnology *tech = static_cast(sender()); qDebug() << tech->name() << powered; - if (tech->type() == "wifi") { - if (powered) { - tetheringWifiTech->scan(); - } else { + + if (netman && tech->type() == "wifi" && powered && delayedTethering) { + tech->setTethering(true); + } + + if (!delayedTethering && tech->type() == "wifi") { + if (!powered) { removeAllTypes("wifi"); //dont wait for connman, he's too slow at this QString bestService = findBestConnectableService(); if (!bestService.isEmpty()) { @@ -473,7 +509,8 @@ void QConnectionAgent::technologyPowerChanged(bool powered) void QConnectionAgent::techChanged() { - qDebug() << netman->getTechnology("wifi"); + if (!netman) + return; if (netman->getTechnologies().isEmpty()) { knownTechnologies.clear(); } @@ -483,9 +520,6 @@ void QConnectionAgent::techChanged() } if (tetheringWifiTech) { tetheringEnabled = tetheringWifiTech->tethering(); - qDebug() << "tethering is" << tetheringEnabled; - QObject::connect(tetheringWifiTech, SIGNAL(tetheringChanged(bool)), - this,SLOT(techTetheringChanged(bool)), Qt::UniqueConnection); } Q_FOREACH(NetworkTechnology *technology,netman->getTechnologies()) { @@ -495,6 +529,8 @@ void QConnectionAgent::techChanged() tetheringWifiTech = technology; connect(tetheringWifiTech,SIGNAL(poweredChanged(bool)),this,SLOT(technologyPowerChanged(bool))); connect(tetheringWifiTech,SIGNAL(scanFinished()),this,SLOT(onScanFinished())); + connect(tetheringWifiTech, SIGNAL(tetheringChanged(bool)), + this,SLOT(techTetheringChanged(bool)), Qt::UniqueConnection); } } else { knownTechnologies.removeOne(technology->path()); @@ -518,10 +554,28 @@ bool QConnectionAgent::isStateOnline(const QString &state) return false; } -void QConnectionAgent::techTetheringChanged(bool b) +void QConnectionAgent::techTetheringChanged(bool on) { - qDebug() << b; - tetheringEnabled = b; + qDebug() << on; + tetheringEnabled = on; + NetworkTechnology *technology = static_cast(sender()); + + if (on && delayedTethering && technology) { + QVector services = netman->getServices("cellular"); + if (services.isEmpty()) + return; + NetworkService* cellService = services.at(0); + if (cellService) { + if (cellService->state() == "idle"|| cellService->state() == "failure") { + cellService->requestConnect(); + } else if (cellService->connected()) { + delayedTethering = false; + Q_EMIT tetheringFinished(true); + } + } else { + stopTethering(); + } + } } void QConnectionAgent::offlineModeChanged(bool b) @@ -542,7 +596,7 @@ void QConnectionAgent::displayStateChanged(const QString &state) { if (state == "on") { NetworkTechnology *wifiTech = netman->getTechnology("wifi"); - if (wifiTech && wifiTech->powered() && !wifiTech->connected()) { + if (wifiTech && wifiTech->powered() && !wifiTech->connected() && !wifiTech->tethering()) { wifiTech->scan(); } } @@ -603,7 +657,10 @@ bool QConnectionAgent::isBestService(NetworkService *service) void QConnectionAgent::scanTimeout() { - if (tetheringWifiTech && tetheringWifiTech->powered() && !tetheringWifiTech->connected() && netman->defaultRoute()->type() != "wifi" ) { + if (!tetheringWifiTech || tetheringWifiTech->tethering()) + return; + + if (tetheringWifiTech->powered() && !tetheringWifiTech->connected() && netman->defaultRoute()->type() != "wifi" ) { tetheringWifiTech->scan(); qDebug() << "start scanner" << scanTimeoutInterval; if (scanTimeoutInterval != 0) { @@ -722,3 +779,83 @@ void QConnectionAgent::openConnectionDialog(const QString &type) QDBusMessage reply = connSelectorInterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("openConnection"), args); } + +void QConnectionAgent::startTethering(const QString &type) +{ + if (!netman | (type != "wifi")) { //we only support wifi for now + Q_EMIT tetheringFinished(false); + return; + } + + NetworkTechnology *tetherTech = netman->getTechnology(type); + if (!tetherTech) { + Q_EMIT tetheringFinished(false); + return; + } + + QVector services = netman->getServices("cellular"); + if (services.isEmpty()) { + Q_EMIT tetheringFinished(false); + return; + } + + NetworkService *cellService = services.at(0); + if (!cellService || netman->offlineMode()) { + Q_EMIT tetheringFinished(false); + return; + } + + QSettings confFile; + confFile.beginGroup("Connectionagent"); + bool cellConnected = cellService->connected(); + bool cellAutoconnect = cellService->autoConnect(); + + // save cellular connection state + confFile.setValue("tetheringCellularConnected",cellConnected); + confFile.setValue("tetheringCellularAutoconnect",cellAutoconnect); + + bool techPowered = tetherTech->powered(); + + // save wifi powered state + confFile.setValue("tetheringTechPowered",techPowered); + confFile.setValue("tetheringType",type); + + delayedTethering = true; + if (!techPowered) { + tetherTech->setPowered(true); + } else { + tetherTech->setTethering(true); + } +} + +void QConnectionAgent::stopTethering() +{ + delayedTethering = false; + QSettings confFile; + confFile.beginGroup("Connectionagent"); + + NetworkTechnology *tetherTech = netman->getTechnology(confFile.value("tetheringType","wifi").toString()); + if (tetherTech && tetherTech->tethering()) { + tetherTech->setTethering(false); + } + bool b = confFile.value("tetheringCellularConnected").toBool(); + bool ab = confFile.value("tetheringCellularAutoconnect").toBool(); + + Q_FOREACH (const QString &path, servicesMap.keys()) { + if (path.contains("cellular")) { + if (isStateOnline(servicesMap.value(path)->state())) { + qDebug() << "disconnect mobile data"; + if (!b) + servicesMap.value(path)->requestDisconnect(); + if (!ab) + servicesMap.value(path)->setAutoConnect(false); + } + } + } + + b = confFile.value("tetheringTechPowered").toBool(); + if (!b && tetherTech) { + tetherTech->setPowered(false); + } + Q_EMIT tetheringFinished(false); +} diff --git a/connd/qconnectionagent.h b/connd/qconnectionagent.h index f453d9d..1b6769b 100644 --- a/connd/qconnectionagent.h +++ b/connd/qconnectionagent.h @@ -61,6 +61,7 @@ class QConnectionAgent : public QObject void connectNow(const QString &path); void requestBrowser(const QString &url); + void tetheringFinished(bool); public Q_SLOTS: @@ -75,6 +76,9 @@ public Q_SLOTS: void connectToType(const QString &type); + void startTethering(const QString &type); + void stopTethering(); + private: explicit QConnectionAgent(QObject *parent = 0); static QConnectionAgent *self; @@ -107,6 +111,8 @@ public Q_SLOTS: bool isBestService(NetworkService *service); QString findBestConnectableService(); void removeAllTypes(const QString &type); + bool tetheringStarted; + bool delayedTethering; private slots: void onScanFinished(); diff --git a/connectionagentplugin/connectionagentplugin.cpp b/connectionagentplugin/connectionagentplugin.cpp index 2505fc1..9354c71 100644 --- a/connectionagentplugin/connectionagentplugin.cpp +++ b/connectionagentplugin/connectionagentplugin.cpp @@ -87,10 +87,13 @@ void ConnectionAgentPlugin::connectToConnectiond(QString) connect(connManagerInterface,SIGNAL(userInputRequested(QString,QVariantMap)), this,SLOT(onUserInputRequested(QString,QVariantMap)), Qt::UniqueConnection); + + connect(connManagerInterface,SIGNAL(tetheringFinished(bool)), + this,SLOT(onTetheringFinished(bool))); } void ConnectionAgentPlugin::sendUserReply(const QVariantMap &input) -{ +{ if (!connManagerInterface || !connManagerInterface->isValid()) { Q_EMIT errorReported("","ConnectionAgent not available"); return; @@ -179,3 +182,17 @@ void ConnectionAgentPlugin::setAskRoaming(bool value) connManagerInterface->setAskRoaming(value); } +void ConnectionAgentPlugin::startTethering(const QString &type) +{ + connManagerInterface->startTethering(type); +} + +void ConnectionAgentPlugin::onTetheringFinished(bool success) +{ + Q_EMIT tetheringFinished(success); +} + +void ConnectionAgentPlugin::stopTethering() +{ + connManagerInterface->stopTethering(); +} diff --git a/connectionagentplugin/connectionagentplugin.h b/connectionagentplugin/connectionagentplugin.h index 0b748f3..b7fc4a0 100644 --- a/connectionagentplugin/connectionagentplugin.h +++ b/connectionagentplugin/connectionagentplugin.h @@ -27,7 +27,7 @@ class ConnectionAgentPlugin : public QObject Q_PROPERTY(bool askRoaming READ askRoaming WRITE setAskRoaming) Q_DISABLE_COPY(ConnectionAgentPlugin) - + public: explicit ConnectionAgentPlugin(QObject *parent = 0); ~ConnectionAgentPlugin(); @@ -38,6 +38,8 @@ public slots: void sendUserReply(const QVariantMap &input); void sendConnectReply(const QString &replyMessage, int timeout = 120); void connectToType(const QString &type); + void startTethering(const QString &type); + void stopTethering(); signals: void userInputRequested(const QString &servicePath, const QVariantMap &fields); @@ -47,6 +49,7 @@ public slots: void configurationNeeded(const QString &type); void connectionState(const QString &state, const QString &type); void browserRequested(const QString &url); + void tetheringFinished(bool); private: com::jolla::Connectiond *connManagerInterface; @@ -58,6 +61,7 @@ private slots: void onUserInputRequested(const QString &service, const QVariantMap &fields); void onConnectionRequested(); void onConnectionState(const QString &state, const QString &type); + void onTetheringFinished(bool); void connectToConnectiond(const QString = QString()); void connectiondUnregistered(const QString = QString()); diff --git a/connectionagentplugin/connectionamanagerinterface.h b/connectionagentplugin/connectionamanagerinterface.h index 9231b4a..7462873 100644 --- a/connectionagentplugin/connectionamanagerinterface.h +++ b/connectionagentplugin/connectionamanagerinterface.h @@ -63,6 +63,19 @@ public Q_SLOTS: // METHODS return asyncCallWithArgumentList(QLatin1String("sendUserReply"), argumentList); } + inline QDBusPendingReply<> startTethering(const QString &in0) + { + QList argumentList; + argumentList << QVariant::fromValue(in0); + return asyncCallWithArgumentList(QLatin1String("startTethering"), argumentList); + } + + inline QDBusPendingReply<> stopTethering() + { + return asyncCall(QLatin1String("stopTethering")); + } + + Q_SIGNALS: // SIGNALS void configurationNeeded(const QString &type); void connectionRequest(); @@ -72,6 +85,7 @@ public Q_SLOTS: // METHODS void roamingAskChanged(bool askRoaming); void userInputCanceled(); void userInputRequested(const QString &service, const QVariantMap &fields); + void tetheringFinished(bool); }; namespace com { diff --git a/test/auto/tst_connectionagent_plugin/tst_connectionagent_plugintest.cpp b/test/auto/tst_connectionagent_plugin/tst_connectionagent_plugintest.cpp index 8e3562c..743aa87 100644 --- a/test/auto/tst_connectionagent_plugin/tst_connectionagent_plugintest.cpp +++ b/test/auto/tst_connectionagent_plugin/tst_connectionagent_plugintest.cpp @@ -33,7 +33,7 @@ class Tst_connectionagent_pluginTest : public QObject { Q_OBJECT - + public: Tst_connectionagent_pluginTest(); ~Tst_connectionagent_pluginTest(); @@ -44,15 +44,20 @@ private Q_SLOTS: void testUserInputRequested_data(); void testUserInputRequested(); - void testErrorReported(); + + void tst_tethering(); + private: ConnectionAgentPlugin *plugin; + NetworkManager *netman; }; Tst_connectionagent_pluginTest::Tst_connectionagent_pluginTest() { plugin = new ConnectionAgentPlugin(this); + netman = NetworkManagerFactory::createInstance(); + QTest::qWait(5000); } Tst_connectionagent_pluginTest::~Tst_connectionagent_pluginTest() @@ -147,6 +152,70 @@ void Tst_connectionagent_pluginTest::testUserInputRequested() } +void Tst_connectionagent_pluginTest::tst_tethering() +{ + NetworkService *wlanService; + NetworkService *mobiledataService; + + QVector wifiServices = netman->getServices("wifi"); + QVERIFY(wifiServices.count() > 0); + + Q_FOREACH (wlanService, wifiServices) { + if (wlanService->autoConnect()) { + break; + } + } + bool wlanOnline = wlanService->connected(); + + QVector cellServices = netman->getServices("cellular"); + QVERIFY(cellServices.count() > 0); + mobiledataService = cellServices.at(0); + + bool mdOnline = mobiledataService->connected(); + bool mdAutoconnect = mobiledataService->autoConnect(); + + QSignalSpy spy(plugin, SIGNAL(tetheringFinished(bool))); + plugin->startTethering("wifi"); + + QVERIFY(spy.isValid()); + QVERIFY(spy.wait(7000)); + + QCOMPARE(spy.count(),1); + QList arguments; + arguments = spy.takeFirst(); + QCOMPARE(arguments.at(0).toBool(), true); + + QTest::qWait(5000); + + QVERIFY(mobiledataService->state() == "online"); + + plugin->stopTethering(); + QTest::qWait(2500); + + QCOMPARE(spy.count(),1); + arguments = spy.takeFirst(); + QCOMPARE(arguments.at(0).toBool(), false); + + QTest::qWait(5000); + + QVERIFY(wlanService->connected() == wlanOnline); + QVERIFY(mobiledataService->connected() == mdOnline); + QVERIFY(mobiledataService->autoConnect() == mdAutoconnect); + +// plugin->startTethering("wifi"); + + +// plugin->stopTethering(); + +// QCOMPARE(spy.count(),1); +// arguments = spy.takeFirst(); +// QCOMPARE(arguments.at(0).toBool(), false); + +// NetworkManager *netman = NetworkManagerFactory::createInstance(); +// NetworkService *cellServices = netman->getServices("cellular").at(0); +// QVERIFY(cellServices->state() == "idle"); +} + QTEST_MAIN(Tst_connectionagent_pluginTest) #include "tst_connectionagent_plugintest.moc"