diff options
author | Alex Blasche <alexander.blasche@theqtcompany.com> | 2015-09-22 11:36:33 +0200 |
---|---|---|
committer | Alex Blasche <alexander.blasche@theqtcompany.com> | 2015-09-22 11:36:33 +0200 |
commit | b4a065d70e86405bc658b54fffad7c69a12f27aa (patch) | |
tree | 46f2efb8c67188e41aa2b72870a5b2415dbbbacc /src | |
parent | f983215417a8128010b156ab0371380563fa1a4a (diff) | |
parent | 116b41eed67ca923ca205d2c7aa0776b0eaa1a4e (diff) | |
download | qtlocation-b4a065d70e86405bc658b54fffad7c69a12f27aa.tar.gz |
Merge remote-tracking branch 'gerrit/5.6' into dev
Conflicts:
tests/auto/qgeosatelliteinfosource/qgeosatelliteinfosource.pro
Change-Id: I1cd05c8e9c9e55edc0d2d1c2b967d94a9efd0394
Diffstat (limited to 'src')
44 files changed, 1259 insertions, 671 deletions
diff --git a/src/imports/location/location.pro b/src/imports/location/location.pro index 254802e4..7441fab3 100644 --- a/src/imports/location/location.pro +++ b/src/imports/location/location.pro @@ -28,7 +28,8 @@ HEADERS += \ error_messages.h \ locationvaluetypehelper_p.h\ qquickgeomapgesturearea_p.h\ - ../positioning/qquickgeocoordinateanimation_p.h + ../positioning/qquickgeocoordinateanimation_p.h \ + mapitemviewdelegateincubator.h SOURCES += \ location.cpp \ @@ -53,7 +54,8 @@ SOURCES += \ error_messages.cpp \ locationvaluetypehelper.cpp \ qquickgeomapgesturearea.cpp \ - ../positioning/qquickgeocoordinateanimation.cpp + ../positioning/qquickgeocoordinateanimation.cpp \ + mapitemviewdelegateincubator.cpp include(declarativeplaces/declarativeplaces.pri) diff --git a/src/imports/location/mapitemviewdelegateincubator.cpp b/src/imports/location/mapitemviewdelegateincubator.cpp new file mode 100644 index 00000000..2c4ba823 --- /dev/null +++ b/src/imports/location/mapitemviewdelegateincubator.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Jolla Ltd, author: Aaron McCarthy <aaron.mccarthy@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtLocation 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mapitemviewdelegateincubator.h" +#include "qdeclarativegeomapitemview_p.h" + +QT_BEGIN_NAMESPACE + +MapItemViewDelegateIncubator::MapItemViewDelegateIncubator(QDeclarativeGeoMapItemView *view) +: m_view(view) +{ +} + +void MapItemViewDelegateIncubator::statusChanged(QQmlIncubator::Status status) +{ + m_view->incubatorStatusChanged(this, status); +} + +QT_END_NAMESPACE diff --git a/src/imports/location/mapitemviewdelegateincubator.h b/src/imports/location/mapitemviewdelegateincubator.h new file mode 100644 index 00000000..7e0813c0 --- /dev/null +++ b/src/imports/location/mapitemviewdelegateincubator.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Jolla Ltd, author: Aaron McCarthy <aaron.mccarthy@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtLocation 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAPITEMVIEWDELEGATEINCUBATOR_H +#define MAPITEMVIEWDELEGATEINCUBATOR_H + +#include <QtQml/QQmlIncubator> + +QT_BEGIN_NAMESPACE + +class QDeclarativeGeoMapItemView; + +class MapItemViewDelegateIncubator : public QQmlIncubator +{ +public: + MapItemViewDelegateIncubator(QDeclarativeGeoMapItemView *view); + +protected: + void statusChanged(Status status) Q_DECL_OVERRIDE; + +private: + QDeclarativeGeoMapItemView *m_view; +}; + +QT_END_NAMESPACE + +#endif // MAPITEMVIEWDELEGATEINCUBATOR_H diff --git a/src/imports/location/qdeclarativegeomapitemview.cpp b/src/imports/location/qdeclarativegeomapitemview.cpp index 0ad69dcf..eff03b17 100644 --- a/src/imports/location/qdeclarativegeomapitemview.cpp +++ b/src/imports/location/qdeclarativegeomapitemview.cpp @@ -1,5 +1,7 @@ /**************************************************************************** ** +** Copyright (C) 2015 Jolla Ltd. +** Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com> ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** @@ -37,9 +39,11 @@ #include "qdeclarativegeomapitemview_p.h" #include "qdeclarativegeomap_p.h" #include "qdeclarativegeomapitembase_p.h" +#include "mapitemviewdelegateincubator.h" #include <QtCore/QAbstractItemModel> #include <QtQml/QQmlContext> +#include <QtQml/QQmlIncubator> #include <QtQml/private/qqmlopenmetaobject_p.h> QT_BEGIN_NAMESPACE @@ -71,13 +75,15 @@ QT_BEGIN_NAMESPACE QDeclarativeGeoMapItemView::QDeclarativeGeoMapItemView(QQuickItem *parent) : QObject(parent), componentCompleted_(false), delegate_(0), - itemModel_(0), map_(0), fitViewport_(false) + itemModel_(0), map_(0), fitViewport_(false), m_metaObjectType(0) { } QDeclarativeGeoMapItemView::~QDeclarativeGeoMapItemView() { removeInstantiatedItems(); + if (m_metaObjectType) + m_metaObjectType->release(); } /*! @@ -88,6 +94,49 @@ void QDeclarativeGeoMapItemView::componentComplete() componentCompleted_ = true; } +void QDeclarativeGeoMapItemView::incubatorStatusChanged(MapItemViewDelegateIncubator *incubator, + QQmlIncubator::Status status) +{ + if (status == QQmlIncubator::Loading) + return; + + for (int i = 0; i < m_itemData.length(); ++i) { + ItemData *itemData = m_itemData.at(i); + if (itemData->incubator != incubator) + continue; + + switch (status) { + case QQmlIncubator::Ready: + itemData->item = qobject_cast<QDeclarativeGeoMapItemBase *>(incubator->object()); + if (!itemData->item) { + qWarning() << "QDeclarativeGeoMapItemView map item delegate is of unsupported type."; + delete incubator->object(); + } else { + map_->addMapItem(itemData->item); + if (fitViewport_) + fitViewport(); + } + delete itemData->incubator; + itemData->incubator = 0; + break; + case QQmlIncubator::Null: + // Should never get here + delete itemData->incubator; + itemData->incubator = 0; + break; + case QQmlIncubator::Error: + qWarning() << "QDeclarativeGeoMapItemView map item creation failed."; + delete itemData->incubator; + itemData->incubator = 0; + break; + default: + ; + } + + break; + } +} + /*! \qmlproperty model QtLocation::MapItemView::model @@ -111,6 +160,14 @@ void QDeclarativeGeoMapItemView::setModel(const QVariant &model) this, SLOT(itemModelRowsRemoved(QModelIndex,int,int))); disconnect(itemModel_, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(itemModelRowsInserted(QModelIndex,int,int))); + disconnect(itemModel_, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), + this, SLOT(itemModelRowsMoved(QModelIndex,int,int,QModelIndex,int))); + disconnect(itemModel_, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), + this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex,QVector<int>))); + + removeInstantiatedItems(); + m_metaObjectType->release(); + m_metaObjectType = 0; itemModel_ = 0; } @@ -122,9 +179,18 @@ void QDeclarativeGeoMapItemView::setModel(const QVariant &model) this, SLOT(itemModelRowsRemoved(QModelIndex,int,int))); connect(itemModel_, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(itemModelRowsInserted(QModelIndex,int,int))); + connect(itemModel_, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), + this, SLOT(itemModelRowsMoved(QModelIndex,int,int,QModelIndex,int))); + connect(itemModel_, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), + this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex,QVector<int>))); + + m_metaObjectType = new QQmlOpenMetaObjectType(&QObject::staticMetaObject, 0); + foreach (const QByteArray &name, itemModel_->roleNames()) + m_metaObjectType->createProperty(name); + + instantiateAllItems(); } - repopulate(); emit modelChanged(); } @@ -146,15 +212,11 @@ void QDeclarativeGeoMapItemView::itemModelRowsInserted(const QModelIndex &index, if (!componentCompleted_ || !map_ || !delegate_ || !itemModel_) return; - QDeclarativeGeoMapItemBase *mapItem; for (int i = start; i <= end; ++i) { - mapItem = createItemFromItemModel(i); - if (!mapItem) { - break; - } - mapItemList_.append(mapItem); - map_->addMapItem(mapItem); + const QModelIndex insertedIndex = itemModel_->index(i, 0, index); + createItemForIndex(insertedIndex); } + if (fitViewport_) fitViewport(); } @@ -170,17 +232,56 @@ void QDeclarativeGeoMapItemView::itemModelRowsRemoved(const QModelIndex &index, return; for (int i = end; i >= start; --i) { - QDeclarativeGeoMapItemBase *mapItem = mapItemList_.takeAt(i); - Q_ASSERT(mapItem); - if (!mapItem) // bad + ItemData *itemData = m_itemData.takeAt(i); + if (!itemData) break; - map_->removeMapItem(mapItem); - mapItem->deleteLater(); + + map_->removeMapItem(itemData->item); + delete itemData; } + if (fitViewport_) fitViewport(); } +void QDeclarativeGeoMapItemView::itemModelRowsMoved(const QModelIndex &parent, int start, int end, + const QModelIndex &destination, int row) +{ + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + Q_UNUSED(destination) + Q_UNUSED(row) + + qWarning() << "QDeclarativeGeoMapItemView does not support models that move rows."; +} + +void QDeclarativeGeoMapItemView::itemModelDataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight, + const QVector<int> &roles) +{ + Q_UNUSED(roles) + + for (int i = topLeft.row(); i <= bottomRight.row(); ++i) { + const QModelIndex index = itemModel_->index(i, 0); + ItemData *itemData = m_itemData.at(i); + + QHashIterator<int, QByteArray> iterator(itemModel_->roleNames()); + while (iterator.hasNext()) { + iterator.next(); + + QVariant modelData = itemModel_->data(index, iterator.key()); + if (!modelData.isValid()) + continue; + + itemData->context->setContextProperty(QString::fromLatin1(iterator.value().constData()), + modelData); + + itemData->modelDataMeta->setValue(iterator.value(), modelData); + } + } +} + /*! \qmlproperty Component QtLocation::MapItemView::delegate @@ -254,87 +355,87 @@ void QDeclarativeGeoMapItemView::removeInstantiatedItems() { if (!map_) return; - foreach (QDeclarativeGeoMapItemBase *mapItem, mapItemList_) { - mapItem->deleteLater(); - map_->removeMapItem(mapItem); + + foreach (ItemData *itemData, m_itemData) { + map_->removeMapItem(itemData->item); + delete itemData; } - mapItemList_.clear(); + m_itemData.clear(); } /*! \internal - Removes and repopulates all items. + + Instantiates all items. */ -void QDeclarativeGeoMapItemView::repopulate() +void QDeclarativeGeoMapItemView::instantiateAllItems() { - // Free any earlier instances - removeInstantiatedItems(); - if (!componentCompleted_ || !map_ || !delegate_ || !itemModel_) return; - // Iterate model data and instantiate delegates. for (int i = 0; i < itemModel_->rowCount(); ++i) { - QDeclarativeGeoMapItemBase *mapItem = createItemFromItemModel(i); - Q_ASSERT(mapItem); - if (!mapItem) // bad - break; - mapItemList_.append(mapItem); - map_->addMapItem(mapItem); + const QModelIndex index = itemModel_->index(i, 0); + createItemForIndex(index); } + if (fitViewport_) fitViewport(); } /*! \internal + Removes and repopulates all items. +*/ +void QDeclarativeGeoMapItemView::repopulate() +{ + removeInstantiatedItems(); + instantiateAllItems(); +} + +/*! + \internal */ -QDeclarativeGeoMapItemBase *QDeclarativeGeoMapItemView::createItemFromItemModel(int modelRow) +void QDeclarativeGeoMapItemView::createItemForIndex(const QModelIndex &index) { - if (!delegate_ || !itemModel_) - return 0; + // Expected to be already tested by caller. + Q_ASSERT(delegate_); + Q_ASSERT(itemModel_); - QModelIndex index = itemModel_->index(modelRow, 0); // column 0 - if (!index.isValid()) { - qWarning() << "QDeclarativeGeoMapItemView Index is not valid: " << modelRow; - return 0; - } + ItemData *itemData = new ItemData; - QObject *model = new QObject(this); - QQmlOpenMetaObject *modelMetaObject = new QQmlOpenMetaObject(model); + itemData->modelData = new QObject; + itemData->modelDataMeta = new QQmlOpenMetaObject(itemData->modelData, m_metaObjectType, false); + itemData->context = new QQmlContext(qmlContext(this)); QHashIterator<int, QByteArray> iterator(itemModel_->roleNames()); - QQmlContext *itemContext = new QQmlContext(qmlContext(this)); while (iterator.hasNext()) { iterator.next(); + QVariant modelData = itemModel_->data(index, iterator.key()); if (!modelData.isValid()) continue; - itemContext->setContextProperty(QString::fromLatin1(iterator.value().constData()), - modelData); + itemData->context->setContextProperty(QString::fromLatin1(iterator.value().constData()), + modelData); - modelMetaObject->setValue(iterator.value(), modelData); + itemData->modelDataMeta->setValue(iterator.value(), modelData); } - itemContext->setContextProperty(QStringLiteral("model"), model); - itemContext->setContextProperty(QStringLiteral("index"), modelRow); - QObject *obj = delegate_->create(itemContext); + itemData->context->setContextProperty(QLatin1String("model"), itemData->modelData); + itemData->context->setContextProperty(QLatin1String("index"), index.row()); - if (!obj) { - qWarning() << "QDeclarativeGeoMapItemView map item creation failed."; - delete itemContext; - return 0; - } - QDeclarativeGeoMapItemBase *declMapObj = qobject_cast<QDeclarativeGeoMapItemBase *>(obj); - if (!declMapObj) { - qWarning() << "QDeclarativeGeoMapItemView map item delegate is of unsupported type."; - delete itemContext; - return 0; - } - itemContext->setParent(declMapObj); - model->setParent(declMapObj); - return declMapObj; + itemData->incubator = new MapItemViewDelegateIncubator(this); + delegate_->create(*itemData->incubator, itemData->context); + + m_itemData.insert(index.row(), itemData); +} + +QDeclarativeGeoMapItemView::ItemData::~ItemData() +{ + delete incubator; + delete item; + delete context; + delete modelData; } #include "moc_qdeclarativegeomapitemview_p.cpp" diff --git a/src/imports/location/qdeclarativegeomapitemview_p.h b/src/imports/location/qdeclarativegeomapitemview_p.h index b39a47f0..29675295 100644 --- a/src/imports/location/qdeclarativegeomapitemview_p.h +++ b/src/imports/location/qdeclarativegeomapitemview_p.h @@ -1,5 +1,7 @@ /**************************************************************************** ** +** Copyright (C) 2015 Jolla Ltd. +** Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com> ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** @@ -39,6 +41,7 @@ #include <QtCore/QModelIndex> #include <QtQml/QQmlParserStatus> +#include <QtQml/QQmlIncubator> #include <QtQml/qqml.h> QT_BEGIN_NAMESPACE @@ -48,6 +51,9 @@ class QQmlComponent; class QQuickItem; class QDeclarativeGeoMap; class QDeclarativeGeoMapItemBase; +class QQmlOpenMetaObject; +class QQmlOpenMetaObjectType; +class MapItemViewDelegateIncubator; class QDeclarativeGeoMapItemView : public QObject, public QQmlParserStatus { @@ -75,6 +81,7 @@ public: void setMap(QDeclarativeGeoMap *); void repopulate(); void removeInstantiatedItems(); + void instantiateAllItems(); qreal zValue(); void setZValue(qreal zValue); @@ -88,25 +95,53 @@ Q_SIGNALS: void delegateChanged(); void autoFitViewportChanged(); -private: - QDeclarativeGeoMapItemBase *createItemFromItemModel(int modelRow); - - void fitViewport(); +protected: + void incubatorStatusChanged(MapItemViewDelegateIncubator *incubator, + QQmlIncubator::Status status); private Q_SLOTS: void itemModelReset(); void itemModelRowsInserted(const QModelIndex &index, int start, int end); void itemModelRowsRemoved(const QModelIndex &index, int start, int end); + void itemModelRowsMoved(const QModelIndex &parent, int start, int end, + const QModelIndex &destination, int row); + void itemModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, + const QVector<int> &roles); private: + struct ItemData { + ItemData() + : incubator(0), item(0), context(0), modelData(0), modelDataMeta(0) + { + } + + ~ItemData(); + + MapItemViewDelegateIncubator *incubator; + QDeclarativeGeoMapItemBase *item; + QQmlContext *context; + QObject *modelData; + QQmlOpenMetaObject *modelDataMeta; + }; + + void createItemForIndex(const QModelIndex &index); + void fitViewport(); + bool componentCompleted_; QQmlComponent *delegate_; QAbstractItemModel *itemModel_; QDeclarativeGeoMap *map_; - QList<QDeclarativeGeoMapItemBase *> mapItemList_; + QVector<ItemData *> m_itemData; bool fitViewport_; + + QQmlOpenMetaObjectType *m_metaObjectType; + + friend class QTypeInfo<ItemData>; + friend class MapItemViewDelegateIncubator; }; +Q_DECLARE_TYPEINFO(QDeclarativeGeoMapItemView::ItemData, Q_MOVABLE_TYPE); + QT_END_NAMESPACE QML_DECLARE_TYPE(QDeclarativeGeoMapItemView) diff --git a/src/imports/location/qquickgeomapgesturearea.cpp b/src/imports/location/qquickgeomapgesturearea.cpp index 9ab11b97..baa9e702 100644 --- a/src/imports/location/qquickgeomapgesturearea.cpp +++ b/src/imports/location/qquickgeomapgesturearea.cpp @@ -672,6 +672,9 @@ void QQuickGeoMapGestureArea::handleTouchEvent(QTouchEvent *event) void QQuickGeoMapGestureArea::handleWheelEvent(QWheelEvent *event) { + if (!m_map) + return; + QGeoCoordinate wheelGeoPos = m_map->itemPositionToCoordinate(QDoubleVector2D(event->posF()), false); QPointF preZoomPoint = m_map->coordinateToItemPosition(wheelGeoPos, false).toPointF(); @@ -744,7 +747,9 @@ bool QQuickGeoMapGestureArea::isActive() const // simplify the gestures by using a state-machine format (easy to move to a future state machine) void QQuickGeoMapGestureArea::update() { - if (!m_map) return; + if (!m_map) + return; + // First state machine is for the number of touch points //combine touch with mouse event diff --git a/src/location/doc/src/plugins/nokia.qdoc b/src/location/doc/src/plugins/nokia.qdoc index f1a6828a..1ed5e6e1 100644 --- a/src/location/doc/src/plugins/nokia.qdoc +++ b/src/location/doc/src/plugins/nokia.qdoc @@ -92,7 +92,9 @@ a prefix. \li here.mapping.cache.directory \li Absolute path to map tile cache directory used as network disk cache. - Default place for the cache is "QtLocation" directory in \l {QStandardPaths::writableLocation()} {QStandardPaths::writableLocation}(\l{QStandardPaths::GenericCacheLocation}). + The default place for the cache is \c{QtLocation/here} directory in \l {QStandardPaths::writableLocation()} {QStandardPaths::writableLocation}(\l{QStandardPaths::GenericCacheLocation}). + On systems that have no concept of a shared cache, the application-specific \l{QStandardPaths::CacheLocation} is used instead. + \row \li here.mapping.cache.disk.size \li Map tile disk cache size in bytes. Default size of the cache is 20MB. diff --git a/src/location/doc/src/plugins/osm.qdoc b/src/location/doc/src/plugins/osm.qdoc index f6de9c20..1c924fd3 100644 --- a/src/location/doc/src/plugins/osm.qdoc +++ b/src/location/doc/src/plugins/osm.qdoc @@ -106,4 +106,12 @@ Plugin { PluginParameter { name: "osm.geocoding.host"; value: "http://geocoding.server.address" } } \endcode + +\section1 Other Plugin-specific Information + +\section2 Tile cache + +The tiles are cached in a \c{QtLocation/osm} directory in \l {QStandardPaths::writableLocation()}{QStandardPaths::writableLocation} +(\l{QStandardPaths::GenericCacheLocation}). On systems that have no concept of a shared cache, the application-specific +\l{QStandardPaths::CacheLocation} is used instead. */ diff --git a/src/location/maps/qgeotilecache.cpp b/src/location/maps/qgeotilecache.cpp index aa76735f..3da2865b 100644 --- a/src/location/maps/qgeotilecache.cpp +++ b/src/location/maps/qgeotilecache.cpp @@ -100,14 +100,10 @@ QGeoTileCache::QGeoTileCache(const QString &directory, QObject *parent) qRegisterMetaType<QList<QGeoTileSpec> >(); qRegisterMetaType<QSet<QGeoTileSpec> >(); - // We keep default values here so that they are in one place - // rather than in each individual plugin (the plugins can - // of course override them) - - const QString basePath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) - + QLatin1String("/QtLocation"); + const QString basePath = baseCacheDirectory(); // delete old tiles from QtLocation 5.4 or prior + // Newer version use plugin-specific subdirectories so those are not affected. // TODO Remove cache cleanup in Qt 6 QDir baseDir(basePath); if (baseDir.exists()) { @@ -118,8 +114,7 @@ QGeoTileCache::QGeoTileCache(const QString &directory, QObject *parent) if (directory_.isEmpty()) { directory_ = basePath; - qWarning() << "Plugin uses uninitialized directory for QGeoTileCache" - " which will was deleted during startup"; + qWarning() << "Plugin uses uninitialized QGeoTileCache directory which was deleted during startup"; } QDir::root().mkpath(directory_); @@ -297,19 +292,19 @@ QSharedPointer<QGeoTileTexture> QGeoTileCache::get(const QGeoTileSpec &spec) QSharedPointer<QGeoCachedTileDisk> td = diskCache_.object(spec); if (td) { - QStringList parts = td->filename.split('.'); + const QString format = QFileInfo(td->filename).suffix(); QFile file(td->filename); file.open(QIODevice::ReadOnly); QByteArray bytes = file.readAll(); file.close(); QPixmap pixmap; - if (!pixmap.loadFromData(bytes, (parts.size() == 2 ? parts.at(1).toLocal8Bit().constData() : 0))) { + if (!pixmap.loadFromData(bytes)) { handleError(spec, QLatin1String("Problem with tile image")); return QSharedPointer<QGeoTileTexture>(0); } - addToMemoryCache(spec, bytes, (parts.size() == 2 ? parts.at(1) : QLatin1String(""))); + addToMemoryCache(spec, bytes, format); QSharedPointer<QGeoTileTexture> tt = addToTextureCache(td->spec, pixmap); if (tt) return tt; @@ -465,4 +460,23 @@ QGeoTileSpec QGeoTileCache::filenameToTileSpec(const QString &filename) numbers.at(4)); } +QString QGeoTileCache::baseCacheDirectory() +{ + QString dir; + + // Try the shared cache first and use a specific directory. (e.g. ~/.cache/QtLocation) + // If this is not supported by the platform, use the application-specific cache + // location. (e.g. ~/.cache/<app_name>/QtLocation) + dir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation); + if (dir.isEmpty()) + dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); + + if (!dir.endsWith(QLatin1Char('/'))) + dir += QLatin1Char('/'); + + dir += QLatin1String("QtLocation/"); + + return dir; +} + QT_END_NAMESPACE diff --git a/src/location/maps/qgeotilecache_p.h b/src/location/maps/qgeotilecache_p.h index 9cf31db0..d9f7bce9 100644 --- a/src/location/maps/qgeotilecache_p.h +++ b/src/location/maps/qgeotilecache_p.h @@ -141,6 +141,8 @@ public: QGeoTiledMappingManagerEngine::CacheAreas areas = QGeoTiledMappingManagerEngine::AllCaches); void handleError(const QGeoTileSpec &spec, const QString &errorString); + static QString baseCacheDirectory(); + public Q_SLOTS: void printStats(); diff --git a/src/location/maps/qgeotiledmappingmanagerengine.cpp b/src/location/maps/qgeotiledmappingmanagerengine.cpp index b9322c13..43f56872 100644 --- a/src/location/maps/qgeotiledmappingmanagerengine.cpp +++ b/src/location/maps/qgeotiledmappingmanagerengine.cpp @@ -288,10 +288,8 @@ QGeoTileCache *QGeoTiledMappingManagerEngine::tileCache() Q_D(QGeoTiledMappingManagerEngine); if (!d->tileCache_) { QString cacheDirectory; - if (!managerName().isEmpty()) { - cacheDirectory = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) - + QLatin1String("/QtLocation/") + managerName(); - } + if (!managerName().isEmpty()) + cacheDirectory = QGeoTileCache::baseCacheDirectory() + managerName(); d->tileCache_ = new QGeoTileCache(cacheDirectory); } return d->tileCache_; diff --git a/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp b/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp index 54bf29af..1b1163a6 100644 --- a/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp +++ b/src/plugins/geoservices/nokia/qgeotiledmappingmanagerengine_nokia.cpp @@ -106,8 +106,7 @@ QGeoTiledMappingManagerEngineNokia::QGeoTiledMappingManagerEngineNokia( cacheDir = parameters.value(QStringLiteral("here.mapping.cache.directory")).toString(); } else { // managerName() is not yet set, we have to hardcode the plugin name below - cacheDir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) - + QLatin1String("/QtLocation/here"); + cacheDir = QGeoTileCache::baseCacheDirectory() + QLatin1String("here"); } QGeoTileCache *tileCache = createTileCacheWithDir(cacheDir); diff --git a/src/plugins/geoservices/osm/qgeomapreplyosm.cpp b/src/plugins/geoservices/osm/qgeomapreplyosm.cpp index b540683b..d020716e 100644 --- a/src/plugins/geoservices/osm/qgeomapreplyosm.cpp +++ b/src/plugins/geoservices/osm/qgeomapreplyosm.cpp @@ -75,7 +75,11 @@ void QGeoMapReplyOsm::networkReplyFinished() QByteArray a = m_reply->readAll(); setMapImageData(a); - setMapImageFormat("png"); + int mapId = tileSpec().mapId(); + if (mapId == 1 || mapId == 2) + setMapImageFormat(QStringLiteral("jpg")); + else + setMapImageFormat(QStringLiteral("png")); setFinished(true); diff --git a/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp b/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp index 95a4355e..9d2a83fa 100644 --- a/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp +++ b/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp @@ -62,13 +62,16 @@ QGeoTiledMapReply *QGeoTileFetcherOsm::getTileImage(const QGeoTileSpec &spec) request.setRawHeader("User-Agent", m_userAgent); QString urlPrefix; + QString suffix = QStringLiteral(".png"); switch (spec.mapId()) { case 1: urlPrefix = QStringLiteral("http://otile1.mqcdn.com/tiles/1.0.0/map/"); + suffix = QStringLiteral(".jpg"); break; case 2: urlPrefix = QStringLiteral("http://otile1.mqcdn.com/tiles/1.0.0/sat/"); + suffix = QStringLiteral(".jpg"); break; case 3: urlPrefix = QStringLiteral("http://a.tile.thunderforest.com/cycle/"); @@ -94,7 +97,7 @@ QGeoTiledMapReply *QGeoTileFetcherOsm::getTileImage(const QGeoTileSpec &spec) request.setUrl(QUrl(urlPrefix + QString::number(spec.zoom()) + QLatin1Char('/') + QString::number(spec.x()) + QLatin1Char('/') + - QString::number(spec.y()) + QStringLiteral(".png"))); + QString::number(spec.y()) + suffix)); QNetworkReply *reply = m_networkManager->get(request); diff --git a/src/plugins/position/android/src/plugin.json b/src/plugins/position/android/src/plugin.json index b84fafea..4fd87892 100644 --- a/src/plugins/position/android/src/plugin.json +++ b/src/plugins/position/android/src/plugin.json @@ -4,5 +4,6 @@ "Position": true, "Satellite": true, "Monitor": false, - "Priority": 1000 + "Priority": 1000, + "Testable": false } diff --git a/src/plugins/position/corelocation/plugin.json b/src/plugins/position/corelocation/plugin.json index 96e5cbf1..58e3acd0 100644 --- a/src/plugins/position/corelocation/plugin.json +++ b/src/plugins/position/corelocation/plugin.json @@ -4,5 +4,6 @@ "Position": true, "Satellite": false, "Monitor" : false, - "Priority": 1000 + "Priority": 1000, + "Testable": false } diff --git a/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm b/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm index c92e468f..0e5e261b 100644 --- a/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm +++ b/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm @@ -88,6 +88,10 @@ m_positionInfoSource->setError(QGeoPositionInfoSource::AccessError); qWarning() << QString::fromNSString([error localizedDescription]); + + if ([error code] == 0 + && QString::fromNSString([error domain]) == QStringLiteral("kCLErrorDomain")) + qWarning() << "(is Wi-Fi turned on?)"; } @end diff --git a/src/plugins/position/geoclue/geoclue.pro b/src/plugins/position/geoclue/geoclue.pro index a3c34ece..0d9aab7d 100644 --- a/src/plugins/position/geoclue/geoclue.pro +++ b/src/plugins/position/geoclue/geoclue.pro @@ -1,32 +1,37 @@ TARGET = qtposition_geoclue -QT = core positioning +QT = core positioning dbus PLUGIN_TYPE = position PLUGIN_CLASS_NAME = QGeoPositionInfoSourceFactoryGeoclue load(qt_plugin) HEADERS += \ - qgeopositioninfosource_geocluemaster_p.h \ + qgeopositioninfosource_geocluemaster.h \ + qgeosatelliteinfosource_geocluemaster.h \ qgeopositioninfosourcefactory_geoclue.h \ - qgeocluemaster.h + qgeocluemaster.h \ + geocluetypes.h SOURCES += \ qgeopositioninfosource_geocluemaster.cpp \ + qgeosatelliteinfosource_geocluemaster.cpp \ qgeopositioninfosourcefactory_geoclue.cpp \ - qgeocluemaster.cpp + qgeocluemaster.cpp \ + geocluetypes.cpp + +QDBUSXML2CPP_INTERFACE_HEADER_FLAGS += "-N -i geocluetypes.h" +DBUS_INTERFACES += \ + org.freedesktop.Geoclue.MasterClient.xml \ + org.freedesktop.Geoclue.Master.xml \ + org.freedesktop.Geoclue.Position.xml \ + org.freedesktop.Geoclue.Velocity.xml \ + org.freedesktop.Geoclue.Satellite.xml \ + org.freedesktop.Geoclue.xml -qtHaveModule(dbus):config_geoclue-satellite { - DEFINES += HAS_SATELLITE - - QT *= dbus - - HEADERS += qgeosatelliteinfosource_geocluemaster.h - SOURCES += qgeosatelliteinfosource_geocluemaster.cpp -} +OTHER_FILES += \ + $$DBUS_INTERFACES -CONFIG += link_pkgconfig -PKGCONFIG += geoclue +INCLUDEPATH += $$QT.location.includes $$OUT_PWD OTHER_FILES += \ - plugin.json \ - plugin-satellite.json + plugin.json diff --git a/src/plugins/position/geoclue/geocluetypes.cpp b/src/plugins/position/geoclue/geocluetypes.cpp new file mode 100644 index 00000000..ece3d113 --- /dev/null +++ b/src/plugins/position/geoclue/geocluetypes.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Aaron McCarthy <mccarthy.aaron@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtPositioning module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "geocluetypes.h" + +const QDBusArgument &dbus_argument_helper(const QDBusArgument &arg, Accuracy &accuracy) +{ + arg.beginStructure(); + qint32 level; + arg >> level; + accuracy.m_level = static_cast<Accuracy::Level>(level); + arg >> accuracy.m_horizontal; + arg >> accuracy.m_vertical; + arg.endStructure(); + + return arg; +} + +QT_BEGIN_NAMESPACE + +QDBusArgument &operator<<(QDBusArgument &arg, const Accuracy &accuracy) +{ + arg.beginStructure(); + arg << qint32(accuracy.level()); + arg << accuracy.horizontal(); + arg << accuracy.vertical(); + arg.endStructure(); + + return arg; +} + +const QDBusArgument &operator>>(const QDBusArgument &arg, Accuracy &accuracy) +{ + return dbus_argument_helper(arg, accuracy); +} + +const QDBusArgument &operator>>(const QDBusArgument &argument, QGeoSatelliteInfo &si) +{ + qint32 a; + + argument.beginStructure(); + argument >> a; + si.setSatelliteIdentifier(a); + argument >> a; + si.setAttribute(QGeoSatelliteInfo::Elevation, a); + argument >> a; + si.setAttribute(QGeoSatelliteInfo::Azimuth, a); + argument >> a; + si.setSignalStrength(a); + argument.endStructure(); + return argument; +} + +const QDBusArgument &operator>>(const QDBusArgument &argument, QList<QGeoSatelliteInfo> &sis) +{ + sis.clear(); + + argument.beginArray(); + while (!argument.atEnd()) { + QGeoSatelliteInfo si; + argument >> si; + sis.append(si); + } + argument.endArray(); + + return argument; +} + +QT_END_NAMESPACE diff --git a/src/plugins/position/geoclue/geocluetypes.h b/src/plugins/position/geoclue/geocluetypes.h new file mode 100644 index 00000000..ff748b13 --- /dev/null +++ b/src/plugins/position/geoclue/geocluetypes.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Aaron McCarthy <mccarthy.aaron@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtPositioning module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GEOCLUETYPES_H +#define GEOCLUETYPES_H + +#include <QtDBus/QDBusArgument> +#include <QtPositioning/QGeoSatelliteInfo> + +class Accuracy +{ +public: + enum Level { + None = 0, + Country, + Region, + Locality, + PostalCode, + Street, + Detailed + }; + + Accuracy() + : m_level(None), m_horizontal(0), m_vertical(0) + { + } + + inline Level level() const { return m_level; } + inline double horizontal() const { return m_horizontal; } + inline double vertical() const { return m_vertical; } + +private: + Level m_level; + double m_horizontal; + double m_vertical; + + friend const QDBusArgument &dbus_argument_helper(const QDBusArgument &arg, Accuracy &accuracy); +}; + +Q_DECLARE_METATYPE(Accuracy) +Q_DECLARE_METATYPE(QList<QGeoSatelliteInfo>) + + +QT_BEGIN_NAMESPACE + +Q_DECLARE_TYPEINFO(Accuracy, Q_MOVABLE_TYPE); + +QDBusArgument &operator<<(QDBusArgument &arg, const Accuracy &accuracy); +const QDBusArgument &operator>>(const QDBusArgument &arg, Accuracy &accuracy); + +const QDBusArgument &operator>>(const QDBusArgument &arg, QGeoSatelliteInfo &si); +const QDBusArgument &operator>>(const QDBusArgument &arg, QList<QGeoSatelliteInfo> &sis); + +QT_END_NAMESPACE + +#endif // GEOCLUETYPES_H + diff --git a/src/plugins/position/geoclue/org.freedesktop.Geoclue.Master.xml b/src/plugins/position/geoclue/org.freedesktop.Geoclue.Master.xml new file mode 100644 index 00000000..e7df140c --- /dev/null +++ b/src/plugins/position/geoclue/org.freedesktop.Geoclue.Master.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.freedesktop.Geoclue.Master"> + <method name="Create"> + <arg name="path" type="o" direction="out"/> + </method> + </interface> +</node> + diff --git a/src/plugins/position/geoclue/org.freedesktop.Geoclue.MasterClient.xml b/src/plugins/position/geoclue/org.freedesktop.Geoclue.MasterClient.xml new file mode 100644 index 00000000..29c95885 --- /dev/null +++ b/src/plugins/position/geoclue/org.freedesktop.Geoclue.MasterClient.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.freedesktop.Geoclue.MasterClient"> + <method name="GetPositionProvider"> + <arg name="name" type="s" direction="out"/> + <arg name="description" type="s" direction="out"/> + <arg name="service" type="s" direction="out"/> + <arg name="path" type="s" direction="out"/> + </method> + <method name="GetAddressProvider"> + <arg name="name" type="s" direction="out"/> + <arg name="description" type="s" direction="out"/> + <arg name="service" type="s" direction="out"/> + <arg name="path" type="s" direction="out"/> + </method> + <method name="PositionStart"> + </method> + <method name="AddressStart"> + </method> + <method name="SetRequirements"> + <arg name="accuracyLevel" type="i" direction="in"/> + <arg name="time" type="i" direction="in"/> + <arg name="requireUpdates" type="b" direction="in"/> + <arg name="allowedResources" type="i" direction="in"/> + </method> + <signal name="PositionProviderChanged"> + <arg name="name" type="s"/> + <arg name="description" type="s"/> + <arg name="service" type="s"/> + <arg name="path" type="s"/> + </signal> + <signal name="AddressProviderChanged"> + <arg name="name" type="s"/> + <arg name="description" type="s"/> + <arg name="service" type="s"/> + <arg name="path" type="s"/> + </signal> + </interface> +</node> + diff --git a/src/plugins/position/geoclue/org.freedesktop.Geoclue.Position.xml b/src/plugins/position/geoclue/org.freedesktop.Geoclue.Position.xml new file mode 100644 index 00000000..ce5c80de --- /dev/null +++ b/src/plugins/position/geoclue/org.freedesktop.Geoclue.Position.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.freedesktop.Geoclue.Position"> + <method name="GetPosition"> + <arg name="fields" type="i" direction="out"/> + <arg name="timestamp" type="i" direction="out"/> + <arg name="latitude" type="d" direction="out"/> + <arg name="longitude" type="d" direction="out"/> + <arg name="altitude" type="d" direction="out"/> + <arg name="accuracy" type="(idd)" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out5" value="Accuracy"/> + </method> + <signal name="PositionChanged"> + <arg name="fields" type="i"/> + <arg name="timestamp" type="i"/> + <arg name="latitude" type="d"/> + <arg name="longitude" type="d"/> + <arg name="altitude" type="d"/> + <arg name="accuracy" type="(idd)"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.In5" value="Accuracy"/> + </signal> + </interface> +</node> + diff --git a/src/plugins/position/geoclue/org.freedesktop.Geoclue.Satellite.xml b/src/plugins/position/geoclue/org.freedesktop.Geoclue.Satellite.xml new file mode 100644 index 00000000..2ed112c9 --- /dev/null +++ b/src/plugins/position/geoclue/org.freedesktop.Geoclue.Satellite.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/"> + <interface name="org.freedesktop.Geoclue.Satellite"> + <method name="GetSatellite"> + <arg name="timestamp" type="i" direction="out" /> + <arg name="satelliteUsed" type="i" direction="out" /> + <arg name="satelliteVisible" type="i" direction="out" /> + <arg name="usedPrn" type="ai" direction="out" /> + <arg name="satInfo" type="a(iiii)" direction="out" /> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out3" value="QList<qint32>"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out4" value="QList<QGeoSatelliteInfo>"/> + </method> + <method name="GetLastSatellite"> + <arg name="timestamp" type="i" direction="out" /> + <arg name="satelliteUsed" type="i" direction="out" /> + <arg name="satelliteVisible" type="i" direction="out" /> + <arg name="usedPrn" type="ai" direction="out" /> + <arg name="satInfo" type="a(iiii)" direction="out" /> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out3" value="QList<qint32>"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out4" value="QList<QGeoSatelliteInfo>"/> + </method> + <signal name="SatelliteChanged"> + <arg name="timestamp" type="i" /> + <arg name="satelliteUsed" type="i" /> + <arg name="satelliteVisible" type="i" /> + <arg name="usedPrn" type="ai" /> + <arg name="satInfo" type="a(iiii)" />' + <annotation name="org.qtproject.QtDBus.QtTypeName.In3" value="QList<qint32>"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.In4" value="QList<QGeoSatelliteInfo>"/> + </signal> + </interface> +</node> diff --git a/src/plugins/position/geoclue/org.freedesktop.Geoclue.Velocity.xml b/src/plugins/position/geoclue/org.freedesktop.Geoclue.Velocity.xml new file mode 100644 index 00000000..a1be122a --- /dev/null +++ b/src/plugins/position/geoclue/org.freedesktop.Geoclue.Velocity.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/"> + <interface name="org.freedesktop.Geoclue.Velocity"> + <method name="GetVelocity"> + <arg name="fields" type="i" direction="out" /> + <arg name="timestamp" type="i" direction="out" /> + <arg name="speed" type="d" direction="out" /> + <arg name="direction" type="d" direction="out" /> + <arg name="climb" type="d" direction="out" /> + </method> + <signal name="VelocityChanged"> + <arg name="fields" type="i" /> + <arg name="timestamp" type="i" /> + <arg name="speed" type="d" /> + <arg name="direction" type="d" /> + <arg name="climb" type="d" /> + </signal> + </interface> +</node> diff --git a/src/plugins/position/geoclue/org.freedesktop.Geoclue.xml b/src/plugins/position/geoclue/org.freedesktop.Geoclue.xml new file mode 100644 index 00000000..c9b6f635 --- /dev/null +++ b/src/plugins/position/geoclue/org.freedesktop.Geoclue.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.freedesktop.Geoclue"> + <method name="RemoveReference"> + </method> + <method name="AddReference"> + </method> + <method name="SetOptions"> + <arg name="options" type="a{sv}" direction="in"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/> + </method> + <method name="GetStatus"> + <arg name="status" type="i" direction="out"/> + </method> + <method name="GetProviderInfo"> + <arg name="name" type="s" direction="out"/> + <arg name="description" type="s" direction="out"/> + </method> + <signal name="StatusChanged"> + <arg name="status" type="i"/> + </signal> + </interface> +</node> diff --git a/src/plugins/position/geoclue/plugin-satellite.json b/src/plugins/position/geoclue/plugin-satellite.json deleted file mode 100644 index 59e190f1..00000000 --- a/src/plugins/position/geoclue/plugin-satellite.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "Keys": ["geoclue"], - "Provider": "geoclue", - "Position": true, - "Satellite": true, - "Priority": 1000 -} diff --git a/src/plugins/position/geoclue/plugin.json b/src/plugins/position/geoclue/plugin.json index cac7345b..82f8afc6 100644 --- a/src/plugins/position/geoclue/plugin.json +++ b/src/plugins/position/geoclue/plugin.json @@ -2,7 +2,8 @@ "Keys": ["geoclue"], "Provider": "geoclue", "Position": true, - "Satellite": false, + "Satellite": true, "Monitor": false, - "Priority": 1000 + "Priority": 999, + "Testable": false } diff --git a/src/plugins/position/geoclue/qgeocluemaster.cpp b/src/plugins/position/geoclue/qgeocluemaster.cpp index 7c340ba7..b7f4c6a3 100644 --- a/src/plugins/position/geoclue/qgeocluemaster.cpp +++ b/src/plugins/position/geoclue/qgeocluemaster.cpp @@ -33,94 +33,85 @@ #include "qgeocluemaster.h" -#include <QtCore/QByteArray> -#include <QtCore/QMetaMethod> +#include <master_interface.h> +#include <geoclue_interface.h> +#include <masterclient_interface.h> -QT_BEGIN_NAMESPACE - -namespace -{ - -void position_provider_changed(GeoclueMasterClient *client, char *name, char *description, - char *service, char *path, QObject *handler) -{ - Q_UNUSED(client) - Q_UNUSED(name) - Q_UNUSED(description) +#include <QtCore/QLoggingCategory> - const QByteArray pService = QByteArray(service); - const QByteArray pPath = QByteArray(path); +Q_DECLARE_LOGGING_CATEGORY(lcPositioningGeoclue) - QMetaObject::invokeMethod(handler, "positionProviderChanged", Qt::QueuedConnection, - Q_ARG(QByteArray, pService), Q_ARG(QByteArray, pPath)); -} - -} +QT_BEGIN_NAMESPACE -QGeoclueMaster::QGeoclueMaster(QObject *handler) -: m_client(0), m_masterPosition(0), m_handler(handler) +QGeoclueMaster::QGeoclueMaster(QObject *parent) +: QObject(parent), m_master(0), m_provider(0), m_client(0) { -#if !defined(GLIB_VERSION_2_36) - g_type_init(); -#endif } QGeoclueMaster::~QGeoclueMaster() { releaseMasterClient(); + + delete m_master; } bool QGeoclueMaster::hasMasterClient() const { - return m_client && m_masterPosition; + return m_client; } -bool QGeoclueMaster::createMasterClient(GeoclueAccuracyLevel accuracy, GeoclueResourceFlags resourceFlags) +bool QGeoclueMaster::createMasterClient(Accuracy::Level accuracyLevel, ResourceFlags resourceFlags) { - Q_ASSERT(!m_client && !m_masterPosition); + Q_ASSERT(!m_provider || !m_client); - GeoclueMaster *master = geoclue_master_get_default(); - if (!master) { - qCritical("QGeoclueMaster error creating GeoclueMaster"); + if (!m_master) { + qCDebug(lcPositioningGeoclue) << "creating master interface"; + m_master = new OrgFreedesktopGeoclueMasterInterface(QStringLiteral("org.freedesktop.Geoclue.Master"), + QStringLiteral("/org/freedesktop/Geoclue/Master"), + QDBusConnection::sessionBus()); + } + + qCDebug(lcPositioningGeoclue) << "creating client"; + QDBusPendingReply<QDBusObjectPath> client = m_master->Create(); + if (client.isError()) { + QDBusError e = client.error(); + qCritical("Failed to create Geoclue client interface. Geoclue error: %s", + qPrintable(e.errorString(e.type()))); return false; } - GError *error = 0; + qCDebug(lcPositioningGeoclue) << "Geoclue client path:" << client.value().path(); - m_client = geoclue_master_create_client(master, 0, &error); - g_object_unref (master); + m_provider = new OrgFreedesktopGeoclueInterface(QStringLiteral("org.freedesktop.Geoclue.Master"), + client.value().path(), QDBusConnection::sessionBus()); + m_provider->AddReference(); - if (!m_client) { - qCritical("QGeoclueMaster error creating GeoclueMasterClient."); - if (error) { - qCritical("Geoclue error: %s", error->message); - g_error_free(error); - } - return false; - } + m_client = new OrgFreedesktopGeoclueMasterClientInterface(QStringLiteral("org.freedesktop.Geoclue.Master"), + client.value().path(), + QDBusConnection::sessionBus()); + + connect(m_client, SIGNAL(PositionProviderChanged(QString,QString,QString,QString)), + this, SIGNAL(positionProviderChanged(QString,QString,QString,QString))); - g_signal_connect(G_OBJECT(m_client), "position-provider-changed", - G_CALLBACK(position_provider_changed), m_handler); - - if (!geoclue_master_client_set_requirements(m_client, accuracy, 0, true, - resourceFlags, &error)) { - qCritical("QGeoclueMaster geoclue set_requirements failed."); - if (error) { - qCritical ("Geoclue error: %s", error->message); - g_error_free (error); - } - g_object_unref(m_client); - m_client = 0; + QDBusPendingReply<> reply = m_client->SetRequirements(accuracyLevel, 0, true, resourceFlags); + if (reply.isError()) { + QDBusError e = reply.error(); + qCritical("Failed to set Geoclue positioning requirements. Geoclue error: %s", + qPrintable(e.errorString(e.type()))); + + releaseMasterClient(); return false; } // Need to create the master position interface even though it will not be used, otherwise // GetPositionProvider always returns empty strings. - m_masterPosition = geoclue_master_client_create_position(m_client, 0); - if (!m_masterPosition) { - qCritical("QGeoclueMaster failed to get master position object"); - g_object_unref(m_client); - m_client = 0; + reply = m_client->PositionStart(); + if (reply.isError()) { + QDBusError e = reply.error(); + qCritical("Failed to start positioning. Geoclue error: %s", + qPrintable(e.errorString(e.type()))); + + releaseMasterClient(); return false; } @@ -129,16 +120,12 @@ bool QGeoclueMaster::createMasterClient(GeoclueAccuracyLevel accuracy, GeoclueRe void QGeoclueMaster::releaseMasterClient() { - if (m_masterPosition) { - g_object_unref(m_masterPosition); - m_masterPosition = 0; - } - if (m_client) { - g_signal_handlers_disconnect_by_func(G_OBJECT(m_client), (void *)position_provider_changed, - m_handler); - g_object_unref(m_client); - m_client = 0; - } + if (m_provider) + m_provider->RemoveReference(); + delete m_provider; + m_provider = 0; + delete m_client; + m_client = 0; } QT_END_NAMESPACE diff --git a/src/plugins/position/geoclue/qgeocluemaster.h b/src/plugins/position/geoclue/qgeocluemaster.h index 0451f812..83c1eb94 100644 --- a/src/plugins/position/geoclue/qgeocluemaster.h +++ b/src/plugins/position/geoclue/qgeocluemaster.h @@ -34,29 +34,51 @@ #ifndef QGEOCLUEMASTER_H #define QGEOCLUEMASTER_H +#include "geocluetypes.h" + #include <QtCore/QObject> -#include <geoclue/geoclue-master.h> +class OrgFreedesktopGeoclueMasterInterface; +class OrgFreedesktopGeoclueInterface; +class OrgFreedesktopGeoclueMasterClientInterface; QT_BEGIN_NAMESPACE -class QGeoclueMaster +class QGeoclueMaster : public QObject { + Q_OBJECT + public: - QGeoclueMaster(QObject *handler); - virtual ~QGeoclueMaster(); + QGeoclueMaster(QObject *parent = 0); + ~QGeoclueMaster(); + + enum ResourceFlag + { + ResourceNone = 0, + ResourceNetwork = 1 << 0, + ResourceCell = 1 << 1, + ResourceGps = 1 << 2, + ResourceAll = (1 << 10) - 1 + }; + + Q_DECLARE_FLAGS(ResourceFlags, ResourceFlag) bool hasMasterClient() const; - bool createMasterClient(GeoclueAccuracyLevel accuracy, GeoclueResourceFlags resourceFlags); + bool createMasterClient(Accuracy::Level accuracyLevel, ResourceFlags resourceFlags); void releaseMasterClient(); -private: - GeoclueMasterClient *m_client; - GeocluePosition *m_masterPosition; +signals: + void positionProviderChanged(const QString &name, const QString &description, + const QString &service, const QString &path); - QObject *m_handler; +private: + OrgFreedesktopGeoclueMasterInterface *m_master; + OrgFreedesktopGeoclueInterface *m_provider; + OrgFreedesktopGeoclueMasterClientInterface *m_client; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QGeoclueMaster::ResourceFlags) + QT_END_NAMESPACE #endif // QGEOCLUEMASTER_H diff --git a/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster.cpp b/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster.cpp index fe5b048e..5311e18f 100644 --- a/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster.cpp +++ b/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster.cpp @@ -33,7 +33,11 @@ ** ****************************************************************************/ -#include "qgeopositioninfosource_geocluemaster_p.h" +#include "qgeopositioninfosource_geocluemaster.h" + +#include <geoclue_interface.h> +#include <position_interface.h> +#include <velocity_interface.h> #include <QtCore/QDateTime> #include <QtCore/QFile> @@ -41,64 +45,22 @@ #include <QtCore/QStandardPaths> #include <QtCore/QVariantMap> #include <QtCore/QtNumeric> - -#ifdef Q_LOCATION_GEOCLUE_DEBUG -#include <QDebug> -#endif - -#include <dbus/dbus-glib.h> +#include <QtCore/QLoggingCategory> +#include <QtDBus/QDBusMetaType> #ifndef QT_NO_DATASTREAM #include <QtCore/QDataStream> #endif -QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcPositioningGeoclue) #define MINIMUM_UPDATE_INTERVAL 1000 #define UPDATE_TIMEOUT_COLD_START 120000 -namespace -{ - -void position_changed(GeocluePosition *position, GeocluePositionFields fields, int timestamp, - double latitude, double longitude, double altitude, - GeoclueAccuracy *accuracy, QGeoPositionInfoSourceGeoclueMaster *master) -{ - Q_UNUSED(position) - - if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE && fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) - master->updatePosition(fields, timestamp, latitude, longitude, altitude, accuracy); - else - master->regularUpdateFailed(); -} - -void velocity_changed(GeoclueVelocity *velocity, GeoclueVelocityFields fields, int timestamp, - double speed, double direction, double climb, - QGeoPositionInfoSourceGeoclueMaster *master) -{ - Q_UNUSED(velocity) - - if (fields == GEOCLUE_VELOCITY_FIELDS_NONE) - master->velocityUpdateFailed(); - else - master->velocityUpdateSucceeded(fields, timestamp, speed, direction, climb); -} +QT_BEGIN_NAMESPACE -void position_callback(GeocluePosition *pos, GeocluePositionFields fields, int timestamp, - double latitude, double longitude, double altitude, - GeoclueAccuracy *accuracy, GError *error, gpointer userdata) +namespace { - Q_UNUSED(pos) - - if (error) - g_error_free(error); - - QGeoPositionInfoSourceGeoclueMaster *master = - static_cast<QGeoPositionInfoSourceGeoclueMaster *>(userdata); - - if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE && fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) - master->updatePosition(fields, timestamp, latitude, longitude, altitude, accuracy); -} double knotsToMetersPerSecond(double knots) { @@ -108,11 +70,13 @@ double knotsToMetersPerSecond(double knots) } QGeoPositionInfoSourceGeoclueMaster::QGeoPositionInfoSourceGeoclueMaster(QObject *parent) -: QGeoPositionInfoSource(parent), QGeoclueMaster(this), m_pos(0), m_vel(0), - m_lastVelocityIsFresh(false), m_regularUpdateTimedOut(false), m_lastVelocity(qQNaN()), +: QGeoPositionInfoSource(parent), m_master(new QGeoclueMaster(this)), m_provider(0), m_pos(0), + m_vel(0), m_lastVelocityIsFresh(false), m_regularUpdateTimedOut(false), m_lastVelocity(qQNaN()), m_lastDirection(qQNaN()), m_lastClimb(qQNaN()), m_lastPositionFromSatellite(false), - m_methods(AllPositioningMethods), m_running(false), m_error(NoError) + m_running(false), m_error(NoError) { + qDBusRegisterMetaType<Accuracy>(); + #ifndef QT_NO_DATASTREAM // Load the last known location QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + @@ -123,8 +87,11 @@ QGeoPositionInfoSourceGeoclueMaster::QGeoPositionInfoSourceGeoclueMaster(QObject } #endif + connect(m_master, SIGNAL(positionProviderChanged(QString,QString,QString,QString)), + this, SLOT(positionProviderChanged(QString,QString,QString,QString))); + m_requestTimer.setSingleShot(true); - QObject::connect(&m_requestTimer, SIGNAL(timeout()), this, SLOT(requestUpdateTimeout())); + connect(&m_requestTimer, SIGNAL(timeout()), this, SLOT(requestUpdateTimeout())); setPreferredPositioningMethods(AllPositioningMethods); } @@ -144,54 +111,12 @@ QGeoPositionInfoSourceGeoclueMaster::~QGeoPositionInfoSourceGeoclueMaster() } #endif - if (m_pos) - g_object_unref (m_pos); - if (m_vel) - g_object_unref(m_vel); -} - -void QGeoPositionInfoSourceGeoclueMaster::velocityUpdateFailed() -{ -#ifdef Q_LOCATION_GEOCLUE_DEBUG - qDebug() << "QGeoPositionInfoSourceGeoclueMaster velocity update failed."; -#endif - // Set the velocitydata non-fresh. - m_lastVelocityIsFresh = false; -} - -void QGeoPositionInfoSourceGeoclueMaster::velocityUpdateSucceeded(GeoclueVelocityFields fields, - int timestamp, double speed, - double direction, double climb) -{ - Q_UNUSED(timestamp); - -#ifdef Q_LOCATION_GEOCLUE_DEBUG - qDebug() << "QGeoPositionInfoSourceGeoclueMaster velocity update succeeded, speed: " << speed; -#endif - // Store the velocity and mark it as fresh. Simple but hopefully adequate. - if (fields & GEOCLUE_VELOCITY_FIELDS_SPEED) - m_lastVelocity = knotsToMetersPerSecond(speed); - else - m_lastVelocity = qQNaN(); - - if (fields & GEOCLUE_VELOCITY_FIELDS_DIRECTION) - m_lastDirection = direction; - else - m_lastDirection = qQNaN(); - - if (fields & GEOCLUE_VELOCITY_FIELDS_CLIMB) - m_lastClimb = climb; - else - m_lastClimb = qQNaN(); - - m_lastVelocityIsFresh = true; + cleanupPositionSource(); } -void QGeoPositionInfoSourceGeoclueMaster::regularUpdateFailed() +void QGeoPositionInfoSourceGeoclueMaster::positionUpdateFailed() { -#ifdef Q_LOCATION_GEOCLUE_DEBUG - qDebug() << "QGeoPositionInfoSourceGeoclueMaster regular update failed."; -#endif + qCDebug(lcPositioningGeoclue) << "position update failed."; m_lastVelocityIsFresh = false; if (m_running && !m_regularUpdateTimedOut) { @@ -200,33 +125,25 @@ void QGeoPositionInfoSourceGeoclueMaster::regularUpdateFailed() } } -void QGeoPositionInfoSourceGeoclueMaster::updatePosition(GeocluePositionFields fields, - int timestamp, double latitude, - double longitude, double altitude, - GeoclueAccuracy *accuracy) +void QGeoPositionInfoSourceGeoclueMaster::updatePosition(PositionFields fields, int timestamp, + double latitude, double longitude, + double altitude, Accuracy accuracy) { if (m_requestTimer.isActive()) m_requestTimer.stop(); QGeoCoordinate coordinate(latitude, longitude); - if (fields & GEOCLUE_POSITION_FIELDS_ALTITUDE) + if (fields & Altitude) coordinate.setAltitude(altitude); m_lastPosition = QGeoPositionInfo(coordinate, QDateTime::fromTime_t(timestamp)); - if (accuracy) { - double horizontalAccuracy = qQNaN(); - double verticalAccuracy = qQNaN(); - GeoclueAccuracyLevel accuracyLevel = GEOCLUE_ACCURACY_LEVEL_NONE; - geoclue_accuracy_get_details(accuracy, &accuracyLevel, &horizontalAccuracy, &verticalAccuracy); - - m_lastPositionFromSatellite = accuracyLevel & GEOCLUE_ACCURACY_LEVEL_DETAILED; + m_lastPositionFromSatellite = accuracy.level() == Accuracy::Detailed; - if (!qIsNaN(horizontalAccuracy)) - m_lastPosition.setAttribute(QGeoPositionInfo::HorizontalAccuracy, horizontalAccuracy); - if (!qIsNaN(verticalAccuracy)) - m_lastPosition.setAttribute(QGeoPositionInfo::VerticalAccuracy, verticalAccuracy); - } + if (!qIsNaN(accuracy.horizontal())) + m_lastPosition.setAttribute(QGeoPositionInfo::HorizontalAccuracy, accuracy.horizontal()); + if (!qIsNaN(accuracy.vertical())) + m_lastPosition.setAttribute(QGeoPositionInfo::VerticalAccuracy, accuracy.vertical()); if (m_lastVelocityIsFresh) { if (!qIsNaN(m_lastVelocity)) @@ -242,80 +159,61 @@ void QGeoPositionInfoSourceGeoclueMaster::updatePosition(GeocluePositionFields f emit positionUpdated(m_lastPosition); -#ifdef Q_LOCATION_GEOCLUE_DEBUG - qDebug() << "Lat, lon, alt, speed:" - << m_lastPosition.coordinate().latitude() - << m_lastPosition.coordinate().longitude() - << m_lastPosition.coordinate().altitude() - << m_lastPosition.attribute(QGeoPositionInfo::GroundSpeed); -#endif + qCDebug(lcPositioningGeoclue) << m_lastPosition; // Only stop positioning if regular updates not active. if (!m_running) { cleanupPositionSource(); - releaseMasterClient(); + m_master->releaseMasterClient(); } } +void QGeoPositionInfoSourceGeoclueMaster::velocityUpdateFailed() +{ + qCDebug(lcPositioningGeoclue) << "velocity update failed."; + + // Set the velocitydata non-fresh. + m_lastVelocityIsFresh = false; +} + +void QGeoPositionInfoSourceGeoclueMaster::updateVelocity(VelocityFields fields, int timestamp, + double speed, double direction, + double climb) +{ + Q_UNUSED(timestamp) + + // Store the velocity and mark it as fresh. Simple but hopefully adequate. + m_lastVelocity = (fields & Speed) ? knotsToMetersPerSecond(speed) : qQNaN(); + m_lastDirection = (fields & Direction) ? direction : qQNaN(); + m_lastClimb = (fields & Climb) ? climb : qQNaN(); + m_lastVelocityIsFresh = true; + + qCDebug(lcPositioningGeoclue) << m_lastVelocity << m_lastDirection << m_lastClimb; +} + void QGeoPositionInfoSourceGeoclueMaster::cleanupPositionSource() { - if (m_pos) { - g_object_unref(m_pos); - m_pos = 0; - } - if (m_vel) { - g_object_unref(m_vel); - m_vel = 0; - } + qCDebug(lcPositioningGeoclue) << "cleaning up position source"; + + if (m_provider) + m_provider->RemoveReference(); + delete m_provider; + m_provider = 0; + delete m_pos; + m_pos = 0; + delete m_vel; + m_vel = 0; } void QGeoPositionInfoSourceGeoclueMaster::setOptions() { - if (!m_pos) + if (!m_provider) return; QVariantMap options; options.insert(QStringLiteral("UpdateInterval"), updateInterval()); - GHashTable *gOptions = g_hash_table_new(g_str_hash, g_str_equal); - - for (QVariantMap::ConstIterator i = options.constBegin(); i != options.constEnd(); ++i) { - char *key = qstrdup(i.key().toUtf8().constData()); - - const QVariant v = i.value(); - - GValue *value = new GValue; - memset(value, 0, sizeof(*value)); - - switch (v.userType()) { - case QMetaType::QString: - g_value_init(value, G_TYPE_STRING); - g_value_set_string(value, v.toString().toUtf8().constData()); - break; - case QMetaType::Int: - g_value_init(value, G_TYPE_INT); - g_value_set_int(value, v.toInt()); - break; - default: - qWarning("Unexpected type %d %s", v.userType(), v.typeName()); - } - - g_hash_table_insert(gOptions, key, value); - } - - geoclue_provider_set_options(GEOCLUE_PROVIDER(m_pos), gOptions, 0); - - GHashTableIter iter; - char *key; - GValue *value; - - g_hash_table_iter_init(&iter, gOptions); - while (g_hash_table_iter_next(&iter, reinterpret_cast<void **>(&key), reinterpret_cast<void **>(&value))) { - delete[] key; - delete value; - } - - g_hash_table_destroy(gOptions); + m_provider->SetOptions(options); } void QGeoPositionInfoSourceGeoclueMaster::setUpdateInterval(int msec) @@ -331,23 +229,21 @@ void QGeoPositionInfoSourceGeoclueMaster::setPreferredPositioningMethods(Positio if (previousPreferredPositioningMethods == preferredPositioningMethods()) return; -#ifdef Q_LOCATION_GEOCLUE_DEBUG - qDebug() << "QGeoPositionInfoSourceGeoclueMaster requested to set methods to" << methods - << ", and set them to:" << preferredPositioningMethods(); -#endif + qCDebug(lcPositioningGeoclue) << "requested to set methods to" << methods + << ", and set them to:" << preferredPositioningMethods(); m_lastVelocityIsFresh = false; m_regularUpdateTimedOut = false; // Don't start Geoclue provider until necessary. Don't currently have a master client, no need // no recreate one. - if (!hasMasterClient()) + if (!m_master->hasMasterClient()) return; // Free potential previous sources, because new requirements can't be set for the client // (creating a position object after changing requirements seems to fail). cleanupPositionSource(); - releaseMasterClient(); + m_master->releaseMasterClient(); // Restart Geoclue provider with new requirements. configurePositionSource(); @@ -356,34 +252,30 @@ void QGeoPositionInfoSourceGeoclueMaster::setPreferredPositioningMethods(Positio QGeoPositionInfo QGeoPositionInfoSourceGeoclueMaster::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const { - if (fromSatellitePositioningMethodsOnly) { - if (m_lastPositionFromSatellite) - return m_lastPosition; - else - return QGeoPositionInfo(); - } + if (fromSatellitePositioningMethodsOnly && !m_lastPositionFromSatellite) + return QGeoPositionInfo(); + return m_lastPosition; } QGeoPositionInfoSourceGeoclueMaster::PositioningMethods QGeoPositionInfoSourceGeoclueMaster::supportedPositioningMethods() const { - // There is no really knowing which methods the GeoClue master supports. return AllPositioningMethods; } void QGeoPositionInfoSourceGeoclueMaster::startUpdates() { if (m_running) { -#ifdef Q_LOCATION_GEOCLUE_DEBUG - qDebug() << "QGeoPositionInfoSourceGeoclueMaster already running"; -#endif + qCDebug(lcPositioningGeoclue) << "already running."; return; } m_running = true; + qCDebug(lcPositioningGeoclue) << "starting updates"; + // Start Geoclue provider. - if (!hasMasterClient()) { + if (!m_master->hasMasterClient()) { configurePositionSource(); setOptions(); } @@ -402,20 +294,29 @@ int QGeoPositionInfoSourceGeoclueMaster::minimumUpdateInterval() const void QGeoPositionInfoSourceGeoclueMaster::stopUpdates() { - if (!m_running) + if (!m_running) { + qCDebug(lcPositioningGeoclue) << "already stopped."; return; + } - if (m_pos) - g_signal_handlers_disconnect_by_func(G_OBJECT(m_pos), (void *)position_changed, this); - if (m_vel) - g_signal_handlers_disconnect_by_func(G_OBJECT(m_vel), (void *)velocity_changed, this); + qCDebug(lcPositioningGeoclue) << "stopping updates"; + + if (m_pos) { + disconnect(m_pos, SIGNAL(PositionChanged(qint32,qint32,double,double,double,Accuracy)), + this, SLOT(positionChanged(qint32,qint32,double,double,double,Accuracy))); + } + + if (m_vel) { + disconnect(m_vel, SIGNAL(VelocityChanged(qint32,qint32,double,double,double)), + this, SLOT(velocityChanged(qint32,qint32,double,double,double))); + } m_running = false; // Only stop positioning if single update not requested. if (!m_requestTimer.isActive()) { cleanupPositionSource(); - releaseMasterClient(); + m_master->releaseMasterClient(); } } @@ -426,13 +327,11 @@ void QGeoPositionInfoSourceGeoclueMaster::requestUpdate(int timeout) return; } if (m_requestTimer.isActive()) { -#ifdef Q_LOCATION_GEOCLUE_DEBUG - qDebug() << "QGeoPositionInfoSourceGeoclueMaster request timer was active, ignoring startUpdates."; -#endif + qCDebug(lcPositioningGeoclue) << "request timer was active, ignoring startUpdates."; return; } - if (!hasMasterClient()) { + if (!m_master->hasMasterClient()) { configurePositionSource(); setOptions(); } @@ -442,85 +341,141 @@ void QGeoPositionInfoSourceGeoclueMaster::requestUpdate(int timeout) // for whole cold start time. m_requestTimer.start(timeout ? timeout : UPDATE_TIMEOUT_COLD_START); - if (m_pos) - geoclue_position_get_position_async(m_pos, position_callback, this); + if (m_pos) { + QDBusPendingReply<qint32, qint32, double, double, double, Accuracy> reply = m_pos->GetPosition(); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(getPositionFinished(QDBusPendingCallWatcher*))); + } +} + +void QGeoPositionInfoSourceGeoclueMaster::positionProviderChanged(const QString &name, + const QString &description, + const QString &service, + const QString &path) +{ + Q_UNUSED(name) + Q_UNUSED(description) + + cleanupPositionSource(); + + if (service.isEmpty() || path.isEmpty()) { + if (!m_regularUpdateTimedOut) { + m_regularUpdateTimedOut = true; + emit updateTimeout(); + } + return; + } + + qCDebug(lcPositioningGeoclue) << "position provider changed to" << name; + + m_provider = new OrgFreedesktopGeoclueInterface(service, path, QDBusConnection::sessionBus()); + m_provider->AddReference(); + + m_pos = new OrgFreedesktopGeocluePositionInterface(service, path, QDBusConnection::sessionBus()); + + if (m_running) { + connect(m_pos, SIGNAL(PositionChanged(qint32,qint32,double,double,double,Accuracy)), + this, SLOT(positionChanged(qint32,qint32,double,double,double,Accuracy))); + } + + // Get the current position immediately. + QDBusPendingReply<qint32, qint32, double, double, double, Accuracy> reply = m_pos->GetPosition(); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(getPositionFinished(QDBusPendingCallWatcher*))); + + setOptions(); + + m_vel = new OrgFreedesktopGeoclueVelocityInterface(service, path, QDBusConnection::sessionBus()); + if (m_vel->isValid() && m_running) { + connect(m_vel, SIGNAL(VelocityChanged(qint32,qint32,double,double,double)), + this, SLOT(velocityChanged(qint32,qint32,double,double,double))); + } } void QGeoPositionInfoSourceGeoclueMaster::requestUpdateTimeout() { -#ifdef Q_LOCATION_GEOCLUE_DEBUG - qDebug() << "QGeoPositionInfoSourceGeoclueMaster requestUpdate timeout occurred."; -#endif + qCDebug(lcPositioningGeoclue) << "request update timeout occurred."; + // If we end up here, there has not been valid position update. emit updateTimeout(); // Only stop positioning if regular updates not active. if (!m_running) { cleanupPositionSource(); - releaseMasterClient(); + m_master->releaseMasterClient(); } } -void QGeoPositionInfoSourceGeoclueMaster::positionProviderChanged(const QByteArray &service, const QByteArray &path) +void QGeoPositionInfoSourceGeoclueMaster::getPositionFinished(QDBusPendingCallWatcher *watcher) { - if (m_pos) - cleanupPositionSource(); + QDBusPendingReply<qint32, qint32, double, double, double, Accuracy> reply = *watcher; + watcher->deleteLater(); - if (service.isEmpty() || path.isEmpty()) { - if (!m_regularUpdateTimedOut) { - m_regularUpdateTimedOut = true; - emit updateTimeout(); - } + if (reply.isError()) return; - } - m_pos = geoclue_position_new(service.constData(), path.constData()); - if (m_pos) { - if (m_running) { - g_signal_connect(G_OBJECT(m_pos), "position-changed", - G_CALLBACK(position_changed), this); - } + PositionFields fields = static_cast<PositionFields>(reply.argumentAt<0>()); - // Get the current position immediately. - geoclue_position_get_position_async(m_pos, position_callback, this); - setOptions(); + qCDebug(lcPositioningGeoclue) << "got position update with fields" << int(fields); - m_vel = geoclue_velocity_new(service.constData(), path.constData()); - if (m_vel && m_running) { - g_signal_connect(G_OBJECT(m_vel), "velocity-changed", - G_CALLBACK(velocity_changed), this); - } + if (fields & Latitude && fields & Longitude) { + qint32 timestamp = reply.argumentAt<1>(); + double latitude = reply.argumentAt<2>(); + double longitude = reply.argumentAt<3>(); + double altitude = reply.argumentAt<4>(); + Accuracy accuracy = reply.argumentAt<5>(); + updatePosition(fields, timestamp, latitude, longitude, altitude, accuracy); } } +void QGeoPositionInfoSourceGeoclueMaster::positionChanged(qint32 fields, qint32 timestamp, double latitude, double longitude, double altitude, const Accuracy &accuracy) +{ + PositionFields pFields = static_cast<PositionFields>(fields); + + qCDebug(lcPositioningGeoclue) << "position changed with fields" << fields; + + if (pFields & Latitude && pFields & Longitude) + updatePosition(pFields, timestamp, latitude, longitude, altitude, accuracy); + else + positionUpdateFailed(); +} + +void QGeoPositionInfoSourceGeoclueMaster::velocityChanged(qint32 fields, qint32 timestamp, double speed, double direction, double climb) +{ + VelocityFields vFields = static_cast<VelocityFields>(fields); + + if (vFields == NoVelocityFields) + velocityUpdateFailed(); + else + updateVelocity(vFields, timestamp, speed, direction, climb); +} + void QGeoPositionInfoSourceGeoclueMaster::configurePositionSource() { - GeoclueAccuracyLevel accuracy; - GeoclueResourceFlags resourceFlags; + qCDebug(lcPositioningGeoclue); + + bool created = false; switch (preferredPositioningMethods()) { case SatellitePositioningMethods: - accuracy = GEOCLUE_ACCURACY_LEVEL_DETAILED; - resourceFlags = GEOCLUE_RESOURCE_GPS; + created = m_master->createMasterClient(Accuracy::Detailed, QGeoclueMaster::ResourceGps); break; case NonSatellitePositioningMethods: - accuracy = GEOCLUE_ACCURACY_LEVEL_NONE; - resourceFlags = GeoclueResourceFlags(GEOCLUE_RESOURCE_CELL | GEOCLUE_RESOURCE_NETWORK); + created = m_master->createMasterClient(Accuracy::None, QGeoclueMaster::ResourceCell | QGeoclueMaster::ResourceNetwork); break; case AllPositioningMethods: - accuracy = GEOCLUE_ACCURACY_LEVEL_NONE; - resourceFlags = GEOCLUE_RESOURCE_ALL; + created = m_master->createMasterClient(Accuracy::None, QGeoclueMaster::ResourceAll); break; default: - qWarning("GeoPositionInfoSourceGeoClueMaster unknown preferred method."); + qWarning("QGeoPositionInfoSourceGeoclueMaster unknown preferred method."); m_error = UnknownSourceError; emit QGeoPositionInfoSource::error(m_error); return; } - if (createMasterClient(accuracy, resourceFlags)) { - m_error = NoError; - } else { + if (!created) { m_error = UnknownSourceError; emit QGeoPositionInfoSource::error(m_error); } @@ -531,6 +486,4 @@ QGeoPositionInfoSource::Error QGeoPositionInfoSourceGeoclueMaster::error() const return m_error; } -#include "moc_qgeopositioninfosource_geocluemaster_p.cpp" - QT_END_NAMESPACE diff --git a/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster_p.h b/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster.h index 2dcd3824..09f6812c 100644 --- a/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster_p.h +++ b/src/plugins/position/geoclue/qgeopositioninfosource_geocluemaster.h @@ -36,33 +36,26 @@ #ifndef QGEOPOSITIONINFOSOURCE_GEOCLUEMASTER_H #define QGEOPOSITIONINFOSOURCE_GEOCLUEMASTER_H -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - #include "qgeocluemaster.h" +#include "geocluetypes.h" -#include <qgeopositioninfosource.h> -#include <geoclue/geoclue-velocity.h> -#include <QTimer> +#include <QtCore/QTimer> +#include <QtPositioning/QGeoPositionInfoSource> -//#define Q_LOCATION_GEOCLUE_DEBUG +class OrgFreedesktopGeoclueInterface; +class OrgFreedesktopGeocluePositionInterface; +class OrgFreedesktopGeoclueVelocityInterface; QT_BEGIN_NAMESPACE -class QGeoPositionInfoSourceGeoclueMaster : public QGeoPositionInfoSource, public QGeoclueMaster +class QDBusPendingCallWatcher; + +class QGeoPositionInfoSourceGeoclueMaster : public QGeoPositionInfoSource { Q_OBJECT public: - QGeoPositionInfoSourceGeoclueMaster(QObject *parent = 0); + explicit QGeoPositionInfoSourceGeoclueMaster(QObject *parent = 0); ~QGeoPositionInfoSourceGeoclueMaster(); // From QGeoPositionInfoSource @@ -72,34 +65,61 @@ public: void setPreferredPositioningMethods(PositioningMethods methods); int minimumUpdateInterval() const; - void updatePosition(GeocluePositionFields fields, int timestamp, double latitude, - double longitude, double altitude, GeoclueAccuracy *accuracy); - - void regularUpdateFailed(); - - void velocityUpdateFailed(); - void velocityUpdateSucceeded(GeoclueVelocityFields fields, int timestamp, double speed, - double direction, double climb); - Error error() const; -public slots: - virtual void startUpdates(); - virtual void stopUpdates(); - virtual void requestUpdate(int timeout = 5000); + virtual void startUpdates() Q_DECL_OVERRIDE; + virtual void stopUpdates() Q_DECL_OVERRIDE; + virtual void requestUpdate(int timeout = 5000) Q_DECL_OVERRIDE; private slots: + void positionProviderChanged(const QString &name, const QString &description, + const QString &service, const QString &path); void requestUpdateTimeout(); - void positionProviderChanged(const QByteArray &service, const QByteArray &path); + + void getPositionFinished(QDBusPendingCallWatcher *watcher); + void positionChanged(qint32 fields, qint32 timestamp, double latitude, double longitude, + double altitude, const Accuracy &accuracy); + void velocityChanged(qint32 fields, qint32 timestamp, double speed, double direction, + double climb); private: void configurePositionSource(); void cleanupPositionSource(); void setOptions(); + enum PositionField + { + NoPositionFields = 0, + Latitude = 1 << 0, + Longitude = 1 << 1, + Altitude = 1 << 2 + }; + Q_DECLARE_FLAGS(PositionFields, PositionField) + + void updatePosition(PositionFields fields, int timestamp, double latitude, + double longitude, double altitude, Accuracy accuracy); + void positionUpdateFailed(); + + enum VelocityField + { + NoVelocityFields = 0, + Speed = 1 << 0, + Direction = 1 << 1, + Climb = 1 << 2 + }; + Q_DECLARE_FLAGS(VelocityFields, VelocityField) + + void updateVelocity(VelocityFields fields, int timestamp, double speed, double direction, + double climb); + void velocityUpdateFailed(); + private: - GeocluePosition *m_pos; - GeoclueVelocity *m_vel; + QGeoclueMaster *m_master; + + OrgFreedesktopGeoclueInterface *m_provider; + OrgFreedesktopGeocluePositionInterface *m_pos; + OrgFreedesktopGeoclueVelocityInterface *m_vel; + QTimer m_requestTimer; bool m_lastVelocityIsFresh; bool m_regularUpdateTimedOut; @@ -108,7 +128,6 @@ private: double m_lastClimb; bool m_lastPositionFromSatellite; QGeoPositionInfo m_lastPosition; - PositioningMethods m_methods; bool m_running; QGeoPositionInfoSource::Error m_error; }; diff --git a/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.cpp b/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.cpp index a7c92678..05d96547 100644 --- a/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.cpp +++ b/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.cpp @@ -34,13 +34,17 @@ ****************************************************************************/ #include "qgeopositioninfosourcefactory_geoclue.h" -#include "qgeopositioninfosource_geocluemaster_p.h" -#ifdef HAS_SATELLITE +#include "qgeopositioninfosource_geocluemaster.h" #include "qgeosatelliteinfosource_geocluemaster.h" -#endif + +#include <QtCore/QLoggingCategory> Q_DECLARE_METATYPE(QGeoPositionInfo) +Q_LOGGING_CATEGORY(lcPositioningGeoclue, "qt.positioning.geoclue") + +QT_BEGIN_NAMESPACE + QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryGeoclue::positionInfoSource(QObject *parent) { qRegisterMetaType<QGeoPositionInfo>(); @@ -49,17 +53,13 @@ QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryGeoclue::positionInfoSource QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryGeoclue::satelliteInfoSource(QObject *parent) { -#ifdef HAS_SATELLITE return new QGeoSatelliteInfoSourceGeoclueMaster(parent); -#else - Q_UNUSED(parent) - - return 0; -#endif } QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryGeoclue::areaMonitor(QObject *parent) { - Q_UNUSED(parent); + Q_UNUSED(parent) return 0; } + +QT_END_NAMESPACE diff --git a/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.h b/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.h index fdd0675f..17da509e 100644 --- a/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.h +++ b/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.h @@ -36,28 +36,29 @@ #ifndef QGEOPOSITIONINFOSOURCEFACTORY_GEOCLUE_H #define QGEOPOSITIONINFOSOURCEFACTORY_GEOCLUE_H -#include <QObject> -#include <qgeopositioninfosourcefactory.h> +#include <QtCore/QObject> +#include <QtPositioning/QGeoPositionInfoSourceFactory> -#ifdef HAS_SATELLITE -#define PLUGIN_JSON "plugin-satellite.json" -#else -#define PLUGIN_JSON "plugin.json" -#endif +QT_BEGIN_NAMESPACE +/* + Qt Positioning plugin for Geoclue. This plugin supports Geoclue version 0.12.99. +*/ class QGeoPositionInfoSourceFactoryGeoclue : public QObject, public QGeoPositionInfoSourceFactory { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.qt.position.sourcefactory/5.0" - FILE PLUGIN_JSON) + FILE "plugin.json") Q_INTERFACES(QGeoPositionInfoSourceFactory) public: - QGeoPositionInfoSource *positionInfoSource(QObject *parent); - QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent); - QGeoAreaMonitorSource *areaMonitor(QObject *parent); + QGeoPositionInfoSource *positionInfoSource(QObject *parent) Q_DECL_OVERRIDE; + QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent) Q_DECL_OVERRIDE; + QGeoAreaMonitorSource *areaMonitor(QObject *parent) Q_DECL_OVERRIDE; }; +QT_END_NAMESPACE + #endif diff --git a/src/plugins/position/geoclue/qgeosatelliteinfosource_geocluemaster.cpp b/src/plugins/position/geoclue/qgeosatelliteinfosource_geocluemaster.cpp index 501a983c..8e646bff 100644 --- a/src/plugins/position/geoclue/qgeosatelliteinfosource_geocluemaster.cpp +++ b/src/plugins/position/geoclue/qgeosatelliteinfosource_geocluemaster.cpp @@ -33,122 +33,25 @@ #include "qgeosatelliteinfosource_geocluemaster.h" -#include <QtDBus/QDBusConnection> -#include <QtDBus/QDBusMessage> -#include <QtDBus/QDBusArgument> +#include <geoclue_interface.h> +#include <satellite_interface.h> -#define MINIMUM_UPDATE_INTERVAL 1000 - -QT_BEGIN_NAMESPACE - -namespace -{ - -void satellite_changed(GeoclueSatellite *satellite, int timestamp, int satellite_used, - int satellite_visible, GArray *used_prn, GPtrArray *sat_info, - gpointer userdata) -{ - Q_UNUSED(satellite) - - QGeoSatelliteInfoSourceGeoclueMaster *source = - static_cast<QGeoSatelliteInfoSourceGeoclueMaster *>(userdata); - - QList<int> usedPrns; - for (unsigned int i = 0; i < used_prn->len; ++i) - usedPrns.append(g_array_index(used_prn, int, i)); - - QList<QGeoSatelliteInfo> satInfos; - for (unsigned int i = 0; i < sat_info->len; ++i) { - GValueArray *a = static_cast<GValueArray *>(g_ptr_array_index(sat_info, i)); - - QGeoSatelliteInfo satInfo; - - satInfo.setSatelliteIdentifier(g_value_get_int(g_value_array_get_nth(a, 0))); - satInfo.setAttribute(QGeoSatelliteInfo::Elevation, - g_value_get_int(g_value_array_get_nth(a, 1))); - satInfo.setAttribute(QGeoSatelliteInfo::Azimuth, - g_value_get_int(g_value_array_get_nth(a, 2))); - satInfo.setSignalStrength(g_value_get_int(g_value_array_get_nth(a, 3))); - - satInfos.append(satInfo); - } - - source->satelliteChanged(timestamp, satellite_used, satellite_visible, usedPrns, satInfos); -} - -void satellite_callback(GeoclueSatellite *satellite, int timestamp, int satellite_used, - int satellite_visible, GArray *used_prn, GPtrArray *sat_info, - GError *error, gpointer userdata) -{ - Q_UNUSED(satellite) - - if (error) - g_error_free(error); - - QGeoSatelliteInfoSourceGeoclueMaster *source = - static_cast<QGeoSatelliteInfoSourceGeoclueMaster *>(userdata); +#include <QtCore/QLoggingCategory> +#include <QtDBus/QDBusPendingCallWatcher> - QList<int> usedPrns; - for (unsigned int i = 0; i < used_prn->len; ++i) - usedPrns.append(g_array_index(used_prn, int, i)); +Q_DECLARE_LOGGING_CATEGORY(lcPositioningGeoclue) - QList<QGeoSatelliteInfo> satInfos; - for (unsigned int i = 0; i < sat_info->len; ++i) { - GValueArray *a = static_cast<GValueArray *>(g_ptr_array_index(sat_info, i)); - - QGeoSatelliteInfo satInfo; - - satInfo.setSatelliteIdentifier(g_value_get_int(g_value_array_get_nth(a, 0))); - satInfo.setAttribute(QGeoSatelliteInfo::Elevation, - g_value_get_int(g_value_array_get_nth(a, 1))); - satInfo.setAttribute(QGeoSatelliteInfo::Azimuth, - g_value_get_int(g_value_array_get_nth(a, 2))); - satInfo.setSignalStrength(g_value_get_int(g_value_array_get_nth(a, 3))); - - satInfos.append(satInfo); - } - - source->requestUpdateFinished(timestamp, satellite_used, satellite_visible, usedPrns, satInfos); -} - -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, QGeoSatelliteInfo &si) -{ - int a; - - argument.beginStructure(); - argument >> a; - si.setSatelliteIdentifier(a); - argument >> a; - si.setAttribute(QGeoSatelliteInfo::Elevation, a); - argument >> a; - si.setAttribute(QGeoSatelliteInfo::Azimuth, a); - argument >> a; - si.setSignalStrength(a); - argument.endStructure(); - return argument; -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, QList<QGeoSatelliteInfo> &sis) -{ - sis.clear(); - - argument.beginArray(); - while (!argument.atEnd()) { - QGeoSatelliteInfo si; - argument >> si; - sis.append(si); - } - argument.endArray(); +#define MINIMUM_UPDATE_INTERVAL 1000 - return argument; -} +QT_BEGIN_NAMESPACE QGeoSatelliteInfoSourceGeoclueMaster::QGeoSatelliteInfoSourceGeoclueMaster(QObject *parent) -: QGeoSatelliteInfoSource(parent), QGeoclueMaster(this), m_sat(0), m_error(NoError), - m_satellitesChangedConnected(false), m_running(false) +: QGeoSatelliteInfoSource(parent), m_master(new QGeoclueMaster(this)), m_provider(0), m_sat(0), + m_error(NoError), m_satellitesChangedConnected(false), m_running(false) { + connect(m_master, SIGNAL(positionProviderChanged(QString,QString,QString,QString)), + this, SLOT(positionProviderChanged(QString,QString,QString,QString))); + m_requestTimer.setSingleShot(true); connect(&m_requestTimer, SIGNAL(timeout()), this, SLOT(requestUpdateTimeout())); } @@ -163,6 +66,14 @@ int QGeoSatelliteInfoSourceGeoclueMaster::minimumUpdateInterval() const return MINIMUM_UPDATE_INTERVAL; } +void QGeoSatelliteInfoSourceGeoclueMaster::setUpdateInterval(int msec) +{ + if (msec < 0 || (msec > 0 && msec < MINIMUM_UPDATE_INTERVAL)) + msec = MINIMUM_UPDATE_INTERVAL; + + QGeoSatelliteInfoSource::setUpdateInterval(msec); +} + QGeoSatelliteInfoSource::Error QGeoSatelliteInfoSourceGeoclueMaster::error() const { return m_error; @@ -176,14 +87,10 @@ void QGeoSatelliteInfoSourceGeoclueMaster::startUpdates() m_running = true; // Start Geoclue provider. - if (!hasMasterClient()) + if (!m_master->hasMasterClient()) configureSatelliteSource(); - // m_sat is likely to be invalid until Geoclue master selects a position provider. - if (!m_sat) - return; - - g_signal_connect(G_OBJECT(m_sat), "satellite-changed", G_CALLBACK(satellite_changed), this); + m_requestTimer.start(updateInterval()); } void QGeoSatelliteInfoSourceGeoclueMaster::stopUpdates() @@ -191,15 +98,17 @@ void QGeoSatelliteInfoSourceGeoclueMaster::stopUpdates() if (!m_running) return; - if (m_sat) - g_signal_handlers_disconnect_by_func(G_OBJECT(m_sat), gpointer(satellite_changed), this); + if (m_sat) { + disconnect(m_sat, SIGNAL(SatelliteChanged(qint32,qint32,qint32,QList<qint32>,QList<QGeoSatelliteInfo>)), + this, SLOT(satelliteChanged(qint32,qint32,qint32,QList<qint32>,QList<QGeoSatelliteInfo>))); + } m_running = false; // Only stop positioning if single update not requested. if (!m_requestTimer.isActive()) { cleanupSatelliteSource(); - releaseMasterClient(); + m_master->releaseMasterClient(); } } @@ -213,19 +122,24 @@ void QGeoSatelliteInfoSourceGeoclueMaster::requestUpdate(int timeout) if (m_requestTimer.isActive()) return; - if (!hasMasterClient()) + if (!m_master->hasMasterClient()) configureSatelliteSource(); m_requestTimer.start(qMax(timeout, minimumUpdateInterval())); - if (m_sat) - geoclue_satellite_get_satellite_async(m_sat, satellite_callback, this); + if (m_sat) { + QDBusPendingReply<qint32, qint32, qint32, QList<qint32>, QList<QGeoSatelliteInfo> > reply = + m_sat->GetSatellite(); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(getSatelliteFinished(QDBusPendingCallWatcher*))); + } } -void QGeoSatelliteInfoSourceGeoclueMaster::satelliteChanged(int timestamp, int satellitesUsed, - int satellitesVisible, - const QList<int> &usedPrn, - const QList<QGeoSatelliteInfo> &satInfos) +void QGeoSatelliteInfoSourceGeoclueMaster::updateSatelliteInfo(int timestamp, int satellitesUsed, + int satellitesVisible, + const QList<int> &usedPrn, + const QList<QGeoSatelliteInfo> &satInfos) { Q_UNUSED(timestamp) @@ -252,36 +166,57 @@ void QGeoSatelliteInfoSourceGeoclueMaster::satelliteChanged(int timestamp, int s m_inUse = inUse; emit satellitesInUseUpdated(m_inUse); -} -void QGeoSatelliteInfoSourceGeoclueMaster::requestUpdateFinished(int timestamp, int satellitesUsed, - int satellitesVisible, - const QList<int> &usedPrn, - const QList<QGeoSatelliteInfo> &satInfos) -{ - m_requestTimer.stop(); - satelliteChanged(timestamp, satellitesUsed, satellitesVisible, usedPrn, satInfos); + m_requestTimer.start(updateInterval()); } void QGeoSatelliteInfoSourceGeoclueMaster::requestUpdateTimeout() { // If we end up here, there has not been a valid satellite info update. - emit requestTimeout(); + if (m_running) { + m_inView.clear(); + m_inUse.clear(); + emit satellitesInViewUpdated(m_inView); + emit satellitesInUseUpdated(m_inUse); + } else { + emit requestTimeout(); - // Only stop satellite info if regular updates not active. - if (!m_running) { + // Only stop satellite info if regular updates not active. cleanupSatelliteSource(); - releaseMasterClient(); + m_master->releaseMasterClient(); } } -void QGeoSatelliteInfoSourceGeoclueMaster::positionProviderChanged(const QByteArray &service, const QByteArray &path) +void QGeoSatelliteInfoSourceGeoclueMaster::getSatelliteFinished(QDBusPendingCallWatcher *watcher) { - if (m_sat) - cleanupSatelliteSource(); + QDBusPendingReply<qint32, qint32, qint32, QList<qint32>, QList<QGeoSatelliteInfo> > reply = *watcher; + watcher->deleteLater(); + + if (reply.isError()) + return; + + m_requestTimer.stop(); + updateSatelliteInfo(reply.argumentAt<0>(), reply.argumentAt<1>(), reply.argumentAt<2>(), + reply.argumentAt<3>(), reply.argumentAt<4>()); +} + +void QGeoSatelliteInfoSourceGeoclueMaster::satelliteChanged(int timestamp, int satellitesUsed, int satellitesVisible, const QList<int> &usedPrn, const QList<QGeoSatelliteInfo> &satInfos) +{ + updateSatelliteInfo(timestamp, satellitesUsed, satellitesVisible, usedPrn, satInfos); +} - QByteArray providerService; - QByteArray providerPath; +void QGeoSatelliteInfoSourceGeoclueMaster::positionProviderChanged(const QString &name, + const QString &description, + const QString &service, + const QString &path) +{ + Q_UNUSED(name) + Q_UNUSED(description) + + cleanupSatelliteSource(); + + QString providerService; + QString providerPath; if (service.isEmpty() || path.isEmpty()) { // No valid position provider has been selected. This probably means that the GPS provider @@ -290,7 +225,7 @@ void QGeoSatelliteInfoSourceGeoclueMaster::positionProviderChanged(const QByteAr QDBusConnection conn = QDBusConnection::sessionBus(); conn.connect(QString(), QString(), QStringLiteral("org.freedesktop.Geoclue.Satellite"), QStringLiteral("SatelliteChanged"), this, - SLOT(satellitesChanged(QDBusMessage))); + SLOT(satelliteChanged(QDBusMessage))); m_satellitesChangedConnected = true; return; } @@ -300,7 +235,7 @@ void QGeoSatelliteInfoSourceGeoclueMaster::positionProviderChanged(const QByteAr conn.disconnect(QString(), QString(), QStringLiteral("org.freedesktop.Geoclue.Satellite"), QStringLiteral("SatelliteChanged"), this, - SLOT(satellitesChanged(QDBusMessage))); + SLOT(satelliteChanged(QDBusMessage))); m_satellitesChangedConnected = false; } @@ -314,17 +249,18 @@ void QGeoSatelliteInfoSourceGeoclueMaster::positionProviderChanged(const QByteAr return; } - m_sat = geoclue_satellite_new(providerService.constData(), providerPath.constData()); - if (!m_sat) { - m_error = AccessError; - emit QGeoSatelliteInfoSource::error(m_error); - return; - } + m_provider = new OrgFreedesktopGeoclueInterface(providerService, providerPath, QDBusConnection::sessionBus()); + m_provider->AddReference(); - g_signal_connect(G_OBJECT(m_sat), "satellite-changed", G_CALLBACK(satellite_changed), this); + m_sat = new OrgFreedesktopGeoclueSatelliteInterface(providerService, providerPath, QDBusConnection::sessionBus()); + + if (m_running) { + connect(m_sat, SIGNAL(SatelliteChanged(qint32,qint32,qint32,QList<qint32>,QList<QGeoSatelliteInfo>)), + this, SLOT(satelliteChanged(qint32,qint32,qint32,QList<qint32>,QList<QGeoSatelliteInfo>))); + } } -void QGeoSatelliteInfoSourceGeoclueMaster::satellitesChanged(const QDBusMessage &message) +void QGeoSatelliteInfoSourceGeoclueMaster::satelliteChanged(const QDBusMessage &message) { QVariantList arguments = message.arguments(); if (arguments.length() != 5) @@ -347,17 +283,22 @@ void QGeoSatelliteInfoSourceGeoclueMaster::satellitesChanged(const QDBusMessage satelliteChanged(timestamp, usedSatellites, visibleSatellites, usedPrn, satelliteInfos); } -bool QGeoSatelliteInfoSourceGeoclueMaster::configureSatelliteSource() +void QGeoSatelliteInfoSourceGeoclueMaster::configureSatelliteSource() { - return createMasterClient(GEOCLUE_ACCURACY_LEVEL_DETAILED, GEOCLUE_RESOURCE_GPS); + if (!m_master->createMasterClient(Accuracy::Detailed, QGeoclueMaster::ResourceGps)) { + m_error = UnknownSourceError; + emit QGeoSatelliteInfoSource::error(m_error); + } } void QGeoSatelliteInfoSourceGeoclueMaster::cleanupSatelliteSource() { - if (m_sat) { - g_object_unref(m_sat); - m_sat = 0; - } + if (m_provider) + m_provider->RemoveReference(); + delete m_provider; + m_provider = 0; + delete m_sat; + m_sat = 0; } QT_END_NAMESPACE diff --git a/src/plugins/position/geoclue/qgeosatelliteinfosource_geocluemaster.h b/src/plugins/position/geoclue/qgeosatelliteinfosource_geocluemaster.h index 3269a423..e840e8a3 100644 --- a/src/plugins/position/geoclue/qgeosatelliteinfosource_geocluemaster.h +++ b/src/plugins/position/geoclue/qgeosatelliteinfosource_geocluemaster.h @@ -36,17 +36,18 @@ #include "qgeocluemaster.h" -#include <geoclue/geoclue-satellite.h> - -#include <QtCore/qcompilerdetection.h> #include <QtCore/QTimer> #include <QtPositioning/QGeoSatelliteInfoSource> +class OrgFreedesktopGeoclueInterface; +class OrgFreedesktopGeoclueSatelliteInterface; + QT_BEGIN_NAMESPACE class QDBusMessage; +class QDBusPendingCallWatcher; -class QGeoSatelliteInfoSourceGeoclueMaster : public QGeoSatelliteInfoSource, public QGeoclueMaster +class QGeoSatelliteInfoSourceGeoclueMaster : public QGeoSatelliteInfoSource { Q_OBJECT @@ -55,28 +56,36 @@ public: ~QGeoSatelliteInfoSourceGeoclueMaster(); int minimumUpdateInterval() const Q_DECL_OVERRIDE; + void setUpdateInterval(int msec) Q_DECL_OVERRIDE; + Error error() const Q_DECL_OVERRIDE; void startUpdates() Q_DECL_OVERRIDE; void stopUpdates() Q_DECL_OVERRIDE; void requestUpdate(int timeout = 0) Q_DECL_OVERRIDE; - void satelliteChanged(int timestamp, int satellitesUsed, int satellitesVisible, - const QList<int> &usedPrn, const QList<QGeoSatelliteInfo> &satInfos); - - void requestUpdateFinished(int timestamp, int satellitesUsed, int satellitesVisible, - const QList<int> &usedPrn, const QList<QGeoSatelliteInfo> &satInfos); - private slots: + void positionProviderChanged(const QString &name, const QString &description, + const QString &service, const QString &path); void requestUpdateTimeout(); - void positionProviderChanged(const QByteArray &service, const QByteArray &path); - void satellitesChanged(const QDBusMessage &message); + + void getSatelliteFinished(QDBusPendingCallWatcher *watcher); + void satelliteChanged(int timestamp, int satellitesUsed, int satellitesVisible, + const QList<int> &usedPrn, const QList<QGeoSatelliteInfo> &satInfos); + void satelliteChanged(const QDBusMessage &message); private: - bool configureSatelliteSource(); + void configureSatelliteSource(); void cleanupSatelliteSource(); - GeoclueSatellite *m_sat; + void updateSatelliteInfo(int timestamp, int satellitesUsed, int satellitesVisible, + const QList<int> &usedPrn, const QList<QGeoSatelliteInfo> &satInfos); + + QGeoclueMaster *m_master; + + OrgFreedesktopGeoclueInterface *m_provider; + OrgFreedesktopGeoclueSatelliteInterface *m_sat; + QTimer m_requestTimer; QList<QGeoSatelliteInfo> m_inView; QList<QGeoSatelliteInfo> m_inUse; diff --git a/src/plugins/position/gypsy/plugin.json b/src/plugins/position/gypsy/plugin.json index b3ecc0f7..9cef03f8 100644 --- a/src/plugins/position/gypsy/plugin.json +++ b/src/plugins/position/gypsy/plugin.json @@ -4,5 +4,6 @@ "Position": false, "Satellite": true, "Monitor" : false, - "Priority": 1000 + "Priority": 1000, + "Testable": false } diff --git a/src/plugins/position/position.pro b/src/plugins/position/position.pro index 8374a489..3886eb4d 100644 --- a/src/plugins/position/position.pro +++ b/src/plugins/position/position.pro @@ -1,9 +1,9 @@ TEMPLATE = subdirs -config_geoclue:SUBDIRS += geoclue +qtHaveModule(dbus):SUBDIRS += geoclue config_gypsy:SUBDIRS += gypsy qtHaveModule(simulator):SUBDIRS += simulator -ios:SUBDIRS += corelocation +osx|ios:SUBDIRS += corelocation android:!android-no-sdk:SUBDIRS += android winrt:SUBDIRS += winrt diff --git a/src/plugins/position/positionpoll/plugin.json b/src/plugins/position/positionpoll/plugin.json index a5b2f602..df1f47de 100644 --- a/src/plugins/position/positionpoll/plugin.json +++ b/src/plugins/position/positionpoll/plugin.json @@ -4,5 +4,6 @@ "Position": false, "Satellite": false, "Monitor": true, - "Priority": 1000 + "Priority": 1000, + "Testable": true } diff --git a/src/plugins/position/simulator/plugin.json b/src/plugins/position/simulator/plugin.json index 8aa5e79f..0935f4dc 100644 --- a/src/plugins/position/simulator/plugin.json +++ b/src/plugins/position/simulator/plugin.json @@ -4,5 +4,6 @@ "Position": true, "Satellite": true, "Monitor" : false, - "Priority": 1000 + "Priority": 1000, + "Testable": true } diff --git a/src/plugins/position/winrt/plugin.json b/src/plugins/position/winrt/plugin.json index 5bb21702..0696cb0a 100644 --- a/src/plugins/position/winrt/plugin.json +++ b/src/plugins/position/winrt/plugin.json @@ -4,5 +4,6 @@ "Position": true, "Satellite": false, "Monitor" : false, - "Priority": 1000 + "Priority": 1000, + "Testable": false } diff --git a/src/positioning/doc/src/qtpositioning.qdoc b/src/positioning/doc/src/qtpositioning.qdoc index c2d6912d..c80ae8e1 100644 --- a/src/positioning/doc/src/qtpositioning.qdoc +++ b/src/positioning/doc/src/qtpositioning.qdoc @@ -61,10 +61,11 @@ The Qt Positioning API provides positioning information via QML and C++ interfaces. -Currently the API is supported on \l{Qt for Android}{Android}, -\l{Qt for iOS}{iOS}, -\l{Qt for Linux/X11}{Linux} (using \l{http://www.freedesktop.org/wiki/Software/GeoClue}{GeoClue}) -and \l {Qt for WinRT} {WinRT}. +Currently the API is supported on \l {Qt for Android}{Android}, \l {Qt for iOS}{iOS}, +\l {Qt for OS X}{OS X}, +\l {Qt for Linux/X11}{Linux} (using +\l {http://www.freedesktop.org/wiki/Software/GeoClue}{GeoClue version 0.12.99}) +and \l {Qt for WinRT}{WinRT}. \section1 Overview diff --git a/src/positioning/qgeopositioninfosource.cpp b/src/positioning/qgeopositioninfosource.cpp index 1cdd4116..0cec8eaa 100644 --- a/src/positioning/qgeopositioninfosource.cpp +++ b/src/positioning/qgeopositioninfosource.cpp @@ -158,6 +158,12 @@ void QGeoPositionInfoSourcePrivate::loadPluginMetadata(QHash<QString, QJsonObjec QList<QJsonObject> meta = l->metaData(); for (int i = 0; i < meta.size(); ++i) { QJsonObject obj = meta.at(i).value(QStringLiteral("MetaData")).toObject(); + const QString testableKey = QStringLiteral("Testable"); + if (obj.contains(testableKey) && !obj.value(testableKey).toBool()) { + static bool inTest = qEnvironmentVariableIsSet("QT_QTESTLIB_RUNNING"); + if (inTest) + continue; + } obj.insert(QStringLiteral("index"), i); plugins.insertMulti(obj.value(QStringLiteral("Provider")).toString(), obj); } diff --git a/src/positioning/qgeosatelliteinfosource.cpp b/src/positioning/qgeosatelliteinfosource.cpp index 06d6771d..da6eb8a0 100644 --- a/src/positioning/qgeosatelliteinfosource.cpp +++ b/src/positioning/qgeosatelliteinfosource.cpp @@ -167,6 +167,12 @@ QGeoSatelliteInfoSource *QGeoSatelliteInfoSource::createDefaultSource(QObject *p if (obj.value(QStringLiteral("Satellite")).isBool() && obj.value(QStringLiteral("Satellite")).toBool()) { + const QString testableKey = QStringLiteral("Testable"); + if (obj.contains(testableKey) && !obj.value(testableKey).toBool()) { + static bool inTest = qEnvironmentVariableIsSet("QT_QTESTLIB_RUNNING"); + if (inTest) + continue; + } QGeoPositionInfoSourcePrivate d; d.metaData = obj; d.loadPlugin(); |