From 1c052fd1e5474b2ebf80636a75a8baa5a3a92bce Mon Sep 17 00:00:00 2001 From: Alex Zolotarev Date: Tue, 3 May 2011 16:03:58 +0200 Subject: Introduced LocationManager with multiple location services support Added WiFi location service for Mac @TODO filter location events from different sources --- platform/apple_location_service.mm | 5 +- platform/location.hpp | 6 +- platform/location_manager.cpp | 75 +++++++++++++++++++++ platform/platform.pro | 22 ++++++- platform/platform_tests/platform_tests.pro | 2 +- platform/qt_location_service.cpp | 23 ------- platform/wifi_info.hpp | 26 ++++++++ platform/wifi_info_mac.mm | 101 +++++++++++++++++++++++++++++ platform/wifi_info_windows.cpp | 34 ++++++++++ platform/wifi_location_service.cpp | 96 +++++++++++++++++++++++++++ 10 files changed, 359 insertions(+), 31 deletions(-) create mode 100644 platform/location_manager.cpp delete mode 100644 platform/qt_location_service.cpp create mode 100644 platform/wifi_info.hpp create mode 100644 platform/wifi_info_mac.mm create mode 100644 platform/wifi_info_windows.cpp create mode 100644 platform/wifi_location_service.cpp (limited to 'platform') diff --git a/platform/apple_location_service.mm b/platform/apple_location_service.mm index 216436daec..64d89d7a61 100644 --- a/platform/apple_location_service.mm +++ b/platform/apple_location_service.mm @@ -179,8 +179,7 @@ public: @end -extern "C" location::LocationService & GetLocationService() +location::LocationService * CreateAppleLocationService() { - static AppleLocationService ls; - return ls; + return new AppleLocationService(); } diff --git a/platform/location.hpp b/platform/location.hpp index 45a38bcde7..839475eedf 100644 --- a/platform/location.hpp +++ b/platform/location.hpp @@ -67,6 +67,8 @@ namespace location } public: + virtual ~LocationService() {} + void SetGpsObserver(TGpsCallback observer) { m_gpsObserver = observer; @@ -85,4 +87,6 @@ namespace location } -extern "C" location::LocationService & GetLocationService(); +extern "C" location::LocationService & GetLocationManager(); +extern "C" location::LocationService * CreateAppleLocationService(); +extern "C" location::LocationService * CreateWiFiLocationService(); diff --git a/platform/location_manager.cpp b/platform/location_manager.cpp new file mode 100644 index 0000000000..b84c09c7d1 --- /dev/null +++ b/platform/location_manager.cpp @@ -0,0 +1,75 @@ +#include "location.hpp" + +#include "../std/target_os.hpp" +#include "../std/vector.hpp" +#include "../std/bind.hpp" + +/// Chooses most accurate data from different position services +class PositionFilter +{ +public: + GpsInfo const & MostNewAndAccuratePosition() + { + } +}; + +namespace location +{ + class LocationManager : public LocationService + { + vector m_services; + + void OnGpsUpdate(GpsInfo const & info) + { + NotifyGpsObserver(info); + } + + void OnCompassUpdate(CompassInfo const & info) + { + NotifyCompassObserver(info); + } + + public: + LocationManager() + { + LocationService * service; + +#if defined(OMIM_OS_IPHONE) || defined(OMIM_OS_MAC) + service = CreateAppleLocationService(); + service->SetGpsObserver(bind(&LocationManager::OnGpsUpdate, this, _1)); + service->SetCompassObserver(bind(&LocationManager::OnCompassUpdate, this, _1)); + m_services.push_back(service); +#endif + +#if defined(OMIM_OS_WINDOWS) || defined(OMIM_OS_MAC) + service = CreateWiFiLocationService(); + service->SetGpsObserver(bind(&LocationManager::OnGpsUpdate, this, _1)); + m_services.push_back(service); +#endif + } + + virtual ~LocationManager() + { + for (size_t i = 0; i < m_services.size(); ++i) + delete m_services[i]; + } + + virtual void StartUpdate(bool useAccurateMode) + { + for (size_t i = 0; i < m_services.size(); ++i) + m_services[i]->StartUpdate(useAccurateMode); + } + + virtual void StopUpdate() + { + for (size_t i = 0; i < m_services.size(); ++i) + m_services[i]->StopUpdate(); + } + }; +} + +location::LocationService & GetLocationManager() +{ + static location::LocationManager mgr; + return mgr; +} diff --git a/platform/platform.pro b/platform/platform.pro index a0c5d08022..7339bd2b1e 100644 --- a/platform/platform.pro +++ b/platform/platform.pro @@ -5,17 +5,20 @@ TEMPLATE = lib CONFIG += staticlib ROOT_DIR = .. -DEPENDENCIES = coding base +DEPENDENCIES = coding base jansson include($$ROOT_DIR/common.pri) QT *= core network !iphone* { + INCLUDEPATH += $$ROOT_DIR/3party/jansson/src + SOURCES += \ qtplatform.cpp \ + wifi_location_service.cpp \ qt_download_manager.cpp \ - qt_download.cpp + qt_download.cpp \ HEADERS += \ qt_download_manager.hpp \ @@ -26,10 +29,23 @@ HEADERS += \ platform.hpp \ download_manager.hpp \ location.hpp \ + wifi_info.hpp macx|iphone* { OBJECTIVE_SOURCES += apple_location_service.mm LIBS += -framework CoreLocation -framework Foundation } else { - SOURCES += qt_location_service.cpp + SOURCES += +} + +macx:!iphone* { + OBJECTIVE_SOURCES += wifi_info_mac.mm + LIBS += -framework CoreWLAN } +win32 { + SOURCES += wifi_info_windows.cpp +} + +# common sources for all platforms +SOURCES += \ + location_manager.cpp \ diff --git a/platform/platform_tests/platform_tests.pro b/platform/platform_tests/platform_tests.pro index 97c629a0ec..ccb68adc87 100644 --- a/platform/platform_tests/platform_tests.pro +++ b/platform/platform_tests/platform_tests.pro @@ -8,7 +8,7 @@ DEPENDENCIES = platform coding base tomcrypt jansson include($$ROOT_DIR/common.pri) -INCLUDEPATH += $$ROOT_DIR/3party/jansson $$ROOT_DIR/3party/jansson/src +INCLUDEPATH += $$ROOT_DIR/3party/jansson/src QT *= core network diff --git a/platform/qt_location_service.cpp b/platform/qt_location_service.cpp deleted file mode 100644 index 35b29875af..0000000000 --- a/platform/qt_location_service.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "location.hpp" - -using namespace location; - -class QtLocationService : public LocationService -{ -public: - virtual void StartUpdate(bool /*useAccurateMode*/) - { - // @TODO - } - - virtual void StopUpdate() - { - // @TODO - } -}; - -extern "C" location::LocationService & GetLocationService() -{ - static QtLocationService ls; - return ls; -} diff --git a/platform/wifi_info.hpp b/platform/wifi_info.hpp new file mode 100644 index 0000000000..7584031f1e --- /dev/null +++ b/platform/wifi_info.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "../std/function.hpp" + +#include "../std/vector.hpp" +#include "../std/string.hpp" + +class WiFiInfo +{ + class Impl; + Impl * m_pImpl; + +public: + struct AccessPoint + { + string m_bssid; //!< for example, "33-12-03-5b-44-9a" + string m_ssid; //!< name for APN + string m_signalStrength; //!< for example, "-54" + }; + + WiFiInfo(); + ~WiFiInfo(); + + typedef boost::function const &)> WifiRequestCallbackT; + void RequestWiFiBSSIDs(WifiRequestCallbackT callback); +}; diff --git a/platform/wifi_info_mac.mm b/platform/wifi_info_mac.mm new file mode 100644 index 0000000000..2b904c4d18 --- /dev/null +++ b/platform/wifi_info_mac.mm @@ -0,0 +1,101 @@ +#include "../std/target_os.hpp" +#ifdef OMIM_OS_MAC + +#include "wifi_info.hpp" + +#include "../base/string_utils.hpp" + +#import +#import +#import + +static string AppendZeroIfNeeded(string const & macAddrPart) +{ + string res(macAddrPart); + if (res.size() == 1) + res.insert(0, "0"); + return res; +} + +@interface WiFiInfoMac : NSObject { +@private + WiFiInfo::WifiRequestCallbackT m_callback; + vector m_accessPoints; +} +@end +//- (id)InitWithCallback:(WiFiInfo::WifiRequestCallbackT)callback; +@implementation WiFiInfoMac + +- (id)InitWithCallback:(WiFiInfo::WifiRequestCallbackT)callback +{ + self = [super init]; + m_callback = callback; + [self performSelectorInBackground:@selector(WifiScanThread) withObject:nil]; + return self; +} + +- (void)dealloc +{ + [super dealloc]; + NSLog(@"Mac OS WiFiInfo selfdestructed successfully"); +} + +/// Executed on main thread +- (void)NotifyGUI +{ + m_callback(m_accessPoints); + // selfdestruct + [self release]; +} + +/// new background thread +- (void)WifiScanThread +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + m_accessPoints.clear(); + + CWInterface * iFace = [CWInterface interface]; + NSArray * nets = [iFace scanForNetworksWithParameters:nil error:nil]; + for (NSUInteger i = 0; i < [nets count]; ++i) + { + CWNetwork * net = (CWNetwork *)[nets objectAtIndex:i]; + WiFiInfo::AccessPoint apn; + apn.m_ssid = [net.ssid UTF8String]; + apn.m_signalStrength = utils::to_string([net.rssi intValue]); + // fix formatting for wifi address + string const rawBssid = [net.bssid UTF8String]; + if (!rawBssid.empty()) + { + utils::TokenizeIterator tokIt(rawBssid, ":"); + apn.m_bssid = AppendZeroIfNeeded(*tokIt); + while (!(++tokIt).is_last()) + { + apn.m_bssid += "-"; + apn.m_bssid += AppendZeroIfNeeded(*tokIt); + } + } + m_accessPoints.push_back(apn); + } + + [pool drain]; + + [self performSelectorOnMainThread:@selector(NotifyGUI) withObject:nil waitUntilDone:NO]; +} +@end +///////////////////////////////////////////////////////////////////////////// +WiFiInfo::WiFiInfo() +{ +} + +WiFiInfo::~WiFiInfo() +{ +} + +void WiFiInfo::RequestWiFiBSSIDs(WifiRequestCallbackT callback) +{ + // it will be self-destroyed when finished + [[WiFiInfoMac alloc] InitWithCallback:callback]; +} + +#endif diff --git a/platform/wifi_info_windows.cpp b/platform/wifi_info_windows.cpp new file mode 100644 index 0000000000..cebaddf390 --- /dev/null +++ b/platform/wifi_info_windows.cpp @@ -0,0 +1,34 @@ +#include "wifi_info.hpp" + +#if defined(OMIM_OS_WINDOWS) + #include "internal/wifi_impl_windows.hpp" +#elif defined(OMIM_OS_MAC) + #include "internal/wifi_impl_mac.hpp" +#else + #error "Please add your OS implementation" +#endif + +class WiFiInfo::Impl +{ + WiFiInfo::WifiRequestCallbackT m_callback; + +public: + void RequestWiFiBSSIDs(WifiRequestCallbackT callback) + { + } +}; + + +WiFiInfo::WiFiInfo() : m_pImpl(new WiFiInfo::Impl) +{ +} + +WiFiInfo::~WiFiInfo() +{ + delete m_pImpl; +} + +void WiFiInfo::RequestWiFiBSSIDs(WifiRequestCallbackT callback) +{ + m_pImpl->RequestWiFiBSSIDs(callback); +} diff --git a/platform/wifi_location_service.cpp b/platform/wifi_location_service.cpp new file mode 100644 index 0000000000..a3f9a3803c --- /dev/null +++ b/platform/wifi_location_service.cpp @@ -0,0 +1,96 @@ +#include "location.hpp" +#include "wifi_info.hpp" +#include "download_manager.hpp" + +#include "../base/logging.hpp" + +#include "../std/bind.hpp" + +#include "../3party/jansson/myjansson.hpp" + +#define MWM_GEOLOCATION_SERVER "http://geolocation.server/" + +namespace location +{ + class WiFiLocationService : public LocationService + { + WiFiInfo m_wifiInfo; + + void OnHttpPostFinished(HttpFinishedParams const & result) + { + // here we should receive json reply with coordinates and accuracy + try + { + my::Json root(result.m_data.c_str()); + if (json_is_object(root)) + { + json_t * location = json_object_get(root, "location"); + if (json_is_object(location)) + { + json_t * lat = json_object_get(location, "latitude"); + json_t * lon = json_object_get(location, "longitude"); + json_t * acc = json_object_get(location, "accuracy"); + if (json_is_real(lat) && json_is_real(lon) && json_is_real(acc)) + { + GpsInfo info; + info.m_latitude = json_real_value(lat); + info.m_longitude = json_real_value(lon); + info.m_horizontalAccuracy = json_real_value(acc); + // @TODO introduce flags to mark valid values + info.m_status = ERoughMode; + NotifyGpsObserver(info); + } + } + } + } + catch (my::Json::Exception const & e) + { + LOG(LWARNING, ("Invalid reply from location server:", e.what(), result.m_data)); + } + LOG(LWARNING, ("Invalid reply from location server:", result.m_data)); + } + + void OnWifiScanCompleted(vector const & accessPoints) + { + string jsonRequest("{\"version\":\"1.1.0\""); + if (accessPoints.size()) + jsonRequest += ",\"wifi_towers\":["; + + for (size_t i = 0; i < accessPoints.size(); ++i) + { + jsonRequest += "{\"mac_address\":\""; + jsonRequest += accessPoints[i].m_bssid; + jsonRequest += "\",\"ssid\":\""; + jsonRequest += accessPoints[i].m_ssid; + jsonRequest += "\",\"signal_strength\":"; + jsonRequest += accessPoints[i].m_signalStrength; + jsonRequest += "},"; + } + if (accessPoints.size()) + jsonRequest[jsonRequest.size() - 1] = ']'; + jsonRequest += "}"; + + HttpStartParams params; + params.m_finish = bind(&WiFiLocationService::OnHttpPostFinished, this, _1); + params.m_contentType = "application/json"; + params.m_postData = jsonRequest; + params.m_url = MWM_GEOLOCATION_SERVER; + GetDownloadManager().HttpRequest(params); + } + + public: + virtual void StartUpdate(bool) + { + m_wifiInfo.RequestWiFiBSSIDs(bind(&WiFiLocationService::OnWifiScanCompleted, this, _1)); + } + + virtual void StopUpdate() + { + } + }; +} + +location::LocationService * CreateWiFiLocationService() +{ + return new location::WiFiLocationService(); +} -- cgit v1.2.3