diff options
28 files changed, 871 insertions, 642 deletions
diff --git a/config.tests/geoclue-satellite/geoclue-satellite.pro b/config.tests/geoclue-satellite/geoclue-satellite.pro deleted file mode 100644 index 1ebc2e84..00000000 --- a/config.tests/geoclue-satellite/geoclue-satellite.pro +++ /dev/null @@ -1,6 +0,0 @@ -TEMPLATE = app -unix { - CONFIG += link_pkgconfig - PKGCONFIG += geoclue -} -SOURCES += main.cpp diff --git a/config.tests/geoclue-satellite/main.cpp b/config.tests/geoclue-satellite/main.cpp deleted file mode 100644 index 60bd30a0..00000000 --- a/config.tests/geoclue-satellite/main.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Jolla Ltd, author: Aaron McCarthy <aaron.mccarthy@jollamobile.com> -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtLocation 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 <geoclue/geoclue-satellite.h> - -int main() -{ - GeoclueSatellite satellite; - - return 0; -} diff --git a/config.tests/geoclue/geoclue.pro b/config.tests/geoclue/geoclue.pro deleted file mode 100644 index 1ebc2e84..00000000 --- a/config.tests/geoclue/geoclue.pro +++ /dev/null @@ -1,6 +0,0 @@ -TEMPLATE = app -unix { - CONFIG += link_pkgconfig - PKGCONFIG += geoclue -} -SOURCES += main.cpp diff --git a/qtlocation.pro b/qtlocation.pro index d3a1ba65..3104465f 100644 --- a/qtlocation.pro +++ b/qtlocation.pro @@ -1,6 +1,4 @@ load(configure) -qtCompileTest(geoclue) -qtCompileTest(geoclue-satellite) qtCompileTest(gypsy) load(qt_parts) 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/config.tests/geoclue/main.cpp b/src/plugins/position/geoclue/geocluetypes.h index 08271c41..ff748b13 100644 --- a/config.tests/geoclue/main.cpp +++ b/src/plugins/position/geoclue/geocluetypes.h @@ -1,11 +1,9 @@ /**************************************************************************** ** -** Copyright (C) 2013 Jolla Ltd. -** Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com> -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2015 Aaron McCarthy <mccarthy.aaron@gmail.com> +** Contact: http://www.qt-project.org/legal ** -** This file is part of the QtLocation module of the Qt Toolkit. +** This file is part of the QtPositioning module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage @@ -33,16 +31,57 @@ ** ****************************************************************************/ -#include <geoclue/geoclue-position.h> -#include <geoclue/geoclue-velocity.h> +#ifndef GEOCLUETYPES_H +#define GEOCLUETYPES_H -int main() +#include <QtDBus/QDBusArgument> +#include <QtPositioning/QGeoSatelliteInfo> + +class Accuracy { - GType type = geoclue_position_get_type(); - GeocluePosition position; +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 - type = geoclue_velocity_get_type(); - GeoclueVelocity velocity; +#endif // GEOCLUETYPES_H - return 0; -} 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 cf03d6ed..00000000 --- a/src/plugins/position/geoclue/plugin-satellite.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Keys": ["geoclue"], - "Provider": "geoclue", - "Position": true, - "Satellite": true, - "Priority": 1000, - "Testable": false -} diff --git a/src/plugins/position/geoclue/plugin.json b/src/plugins/position/geoclue/plugin.json index f11d27cb..82f8afc6 100644 --- a/src/plugins/position/geoclue/plugin.json +++ b/src/plugins/position/geoclue/plugin.json @@ -2,8 +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..db074f59 100644 --- a/src/plugins/position/geoclue/qgeocluemaster.cpp +++ b/src/plugins/position/geoclue/qgeocluemaster.cpp @@ -33,94 +33,79 @@ #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 +QGeoclueMaster::QGeoclueMaster(QObject *parent) +: QObject(parent), m_master(0), m_provider(0), m_client(0) { - -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) - - const QByteArray pService = QByteArray(service); - const QByteArray pPath = QByteArray(path); - - QMetaObject::invokeMethod(handler, "positionProviderChanged", Qt::QueuedConnection, - Q_ARG(QByteArray, pService), Q_ARG(QByteArray, pPath)); -} - -} - -QGeoclueMaster::QGeoclueMaster(QObject *handler) -: m_client(0), m_masterPosition(0), m_handler(handler) -{ -#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) { + m_master = new OrgFreedesktopGeoclueMasterInterface(QStringLiteral("org.freedesktop.Geoclue.Master"), + QStringLiteral("/org/freedesktop/Geoclue/Master"), + QDBusConnection::sessionBus()); + } + + 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; + qDebug() << "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 +114,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..cc0a8119 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,23 @@ #include <QtCore/QStandardPaths> #include <QtCore/QVariantMap> #include <QtCore/QtNumeric> +#include <QtDBus/QDBusMetaType> #ifdef Q_LOCATION_GEOCLUE_DEBUG #include <QDebug> #endif -#include <dbus/dbus-glib.h> - #ifndef QT_NO_DATASTREAM #include <QtCore/QDataStream> #endif -QT_BEGIN_NAMESPACE - #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 +71,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 +88,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,50 +112,10 @@ 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."; @@ -200,33 +128,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 = accuracy.level() == Accuracy::Detailed; - m_lastPositionFromSatellite = accuracyLevel & GEOCLUE_ACCURACY_LEVEL_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)) @@ -253,69 +173,50 @@ void QGeoPositionInfoSourceGeoclueMaster::updatePosition(GeocluePositionFields f // Only stop positioning if regular updates not active. if (!m_running) { cleanupPositionSource(); - releaseMasterClient(); + m_master->releaseMasterClient(); } } +void QGeoPositionInfoSourceGeoclueMaster::velocityUpdateFailed() +{ + // 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; +} + 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; - } + 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) @@ -341,13 +242,13 @@ void QGeoPositionInfoSourceGeoclueMaster::setPreferredPositioningMethods(Positio // 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,18 +257,14 @@ 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; } @@ -383,7 +280,7 @@ void QGeoPositionInfoSourceGeoclueMaster::startUpdates() m_running = true; // Start Geoclue provider. - if (!hasMasterClient()) { + if (!m_master->hasMasterClient()) { configurePositionSource(); setOptions(); } @@ -405,17 +302,22 @@ void QGeoPositionInfoSourceGeoclueMaster::stopUpdates() if (!m_running) 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); + 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(); } } @@ -432,7 +334,7 @@ void QGeoPositionInfoSourceGeoclueMaster::requestUpdate(int timeout) return; } - if (!hasMasterClient()) { + if (!m_master->hasMasterClient()) { configurePositionSource(); setOptions(); } @@ -442,8 +344,55 @@ 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; + } + + 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() @@ -457,70 +406,71 @@ void QGeoPositionInfoSourceGeoclueMaster::requestUpdateTimeout() // 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; + + PositionFields fields = static_cast<PositionFields>(reply.argumentAt<0>()); + 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); } +} - 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); - } +void QGeoPositionInfoSourceGeoclueMaster::positionChanged(qint32 fields, qint32 timestamp, double latitude, double longitude, double altitude, const Accuracy &accuracy) +{ + PositionFields pFields = static_cast<PositionFields>(fields); - // Get the current position immediately. - geoclue_position_get_position_async(m_pos, position_callback, this); - setOptions(); + if (pFields & Latitude && pFields & Longitude) + updatePosition(pFields, timestamp, latitude, longitude, altitude, accuracy); + else + positionUpdateFailed(); +} - 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); - } - } +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; + 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 +481,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..18f90fbf 100644 --- a/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.cpp +++ b/src/plugins/position/geoclue/qgeopositioninfosourcefactory_geoclue.cpp @@ -34,13 +34,13 @@ ****************************************************************************/ #include "qgeopositioninfosourcefactory_geoclue.h" -#include "qgeopositioninfosource_geocluemaster_p.h" -#ifdef HAS_SATELLITE +#include "qgeopositioninfosource_geocluemaster.h" #include "qgeosatelliteinfosource_geocluemaster.h" -#endif Q_DECLARE_METATYPE(QGeoPositionInfo) +QT_BEGIN_NAMESPACE + QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryGeoclue::positionInfoSource(QObject *parent) { qRegisterMetaType<QGeoPositionInfo>(); @@ -49,17 +49,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..47b60b95 100644 --- a/src/plugins/position/geoclue/qgeosatelliteinfosource_geocluemaster.cpp +++ b/src/plugins/position/geoclue/qgeosatelliteinfosource_geocluemaster.cpp @@ -33,122 +33,22 @@ #include "qgeosatelliteinfosource_geocluemaster.h" -#include <QtDBus/QDBusConnection> -#include <QtDBus/QDBusMessage> -#include <QtDBus/QDBusArgument> +#include <geoclue_interface.h> +#include <satellite_interface.h> + +#include <QtDBus/QDBusPendingCallWatcher> #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); - - 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->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(); - - return argument; -} - 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 +63,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 +84,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 +95,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 +119,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 +163,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 +222,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 +232,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 +246,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 +280,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/position.pro b/src/plugins/position/position.pro index 8374a489..6a6264e2 100644 --- a/src/plugins/position/position.pro +++ b/src/plugins/position/position.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -config_geoclue:SUBDIRS += geoclue +qtHaveModule(dbus):SUBDIRS += geoclue config_gypsy:SUBDIRS += gypsy qtHaveModule(simulator):SUBDIRS += simulator ios:SUBDIRS += corelocation diff --git a/src/positioning/doc/src/qtpositioning.qdoc b/src/positioning/doc/src/qtpositioning.qdoc index c2d6912d..95a267ab 100644 --- a/src/positioning/doc/src/qtpositioning.qdoc +++ b/src/positioning/doc/src/qtpositioning.qdoc @@ -61,10 +61,10 @@ 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 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/tests/auto/qgeosatelliteinfosource/qgeosatelliteinfosource.pro b/tests/auto/qgeosatelliteinfosource/qgeosatelliteinfosource.pro index 1fb72da7..7c0e7ee2 100644 --- a/tests/auto/qgeosatelliteinfosource/qgeosatelliteinfosource.pro +++ b/tests/auto/qgeosatelliteinfosource/qgeosatelliteinfosource.pro @@ -11,7 +11,4 @@ HEADERS += testqgeosatelliteinfosource_p.h \ QT += positioning testlib -# Define whether a satellite source is available. This must match the logic in -# src/location/location.pro or the test will fail on some platforms. -qtHaveModule(simulator):DEFINES += SATELLITE_SOURCE_AVAILABLE DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/qgeosatelliteinfosource/testqgeosatelliteinfosource.cpp b/tests/auto/qgeosatelliteinfosource/testqgeosatelliteinfosource.cpp index c825cdad..d80385c8 100644 --- a/tests/auto/qgeosatelliteinfosource/testqgeosatelliteinfosource.cpp +++ b/tests/auto/qgeosatelliteinfosource/testqgeosatelliteinfosource.cpp @@ -46,6 +46,7 @@ #include "../utils/qlocationtestutils_p.h" Q_DECLARE_METATYPE(QList<QGeoSatelliteInfo>) +Q_DECLARE_METATYPE(QGeoSatelliteInfoSource::Error) #define MAX_WAITING_TIME 50000 @@ -90,6 +91,8 @@ protected: TestQGeoSatelliteInfoSource::TestQGeoSatelliteInfoSource(QObject *parent) : QObject(parent) { + qRegisterMetaType<QGeoSatelliteInfoSource::Error>(); + m_testingDefaultSource = false; } @@ -167,23 +170,26 @@ void TestQGeoSatelliteInfoSource::createDefaultSource() { QObject *parent = new QObject; QGeoSatelliteInfoSource *source = QGeoSatelliteInfoSource::createDefaultSource(parent); - // Satellite sources are available when SATELLITE_SOURCE_AVAILABLE is defined -#if defined(SATELLITE_SOURCE_AVAILABLE) - QVERIFY(source != 0); -#else - QVERIFY(source == 0); -#endif + + // Check that default satellite source is successfully created. + if (!QGeoSatelliteInfoSource::availableSources().isEmpty()) + QVERIFY(source); + else + QVERIFY(!source); + delete parent; } void TestQGeoSatelliteInfoSource::createDefaultSource_noParent() { QGeoSatelliteInfoSource *source = QGeoSatelliteInfoSource::createDefaultSource(0); -#if defined(SATELLITE_SOURCE_AVAILABLE) - QVERIFY(source != 0); -#else - QVERIFY(source == 0); -#endif + + // Check that default satellite source is successfully created. + if (!QGeoSatelliteInfoSource::availableSources().isEmpty()) + QVERIFY(source); + else + QVERIFY(!source); + delete source; } @@ -246,10 +252,16 @@ void TestQGeoSatelliteInfoSource::startUpdates_testIntervals() QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy timeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); + m_source->setUpdateInterval(7000); int interval = m_source->updateInterval(); m_source->startUpdates(); + + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + QTRY_VERIFY_WITH_TIMEOUT((spyView.count() == 1) && (spyUse.count() == 1), 9500); for (int i = 0; i < 6; i++) { QTRY_VERIFY_WITH_TIMEOUT((spyView.count() == 1) && (spyUse.count() == 1) && (timeout.count() == 0), (interval*2)); @@ -275,10 +287,15 @@ void TestQGeoSatelliteInfoSource::startUpdates_testIntervalChangesWhileRunning() QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy timeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); + m_source->setUpdateInterval(0); m_source->startUpdates(); m_source->setUpdateInterval(0); + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + QTRY_VERIFY_WITH_TIMEOUT((spyView.count() > 0) && (spyUse.count() > 0), 7000); QCOMPARE(timeout.count(), 0); spyView.clear(); @@ -330,7 +347,13 @@ void TestQGeoSatelliteInfoSource::startUpdates_testDefaultInterval() QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy timeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); + m_source->startUpdates(); + + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + for (int i = 0; i < 3; i++) { QTRY_VERIFY_WITH_TIMEOUT( (spyView.count() > 0 ) && (spyUse.count() > 0) && (timeout.count() == 0), 7000); spyView.clear(); @@ -347,9 +370,14 @@ void TestQGeoSatelliteInfoSource::startUpdates_testZeroInterval() QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy timeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); m_source->setUpdateInterval(0); m_source->startUpdates(); + + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + for (int i = 0; i < 3; i++) { QTRY_VERIFY_WITH_TIMEOUT( (spyView.count() > 0 ) && (spyUse.count() > 0) && (timeout.count() == 0), 7000); spyView.clear(); @@ -365,9 +393,14 @@ void TestQGeoSatelliteInfoSource::startUpdates_moreThanOnce() SIGNAL(satellitesInViewUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); + m_source->setUpdateInterval(0); m_source->startUpdates(); + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + m_source->startUpdates(); // check there is no crash QTRY_VERIFY_WITH_TIMEOUT((spyView.count() > 0) && (spyUse.count() > 0), MAX_WAITING_TIME); @@ -379,16 +412,20 @@ void TestQGeoSatelliteInfoSource::startUpdates_moreThanOnce() void TestQGeoSatelliteInfoSource::stopUpdates() { - CHECK_SOURCE_VALID; QSignalSpy spyView(m_source, SIGNAL(satellitesInViewUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); + m_source->setUpdateInterval(10000); m_source->startUpdates(); + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + for (int i = 0; i < 2; i++) { QTRY_VERIFY_WITH_TIMEOUT((spyView.count() == 1) && (spyUse.count() == 1), 12000); spyView.clear(); @@ -415,7 +452,13 @@ void TestQGeoSatelliteInfoSource::requestUpdate() QSignalSpy spy(m_source, SIGNAL(requestTimeout())); QSignalSpy spyView(m_source, SIGNAL(satellitesInViewUpdated(QList<QGeoSatelliteInfo>))); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); + m_source->requestUpdate(timeout); + + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + // Geoclue may deliver update instantly if there is a satellite fix QTRY_VERIFY_WITH_TIMEOUT(!spy.isEmpty() || !spyView.isEmpty(), 10); } @@ -436,9 +479,13 @@ void TestQGeoSatelliteInfoSource::requestUpdate_validTimeout() QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy spyTimeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); m_source->requestUpdate(7000); + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + QTRY_VERIFY_WITH_TIMEOUT( (spyView.count() == 1) && (spyUse.count() == 1 && (spyTimeout.count()) == 0), 7000); } @@ -452,9 +499,13 @@ void TestQGeoSatelliteInfoSource::requestUpdate_defaultTimeout() QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy spyTimeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); m_source->requestUpdate(0); + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + QTRY_VERIFY_WITH_TIMEOUT( (spyView.count() == 1) && (spyUse.count() == 1 && (spyTimeout.count()) == 0), MAX_WAITING_TIME); @@ -465,8 +516,13 @@ void TestQGeoSatelliteInfoSource::requestUpdate_timeoutLessThanMinimumInterval() CHECK_SOURCE_VALID; QSignalSpy spyTimeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); + m_source->requestUpdate(1); + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + QTRY_COMPARE_WITH_TIMEOUT(spyTimeout.count(), 1, 1000); } @@ -478,9 +534,13 @@ void TestQGeoSatelliteInfoSource::requestUpdate_repeatedCalls() SIGNAL(satellitesInViewUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); m_source->requestUpdate(7000); + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + QTRY_VERIFY_WITH_TIMEOUT((spyView.count() == 1) && (spyUse.count() == 1), 7000); spyView.clear(); spyUse.clear(); @@ -498,8 +558,13 @@ void TestQGeoSatelliteInfoSource::requestUpdate_overlappingCalls() SIGNAL(satellitesInViewUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); m_source->requestUpdate(7000); + + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + m_source->requestUpdate(7000); QTRY_VERIFY_WITH_TIMEOUT((spyView.count() == 1) && (spyUse.count() == 1), 7000); @@ -515,8 +580,13 @@ void TestQGeoSatelliteInfoSource::requestUpdate_overlappingCallsWithTimeout() SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy spyTimeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); m_source->requestUpdate(0); + + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + m_source->requestUpdate(1); QTRY_COMPARE_WITH_TIMEOUT(spyTimeout.count(), 0, 7000); @@ -533,10 +603,14 @@ void TestQGeoSatelliteInfoSource::requestUpdateAfterStartUpdates_ZeroInterval() QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy spyTimeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); m_source->setUpdateInterval(0); m_source->startUpdates(); + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + QTRY_VERIFY_WITH_TIMEOUT((spyView.count() == 1) && (spyUse.count() == 1), MAX_WAITING_TIME); spyView.clear(); spyUse.clear(); @@ -563,9 +637,14 @@ void TestQGeoSatelliteInfoSource::requestUpdateAfterStartUpdates_SmallInterval() QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy spyTimeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); + m_source->setUpdateInterval(10000); m_source->requestUpdate(7000); + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + m_source->startUpdates(); QTRY_VERIFY_WITH_TIMEOUT((spyView.count() > 0) && (spyUse.count() > 0) @@ -587,9 +666,13 @@ void TestQGeoSatelliteInfoSource::requestUpdateBeforeStartUpdates_ZeroInterval() QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy timeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); m_source->requestUpdate(7000); + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + m_source->setUpdateInterval(0); m_source->startUpdates(); @@ -612,9 +695,13 @@ void TestQGeoSatelliteInfoSource::requestUpdateBeforeStartUpdates_SmallInterval( QSignalSpy spyUse(m_source, SIGNAL(satellitesInUseUpdated(QList<QGeoSatelliteInfo>))); QSignalSpy timeout(m_source, SIGNAL(requestTimeout())); + QSignalSpy errorSpy(m_source, SIGNAL(error(QGeoSatelliteInfoSource::Error))); m_source->requestUpdate(7000); + if (!errorSpy.isEmpty()) + QSKIP("Error starting satellite updates."); + m_source->setUpdateInterval(10000); m_source->startUpdates(); @@ -657,6 +744,9 @@ void TestQGeoSatelliteInfoSource::removeSlotForSatellitesInUseUpdated() m_source->requestUpdate(7000); + if (m_source->error() != QGeoSatelliteInfoSource::NoError) + QSKIP("Error starting satellite updates."); + QTRY_VERIFY_WITH_TIMEOUT((m_testSlot2Called == true), 7000); } @@ -673,6 +763,9 @@ void TestQGeoSatelliteInfoSource::removeSlotForSatellitesInViewUpdated() m_source->requestUpdate(7000); + if (m_source->error() != QGeoSatelliteInfoSource::NoError) + QSKIP("Error starting satellite updates."); + QTRY_VERIFY_WITH_TIMEOUT((m_testSlot2Called == true), 7000); } diff --git a/tests/auto/qgeosatelliteinfosource/testqgeosatelliteinfosource_p.h b/tests/auto/qgeosatelliteinfosource/testqgeosatelliteinfosource_p.h index f62bc28c..9efb9dde 100644 --- a/tests/auto/qgeosatelliteinfosource/testqgeosatelliteinfosource_p.h +++ b/tests/auto/qgeosatelliteinfosource/testqgeosatelliteinfosource_p.h @@ -110,14 +110,6 @@ private slots: void removeSlotForSatellitesInUseUpdated(); void removeSlotForSatellitesInViewUpdated(); -#ifdef TST_GYPSYMOCK_ENABLED - // Cases only ran with mock backend - void updateValues(); - void initGoneBad(); - void badUpdates(); -#endif - - private: QGeoSatelliteInfoSource *m_source; bool m_testingDefaultSource; |