| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the plugins of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qandroidbearerengine.h" |
| #include "../../qnetworksession_impl.h" |
| #include "wrappers/androidconnectivitymanager.h" |
| |
| #ifndef QT_NO_BEARERMANAGEMENT |
| |
| QT_BEGIN_NAMESPACE |
| |
| static QString networkConfType(const AndroidNetworkInfo &networkInfo) |
| { |
| switch (networkInfo.getType()) { |
| case AndroidNetworkInfo::Mobile: |
| return QStringLiteral("Mobile"); |
| case AndroidNetworkInfo::Wifi: |
| return QStringLiteral("WiFi"); |
| case AndroidNetworkInfo::Wimax: |
| return QStringLiteral("WiMax"); |
| case AndroidNetworkInfo::Ethernet: |
| return QStringLiteral("Ethernet"); |
| case AndroidNetworkInfo::Bluetooth: |
| return QStringLiteral("Bluetooth"); |
| default: |
| break; |
| } |
| |
| return QString(); |
| } |
| |
| static inline bool isMobile(QNetworkConfiguration::BearerType type) |
| { |
| if (type == QNetworkConfiguration::BearerWLAN |
| || type == QNetworkConfiguration::BearerWiMAX |
| || type == QNetworkConfiguration::BearerBluetooth |
| || type == QNetworkConfiguration::BearerEthernet |
| || type == QNetworkConfiguration::BearerUnknown) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static QNetworkConfiguration::BearerType getBearerType(const AndroidNetworkInfo &networkInfo) |
| { |
| switch (networkInfo.getType()) { |
| case AndroidNetworkInfo::Mobile: |
| { |
| switch (networkInfo.getSubtype()) { |
| case AndroidNetworkInfo::Gprs: |
| case AndroidNetworkInfo::Edge: |
| case AndroidNetworkInfo::Iden: // 2G |
| return QNetworkConfiguration::Bearer2G; |
| case AndroidNetworkInfo::Umts: // BearerWCDMA (3 .5 .75 G) |
| case AndroidNetworkInfo::Hsdpa: // 3G (?) UMTS |
| case AndroidNetworkInfo::Hsupa: // 3G (?) UMTS |
| return QNetworkConfiguration::BearerWCDMA; |
| case AndroidNetworkInfo::Cdma: // CDMA ISA95[AB] |
| case AndroidNetworkInfo::Cdma1xRTT: // BearerCDMA2000 (3G) |
| case AndroidNetworkInfo::Ehrpd: // CDMA Bridge thing?!? |
| return QNetworkConfiguration::BearerCDMA2000; |
| case AndroidNetworkInfo::Evdo0: // BearerEVDO |
| case AndroidNetworkInfo::EvdoA: // BearerEVDO |
| case AndroidNetworkInfo::EvdoB: // BearerEVDO |
| return QNetworkConfiguration::BearerEVDO; |
| case AndroidNetworkInfo::Hspa: |
| case AndroidNetworkInfo::Hspap: // HSPA+ |
| return QNetworkConfiguration::BearerHSPA; |
| case AndroidNetworkInfo::Lte: // BearerLTE (4G) |
| return QNetworkConfiguration::BearerLTE; |
| default: |
| break; |
| } |
| } |
| case AndroidNetworkInfo::Wifi: |
| return QNetworkConfiguration::BearerWLAN; |
| case AndroidNetworkInfo::Wimax: |
| return QNetworkConfiguration::BearerWiMAX; |
| case AndroidNetworkInfo::Bluetooth: |
| case AndroidNetworkInfo::MobileDun: |
| return QNetworkConfiguration::BearerBluetooth; |
| case AndroidNetworkInfo::Ethernet: |
| return QNetworkConfiguration::BearerEthernet; |
| case AndroidNetworkInfo::MobileMms: |
| case AndroidNetworkInfo::MobileSupl: |
| case AndroidNetworkInfo::MobileHipri: |
| case AndroidNetworkInfo::Dummy: |
| case AndroidNetworkInfo::UnknownType: |
| break; |
| } |
| |
| return QNetworkConfiguration::BearerUnknown; |
| } |
| |
| QAndroidBearerEngine::QAndroidBearerEngine(QObject *parent) |
| : QBearerEngineImpl(parent), |
| m_connectivityManager(0) |
| { |
| } |
| |
| QAndroidBearerEngine::~QAndroidBearerEngine() |
| { |
| } |
| |
| QString QAndroidBearerEngine::getInterfaceFromId(const QString &id) |
| { |
| const QMutexLocker locker(&mutex); |
| return m_configurationInterface.value(id); |
| } |
| |
| bool QAndroidBearerEngine::hasIdentifier(const QString &id) |
| { |
| const QMutexLocker locker(&mutex); |
| return m_configurationInterface.contains(id); |
| } |
| |
| void QAndroidBearerEngine::connectToId(const QString &id) |
| { |
| Q_EMIT connectionError(id, OperationNotSupported); |
| } |
| |
| void QAndroidBearerEngine::disconnectFromId(const QString &id) |
| { |
| Q_EMIT connectionError(id, OperationNotSupported); |
| } |
| |
| QNetworkSession::State QAndroidBearerEngine::sessionStateForId(const QString &id) |
| { |
| const QMutexLocker locker(&mutex); |
| QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); |
| |
| if ((!ptr || !ptr->isValid) || m_connectivityManager == 0) |
| return QNetworkSession::Invalid; |
| |
| const QMutexLocker configLocker(&ptr->mutex); |
| // Don't re-order... |
| if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { |
| return QNetworkSession::Connected; |
| } else if ((ptr->state & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered) { |
| return QNetworkSession::Disconnected; |
| } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) { |
| return QNetworkSession::NotAvailable; |
| } else if ((ptr->state & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined) { |
| return QNetworkSession::NotAvailable; |
| } |
| |
| return QNetworkSession::Invalid; |
| } |
| |
| QNetworkConfigurationManager::Capabilities QAndroidBearerEngine::capabilities() const |
| { |
| |
| return AndroidTrafficStats::isTrafficStatsSupported() |
| ? QNetworkConfigurationManager::ForcedRoaming |
| | QNetworkConfigurationManager::DataStatistics |
| : QNetworkConfigurationManager::ForcedRoaming; |
| |
| } |
| |
| QNetworkSessionPrivate *QAndroidBearerEngine::createSessionBackend() |
| { |
| return new QNetworkSessionPrivateImpl(); |
| } |
| |
| QNetworkConfigurationPrivatePointer QAndroidBearerEngine::defaultConfiguration() |
| { |
| return QNetworkConfigurationPrivatePointer(); |
| } |
| |
| bool QAndroidBearerEngine::requiresPolling() const |
| { |
| return false; |
| } |
| |
| quint64 QAndroidBearerEngine::bytesWritten(const QString &id) |
| { |
| QMutexLocker lock(&mutex); |
| QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); |
| if (!ptr || !ptr->isValid) |
| return 0; |
| |
| return isMobile(ptr->bearerType) |
| ? AndroidTrafficStats::getMobileTxBytes() |
| : AndroidTrafficStats::getTotalTxBytes() - AndroidTrafficStats::getMobileTxBytes(); |
| } |
| |
| quint64 QAndroidBearerEngine::bytesReceived(const QString &id) |
| { |
| QMutexLocker lock(&mutex); |
| QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); |
| if (!ptr || !ptr->isValid) |
| return 0; |
| |
| return isMobile(ptr->bearerType) |
| ? AndroidTrafficStats::getMobileRxBytes() |
| : AndroidTrafficStats::getTotalRxBytes() - AndroidTrafficStats::getMobileRxBytes(); |
| } |
| |
| quint64 QAndroidBearerEngine::startTime(const QString &id) |
| { |
| Q_UNUSED(id); |
| return Q_UINT64_C(0); |
| } |
| |
| void QAndroidBearerEngine::initialize() |
| { |
| if (m_connectivityManager != 0) |
| return; |
| |
| m_connectivityManager = AndroidConnectivityManager::getInstance(); |
| if (m_connectivityManager == 0) |
| return; |
| |
| updateConfigurations(); |
| |
| connect(m_connectivityManager, &AndroidConnectivityManager::activeNetworkChanged, |
| this, &QAndroidBearerEngine::updateConfigurations); |
| |
| } |
| |
| void QAndroidBearerEngine::requestUpdate() |
| { |
| updateConfigurations(); |
| } |
| |
| void QAndroidBearerEngine::updateConfigurations() |
| { |
| #ifndef QT_NO_NETWORKINTERFACE |
| if (m_connectivityManager == 0) |
| return; |
| |
| { |
| QMutexLocker locker(&mutex); |
| QStringList oldKeys = accessPointConfigurations.keys(); |
| |
| QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces(); |
| if (interfaces.isEmpty()) |
| interfaces = QNetworkInterface::allInterfaces(); |
| |
| // Create a configuration for each of the main types (WiFi, Mobile, Bluetooth, WiMax, Ethernet) |
| const auto netInfos = m_connectivityManager->getAllNetworkInfo(); |
| for (const AndroidNetworkInfo &netInfo : netInfos) { |
| |
| if (!netInfo.isValid()) |
| continue; |
| |
| const QString name = networkConfType(netInfo); |
| if (name.isEmpty()) |
| continue; |
| |
| QNetworkConfiguration::BearerType bearerType = getBearerType(netInfo); |
| |
| QString interfaceName; |
| QNetworkConfiguration::StateFlag state = QNetworkConfiguration::Defined; |
| if (netInfo.isAvailable()) { |
| if (netInfo.isConnected()) { |
| // Attempt to map an interface to this configuration |
| while (!interfaces.isEmpty()) { |
| QNetworkInterface interface = interfaces.takeFirst(); |
| // ignore loopback interface |
| if (!interface.isValid()) |
| continue; |
| |
| if (interface.flags() & QNetworkInterface::IsLoopBack) |
| continue; |
| // There is no way to get the interface from the NetworkInfo, so |
| // look for an active interface... |
| if (interface.flags() & QNetworkInterface::IsRunning |
| && !interface.addressEntries().isEmpty()) { |
| state = QNetworkConfiguration::Active; |
| interfaceName = interface.name(); |
| break; |
| } |
| } |
| } |
| } |
| |
| const QString key = QString(QLatin1String("android:%1:%2")).arg(name).arg(interfaceName); |
| const QString id = QString::number(qHash(key)); |
| m_configurationInterface[id] = interfaceName; |
| |
| oldKeys.removeAll(id); |
| if (accessPointConfigurations.contains(id)) { |
| QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); |
| bool changed = false; |
| { |
| const QMutexLocker confLocker(&ptr->mutex); |
| |
| if (!ptr->isValid) { |
| ptr->isValid = true; |
| changed = true; |
| } |
| |
| // Don't reset the bearer type to 'Unknown' |
| if (ptr->bearerType != QNetworkConfiguration::BearerUnknown |
| && ptr->bearerType != bearerType) { |
| ptr->bearerType = bearerType; |
| changed = true; |
| } |
| |
| if (ptr->name != name) { |
| ptr->name = name; |
| changed = true; |
| } |
| |
| if (ptr->id != id) { |
| ptr->id = id; |
| changed = true; |
| } |
| |
| if (ptr->state != state) { |
| ptr->state = state; |
| changed = true; |
| } |
| } // Unlock configuration |
| |
| if (changed) { |
| locker.unlock(); |
| Q_EMIT configurationChanged(ptr); |
| locker.relock(); |
| } |
| } else { |
| QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate); |
| ptr->name = name; |
| ptr->isValid = true; |
| ptr->id = id; |
| ptr->state = state; |
| ptr->type = QNetworkConfiguration::InternetAccessPoint; |
| ptr->bearerType = bearerType; |
| accessPointConfigurations.insert(id, ptr); |
| locker.unlock(); |
| Q_EMIT configurationAdded(ptr); |
| locker.relock(); |
| } |
| } |
| |
| while (!oldKeys.isEmpty()) { |
| QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(oldKeys.takeFirst()); |
| m_configurationInterface.remove(ptr->id); |
| locker.unlock(); |
| Q_EMIT configurationRemoved(ptr); |
| locker.relock(); |
| } |
| |
| } // Unlock engine |
| |
| #endif // QT_NO_NETWORKINTERFACE |
| |
| Q_EMIT updateCompleted(); |
| } |
| |
| QT_END_NAMESPACE |
| |
| #endif // QT_NO_BEARERMANAGEMENT |