diff --git a/Subsurface-mobile.pro b/Subsurface-mobile.pro index 7a147e925..ef9623219 100644 --- a/Subsurface-mobile.pro +++ b/Subsurface-mobile.pro @@ -23,7 +23,6 @@ SOURCES += subsurface-mobile-main.cpp \ core/cloudstorage.cpp \ core/configuredivecomputerthreads.cpp \ core/devicedetails.cpp \ - core/gpslocation.cpp \ core/downloadfromdcthread.cpp \ core/qtserialbluetooth.cpp \ core/plannernotes.c \ @@ -204,7 +203,6 @@ HEADERS += \ core/event.h \ core/extradata.h \ core/git-access.h \ - core/gpslocation.h \ core/pref.h \ core/profile.h \ core/qthelper.h \ diff --git a/commands/command_divesite.h b/commands/command_divesite.h index db0c5c73e..c81397410 100644 --- a/commands/command_divesite.h +++ b/commands/command_divesite.h @@ -5,10 +5,15 @@ #define COMMAND_DIVESITE_H #include "command_base.h" -#include "core/gpslocation.h" #include +struct DiveAndLocation { + struct dive *d; + location_t location; + QString name; +}; + // We put everything in a namespace, so that we can shorten names without polluting the global namespace namespace Command { diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 5b356e53f..fd878c7f3 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -106,8 +106,6 @@ set(SUBSURFACE_CORE_LIB_SRCS gettextfromc.h git-access.c git-access.h - gpslocation.cpp - gpslocation.h imagedownloader.cpp imagedownloader.h import-cobalt.c diff --git a/core/gpslocation.cpp b/core/gpslocation.cpp deleted file mode 100644 index f4bb71374..000000000 --- a/core/gpslocation.cpp +++ /dev/null @@ -1,414 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "core/gpslocation.h" -#include "core/divesite.h" -#include "core/dive.h" -#include "core/pref.h" -#include "core/qthelper.h" -#include "core/errorhelper.h" -#include "core/settings/qPrefLocationService.h" -#include -#include -#include -#include -#include -#include -#include - -GpsLocation::GpsLocation() : - m_GpsSource(0), - showMessageCB(0), - waitingForPosition(false), - haveSource(UNKNOWN) -{ - // create a QSettings object that's separate from the main application settings - geoSettings = new QSettings(QSettings::NativeFormat, QSettings::UserScope, - QStringLiteral("org.subsurfacedivelog"), QStringLiteral("subsurfacelocation"), this); - userAgent = getUserAgent(); - (void)getGpsSource(); - loadFromStorage(); - - // register changes in time threshold - connect(qPrefLocationService::instance(), SIGNAL(time_thresholdChanged(int)), this, SLOT(setGpsTimeThreshold(int))); -} - -GpsLocation *GpsLocation::instance() -{ - static GpsLocation self; - return &self; -} - -GpsLocation::~GpsLocation() -{ -} - -void GpsLocation::setLogCallBack(void (*showMsgCB)(const char *)) -{ - showMessageCB = showMsgCB; -} - -void GpsLocation::setGpsTimeThreshold(int seconds) -{ - if (m_GpsSource) { - m_GpsSource->setUpdateInterval(seconds * 1000); - status(QStringLiteral("Set GPS service update interval to %1 s").arg(m_GpsSource->updateInterval() / 1000)); - } -} - -QGeoPositionInfoSource *GpsLocation::getGpsSource() -{ - if (haveSource == NOGPS) - return 0; - - if (!m_GpsSource) { - m_GpsSource = QGeoPositionInfoSource::createDefaultSource(this); - if (m_GpsSource != 0) { -#if defined(Q_OS_IOS) - // at least Qt 5.6.0 isn't doing things right on iOS - it MUST check for permission before - // accessing the position source - // I have a hacked version of Qt 5.6.0 that I will build the iOS binaries with for now; - // this test below righ after creating the source checks if the location service is disabled - // and set's an error right when the position source is created to indicate this - if (m_GpsSource->error() == QGeoPositionInfoSource::AccessError) { - haveSource = NOGPS; - emit haveSourceChanged(); - m_GpsSource = NULL; - return NULL; - } -#endif - haveSource = (m_GpsSource->supportedPositioningMethods() & QGeoPositionInfoSource::SatellitePositioningMethods) ? HAVEGPS : NOGPS; - emit haveSourceChanged(); -#ifndef SUBSURFACE_MOBILE - if (verbose) -#endif - status(QStringLiteral("Created position source %1").arg(m_GpsSource->sourceName())); - connect(m_GpsSource, SIGNAL(positionUpdated(QGeoPositionInfo)), this, SLOT(newPosition(QGeoPositionInfo))); - connect(m_GpsSource, SIGNAL(updateTimeout()), this, SLOT(updateTimeout())); - connect(m_GpsSource, SIGNAL(error(QGeoPositionInfoSource::Error)), this, SLOT(positionSourceError(QGeoPositionInfoSource::Error))); - setGpsTimeThreshold(prefs.time_threshold); - } else { -#ifdef SUBSURFACE_MOBILE - status("don't have GPS source"); -#endif - haveSource = NOGPS; - emit haveSourceChanged(); - } - } - return m_GpsSource; -} - -bool GpsLocation::hasLocationsSource() -{ - (void)getGpsSource(); - return haveSource == HAVEGPS; -} - -void GpsLocation::serviceEnable(bool toggle) -{ - QGeoPositionInfoSource *gpsSource = getGpsSource(); - if (haveSource != HAVEGPS) { - if (toggle) - status("Can't start location service, no location source available"); - return; - } - if (toggle) { - gpsSource->startUpdates(); - status(QStringLiteral("Starting Subsurface GPS service with update interval %1").arg(gpsSource->updateInterval())); - } else { - gpsSource->stopUpdates(); - status("Stopping Subsurface GPS service"); - } -} - -QString GpsLocation::currentPosition() -{ - qDebug() << "current position requested"; - if (!hasLocationsSource()) - return tr("Unknown GPS location (no GPS source)"); - if (m_trackers.count()) { - QDateTime lastFixTime = timestampToDateTime(m_trackers.lastKey() - gettimezoneoffset()); - QDateTime now = QDateTime::currentDateTime(); - int delta = lastFixTime.secsTo(now); - qDebug() << "lastFixTime" << lastFixTime.toString() << "now" << now.toString() << "delta" << delta; - if (delta < 300) { - // we can simply use the last position that we tracked - gpsTracker gt = m_trackers.last(); - QString gpsString = printGPSCoords(>.location); - qDebug() << "returning last position" << gpsString; - return gpsString; - } else { - qDebug() << "last position saved was too old" << lastFixTime.toString(); - } - } - qDebug() << "requesting new GPS position"; - m_GpsSource->requestUpdate(); - // ok, we need to get the current position and somehow in the callback update the location in the QML UI - // punting right now - waitingForPosition = true; - return GPS_CURRENT_POS; -} - -void GpsLocation::newPosition(QGeoPositionInfo pos) -{ - int64_t lastTime = 0; - int64_t thisTime = dateTimeToTimestamp(pos.timestamp()) + gettimezoneoffset(); - QGeoCoordinate lastCoord; - int nr = m_trackers.count(); - if (nr) { - gpsTracker gt = m_trackers.last(); - lastCoord.setLatitude(gt.location.lat.udeg / 1000000.0); - lastCoord.setLongitude(gt.location.lon.udeg / 1000000.0); - lastTime = gt.when; - } - // if we are waiting for a position update or - // if we have no record stored or if at least the configured minimum - // time has passed or we moved at least the configured minimum distance - int64_t delta = thisTime - lastTime; - if (!nr || waitingForPosition || delta > prefs.time_threshold || - lastCoord.distanceTo(pos.coordinate()) > prefs.distance_threshold) { - QString msg = QStringLiteral("received new position %1 after delta %2 threshold %3 (now %4 last %5)"); - status(qPrintable(msg.arg(pos.coordinate().toString()).arg(delta).arg(prefs.time_threshold).arg(pos.timestamp().toString()).arg(timestampToDateTime(lastTime).toString()))); - gpsTracker gt; - gt.when = thisTime; - gt.location = create_location(pos.coordinate().latitude(), pos.coordinate().longitude()); - addFixToStorage(gt); - gpsTracker gtNew = m_trackers.last(); - waitingForPosition = false; - acquiredPosition(); - } -} - -void GpsLocation::updateTimeout() -{ - status("request to get new position timed out"); -} - -void GpsLocation::positionSourceError(QGeoPositionInfoSource::Error) -{ - status("error receiving a GPS location"); - haveSource = NOGPS; - emit haveSourceChanged(); -} - -void GpsLocation::status(QString msg) -{ - if (showMessageCB) - (*showMessageCB)(qPrintable(msg)); - else - qDebug() << msg; -} - -int GpsLocation::getGpsNum() const -{ - return m_trackers.count(); -} - -#define SAME_GROUP 6 * 3600 /* six hours */ -#define ADD_LOCATION(_dive, _gpsfix, _mark) \ -{ \ - fixes.push_back( { _dive, _gpsfix.location, _gpsfix.name } ); \ - last = _mark; \ -} - -std::vector GpsLocation::getLocations() -{ - int i; - int last = 0; - int cnt = m_trackers.count(); - std::vector fixes; - if (cnt == 0) - return fixes; - - // create a table with the GPS information - QList gpsTable = m_trackers.values(); - - // now walk the dive table and see if we can fill in missing gps data - struct dive *d; - for_each_dive(i, d) { - if (dive_has_gps_location(d)) - continue; - for (int j = last; j < cnt; j++) { - if (time_during_dive_with_offset(d, gpsTable[j].when, SAME_GROUP)) { - if (verbose) - qDebug() << "processing gpsFix @" << get_dive_date_string(gpsTable[j].when) << - "which is withing six hours of dive from" << - get_dive_date_string(d->when) << "until" << - get_dive_date_string(dive_endtime(d)); - /* - * If position is fixed during dive. This is the good one. - * Asign and mark position, and end gps_location loop - */ - if (time_during_dive_with_offset(d, gpsTable[j].when, 0)) { - if (verbose) - qDebug() << "gpsFix is during the dive, pick that one"; - ADD_LOCATION(d, gpsTable[j], j); - break; - } else { - /* - * If it is not, check if there are more position fixes in SAME_GROUP range - */ - if (j + 1 < cnt && time_during_dive_with_offset(d, gpsTable[j+1].when, SAME_GROUP)) { - if (verbose) - qDebug() << "look at the next gps fix @" << get_dive_date_string(gpsTable[j+1].when); - /* we know the gps fixes are sorted; if they are both before the dive, ignore the first, - * if theay are both after the dive, take the first, - * if the first is before and the second is after, take the closer one */ - if (gpsTable[j+1].when < d->when) { - if (verbose) - qDebug() << "which is closer to the start of the dive, do continue with that"; - continue; - } else if (gpsTable[j].when > dive_endtime(d)) { - if (verbose) - qDebug() << "which is even later after the end of the dive, so pick the previous one"; - ADD_LOCATION(d, gpsTable[j], j); - break; - } else { - /* ok, gpsFix is before, nextgpsFix is after */ - if (d->when - gpsTable[j].when <= gpsTable[j+1].when - dive_endtime(d)) { - if (verbose) - qDebug() << "pick the one before as it's closer to the start"; - ADD_LOCATION(d, gpsTable[j], j); - break; - } else { - if (verbose) - qDebug() << "pick the one after as it's closer to the start"; - ADD_LOCATION(d, gpsTable[j + 1], j + 1); - break; - } - } - /* - * If no more positions in range, the actual is the one. Asign, mark and end loop. - */ - } else { - if (verbose) - qDebug() << "which seems to be the best one for this dive, so pick it"; - ADD_LOCATION(d, gpsTable[j], j); - break; - } - } - } else { - /* If position is out of SAME_GROUP range and in the future, mark position for - * next dive iteration and end the gps_location loop - */ - if (gpsTable[j].when >= dive_endtime(d) + SAME_GROUP) { - last = j; - break; - } - } - - } - } - - return fixes; -} - -QMap GpsLocation::currentGPSInfo() const -{ - return m_trackers; -} - -void GpsLocation::loadFromStorage() -{ - int nr = geoSettings->value(QStringLiteral("count")).toInt(); - for (int i = 0; i < nr; i++) { - struct gpsTracker gt; - gt.when = geoSettings->value(QStringLiteral("gpsFix%1_time").arg(i)).toLongLong(); - gt.location.lat.udeg = geoSettings->value(QStringLiteral("gpsFix%1_lat").arg(i)).toInt(); - gt.location.lon.udeg = geoSettings->value(QStringLiteral("gpsFix%1_lon").arg(i)).toInt(); - gt.name = geoSettings->value(QStringLiteral("gpsFix%1_name").arg(i)).toString(); - gt.idx = i; - m_trackers.insert(gt.when, gt); - } -} - -QString GpsLocation::getFixString() -{ - // only used for debugging - QString res; - struct gpsTracker gpsEntry; - foreach (gpsEntry, m_trackers.values()) - res += QString("%1: %2; %3 ; \"%4\"\n").arg(gpsEntry.when).arg(gpsEntry.location.lat.udeg).arg(gpsEntry.location.lon.udeg).arg(gpsEntry.name); - return res; -} - -void GpsLocation::replaceFixToStorage(gpsTracker >) -{ - if (!m_trackers.keys().contains(gt.when)) { - addFixToStorage(gt); - return; - } - gpsTracker replacedTracker = m_trackers.value(gt.when); - geoSettings->setValue(QStringLiteral("gpsFix%1_time").arg(replacedTracker.idx), gt.when); - geoSettings->setValue(QStringLiteral("gpsFix%1_lat").arg(replacedTracker.idx), gt.location.lat.udeg); - geoSettings->setValue(QStringLiteral("gpsFix%1_lon").arg(replacedTracker.idx), gt.location.lon.udeg); - geoSettings->setValue(QStringLiteral("gpsFix%1_name").arg(replacedTracker.idx), gt.name); - replacedTracker.location = gt.location; - replacedTracker.name = gt.name; -} - -void GpsLocation::addFixToStorage(gpsTracker >) -{ - int nr = m_trackers.count(); - geoSettings->setValue("count", nr + 1); - geoSettings->setValue(QStringLiteral("gpsFix%1_time").arg(nr), gt.when); - geoSettings->setValue(QStringLiteral("gpsFix%1_lat").arg(nr), gt.location.lat.udeg); - geoSettings->setValue(QStringLiteral("gpsFix%1_lon").arg(nr), gt.location.lon.udeg); - geoSettings->setValue(QStringLiteral("gpsFix%1_name").arg(nr), gt.name); - gt.idx = nr; - geoSettings->sync(); - m_trackers.insert(gt.when, gt); -} - -void GpsLocation::deleteFixFromStorage(gpsTracker >) -{ - qint64 when = gt.when; - int cnt = m_trackers.count(); - if (cnt == 0 || !m_trackers.keys().contains(when)) { - qDebug() << "no gps fix with timestamp" << when; - return; - } - if (geoSettings->value(QStringLiteral("gpsFix%1_time").arg(gt.idx)).toLongLong() != when) { - qDebug() << "uh oh - index for tracker has gotten out of sync..."; - return; - } - if (cnt > 1) { - // now we move the last tracker into that spot (so our settings stay consecutive) - // and delete the last settings entry - when = geoSettings->value(QStringLiteral("gpsFix%1_time").arg(cnt - 1)).toLongLong(); - struct gpsTracker movedTracker = m_trackers.value(when); - movedTracker.idx = gt.idx; - m_trackers.remove(movedTracker.when); - m_trackers.insert(movedTracker.when, movedTracker); - geoSettings->setValue(QStringLiteral("gpsFix%1_time").arg(movedTracker.idx), when); - geoSettings->setValue(QStringLiteral("gpsFix%1_lat").arg(movedTracker.idx), movedTracker.location.lat.udeg); - geoSettings->setValue(QStringLiteral("gpsFix%1_lon").arg(movedTracker.idx), movedTracker.location.lon.udeg); - geoSettings->setValue(QStringLiteral("gpsFix%1_name").arg(movedTracker.idx), movedTracker.name); - geoSettings->remove(QStringLiteral("gpsFix%1_lat").arg(cnt - 1)); - geoSettings->remove(QStringLiteral("gpsFix%1_lon").arg(cnt - 1)); - geoSettings->remove(QStringLiteral("gpsFix%1_time").arg(cnt - 1)); - geoSettings->remove(QStringLiteral("gpsFix%1_name").arg(cnt - 1)); - } - geoSettings->setValue("count", cnt - 1); - geoSettings->sync(); - m_trackers.remove(gt.when); -} - -void GpsLocation::deleteGpsFix(qint64 when) -{ - auto it = m_trackers.find(when); - if (it == m_trackers.end()) { - qWarning() << "GpsLocation::deleteGpsFix(): can't find tracker for timestamp " << when; - return; - } - struct gpsTracker deletedTracker = *it; - deleteFixFromStorage(deletedTracker); - m_deletedTrackers.append(deletedTracker); -} - -#ifdef SUBSURFACE_MOBILE -void GpsLocation::clearGpsData() -{ - m_trackers.clear(); - geoSettings->clear(); - geoSettings->sync(); -} -#endif diff --git a/core/gpslocation.h b/core/gpslocation.h deleted file mode 100644 index eb61fe7ef..000000000 --- a/core/gpslocation.h +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#ifndef GPSLOCATION_H -#define GPSLOCATION_H - -#include "units.h" -#include -#include -#include -#include -#include -#include -#include - -#define GPS_CURRENT_POS gettextFromC::tr("Waiting to aquire GPS location") - -struct gpsTracker { - location_t location; - qint64 when; - QString name; - int idx; -}; - -struct DiveAndLocation { - struct dive *d; - location_t location; - QString name; -}; - -class GpsLocation : public QObject { - Q_OBJECT -public: - GpsLocation(); - ~GpsLocation(); - static GpsLocation *instance(); - std::vector getLocations(); - int getGpsNum() const; - bool hasLocationsSource(); - QString currentPosition(); - void setLogCallBack(void (*showMsgCB)(const char *msg)); - QString getFixString(); - QMap currentGPSInfo() const; - -private: - QGeoPositionInfo lastPos; - QGeoPositionInfoSource *getGpsSource(); - QGeoPositionInfoSource *m_GpsSource; - void status(QString msg); - QSettings *geoSettings; - QNetworkReply *reply; - QString userAgent; - void (*showMessageCB)(const char *msg); - bool waitingForPosition; - QMap m_trackers; - QList m_deletedTrackers; - void loadFromStorage(); - void addFixToStorage(gpsTracker >); - void replaceFixToStorage(gpsTracker >); - void deleteFixFromStorage(gpsTracker >); - void deleteFixesFromServer(); - enum { UNKNOWN, NOGPS, HAVEGPS } haveSource; - -signals: - void haveSourceChanged(); - void acquiredPosition(); - -public slots: - void serviceEnable(bool toggle); - void newPosition(QGeoPositionInfo pos); - void updateTimeout(); - void positionSourceError(QGeoPositionInfoSource::Error error); - void setGpsTimeThreshold(int seconds); -#ifdef SUBSURFACE_MOBILE - void clearGpsData(); -#endif - void deleteGpsFix(qint64 when); -}; - -#endif // GPSLOCATION_H diff --git a/mobile-widgets/qmlmanager.h b/mobile-widgets/qmlmanager.h index 96dff77b5..89fdce323 100644 --- a/mobile-widgets/qmlmanager.h +++ b/mobile-widgets/qmlmanager.h @@ -11,7 +11,6 @@ #include #include "core/btdiscovery.h" -#include "core/gpslocation.h" #include "core/downloadfromdcthread.h" #include "qt-models/completionmodels.h" #include "qt-models/divelocationmodel.h"