blob: a43ed6957088f66a859ea1f2e285bc7ec46e6c7f [file] [log] [blame]
/****************************************************************************
**
** 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