shift-shell/components/mmplugin/signalindicator.cpp
Kevin Kofler 7e47315bcb mmplugin: set all connections to not autoconnect on setMobileDataEnabled(false) (#182)
When disabling mobile data, instead of setting the autoconnect flag to
true for the current active connection, set it to false for all
connections without exception. When reenabling mobile data, instead of
looking for a connection with autoconnect set, look for the connection
with the latest last use timestamp, set that one to autoconnect, and
also connect it immediately.

There should not be any connection with autoconnect enabled if mobile
data is disabled, because that makes NetworkManager reconnect it after a
reboot or a modem restart. The autoconnect state on the modem is
apparently lost on reboot.

Also change the SignalIndicator::mobileDataEnabled() getter to account
for the above.

Fixes #182.
2022-03-20 13:59:32 -04:00

148 lines
4.9 KiB
C++

// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include <NetworkManagerQt/GsmSetting>
#include <NetworkManagerQt/Manager>
#include "signalindicator.h"
SignalIndicator::SignalIndicator()
{
connect(ModemManager::notifier(), &ModemManager::Notifier::modemAdded, this, &SignalIndicator::updateModem);
connect(ModemManager::notifier(), &ModemManager::Notifier::modemRemoved, this, &SignalIndicator::updateModem);
updateModem();
}
int SignalIndicator::strength() const
{
if (!m_modem) {
return 0;
}
return m_modem->signalQuality().signal;
}
QString SignalIndicator::name() const
{
return m_3gppModem ? m_3gppModem->operatorName() : QString();
}
bool SignalIndicator::simLocked() const
{
if (!m_modem) {
return false;
}
return m_modem->unlockRequired() == MM_MODEM_LOCK_SIM_PIN;
}
bool SignalIndicator::available() const
{
return !ModemManager::modemDevices().isEmpty();
}
bool SignalIndicator::mobileDataSupported() const
{
return m_nmModem && m_modemDevice->sim();
}
bool SignalIndicator::mobileDataEnabled() const
{
// no modem -> no mobile data -> report disabled
if (!m_nmModem) {
return false;
}
// mobile data already activated -> report enabled
if (m_nmModem->state() == NetworkManager::Device::Activated) {
return true;
}
// autoconnect disabled on the entire modem -> report disabled
if (!m_nmModem->autoconnect()) {
return false;
}
// at least one connection set to autoconnect -> report enabled
for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
if (con->settings()->autoconnect()) {
return true;
}
}
// modem, but no connection, set to autoconnect -> report disabled (#182)
return false;
}
void SignalIndicator::setMobileDataEnabled(bool enabled)
{
if (!m_nmModem) {
return;
}
if (!enabled) {
m_nmModem->setAutoconnect(false);
// we need to also set all connections to not autoconnect (#182)
for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
con->settings()->setAutoconnect(false);
con->update(con->settings()->toMap());
}
m_nmModem->disconnectInterface().waitForFinished();
} else {
m_nmModem->setAutoconnect(true);
// activate the connection that was last used
QDateTime latestTimestamp;
NetworkManager::Connection::Ptr latestCon;
for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
QDateTime timestamp = con->settings()->timestamp();
// if con was not used yet, skip it, otherwise:
// if we have no latestTimestamp yet, con is the latest
// otherwise, compare the timestamps
// in case of a tie, use the first connection that was found
if (!timestamp.isNull() && (latestTimestamp.isNull() || timestamp > latestTimestamp)) {
latestTimestamp = timestamp;
latestCon = con;
}
}
// if we found the last used connection
if (!latestCon.isNull()) {
// set it to autoconnect and connect it immediately
latestCon->settings()->setAutoconnect(true);
latestCon->update(latestCon->settings()->toMap());
NetworkManager::activateConnection(latestCon->path(), m_nmModem->uni(), "");
}
}
}
void SignalIndicator::updateModem()
{
if (!available()) {
qWarning() << "No modems available";
return;
}
// we assume that there is a single modem
m_modemDevice = ModemManager::modemDevices()[0];
m_modem = m_modemDevice->modemInterface();
m_3gppModem = m_modemDevice->interface(ModemManager::ModemDevice::GsmInterface).objectCast<ModemManager::Modem3gpp>();
// find networkmanager modem
for (NetworkManager::Device::Ptr nmDevice : NetworkManager::networkInterfaces()) {
if (nmDevice->udi() == m_modemDevice->uni()) {
m_nmModem = nmDevice.objectCast<NetworkManager::ModemDevice>();
connect(m_nmModem.get(), &NetworkManager::Device::autoconnectChanged, this, [this]() {
Q_EMIT mobileDataEnabledChanged();
});
connect(m_nmModem.get(), &NetworkManager::Device::stateChanged, this, [this](auto, auto, auto) {
Q_EMIT mobileDataEnabledChanged();
});
}
}
connect(m_modem.get(), &ModemManager::Modem::signalQualityChanged, this, &SignalIndicator::strengthChanged);
connect(m_3gppModem.get(), &ModemManager::Modem3gpp::operatorNameChanged, this, &SignalIndicator::nameChanged);
connect(m_modem.get(), &ModemManager::Modem::unlockRequiredChanged, this, &SignalIndicator::simLockedChanged);
Q_EMIT mobileDataSupportedChanged();
Q_EMIT nameChanged();
Q_EMIT availableChanged();
}