File indexing completed on 2024-04-28 16:52:22

0001 // SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
0002 // SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
0003 // SPDX-License-Identifier: GPL-2.0-or-later
0004 
0005 #include <NetworkManagerQt/GsmSetting>
0006 #include <NetworkManagerQt/Manager>
0007 #include <NetworkManagerQt/Settings>
0008 #include <NetworkManagerQt/Utils>
0009 
0010 #include "signalindicator.h"
0011 
0012 SignalIndicator::SignalIndicator(QObject *parent)
0013     : QObject{parent}
0014     , m_nmModem{nullptr}
0015     , m_modemDevice{nullptr}
0016     , m_modem{nullptr}
0017     , m_3gppModem{nullptr}
0018 {
0019     connect(ModemManager::notifier(), &ModemManager::Notifier::modemAdded, this, &SignalIndicator::updateModemManagerModem);
0020     connect(ModemManager::notifier(), &ModemManager::Notifier::modemRemoved, this, &SignalIndicator::updateModemManagerModem);
0021 
0022     connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionAdded, this, &SignalIndicator::mobileDataEnabledChanged);
0023     connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionRemoved, this, &SignalIndicator::mobileDataEnabledChanged);
0024     connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionAdded, this, &SignalIndicator::mobileDataEnabledChanged);
0025     connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionRemoved, this, &SignalIndicator::mobileDataEnabledChanged);
0026     connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &SignalIndicator::updateNetworkManagerModem);
0027     connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceRemoved, this, &SignalIndicator::updateNetworkManagerModem);
0028 
0029     updateModemManagerModem();
0030 }
0031 
0032 int SignalIndicator::strength() const
0033 {
0034     if (!m_modem) {
0035         return 0;
0036     }
0037     return m_modem->signalQuality().signal;
0038 }
0039 
0040 QString SignalIndicator::name() const
0041 {
0042     return m_3gppModem ? m_3gppModem->operatorName() : QString();
0043 }
0044 
0045 bool SignalIndicator::modemAvailable() const
0046 {
0047     return !m_modem.isNull();
0048 }
0049 
0050 bool SignalIndicator::simLocked() const
0051 {
0052     if (!m_modem) {
0053         return false;
0054     }
0055     return m_modem->unlockRequired() == MM_MODEM_LOCK_SIM_PIN;
0056 }
0057 
0058 bool SignalIndicator::simEmpty() const
0059 {
0060     return !m_modemDevice || !m_modemDevice->sim() || (m_modemDevice->sim()->uni() == QStringLiteral("/"));
0061 }
0062 
0063 bool SignalIndicator::mobileDataSupported() const
0064 {
0065     return m_nmModem && !simEmpty();
0066 }
0067 
0068 bool SignalIndicator::mobileDataEnabled() const
0069 {
0070     // no modem -> no mobile data -> report disabled
0071     if (!m_nmModem) {
0072         return false;
0073     }
0074 
0075     // mobile data already activated -> report enabled
0076     if (m_nmModem->state() == NetworkManager::Device::Activated) {
0077         return true;
0078     }
0079 
0080     // autoconnect disabled on the entire modem -> report disabled
0081     if (!m_nmModem->autoconnect()) {
0082         return false;
0083     }
0084 
0085     // at least one connection set to autoconnect -> report enabled
0086     for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
0087         if (con->settings()->autoconnect()) {
0088             return true;
0089         }
0090     }
0091 
0092     // modem, but no connection, set to autoconnect -> report disabled (#182)
0093     return false;
0094 }
0095 
0096 bool SignalIndicator::needsAPNAdded() const
0097 {
0098     return m_nmModem && mobileDataSupported() && m_nmModem->availableConnections().count() == 0;
0099 }
0100 
0101 void SignalIndicator::setMobileDataEnabled(bool enabled)
0102 {
0103     if (!m_nmModem) {
0104         return;
0105     }
0106     if (!enabled) {
0107         m_nmModem->setAutoconnect(false);
0108         // we need to also set all connections to not autoconnect (#182)
0109         for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
0110             con->settings()->setAutoconnect(false);
0111             con->update(con->settings()->toMap());
0112         }
0113         m_nmModem->disconnectInterface();
0114     } else {
0115         m_nmModem->setAutoconnect(true);
0116         // activate the connection that was last used
0117         QDateTime latestTimestamp;
0118         NetworkManager::Connection::Ptr latestCon;
0119         for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
0120             QDateTime timestamp = con->settings()->timestamp();
0121             // if con was not used yet, skip it, otherwise:
0122             // if we have no latestTimestamp yet, con is the latest
0123             // otherwise, compare the timestamps
0124             // in case of a tie, use the first connection that was found
0125             if (!timestamp.isNull() && (latestTimestamp.isNull() || timestamp > latestTimestamp)) {
0126                 latestTimestamp = timestamp;
0127                 latestCon = con;
0128             }
0129         }
0130         // if we found the last used connection
0131         if (!latestCon.isNull()) {
0132             // set it to autoconnect and connect it immediately
0133             latestCon->settings()->setAutoconnect(true);
0134             latestCon->update(latestCon->settings()->toMap());
0135             NetworkManager::activateConnection(latestCon->path(), m_nmModem->uni(), "");
0136         }
0137     }
0138 }
0139 
0140 void SignalIndicator::updateModemManagerModem()
0141 {
0142     m_modemDevice = nullptr;
0143     m_modem = nullptr;
0144     m_3gppModem = nullptr;
0145 
0146     if (ModemManager::modemDevices().isEmpty()) {
0147         qWarning() << "No modems available";
0148         return;
0149     }
0150 
0151     // TODO: we assume that there is a single modem for the time being
0152     m_modemDevice = ModemManager::modemDevices()[0];
0153     m_modem = m_modemDevice->modemInterface();
0154     m_3gppModem = m_modemDevice->interface(ModemManager::ModemDevice::GsmInterface).objectCast<ModemManager::Modem3gpp>();
0155 
0156     connect(m_modemDevice->sim().get(), &ModemManager::Sim::simIdentifierChanged, this, &SignalIndicator::simEmptyChanged);
0157 
0158     if (m_modem) {
0159         connect(m_modem.get(), &ModemManager::Modem::signalQualityChanged, this, &SignalIndicator::strengthChanged);
0160         connect(m_modem.get(), &ModemManager::Modem::unlockRequiredChanged, this, &SignalIndicator::simLockedChanged);
0161     }
0162     if (m_3gppModem) {
0163         connect(m_3gppModem.get(), &ModemManager::Modem3gpp::operatorNameChanged, this, &SignalIndicator::nameChanged);
0164     }
0165 
0166     updateNetworkManagerModem();
0167 
0168     Q_EMIT nameChanged();
0169     Q_EMIT strengthChanged();
0170     Q_EMIT modemAvailableChanged();
0171 }
0172 
0173 void SignalIndicator::updateNetworkManagerModem()
0174 {
0175     m_nmModem = nullptr;
0176     if (!m_modemDevice) {
0177         return;
0178     }
0179 
0180     // find networkmanager modem
0181     for (NetworkManager::Device::Ptr nmDevice : NetworkManager::networkInterfaces()) {
0182         if (nmDevice->udi() == m_modemDevice->uni()) {
0183             m_nmModem = nmDevice.objectCast<NetworkManager::ModemDevice>();
0184 
0185             connect(m_nmModem.get(), &NetworkManager::Device::autoconnectChanged, this, &SignalIndicator::mobileDataEnabledChanged);
0186             connect(m_nmModem.get(), &NetworkManager::Device::stateChanged, this, &SignalIndicator::mobileDataEnabledChanged);
0187             connect(m_nmModem.get(), &NetworkManager::Device::availableConnectionAppeared, this, &SignalIndicator::mobileDataEnabledChanged);
0188             connect(m_nmModem.get(), &NetworkManager::Device::availableConnectionDisappeared, this, &SignalIndicator::mobileDataEnabledChanged);
0189         }
0190     }
0191 
0192     Q_EMIT mobileDataSupportedChanged();
0193     Q_EMIT mobileDataEnabledChanged();
0194 }