#include "LocationSession.hpp"
#include "RawLocationParser.hpp"
#include <bb/cascades/maps/MapData.hpp>
#include <bb/cascades/maps/MapLongPressToPinDrop.hpp>
#include <bb/multimedia/SystemSound>
#include <bb/platform/geo/GeoLocation.hpp>
#include <QtCore/QVariant>
#include <iostream>
using namespace bb::cascades::maps;
using namespace bb::multimedia;
using namespace bb::platform::geo;
LocationSession::LocationSession(QObject* parent, bool satInfo)
: QObject(parent)
, m_latitude(0)
, m_longitude(0)
, m_altitude(0)
, m_soundEnabled(false)
, m_positionSource(QGeoPositionInfoSource::createDefaultSource(this))
, m_isPropagated(false)
, m_mapView(0)
{
bool ok = false;
if (m_positionSource) {
ok = connect(m_positionSource, SIGNAL(positionUpdated(const QGeoPositionInfo &)), this, SLOT(positionUpdated(const QGeoPositionInfo &)));
Q_ASSERT(ok);
ok = connect(m_positionSource, SIGNAL(updateTimeout()), this, SLOT(positionUpdateTimeout()));
Q_ASSERT(ok);
log(tr("Initialized QGeoPositionInfoSource"));
} else {
log(tr("Failed to initialized QGeoPositionInfoSource"));
}
if (satInfo) {
m_satelliteSource = QGeoSatelliteInfoSource::createDefaultSource(this);
if (m_satelliteSource) {
ok = connect(m_satelliteSource, SIGNAL(satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &)), this, SLOT(satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &)));
Q_ASSERT(ok);
ok = connect(m_satelliteSource, SIGNAL(satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &)), this, SLOT(satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &)));
Q_ASSERT(ok);
log(tr("Initialized QGeoSatelliteInfoSource"));
} else {
log(tr("Failed to initialized QGeoSatelliteInfoSource"));
}
}
m_direction = m_horizontalAccuracy = m_verticalAccuracy = m_magneticVariation = tr("--");
m_time = tr("-/-/- -:-");
m_groundSpeed = tr("-- km/h");
m_verticalSpeed = tr("-- km/h");
m_satellitesInUse = m_satellitesInView = tr("No satellite information available");
}
void LocationSession::startUpdates()
{
if (m_positionSource) {
m_positionSource->startUpdates();
log(tr("Position updates started"));
}
if (m_satelliteSource) {
m_satelliteSource->startUpdates();
log(tr("Satellite updates started"));
}
}
void LocationSession::requestUpdate()
{
if (m_positionSource) {
m_positionSource->requestUpdate(120000);
log(tr("Update requested"));
}
}
void LocationSession::stopUpdates()
{
if (m_positionSource) {
m_positionSource->stopUpdates();
log(tr("Position updates stopped"));
}
if (m_satelliteSource) {
m_satelliteSource->stopUpdates();
log(tr("Satellite updates stopped"));
}
deleteLater();
}
void LocationSession::resetSession(const QString &type)
{
if (m_soundEnabled)
SystemSound::play(SystemSound::GeneralNotification);
if (m_positionSource) {
m_positionSource->stopUpdates();
m_positionSource->setProperty("reset", type);
m_positionSource->startUpdates();
log(tr("%1 RESET").arg(type));
}
}
void LocationSession::positionUpdated(const QGeoPositionInfo& pos)
{
if (m_soundEnabled)
SystemSound::play(SystemSound::GeneralNotification);
m_latitude = pos.coordinate().latitude();
m_longitude = pos.coordinate().longitude();
m_altitude = pos.coordinate().altitude();
m_time = pos.timestamp().toString();
m_direction = QString::number(pos.attribute(QGeoPositionInfo::Direction));
m_groundSpeed = QString::number(pos.attribute(QGeoPositionInfo::GroundSpeed));
m_verticalSpeed = QString::number(pos.attribute(QGeoPositionInfo::VerticalSpeed));
m_horizontalAccuracy = QString::number(pos.attribute(QGeoPositionInfo::HorizontalAccuracy));
m_verticalAccuracy = QString::number(pos.attribute(QGeoPositionInfo::VerticalAccuracy));
m_magneticVariation = QString::number(pos.attribute(QGeoPositionInfo::MagneticVariation));
parseRawData();
emit dataChanged();
if (m_mapView) {
Geographic *myGeo = m_mapView->mapData()->geographic("myLocation");
GeoLocation *myLocation = 0;
if (myGeo) {
myLocation = qobject_cast<GeoLocation*>(myGeo);
}
if (!myLocation) {
myLocation = new GeoLocation("myLocation");
m_mapView->mapData()->add(myLocation);
}
myLocation->setLatitude(latitude());
myLocation->setLongitude(longitude());
myLocation->setName("You're here!");
myLocation->setDescription(QString::number(latitude()) + ", " + QString::number(longitude()));
m_mapView->setFocusedId(myLocation->id());
m_mapView->setLocationOnFocused();
}
log(tr("update"));
}
QGeoPositionInfoSource* LocationSession::positionSource() const
{
return m_positionSource;
}
void LocationSession::setSoundEnabled(bool enabled)
{
m_soundEnabled = enabled;
}
void LocationSession::positionUpdateTimeout()
{
log(tr("positionUpdateTimeout() received"));
}
static QString satellitesToString(const QList<QGeoSatelliteInfo> &satellites)
{
QString text;
foreach (const QGeoSatelliteInfo &info, satellites) {
text += QObject::tr("PRN: %1\nAzimuth: %2\nElevation: %3\nSignal: %4\n")
.arg(info.prnNumber())
.arg(info.attribute(QGeoSatelliteInfo::Azimuth))
.arg(info.attribute(QGeoSatelliteInfo::Elevation))
.arg(info.signalStrength());
}
return text;
}
void LocationSession::satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &satellites)
{
log(tr("satellitesInUseUpdated received"));
m_satellitesInUse = tr("Satellites In Use\n%1").arg(satellitesToString(satellites));
emit dataChanged();
}
void LocationSession::satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &satellites)
{
log(tr("satellitesInViewUpdated received"));
m_satellitesInView = tr("Satellites In View\n%1").arg(satellitesToString(satellites));
emit dataChanged();
}
void LocationSession::parseRawData()
{
const QVariant replyData = (m_positionSource ? m_positionSource->property("replyDat") : QVariant());
if (!replyData.isValid()) {
log(tr("!!! Invalid replyDat."));
}
RawLocationParser parser(replyData);
m_method = parser.positionMethod();
m_horizontalDilution = QString::number(parser.hdop());
m_verticalDilution = QString::number(parser.vdop());
m_positionDilution = QString::number(parser.pdop());
m_ttff = QString::number(parser.ttff());
m_gpsWeek = QString::number(parser.gpsWeek());
m_gpsTimeOfWeek = QString::number(parser.gpsTow());
m_isPropagated = parser.propagated();
const double latitude = parser.latitude();
const double longitude = parser.longitude();
const double altitude = parser.altitude();
const double hAccuracy = parser.horizontalAccuracy();
const double vAccuracy = parser.verticalAccuracy();
const double heading = parser.heading();
const double speed = parser.speed();
const double utc = parser.utc();
log(
tr("Method: %0, Latitude: %1, Longitude: %2, Altitude: %3, Horizontal Accuracy: %4, Vertical Accuracy: %5, Heading: %6, Speed: %7, TTFF: %8, GPS Week: %9, ").arg(m_method).arg(latitude).arg(longitude).arg(altitude).arg(hAccuracy).arg(vAccuracy).arg(heading).arg(speed).arg(m_ttff).arg(m_gpsWeek)
+ tr("GPS TOW: %0, UTC: %1, Horizontal Dilution: %2, Vertical Dilution: %3, Positional Dilution: %4, Propagated: %5").arg(m_gpsTimeOfWeek).arg(utc).arg(m_horizontalDilution).arg(m_verticalDilution).arg(m_positionDilution).arg(m_isPropagated ? tr("true") : tr("false")), false);
const QString error = parser.error();
if (error.length() > 3) {
log(tr("!!! [Error] %1").arg(error));
}
for (int i = 0; i < parser.numberOfSatellites(); i++) {
const double id = parser.satelliteId(i);
const double cno = parser.satelliteCarrierToNoiseRatio(i);
const bool ephemerisAvailable = parser.satelliteEphemerisAvailable(i);
const double azimuth = parser.satelliteAzimuth(i);
const double elevation = parser.satelliteElevation(i);
const bool tracked = parser.satelliteTracked(i);
const bool used = parser.satelliteUsed(i);
log(tr("\t[Satellite %0], ID: %1, CNO: %2, Ephemeris Available: %3, Azimuth: %4, Elevation: %5, Tracked: %6, Used: %7").arg(i).arg(id).arg(cno).arg(ephemerisAvailable ? tr("true") : tr("false")).arg(azimuth).arg(elevation).arg(tracked ? tr("true") : tr("false")).arg(used ? tr("true") : tr("false")), false);
}
}
void LocationSession::log(const QString &msg, bool showInUi)
{
std::cout << msg.toStdString() << std::endl;
if (showInUi) {
m_log += msg + QLatin1String("\n");
emit logChanged();
}
}
QString LocationSession::method() const
{
return m_method;
}
double LocationSession::latitude() const
{
return m_latitude;
}
double LocationSession::longitude() const
{
return m_longitude;
}
double LocationSession::altitude() const
{
return m_altitude;
}
QString LocationSession::time() const
{
return m_time;
}
QString LocationSession::direction() const
{
return m_direction;
}
QString LocationSession::groundSpeed() const
{
return m_groundSpeed;
}
QString LocationSession::verticalSpeed() const
{
return m_verticalSpeed;
}
QString LocationSession::horizontalAccuracy() const
{
return m_horizontalAccuracy;
}
QString LocationSession::verticalAccuracy() const
{
return m_verticalAccuracy;
}
QString LocationSession::magneticVariation() const
{
return m_magneticVariation;
}
QString LocationSession::horizontalDilution() const
{
return m_horizontalDilution;
}
QString LocationSession::verticalDilution() const
{
return m_verticalDilution;
}
QString LocationSession::positionDilution() const
{
return m_positionDilution;
}
QString LocationSession::ttff() const
{
return m_ttff;
}
QString LocationSession::gpsWeek() const
{
return m_gpsWeek;
}
QString LocationSession::gpsTimeOfWeek() const
{
return m_gpsTimeOfWeek;
}
bool LocationSession::isPropagated() const
{
return m_isPropagated;
}
QString LocationSession::satellitesInUse() const
{
return m_satellitesInUse;
}
QString LocationSession::satellitesInView() const
{
return m_satellitesInView;
}
MapView* LocationSession::mapView() const
{
return m_mapView;
}
void LocationSession::setMapView(MapView *mapView)
{
if (m_mapView == mapView)
return;
m_mapView = mapView;
MapLongPressToPinDrop *longPressAction = new MapLongPressToPinDrop(m_mapView);
bool ok = connect(longPressAction, SIGNAL(pinCreated(const QString&)), this, SLOT(onPinCreated(const QString&)));
Q_ASSERT(ok);
Q_UNUSED(ok);
}
void LocationSession::onPinCreated(const QString& pinID)
{
log("pin created: " + pinID, false);
}
QString LocationSession::log() const
{
return m_log;
}