From 3c634e71c76c31a3e8074f2d4772c1c6e1811208 Mon Sep 17 00:00:00 2001 From: Alex Zolotarev Date: Thu, 21 Apr 2011 14:24:39 +0200 Subject: [PATCH] Added mac and ios location services implementation to platform --- platform/apple_location_service.mm | 167 ++++++++++++++++++++++++++ platform/location.cpp | 52 ++++++++ platform/location.hpp | 72 +++++++++++ platform/platform.pro | 25 ++-- platform/windows_location_service.cpp | 23 ++++ 5 files changed, 332 insertions(+), 7 deletions(-) create mode 100644 platform/apple_location_service.mm create mode 100644 platform/location.cpp create mode 100644 platform/location.hpp create mode 100644 platform/windows_location_service.cpp diff --git a/platform/apple_location_service.mm b/platform/apple_location_service.mm new file mode 100644 index 0000000000..a507af0985 --- /dev/null +++ b/platform/apple_location_service.mm @@ -0,0 +1,167 @@ +#include "location.hpp" + +#include "../std/target_os.hpp" + +#import + +class AppleLocationService; + +@interface LocationManagerWrapper : NSObject { +@private + AppleLocationService * m_service; +} +- (id)initWithService:(AppleLocationService *) service; +@end + +using namespace location; + +#define ROUGH_ACCURACY kCLLocationAccuracyNearestTenMeters + +class AppleLocationService : public LocationService +{ + LocationManagerWrapper * m_objCppWrapper; + CLLocationManager * m_locationManager; + + TLocationStatus m_status; + +public: + AppleLocationService() : m_status(ENotSupported) + { + m_objCppWrapper = [[LocationManagerWrapper alloc] initWithService:this]; + m_locationManager = [[CLLocationManager alloc] init]; + m_locationManager.delegate = m_objCppWrapper; + } + + ~AppleLocationService() + { + [m_locationManager release]; + [m_objCppWrapper release]; + } + + void OnLocationUpdate(GpsInfo & newLocation) + { + newLocation.m_status = m_status; + NotifySubscribers(newLocation); + } + +// virtual bool IsServiceSupported() +// { +// // Mac OS 10.6+ and iOS 4.0+ support this definitely +// return true; +// } + +// virtual bool IsServiceEnabled() +// { +// return [CLLocationManager locationServicesEnabled]; +// } + +// virtual bool IsCompassAvailable() +// { +//#ifdef OMIM_OS_MAC +// return false; +//#else // iOS 4.0+ have it +// return [CLLocationManager headingAvailable]; +//#endif +// } + + virtual void StartUpdate(bool useAccurateMode) + { + if (![CLLocationManager locationServicesEnabled]) + { + m_status = EDisabledByUser; + GpsInfo info; + info.m_status = m_status; + NotifySubscribers(info); + } + else + { + if (useAccurateMode) + { + m_status = EAccurateMode; + m_locationManager.desiredAccuracy = kCLLocationAccuracyBest; + // also enable compass +#ifdef OMIM_OS_IPHONE + if ([CLLocationManager headingAvailable]) + [m_locationManager startHeadingUpdate]; +#endif + } + else + { + m_status = ERoughMode; + m_locationManager.desiredAccuracy = ROUGH_ACCURACY; + // also disable compass +#ifdef OMIM_OS_IPHONE + if ([CLLocationManager headingAvailable]) + [m_locationManager stopHeadingUpdate]; +#endif + } + [m_locationManager startUpdatingLocation]; + } + } + + virtual void StopUpdate() + { +#ifdef OMIM_OS_IPHONE + if ([CLLocationManager headingAvailable]) + [m_locationManager stopHeadingUpdate]; +#endif + [m_locationManager stopUpdatingLocation]; + } +}; + +@implementation LocationManagerWrapper + +- (id)initWithService:(AppleLocationService *) service +{ + self = [super init]; + if (self) { + m_service = service; + } + return self; +} + +- (void)dealloc +{ + [super dealloc]; +} + ++ (void)location:(CLLocation *)location toGpsInfo:(GpsInfo &) info +{ + info.m_altitude = location.altitude; + info.m_course = location.course; + info.m_speed = location.speed; + info.m_horizontalAccuracy = location.horizontalAccuracy; + info.m_verticalAccuracy = location.verticalAccuracy; + info.m_latitude = location.coordinate.latitude; + info.m_longitude = location.coordinate.longitude; + info.m_timestamp = [location.timestamp timeIntervalSince1970]; +} + +- (void)locationManager:(CLLocationManager *)manager + didUpdateToLocation:(CLLocation *)newLocation + fromLocation:(CLLocation *)oldLocation +{ + GpsInfo newInfo; + [LocationManagerWrapper location:newLocation toGpsInfo:newInfo]; + m_service->OnLocationUpdate(newInfo); +} + +- (void)locationManager:(CLLocationManager *)manager + didFailWithError:(NSError *)error +{ + NSLog(@"locationManager failed with error: %d, %@", error.code, error.description); + if (error.code == kCLErrorDenied) + { + GpsInfo info; + info.m_status = EDisabledByUser; + m_service->OnLocationUpdate(info); + } +} + +@end + +extern "C" location::LocationService & GetLocationService() +{ + static AppleLocationService ls; + return ls; +} diff --git a/platform/location.cpp b/platform/location.cpp new file mode 100644 index 0000000000..ef93075b04 --- /dev/null +++ b/platform/location.cpp @@ -0,0 +1,52 @@ +#include "location.hpp" + +#include "../std/algorithm.hpp" + +#include + +namespace location +{ + void LocationService::NotifySubscribers(GpsInfo const & info) + { + for (GpsObserversT::iterator it = m_gpsObservers.begin(); + it != m_gpsObservers.end(); ++it) + (*it)(info); + } + + void LocationService::NotifySubscribers(CompassInfo const & info) + { + for (CompassObserversT::iterator it = m_compassObservers.begin(); + it != m_compassObservers.end(); ++it) + (*it)(info); + } + + void LocationService::SubscribeToGpsUpdates(TGpsCallback observer) + { +// if (std::find(m_gpsObservers.begin(), m_gpsObservers.end(), boost::bind(&observer)) +// == m_gpsObservers.end()) + m_gpsObservers.push_back(observer); + } + + void LocationService::SubscribeToCompassUpdates(TCompassCallback observer) + { +// if (std::find(m_compassObservers.begin(), m_compassObservers.end(), observer) +// == m_compassObservers.end()) + m_compassObservers.push_back(observer); + } + +// void LocationService::Unsubscribe(TGpsCallback observer) +// { +// GpsObserversT::iterator found = +// std::find(m_gpsObservers.begin(), m_gpsObservers.end(), observer); +// if (found != m_gpsObservers.end()) +// m_gpsObservers.erase(found); +// } + +// void LocationService::Unsubscribe(TCompassCallback observer) +// { +// CompassObserversT::iterator found = +// std::find(m_compassObservers.begin(), m_compassObservers.end(), observer); +// if (found != m_compassObservers.end()) +// m_compassObservers.erase(found); +// } +} diff --git a/platform/location.hpp b/platform/location.hpp new file mode 100644 index 0000000000..c9cf3d148a --- /dev/null +++ b/platform/location.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include "../std/string.hpp" +#include "../std/vector.hpp" + +#include + +namespace location +{ + enum TLocationStatus + { + ENotSupported, //!< GpsInfo fields are not valid with this value + EDisabledByUser, //!< GpsInfo fields are not valid with this value + EAccurateMode, + ERoughMode //!< in this mode compass is turned off + }; + + /// @note always check m_status before using this structure + struct GpsInfo + { + TLocationStatus m_status; + double m_timestamp; //!< seconds from 01/01/1970 + double m_latitude; //!< degrees @TODO mercator + double m_longitude; //!< degrees @TODO mercator + double m_horizontalAccuracy; //!< metres + double m_altitude; //!< metres + double m_verticalAccuracy; //!< metres + double m_course; //!< positive degrees from the true North + double m_speed; //!< metres per second + }; + + struct CompassInfo + { + double m_timestamp; //!< seconds from 01/01/1970 + double m_magneticHeading; //!< positive degrees from the magnetic North + double m_trueHeading; //!< positive degrees from the true North + double m_accuracy; //!< offset from magnetic to true North + int m_x; + int m_y; + int m_z; + }; + + typedef boost::function1 TGpsCallback; + typedef boost::function1 TCompassCallback; + + class LocationService + { + typedef vector GpsObserversT; + GpsObserversT m_gpsObservers; + typedef vector CompassObserversT; + CompassObserversT m_compassObservers; + + protected: + void NotifySubscribers(GpsInfo const & info); + void NotifySubscribers(CompassInfo const & info); + + public: + /// @note unsubscribe doesn't work with boost::function + void SubscribeToGpsUpdates(TGpsCallback observer); + void SubscribeToCompassUpdates(TCompassCallback observer); +// void Unsubscribe(TGpsCallback observer); +// void Unsubscribe(TCompassCallback observer); + + /// to change active accuracy mode just call it again + /// @param useAccurateMode if true also enables compass if it's available + virtual void StartUpdate(bool useAccurateMode) = 0; + virtual void StopUpdate() = 0; + }; + +} + +extern "C" location::LocationService & GetLocationService(); diff --git a/platform/platform.pro b/platform/platform.pro index a7d9c5dceb..ccbac00b5e 100644 --- a/platform/platform.pro +++ b/platform/platform.pro @@ -12,12 +12,23 @@ include($$ROOT_DIR/common.pri) QT *= core network SOURCES += \ - qtplatform.cpp \ - qt_download_manager.cpp \ - qt_download.cpp \ + qtplatform.cpp \ + qt_download_manager.cpp \ + qt_download.cpp \ + location.cpp \ HEADERS += \ - platform.hpp \ - download_manager.hpp \ - qt_download_manager.hpp \ - qt_download.hpp \ + platform.hpp \ + download_manager.hpp \ + qt_download_manager.hpp \ + qt_download.hpp \ + location.hpp \ + +mac|iphone* { + OBJECTIVE_SOURCES += apple_location_service.mm + LIBS += -framework CoreLocation -framework Foundation +} + +win { + SOURCES += windows_location_service.cpp +} diff --git a/platform/windows_location_service.cpp b/platform/windows_location_service.cpp new file mode 100644 index 0000000000..4799567a5a --- /dev/null +++ b/platform/windows_location_service.cpp @@ -0,0 +1,23 @@ +#include "location.hpp" + +using namespace location; + +class WindowsLocationService : public LocationService +{ +public: + virtual void StartUpdate(bool useAccurateMode) + { + // @TODO + } + + virtual void StopUpdate() + { + // @TODO + } +}; + +extern "C" location::LocationService & GetLocationService() +{ + static WindowsLocationService ls; + return ls; +}