diff options
Diffstat (limited to 'src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp')
-rw-r--r-- | src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp | 458 |
1 files changed, 0 insertions, 458 deletions
diff --git a/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp b/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp deleted file mode 100644 index 3c78a075..00000000 --- a/src/plugins/position/geoclue2/qgeopositioninfosource_geoclue2.cpp +++ /dev/null @@ -1,458 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 Denis Shienkov <denis.shienkov@gmail.com> -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtPositioning module 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 "qgeopositioninfosource_geoclue2_p.h" - -#include <QtCore/QLoggingCategory> -#include <QtCore/QSaveFile> -#include <QtCore/QScopedPointer> -#include <QtCore/QTimer> -#include <QtDBus/QDBusPendingCallWatcher> - -// Auto-generated D-Bus files. -#include <client_interface.h> -#include <location_interface.h> - -Q_DECLARE_LOGGING_CATEGORY(lcPositioningGeoclue2) - -QT_BEGIN_NAMESPACE - -namespace { - -// NOTE: Copied from the /usr/include/libgeoclue-2.0/gclue-client.h -enum GClueAccuracyLevel { - GCLUE_ACCURACY_LEVEL_NONE = 0, - GCLUE_ACCURACY_LEVEL_COUNTRY = 1, - GCLUE_ACCURACY_LEVEL_CITY = 4, - GCLUE_ACCURACY_LEVEL_NEIGHBORHOOD = 5, - GCLUE_ACCURACY_LEVEL_STREET = 6, - GCLUE_ACCURACY_LEVEL_EXACT = 8 -}; - -const char GEOCLUE2_SERVICE_NAME[] = "org.freedesktop.GeoClue2"; -const int MINIMUM_UPDATE_INTERVAL = 1000; -const int UPDATE_TIMEOUT_COLD_START = 120000; -static const auto desktopIdParameter = "desktopId"; - -static QString lastPositionFilePath() -{ - return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) - + QStringLiteral("/qtposition-geoclue2"); -} - -} // namespace - -QGeoPositionInfoSourceGeoclue2::QGeoPositionInfoSourceGeoclue2(const QVariantMap ¶meters, - QObject *parent) - : QGeoPositionInfoSource(parent) - , m_requestTimer(new QTimer(this)) - , m_manager(QLatin1String(GEOCLUE2_SERVICE_NAME), - QStringLiteral("/org/freedesktop/GeoClue2/Manager"), - QDBusConnection::systemBus(), - this) -{ - parseParameters(parameters); - - qDBusRegisterMetaType<Timestamp>(); - - restoreLastPosition(); - - m_requestTimer->setSingleShot(true); - connect(m_requestTimer, &QTimer::timeout, - this, &QGeoPositionInfoSourceGeoclue2::requestUpdateTimeout); -} - -QGeoPositionInfoSourceGeoclue2::~QGeoPositionInfoSourceGeoclue2() -{ - saveLastPosition(); -} - -void QGeoPositionInfoSourceGeoclue2::setUpdateInterval(int msec) -{ - QGeoPositionInfoSource::setUpdateInterval(msec); - configureClient(); -} - -QGeoPositionInfo QGeoPositionInfoSourceGeoclue2::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const -{ - if (fromSatellitePositioningMethodsOnly && !m_lastPositionFromSatellite) - return QGeoPositionInfo(); - return m_lastPosition; -} - -QGeoPositionInfoSourceGeoclue2::PositioningMethods QGeoPositionInfoSourceGeoclue2::supportedPositioningMethods() const -{ - bool ok; - const auto accuracy = m_manager.property("AvailableAccuracyLevel").toUInt(&ok); - if (!ok) { - const_cast<QGeoPositionInfoSourceGeoclue2 *>(this)->setError(AccessError); - return NoPositioningMethods; - } - - switch (accuracy) { - case GCLUE_ACCURACY_LEVEL_COUNTRY: - case GCLUE_ACCURACY_LEVEL_CITY: - case GCLUE_ACCURACY_LEVEL_NEIGHBORHOOD: - case GCLUE_ACCURACY_LEVEL_STREET: - return NonSatellitePositioningMethods; - case GCLUE_ACCURACY_LEVEL_EXACT: - return AllPositioningMethods; - case GCLUE_ACCURACY_LEVEL_NONE: - default: - return NoPositioningMethods; - } -} - -void QGeoPositionInfoSourceGeoclue2::setPreferredPositioningMethods(PositioningMethods methods) -{ - QGeoPositionInfoSource::setPreferredPositioningMethods(methods); - configureClient(); -} - -int QGeoPositionInfoSourceGeoclue2::minimumUpdateInterval() const -{ - return MINIMUM_UPDATE_INTERVAL; -} - -QGeoPositionInfoSource::Error QGeoPositionInfoSourceGeoclue2::error() const -{ - return m_error; -} - -void QGeoPositionInfoSourceGeoclue2::startUpdates() -{ - if (m_running) { - qCWarning(lcPositioningGeoclue2) << "Already running"; - return; - } - - qCDebug(lcPositioningGeoclue2) << "Starting updates"; - - m_error = QGeoPositionInfoSource::NoError; - - m_running = true; - - startClient(); - - if (m_lastPosition.isValid()) { - QMetaObject::invokeMethod(this, "positionUpdated", Qt::QueuedConnection, - Q_ARG(QGeoPositionInfo, m_lastPosition)); - } -} - -void QGeoPositionInfoSourceGeoclue2::stopUpdates() -{ - if (!m_running) { - qCWarning(lcPositioningGeoclue2) << "Already stopped"; - return; - } - - qCDebug(lcPositioningGeoclue2) << "Stopping updates"; - m_running = false; - - stopClient(); -} - -void QGeoPositionInfoSourceGeoclue2::requestUpdate(int timeout) -{ - if (m_requestTimer->isActive()) { - qCDebug(lcPositioningGeoclue2) << "Request timer was active, ignoring startUpdates"; - return; - } - - m_error = QGeoPositionInfoSource::NoError; - - if (timeout < minimumUpdateInterval() && timeout != 0) { - setError(QGeoPositionInfoSource::UpdateTimeoutError); - return; - } - - m_requestTimer->start(timeout ? timeout : UPDATE_TIMEOUT_COLD_START); - startClient(); -} - -void QGeoPositionInfoSourceGeoclue2::setError(QGeoPositionInfoSource::Error error) -{ - m_error = error; - if (m_error != QGeoPositionInfoSource::NoError) - emit QGeoPositionInfoSource::errorOccurred(m_error); -} - -void QGeoPositionInfoSourceGeoclue2::restoreLastPosition() -{ -#if !defined(QT_NO_DATASTREAM) - const auto filePath = lastPositionFilePath(); - QFile file(filePath); - if (file.open(QIODevice::ReadOnly)) { - QDataStream out(&file); - out >> m_lastPosition; - } -#endif -} - -void QGeoPositionInfoSourceGeoclue2::saveLastPosition() -{ -#if !defined(QT_NO_DATASTREAM) && QT_CONFIG(temporaryfile) - if (!m_lastPosition.isValid()) - return; - - const auto filePath = lastPositionFilePath(); - QSaveFile file(filePath); - if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - QDataStream out(&file); - // Only save position and timestamp. - out << QGeoPositionInfo(m_lastPosition.coordinate(), m_lastPosition.timestamp()); - file.commit(); - } -#endif -} - -void QGeoPositionInfoSourceGeoclue2::createClient() -{ - const QDBusPendingReply<QDBusObjectPath> reply = m_manager.GetClient(); - const auto watcher = new QDBusPendingCallWatcher(reply, this); - connect(watcher, &QDBusPendingCallWatcher::finished, - [this](QDBusPendingCallWatcher *watcher) { - const QScopedPointer<QDBusPendingCallWatcher, QScopedPointerDeleteLater> - scopedWatcher(watcher); - const QDBusPendingReply<QDBusObjectPath> reply = *scopedWatcher; - if (reply.isError()) { - const auto error = reply.error(); - qCWarning(lcPositioningGeoclue2) << "Unable to obtain the client patch:" - << error.name() + error.message(); - setError(AccessError); - } else { - const QString clientPath = reply.value().path(); - qCDebug(lcPositioningGeoclue2) << "Client path is:" - << clientPath; - delete m_client; - m_client = new OrgFreedesktopGeoClue2ClientInterface( - QLatin1String(GEOCLUE2_SERVICE_NAME), - clientPath, - QDBusConnection::systemBus(), - this); - if (!m_client->isValid()) { - const auto error = m_client->lastError(); - qCCritical(lcPositioningGeoclue2) << "Unable to create the client object:" - << error.name() << error.message(); - setError(AccessError); - delete m_client; - } else { - connect(m_client.data(), &OrgFreedesktopGeoClue2ClientInterface::LocationUpdated, - this, &QGeoPositionInfoSourceGeoclue2::handleNewLocation); - - if (configureClient()) - startClient(); - } - } - }); -} - -void QGeoPositionInfoSourceGeoclue2::startClient() -{ - // only start the client if someone asked for it already - if (!m_running && !m_requestTimer->isActive()) - return; - - if (!m_client) { - createClient(); - return; - } - - const QDBusPendingReply<> reply = m_client->Start(); - const auto watcher = new QDBusPendingCallWatcher(reply, this); - connect(watcher, &QDBusPendingCallWatcher::finished, - [this](QDBusPendingCallWatcher *watcher) { - const QScopedPointer<QDBusPendingCallWatcher, QScopedPointerDeleteLater> - scopedWatcher(watcher); - const QDBusPendingReply<> reply = *scopedWatcher; - if (reply.isError()) { - const auto error = reply.error(); - qCCritical(lcPositioningGeoclue2) << "Unable to start the client:" - << error.name() << error.message(); - setError(AccessError); - delete m_client; - } else { - qCDebug(lcPositioningGeoclue2) << "Client successfully started"; - - const QDBusObjectPath location = m_client->location(); - const QString path = location.path(); - if (path.isEmpty() || path == QLatin1String("/")) - return; - - handleNewLocation({}, location); - } - }); -} - -void QGeoPositionInfoSourceGeoclue2::stopClient() -{ - // Only stop client if updates are no longer wanted. - if (m_requestTimer->isActive() || m_running || !m_client) - return; - - const QDBusPendingReply<> reply = m_client->Stop(); - const auto watcher = new QDBusPendingCallWatcher(reply, this); - connect(watcher, &QDBusPendingCallWatcher::finished, - [this](QDBusPendingCallWatcher *watcher) { - const QScopedPointer<QDBusPendingCallWatcher, QScopedPointerDeleteLater> - scopedWatcher(watcher); - const QDBusPendingReply<> reply = *scopedWatcher; - if (reply.isError()) { - const auto error = reply.error(); - qCCritical(lcPositioningGeoclue2) << "Unable to stop the client:" - << error.name() << error.message(); - setError(AccessError); - } else { - qCDebug(lcPositioningGeoclue2) << "Client successfully stopped"; - } - delete m_client; - }); -} - -bool QGeoPositionInfoSourceGeoclue2::configureClient() -{ - if (!m_client) - return false; - - if (m_desktopId.isEmpty()) { - qCCritical(lcPositioningGeoclue2) - << "Unable to configure the client due to the desktop id is not set via" - << desktopIdParameter << "plugin parameter or QCoreApplication::applicationName"; - setError(AccessError); - return false; - } - - m_client->setDesktopId(m_desktopId); - - const auto msecs = updateInterval(); - const uint secs = qMax(uint(msecs), 0u) / 1000u; - m_client->setTimeThreshold(secs); - - const auto methods = preferredPositioningMethods(); - switch (methods) { - case SatellitePositioningMethods: - m_client->setRequestedAccuracyLevel(GCLUE_ACCURACY_LEVEL_EXACT); - break; - case NonSatellitePositioningMethods: - m_client->setRequestedAccuracyLevel(GCLUE_ACCURACY_LEVEL_STREET); - break; - case AllPositioningMethods: - m_client->setRequestedAccuracyLevel(GCLUE_ACCURACY_LEVEL_EXACT); - break; - default: - m_client->setRequestedAccuracyLevel(GCLUE_ACCURACY_LEVEL_NONE); - break; - } - - return true; -} - -void QGeoPositionInfoSourceGeoclue2::requestUpdateTimeout() -{ - qCDebug(lcPositioningGeoclue2) << "Request update timeout occurred"; - - setError(QGeoPositionInfoSource::UpdateTimeoutError); - - stopClient(); -} - -void QGeoPositionInfoSourceGeoclue2::handleNewLocation(const QDBusObjectPath &oldLocation, - const QDBusObjectPath &newLocation) -{ - if (m_requestTimer->isActive()) - m_requestTimer->stop(); - - const auto oldPath = oldLocation.path(); - const auto newPath = newLocation.path(); - qCDebug(lcPositioningGeoclue2) << "Old location object path:" << oldPath; - qCDebug(lcPositioningGeoclue2) << "New location object path:" << newPath; - - OrgFreedesktopGeoClue2LocationInterface location( - QLatin1String(GEOCLUE2_SERVICE_NAME), - newPath, - QDBusConnection::systemBus(), - this); - if (!location.isValid()) { - const auto error = location.lastError(); - qCCritical(lcPositioningGeoclue2) << "Unable to create the location object:" - << error.name() << error.message(); - } else { - QGeoCoordinate coordinate(location.latitude(), - location.longitude()); - if (const auto altitude = location.altitude() > std::numeric_limits<double>::min()) - coordinate.setAltitude(altitude); - - const Timestamp ts = location.timestamp(); - if (ts.m_seconds == 0 && ts.m_microseconds == 0) { - const auto dt = QDateTime::currentDateTime(); - m_lastPosition = QGeoPositionInfo(coordinate, dt); - } else { - auto dt = QDateTime::fromSecsSinceEpoch(qint64(ts.m_seconds)); - dt = dt.addMSecs(ts.m_microseconds / 1000); - m_lastPosition = QGeoPositionInfo(coordinate, dt); - } - - const auto accuracy = location.accuracy(); - // We assume that an accuracy as 0.0 means that it comes from a sattelite. - m_lastPositionFromSatellite = qFuzzyCompare(accuracy, 0.0); - - m_lastPosition.setAttribute(QGeoPositionInfo::HorizontalAccuracy, accuracy); - if (const auto speed = location.speed() >= 0.0) - m_lastPosition.setAttribute(QGeoPositionInfo::GroundSpeed, speed); - if (const auto heading = location.heading() >= 0.0) - m_lastPosition.setAttribute(QGeoPositionInfo::Direction, heading); - - emit positionUpdated(m_lastPosition); - qCDebug(lcPositioningGeoclue2) << "New position:" << m_lastPosition; - } - - stopClient(); -} - -void QGeoPositionInfoSourceGeoclue2::parseParameters(const QVariantMap ¶meters) -{ - if (parameters.contains(desktopIdParameter)) - m_desktopId = parameters.value(desktopIdParameter).toString(); - - if (m_desktopId.isEmpty()) - m_desktopId = QCoreApplication::applicationName(); -} - -QT_END_NAMESPACE |