diff options
author | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-28 13:50:04 +0000 |
---|---|---|
committer | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-28 13:50:04 +0000 |
commit | 8f9238fdc4ecd0032423625679ccfa2e71a5edb6 (patch) | |
tree | 2fa5d0fdfa069c25d8d9c491ec2fddbd5b71a299 | |
parent | 10d1c7cd03001c4b58e648257cc72986f8762112 (diff) | |
download | chromium_src-8f9238fdc4ecd0032423625679ccfa2e71a5edb6.zip chromium_src-8f9238fdc4ecd0032423625679ccfa2e71a5edb6.tar.gz chromium_src-8f9238fdc4ecd0032423625679ccfa2e71a5edb6.tar.bz2 |
Add more gears geolocaiton files into chromium: locaiton provider, network location provider, and backoff maanger.
All files are from svn checkout http://gears.googlecode.com/svn/trunk/ gears-read-only r3414
Only modification is #if 0 around each file, to avoid build / checkdeps breakage.
BUG=11246
TEST=None (just importing code, tests to follow)
Review URL: http://codereview.chromium.org/555148
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37400 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/geolocation/backoff_manager.cc | 83 | ||||
-rw-r--r-- | chrome/browser/geolocation/backoff_manager.h | 63 | ||||
-rw-r--r-- | chrome/browser/geolocation/location_provider.cc | 110 | ||||
-rw-r--r-- | chrome/browser/geolocation/location_provider.h | 125 | ||||
-rw-r--r-- | chrome/browser/geolocation/location_provider_pool.cc | 182 | ||||
-rw-r--r-- | chrome/browser/geolocation/location_provider_pool.h | 89 | ||||
-rw-r--r-- | chrome/browser/geolocation/network_location_provider.cc | 508 | ||||
-rw-r--r-- | chrome/browser/geolocation/network_location_provider.h | 144 | ||||
-rw-r--r-- | chrome/browser/geolocation/network_location_request.cc | 561 | ||||
-rw-r--r-- | chrome/browser/geolocation/network_location_request.h | 141 |
10 files changed, 2006 insertions, 0 deletions
diff --git a/chrome/browser/geolocation/backoff_manager.cc b/chrome/browser/geolocation/backoff_manager.cc new file mode 100644 index 0000000..bbdae739 --- /dev/null +++ b/chrome/browser/geolocation/backoff_manager.cc @@ -0,0 +1,83 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// TODO(joth): port to chromium +#if 0 + +#include "gears/geolocation/backoff_manager.h" + +#include <assert.h> + +// The baseline minimum period between network requests. +static const int kBaselineMinimumRequestInterval = 1000 * 5; // 5 seconds +// The upper limit of the minimum period between network requests. +static const int kMinimumRequestIntervalLimit = 1000 * 60 * 60 * 3; // 3 hours + + +// static +BackoffManager::ServerMap BackoffManager::servers_; + +// static +Mutex BackoffManager::servers_mutex_; + +// static +void BackoffManager::ReportRequest(const std::string16 &url) { + MutexLock lock(&servers_mutex_); + ServerMap::iterator iter = servers_.find(url); + if (iter != servers_.end()) { + iter->second.first = GetCurrentTimeMillis(); + } else { + servers_[url] = std::make_pair(GetCurrentTimeMillis(), + kBaselineMinimumRequestInterval); + } +} + +// static +int64 BackoffManager::ReportResponse(const std::string16 &url, + bool server_error) { + // Use exponential back-off on server error. + MutexLock lock(&servers_mutex_); + ServerMap::iterator iter = servers_.find(url); + assert(iter != servers_.end()); + int64 *interval = &iter->second.second; + if (server_error) { + if (*interval < kMinimumRequestIntervalLimit) { + // Increase interval by between 90% and 110%. + srand(static_cast<unsigned int>(GetCurrentTimeMillis())); + double increment_proportion = 0.9 + 0.2 * rand() / RAND_MAX; + int64 increment = static_cast<int64>(*interval * increment_proportion); + if (increment > kMinimumRequestIntervalLimit - *interval) { + *interval = kMinimumRequestIntervalLimit; + } else { + *interval += increment; + } + } + } else { + *interval = kBaselineMinimumRequestInterval; + } + return iter->second.first + *interval; +} + +#endif // if 0 diff --git a/chrome/browser/geolocation/backoff_manager.h b/chrome/browser/geolocation/backoff_manager.h new file mode 100644 index 0000000..395d0e9 --- /dev/null +++ b/chrome/browser/geolocation/backoff_manager.h @@ -0,0 +1,63 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The BackoffManager class is used to implement exponential back-off for +// network requests in case of sever errors. Users report to the BackoffManager +// class when they make a request to or receive a response from a given url. The +// BackoffManager class provides the earliest time at which subsequent requests +// should be made. + +#ifndef GEARS_GEOLOCATION_BACKOFF_MANAGER_H__ +#define GEARS_GEOLOCATION_BACKOFF_MANAGER_H__ + +// TODO(joth): port to chromium +#if 0 + +#include "gears/base/common/common.h" +#include "gears/base/common/mutex.h" +#include "gears/base/common/stopwatch.h" // For GetCurrentTimeMillis +#include <map> + +class BackoffManager { + public: + static void ReportRequest(const std::string16 &url); + static int64 ReportResponse(const std::string16 &url, bool server_error); + + private: + // A map from server URL to a pair of integers representing the last request + // time and the current minimum interval between requests, both in + // milliseconds. + typedef std::map<std::string16, std::pair<int64, int64> > ServerMap; + static ServerMap servers_; + + // The mutex used to protect the map. + static Mutex servers_mutex_; + + DISALLOW_EVIL_CONSTRUCTORS(BackoffManager); +}; + +#endif // if 0 + +#endif // GEARS_GEOLOCATION_BACKOFF_MANAGER_H__ diff --git a/chrome/browser/geolocation/location_provider.cc b/chrome/browser/geolocation/location_provider.cc new file mode 100644 index 0000000..71bf33a --- /dev/null +++ b/chrome/browser/geolocation/location_provider.cc @@ -0,0 +1,110 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file implements a mock location provider and the factory functions for +// creating various types of location provider. + +// TODO(joth): port to chromium +#if 0 + +#include "gears/geolocation/location_provider.h" + +#include <assert.h> +#include "gears/base/common/scoped_refptr.h" // For RefCount + +void LocationProviderBase::RegisterListener(ListenerInterface *listener, + bool request_address) { + assert(listener); + MutexLock lock(&listeners_mutex_); + ListenerMap::iterator iter = listeners_.find(listener); + if (iter == listeners_.end()) { + std::pair<ListenerMap::iterator, bool> result = + listeners_.insert( + std::make_pair(listener, + std::make_pair(request_address, new RefCount()))); + assert(result.second); + iter = result.first; + } + RefCount *count = iter->second.second; + assert(count); + count->Ref(); +} + +void LocationProviderBase::UnregisterListener(ListenerInterface *listener) { + assert(listener); + MutexLock lock(&listeners_mutex_); + ListenerMap::iterator iter = listeners_.find(listener); + if (iter != listeners_.end()) { + RefCount *count = iter->second.second; + assert(count); + if (count->Unref()) { + delete count; + listeners_.erase(iter); + } + } +} + +void LocationProviderBase::UpdateListeners() { + MutexLock lock(&listeners_mutex_); + for (ListenerMap::const_iterator iter = listeners_.begin(); + iter != listeners_.end(); + ++iter) { + iter->first->LocationUpdateAvailable(this); + } +} + +void LocationProviderBase::InformListenersOfMovement() { + MutexLock lock(&listeners_mutex_); + for (ListenerMap::const_iterator iter = listeners_.begin(); + iter != listeners_.end(); + ++iter) { + iter->first->MovementDetected(this); + } +} + +LocationProviderBase::ListenerMap *LocationProviderBase::GetListeners() { + return &listeners_; +} + +Mutex *LocationProviderBase::GetListenersMutex() { + return &listeners_mutex_; +} + +// Win32, Linux and OSX do not have a GPS location provider. +#if (defined(WIN32) && !defined(OS_WINCE)) || \ + defined(LINUX) || \ + defined(OS_MACOSX) + +LocationProviderBase *NewGpsLocationProvider( + BrowsingContext *browsing_context, + const std::string16 &reverse_geocode_url, + const std::string16 &host_name, + const std::string16 &address_language) { + return NULL; +} + +#endif + +#endif // if 0 diff --git a/chrome/browser/geolocation/location_provider.h b/chrome/browser/geolocation/location_provider.h new file mode 100644 index 0000000..5383dd8 --- /dev/null +++ b/chrome/browser/geolocation/location_provider.h @@ -0,0 +1,125 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// A location provider provides position information from a particular source +// (GPS, network etc). The GearsGeolocation object uses a set of location +// providers to obtain a position fix. +// +// This file declares a base class to be used by all location providers. +// Primarily, this class declares interface methods to be implemented by derived +// classes. + +#ifndef GEARS_GEOLOCATION_LOCATION_PROVIDER_H__ +#define GEARS_GEOLOCATION_LOCATION_PROVIDER_H__ + +// TODO(joth): port to chromium +#if 0 + +#include <map> +#include "gears/base/common/base_class.h" +#include "gears/base/common/mutex.h" +#include "gears/base/common/string16.h" + +struct Position; +class RefCount; + +// The base class used by all location providers. +class LocationProviderBase { + public: + class ListenerInterface { + public: + // Used to inform listener that a new position fix is available or that a + // fatal error has occurred. Providers should call this for new listeners + // as soon as a position is available. + virtual bool LocationUpdateAvailable(LocationProviderBase *provider) = 0; + // Used to inform listener that movement has been detected. If obtaining the + // position succeeds, this will be followed by a call to + // LocationUpdateAvailable. Some providers may not be able to detect + // movement before a new fix is obtained, so will never call this method. + // Note that this is not called in response to registration of a new + // listener. + virtual bool MovementDetected(LocationProviderBase *provider) = 0; + virtual ~ListenerInterface() {} + }; + + virtual ~LocationProviderBase() {} + + // Registers a listener, which will be called back on + // ListenerInterface::LocationUpdateAvailable as soon as a position is + // available and again whenever a new position is available. Ref counts the + // listener to handle multiple calls to this method. + virtual void RegisterListener(ListenerInterface *listener, + bool request_address); + // Unregisters a listener. Unrefs the listener to handle multiple calls to + // this method. Once the ref count reaches zero, the listener is removed and + // once this method returns, no further calls to + // ListenerInterface::LocationUpdateAvailable will be made for this listener. + // It may block if a callback is in progress. + virtual void UnregisterListener(ListenerInterface *listener); + + // Interface methods + // Gets the current best position estimate. + virtual void GetPosition(Position *position) = 0; + // Provides a hint to the provider that new location data is needed as soon + // as possible. Default implementation does nothing. + virtual void UpdatePosition() {} + + // Accessor methods. + typedef std::pair<bool, RefCount*> ListenerPair; + typedef std::map<ListenerInterface*, ListenerPair> ListenerMap; + ListenerMap *GetListeners(); + Mutex *GetListenersMutex(); + + protected: + // Inform listeners that a new position or error is available, using + // LocationUpdateAvailable. + virtual void UpdateListeners(); + // Inform listeners that movement has been detected, using MovementDetected. + virtual void InformListenersOfMovement(); + + private: + // The listeners registered to this provider. For each listener, we store a + // ref count and whether it requires an address. + ListenerMap listeners_; + Mutex listeners_mutex_; +}; + +// Factory functions for the various types of location provider to abstract over +// the platform-dependent implementations. +LocationProviderBase *NewMockLocationProvider(); +LocationProviderBase *NewGpsLocationProvider( + BrowsingContext *browsing_context, + const std::string16 &reverse_geocode_url, + const std::string16 &host_name, + const std::string16 &address_language); +LocationProviderBase *NewNetworkLocationProvider( + BrowsingContext *browsing_context, + const std::string16 &url, + const std::string16 &host_name, + const std::string16 &language); + +#endif // if 0 + +#endif // GEARS_GEOLOCATION_LOCATION_PROVIDER_H__ diff --git a/chrome/browser/geolocation/location_provider_pool.cc b/chrome/browser/geolocation/location_provider_pool.cc new file mode 100644 index 0000000..32d6f92 --- /dev/null +++ b/chrome/browser/geolocation/location_provider_pool.cc @@ -0,0 +1,182 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// TODO(joth): port to chromium +#if 0 + +#include "gears/geolocation/location_provider_pool.h" + +#include <assert.h> + +static const char16 *kMockString = STRING16(L"MOCK"); +static const char16 *kGpsString = STRING16(L"GPS"); +static const char16 *kNetworkString = STRING16(L"NETWORK"); + +// Local functions +static std::string16 MakeKey(const std::string16 &type, + const std::string16 &url, + const std::string16 &host, + const std::string16 &language); + +// static member variables +LocationProviderPool LocationProviderPool::instance_; + +LocationProviderPool::LocationProviderPool() + : use_mock_location_provider_(false) { +} + +LocationProviderPool::~LocationProviderPool() { +#if BROWSER_IEMOBILE + // The lack of unload monitoring on IE Mobile on WinCE means that we may leak + // providers. +#else + assert(providers_.empty()); +#endif // BROWSER_IEMOBILE +} + +// static +LocationProviderPool *LocationProviderPool::GetInstance() { + return &instance_; +} + +LocationProviderBase *LocationProviderPool::Register( + BrowsingContext *browsing_context, + const std::string16 &type, + const std::string16 &url, + const std::string16 &host, + bool request_address, + const std::string16 &language, + LocationProviderBase::ListenerInterface *listener) { + assert(listener); + MutexLock lock(&providers_mutex_); + std::string16 key = MakeKey(type, url, host, language); + ProviderMap::iterator iter = providers_.find(key); + if (iter == providers_.end()) { + LocationProviderBase *provider = NewProvider(browsing_context, type, url, + host, language); + if (!provider) { + return NULL; + } + std::pair<ProviderMap::iterator, bool> result = + providers_.insert( + std::make_pair(key, + std::make_pair(provider, new RefCount()))); + assert(result.second); + iter = result.first; + } + LocationProviderBase *provider = iter->second.first; + assert(provider); + provider->RegisterListener(listener, request_address); + RefCount *count = iter->second.second; + assert(count); + count->Ref(); + return provider; +} + +bool LocationProviderPool::Unregister( + LocationProviderBase *provider, + LocationProviderBase::ListenerInterface *listener) { + assert(provider); + assert(listener); + MutexLock lock(&providers_mutex_); + for (ProviderMap::iterator iter = providers_.begin(); + iter != providers_.end(); + ++iter) { + LocationProviderBase *current_provider = iter->second.first; + if (current_provider == provider) { + current_provider->UnregisterListener(listener); + RefCount *count = iter->second.second; + assert(count); + if (count->Unref()) { + delete current_provider; + delete count; + providers_.erase(iter); + } + return true; + } + } + return false; +} + +void LocationProviderPool::UseMockLocationProvider( + bool use_mock_location_provider) { + use_mock_location_provider_ = use_mock_location_provider; +} + +LocationProviderBase *LocationProviderPool::NewProvider( + BrowsingContext *browsing_context, + const std::string16 &type, + const std::string16 &url, + const std::string16 &host, + const std::string16 &language) { + if (type == kMockString) { + // use_mock_location_provider_ can only be set to true in a build that uses + // USING_CCTESTS. +#if USING_CCTESTS + if (use_mock_location_provider_) { + return NewMockLocationProvider(); + } else { + return NULL; + } +#else + return NULL; +#endif // USING_CCTESTS + } else if (type == kGpsString) { + return NewGpsLocationProvider(browsing_context, url, host, language); + } else if (type == kNetworkString) { + return NewNetworkLocationProvider(browsing_context, url, host, language); + } + assert(false); + return NULL; +} + +// Local function +static std::string16 MakeKey(const std::string16 &type, + const std::string16 &url, + const std::string16 &host, + const std::string16 &language) { + // Network requests are made from a specific host and use a specific language. + // Therefore we must key network and GPS providers on server URL, host and + // language. + if (type == kMockString) { + return type; + } else if (type == kGpsString || type == kNetworkString) { + std::string16 key = type; + if (!url.empty()) { + key += STRING16(L" url=") + url; + } + if (!host.empty()) { + key += STRING16(L" host=") + host; + } + if (!language.empty()) { + key += STRING16(L" language=") + language; + } + return key; + } + assert(false); + return STRING16(L""); +} + +#endif // if 0 diff --git a/chrome/browser/geolocation/location_provider_pool.h b/chrome/browser/geolocation/location_provider_pool.h new file mode 100644 index 0000000..c15e54f --- /dev/null +++ b/chrome/browser/geolocation/location_provider_pool.h @@ -0,0 +1,89 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GEARS_GEOLOCATION_LOCATION_PROVIDER_POOL_H__ +#define GEARS_GEOLOCATION_LOCATION_PROVIDER_POOL_H__ + +// TODO(joth): port to chromium +#if 0 + +#include <map> +#include "gears/base/common/common.h" +#include "gears/base/common/mutex.h" +#include "gears/base/common/scoped_refptr.h" // For RefCount +#include "gears/base/common/string16.h" +#include "gears/geolocation/location_provider.h" + +class LocationProviderPool { + public: + LocationProviderPool(); + ~LocationProviderPool(); + + static LocationProviderPool *GetInstance(); + + // Registers a listener with a given type of location provider. Creates the + // provider if the pool does not alrerady contain an instance of that + // provider. Returns the provider, or NULL if it cannot be created. + LocationProviderBase *Register( + BrowsingContext *browsing_context, + const std::string16 &type, + const std::string16 &url, + const std::string16 &host, + bool request_address, + const std::string16 &language, + LocationProviderBase::ListenerInterface *listener); + + // Unregister a listener from a given location provider. Deletes the provider + // if there are no remaining listeners registered with it. Return value + // indicates whether the provider was found in the pool. + bool Unregister(LocationProviderBase *provider, + LocationProviderBase::ListenerInterface *listener); + + // Configures the pool to return a mock location provider for the type "MOCK". + // This method is used only by the Gears test object. + void UseMockLocationProvider(bool use_mock_location_provider); + + LocationProviderBase *NewProvider(BrowsingContext *browsing_context, + const std::string16 &type, + const std::string16 &url, + const std::string16 &host, + const std::string16 &language); + + private: + static LocationProviderPool instance_; + + typedef std::pair<LocationProviderBase*, RefCount*> ProviderPair; + typedef std::map<std::string16, ProviderPair> ProviderMap; + ProviderMap providers_; + Mutex providers_mutex_; + + bool use_mock_location_provider_; + + DISALLOW_EVIL_CONSTRUCTORS(LocationProviderPool); +}; + +#endif // if 0 + +#endif // GEARS_GEOLOCATION_LOCATION_PROVIDER_POOL_H__ diff --git a/chrome/browser/geolocation/network_location_provider.cc b/chrome/browser/geolocation/network_location_provider.cc new file mode 100644 index 0000000..df4c8cb --- /dev/null +++ b/chrome/browser/geolocation/network_location_provider.cc @@ -0,0 +1,508 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// TODO(joth): port to chromium +#if 0 + +#include "gears/geolocation/network_location_provider.h" + +#include "gears/base/common/base_class.h" +#include "gears/base/common/stopwatch.h" // For GetCurrentTimeMillis +#include "gears/geolocation/access_token_manager.h" +#include "gears/geolocation/backoff_manager.h" + +// The maximum period of time we'll wait for a complete set of device data +// before sending the request. +static const int kDataCompleteWaitPeriod = 1000 * 2; // 2 seconds + +// The maximum size of the cache of positions for previously requested device +// data. +static const size_t kMaximumCacheSize = 10; + + +// The PositionCache handles caching and retrieving a position returned by a +// network location provider. It is not thread safe. It's methods are called on +// multiple threads by NetworkLocationProvider, but the timing is such that +// thread safety is not required. +class PositionCache { + public: + // Caches the current position response for the current set of cell ID and + // WiFi data. Returns true on success, false otherwise. + bool CachePosition(const RadioData &radio_data, + const WifiData &wifi_data, + const Position &position) { + // Check that we can generate a valid key for the device data. + std::string16 key; + if (!MakeKey(radio_data, wifi_data, &key)) { + return false; + } + // If the cache is full, remove the oldest entry. + if (cache_.size() == kMaximumCacheSize) { + assert(cache_times_.size() == kMaximumCacheSize); + CacheTimesMap::iterator oldest_entry = cache_times_.begin(); + assert(oldest_entry != cache_times_.end()); + cache_.erase(oldest_entry->second); + cache_times_.erase(oldest_entry); + } + // Insert the position into the cache. + std::pair<CacheMap::iterator, bool> result = + cache_.insert(std::make_pair(key, position)); + assert(result.second); + cache_times_[position.timestamp] = result.first; + assert(cache_.size() == cache_times_.size()); + return true; + } + + // Searches for a cached position response for the current set of cell ID and + // WiFi data. Returns the cached position if available, NULL otherwise. + const Position *FindPosition(const RadioData &radio_data, + const WifiData &wifi_data) { + std::string16 key; + if (!MakeKey(radio_data, wifi_data, &key)) { + return NULL; + } + CacheMap::const_iterator iter = cache_.find(key); + return iter == cache_.end() ? NULL : &iter->second; + } + + // Makes the key for the map of cached positions, using a set of + // device data. Returns true if a good key was generated, false otherwise. + static bool MakeKey(const RadioData& /*radio_data*/, + const WifiData &wifi_data, + std::string16 *key) { + // Currently we use only the WiFi data, and base the key only on the MAC + // addresses. + // TODO(steveblock): Make use of radio_data. + key->clear(); + for (WifiData::AccessPointDataSet::const_iterator iter = + wifi_data.access_point_data.begin(); + iter != wifi_data.access_point_data.begin(); + iter++) { + key->append(STRING16(L"|") + iter->mac_address + STRING16(L"|")); + } + // If the key is the empty string, return false, as we don't want to cache a + // position for such a set of device data. + return !key->empty(); + } + +private: + // The cache of positions. This is stored using two maps. One map is keyed on + // a string that represents a set of device data, the other is keyed on the + // timestamp of the position. + typedef std::map<std::string16, Position> CacheMap; + CacheMap cache_; + typedef std::map<int64, CacheMap::iterator> CacheTimesMap; + CacheTimesMap cache_times_; +}; + + +// NetworkLocationProvider factory function +LocationProviderBase *NewNetworkLocationProvider( + BrowsingContext *browsing_context, + const std::string16 &url, + const std::string16 &host_name, + const std::string16 &language) { + return new NetworkLocationProvider(browsing_context, url, host_name, + language); +} + + +// NetworkLocationProvider +NetworkLocationProvider::NetworkLocationProvider( + BrowsingContext *browsing_context, + const std::string16 &url, + const std::string16 &host_name, + const std::string16 &language) + : request_(NULL), + url_(url), + host_name_(host_name), + request_address_(false), + request_address_from_last_request_(false), + address_language_(language), + is_shutting_down_(false), + is_new_data_available_(false), + is_new_listener_waiting_(false), + browsing_context_(browsing_context) { + // TODO(steveblock): Consider allowing multiple values for "address_language" + // in the network protocol to allow better sharing of network location + // providers. + + // Get the device data providers. The first call to Register will create the + // provider and it will be deleted by ref counting. + radio_data_provider_ = RadioDataProvider::Register(this); + wifi_data_provider_ = WifiDataProvider::Register(this); + + AccessTokenManager::GetInstance()->Register(url_); + + // Create the position cache. + position_cache_.reset(new PositionCache()); + + // Start the worker thread + if (!Start()) { + // This should never happen. + LOG(("Could not start the NLR")); + assert(false); + } +} + +NetworkLocationProvider::~NetworkLocationProvider() { + // Shut down the worker thread + is_shutting_down_ = true; + thread_notification_event_.Signal(); + Join(); + + // Must keep the request around until our worker thread has stopped. + if (request_) { + request_->StopThreadAndDelete(); + request_ = NULL; + } + + radio_data_provider_->Unregister(this); + wifi_data_provider_->Unregister(this); + + AccessTokenManager::GetInstance()->Unregister(); +} + +void NetworkLocationProvider::RegisterListener( + LocationProviderBase::ListenerInterface *listener, + bool request_address) { + // Determine whether this listener requires an address when the last request + // does not. + bool new_listener_requires_address = + !request_address_from_last_request_ && request_address; + + // Update whether or not we need to request an address. + request_address_ |= request_address; + + // If we now need to request an address when we did not before, we don't add + // the listener. This is because if a request is currently in progress, we + // don't want the new listener to be called back with a position without an + // address. We add the listener when we make the next request. + if (new_listener_requires_address) { + MutexLock lock(&new_listeners_requiring_address_mutex_); + new_listeners_requiring_address_.insert(listener); + } else { + LocationProviderBase::RegisterListener(listener, request_address); + } + + // Signal to the worker thread that there is a new listener. + is_new_listener_waiting_ = true; + thread_notification_event_.Signal(); +} + +void NetworkLocationProvider::UnregisterListener( + LocationProviderBase::ListenerInterface *listener) { + assert(listener); + + // First try removing the listener from the set of new listeners waiting for + // an address. Otherwise, try the regular listeners. + MutexLock new_listeners_lock(&new_listeners_requiring_address_mutex_); + ListenerSet::iterator iter = new_listeners_requiring_address_.find(listener); + if (iter != new_listeners_requiring_address_.end()) { + new_listeners_requiring_address_.erase(iter); + } else { + LocationProviderBase::UnregisterListener(listener); + } + + // Update whether or not we need to request an address. + if (request_address_) { + if (!new_listeners_requiring_address_.empty()) { + return; + } + MutexLock listeners_lock(GetListenersMutex()); + ListenerMap *listeners = GetListeners(); + for (ListenerMap::const_iterator iter = listeners->begin(); + iter != listeners->end(); + iter++) { + if (iter->second.first == true) { + return; + } + } + request_address_ = false; + } +} + +// LocationProviderBase implementation +void NetworkLocationProvider::GetPosition(Position *position) { + assert(position); + MutexLock lock(&position_mutex_); + *position = position_; +} + +// DeviceDataProviderInterface::ListenerInterface implementation. +void NetworkLocationProvider::DeviceDataUpdateAvailable( + RadioDataProvider *provider) { + MutexLock lock(&data_mutex_); + assert(provider == radio_data_provider_); + is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_); + + DeviceDataUpdateAvailableImpl(); +} + +void NetworkLocationProvider::DeviceDataUpdateAvailable( + WifiDataProvider *provider) { + assert(provider == wifi_data_provider_); + MutexLock lock(&data_mutex_); + is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_); + + DeviceDataUpdateAvailableImpl(); +} + +// NetworkLocationRequest::ListenerInterface implementation. +void NetworkLocationProvider::LocationResponseAvailable( + const Position &position, + bool server_error, + const std::string16 &access_token) { + // Record the position and update our cache. + position_mutex_.Lock(); + position_ = position; + if (position_.IsGoodFix()) { + MutexLock lock(&data_mutex_); + position_cache_->CachePosition(radio_data_, wifi_data_, position_); + } + position_mutex_.Unlock(); + + // Record access_token if it's set. + if (!access_token.empty()) { + AccessTokenManager::GetInstance()->SetToken(url_, access_token); + } + + // Get earliest time for next request. + earliest_next_request_time_ = BackoffManager::ReportResponse(url_, + server_error); + + // Signal to the worker thread that this request has completed. + is_last_request_complete_ = true; + thread_notification_event_.Signal(); + + // Let listeners know that we now have a position available. + UpdateListeners(); +} + +// Thread implementation +void NetworkLocationProvider::Run() { + // Create the network request object. We must do this on the same thread from + // which we'll call Start(). + request_ = NetworkLocationRequest::Create(browsing_context_, url_, + host_name_, this); + if (!request_) { + LOG(("Failed to create NetworkLocationRequest object.\n")); + assert(false); + return; + } + + // Get the device data. + data_mutex_.Lock(); + is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_); + is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_); + timestamp_ = GetCurrentTimeMillis(); + + // For the first request, wait for a certain maximum time period to get as + // much device data as possible. + int64 start_time = timestamp_; + while (true) { + if (is_radio_data_complete_ && is_wifi_data_complete_) { + data_mutex_.Unlock(); + break; + } + data_mutex_.Unlock(); + + int64 elapsed_time = GetCurrentTimeMillis() - start_time; + int timeout = kDataCompleteWaitPeriod - static_cast<int>(elapsed_time); + if (timeout <= 0) { + break; + } + if (!thread_notification_event_.WaitWithTimeout(timeout)) { + // Quit waiting if we time out. + break; + } + // Terminate the thread if requested. + if (is_shutting_down_) { + return; + } + // The event should be due to new device data or a new listener. + assert(is_new_data_available_ || is_new_listener_waiting_); + // If we have new data available, inform listeners of movement. + if (is_new_data_available_) { + InformListenersOfMovement(); + } + // Lock the data mutex to test is_radio_data_complete_ and + // is_wifi_data_complete_ on the next loop. + data_mutex_.Lock(); + } + + earliest_next_request_time_ = 0; + MakeRequest(); + + // Loop continually, making requests whenever new data becomes available, + // subject to the minimum interval. + // + // This loop is structured such that we don't require mutex locks to + // synchronise changes to is_new_data_available_ etc with signals on + // thread_notification_event_. Note that if we get a signal before we wait, + // the wait will proceed immediately, so we don't miss signals. + int64 remaining_time = 1; + while (!is_shutting_down_) { + if (remaining_time > 0) { + remaining_time = earliest_next_request_time_ - GetCurrentTimeMillis(); + } + + // If the minimum time period has not yet elapsed, set the timeout such + // that the wait expires when the period has elapsed. + if (remaining_time > 0) { + thread_notification_event_.WaitWithTimeout( + static_cast<int>(remaining_time)); + } else { + thread_notification_event_.Wait(); + } + + // Update remaining time now we've woken up. Note that it can never + // transition from <= 0 to > 0. + if (remaining_time > 0) { + remaining_time = earliest_next_request_time_ - GetCurrentTimeMillis(); + } + + bool make_request = false; + if (is_new_listener_waiting_) { + // A new listener has just registered with this provider. If new data is + // available, force a new request now, unless a request is already in + // progress. If not, update listeners with the last known position, + // provided we have one. + if (is_new_data_available_) { + if (is_last_request_complete_) { + make_request = true; + } + } else { + // Before the first network request completes, position_ may not be + // valid, so we do not update the listeners. They will be updated once + // the network request completes. + if (position_.IsInitialized()) { + // Update listeners with the last known position. + UpdateListeners(); + } + } + is_new_listener_waiting_ = false; + } + + // If a new listener has now registered such that we now require an address, + // we make a new request once the current request completes. + new_listeners_requiring_address_mutex_.Lock(); + if (!new_listeners_requiring_address_.empty()) { + if (is_last_request_complete_) { + make_request = true; + } + } + new_listeners_requiring_address_mutex_.Unlock(); + + // If the thread is not shutting down, we have new data, the last request + // has completed, and the minimum time has elapsed, make the next request. + if (!is_shutting_down_ && + is_new_data_available_ && + is_last_request_complete_ && + remaining_time <= 0) { + make_request = true; + } + + // If we have new data available, inform listeners of movement. + if (is_new_data_available_) { + InformListenersOfMovement(); + } + + // TODO(steveblock): If the request does not complete within some maximum + // time period, we should kill it and start a new request. + if (make_request) { + MakeRequest(); + remaining_time = 1; + } + } +} + +// Other methods + +bool NetworkLocationProvider::MakeRequest() { + // If we have new listeners waiting for an address, request_address_ + // must be true. + assert(new_listeners_requiring_address_.empty() || request_address_); + + // Move the new listeners waiting for an address to the list of listeners. + MutexLock lock(&new_listeners_requiring_address_mutex_); + for (ListenerSet::const_iterator iter = + new_listeners_requiring_address_.begin(); + iter != new_listeners_requiring_address_.end(); + iter++) { + LocationProviderBase::RegisterListener(*iter, true); + } + new_listeners_requiring_address_.clear(); + + request_address_from_last_request_ = request_address_; + + BackoffManager::ReportRequest(url_); + + std::string16 access_token; + AccessTokenManager::GetInstance()->GetToken(url_, &access_token); + + // Reset flags + is_new_data_available_ = false; + is_new_listener_waiting_ = false; + + data_mutex_.Lock(); + const Position *cached_position = + position_cache_->FindPosition(radio_data_, wifi_data_); + data_mutex_.Unlock(); + if (cached_position) { + assert(cached_position->IsGoodFix()); + // Record the position and update its timestamp. + position_mutex_.Lock(); + position_ = *cached_position; + position_.timestamp = timestamp_; + position_mutex_.Unlock(); + + // Let listeners know that we now have a position available. + UpdateListeners(); + return true; + } + + assert(request_); + is_last_request_complete_ = false; + MutexLock data_lock(&data_mutex_); + return request_->MakeRequest(access_token, + radio_data_, + wifi_data_, + request_address_, + address_language_, + kBadLatLng, // We don't have a position to pass + kBadLatLng, // to the server. + timestamp_); +} + +void NetworkLocationProvider::DeviceDataUpdateAvailableImpl() { + timestamp_ = GetCurrentTimeMillis(); + + // Signal to the worker thread that new data is available. + is_new_data_available_ = true; + thread_notification_event_.Signal(); +} + +#endif // if 0 diff --git a/chrome/browser/geolocation/network_location_provider.h b/chrome/browser/geolocation/network_location_provider.h new file mode 100644 index 0000000..fed0001 --- /dev/null +++ b/chrome/browser/geolocation/network_location_provider.h @@ -0,0 +1,144 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GEARS_GEOLOCATION_NETWORK_LOCATION_PROVIDER_H__ +#define GEARS_GEOLOCATION_NETWORK_LOCATION_PROVIDER_H__ + +// TODO(joth): port to chromium +#if 0 + +#include "gears/base/common/common.h" +#include "gears/base/common/mutex.h" +#include "gears/base/common/string16.h" +#include "gears/base/common/thread.h" +#include "gears/geolocation/device_data_provider.h" +#include "gears/geolocation/location_provider.h" +#include "gears/geolocation/network_location_request.h" + +// PositionCache is an implementation detail of NetworkLocationProvider. +class PositionCache; + +class NetworkLocationProvider + : public LocationProviderBase, + public RadioDataProvider::ListenerInterface, + public WifiDataProvider::ListenerInterface, + public NetworkLocationRequest::ListenerInterface, + public Thread { + public: + NetworkLocationProvider(BrowsingContext *browsing_context, + const std::string16 &url, + const std::string16 &host_name, + const std::string16 &language); + virtual ~NetworkLocationProvider(); + + // Override LocationProviderBase implementation. + virtual void RegisterListener( + LocationProviderBase::ListenerInterface *listener, + bool request_address); + virtual void UnregisterListener( + LocationProviderBase::ListenerInterface *listener); + + // LocationProviderBase implementation + virtual void GetPosition(Position *position); + + private: + // DeviceDataProvider::ListenerInterface implementation. + virtual void DeviceDataUpdateAvailable(RadioDataProvider *provider); + virtual void DeviceDataUpdateAvailable(WifiDataProvider *provider); + + // NetworkLocationRequest::ListenerInterface implementation. + virtual void LocationResponseAvailable(const Position &position, + bool server_error, + const std::string16 &access_token); + + // Thread implementation + virtual void Run(); + + // Internal helper used by worker thread to make a network request + bool MakeRequest(); + + // Internal helper used by DeviceDataUpdateAvailable + void DeviceDataUpdateAvailableImpl(); + + // The network location request object and the url and host name it will use. + NetworkLocationRequest *request_; + std::string16 url_; + std::string16 host_name_; + + // The device data providers + RadioDataProvider *radio_data_provider_; + WifiDataProvider *wifi_data_provider_; + + // The radio and wifi data, flags to indicate if each data set is complete, + // and their guarding mutex. + RadioData radio_data_; + WifiData wifi_data_; + bool is_radio_data_complete_; + bool is_wifi_data_complete_; + Mutex data_mutex_; + + // The timestamp for the latest device data update. + int64 timestamp_; + + // Parameters for the network request + bool request_address_; + bool request_address_from_last_request_; + std::string16 address_language_; + + // The current best position estimate and its guarding mutex + Position position_; + Mutex position_mutex_; + + // The event used to notify this object's (ie the network location provider) + // worker thread about changes in available data, the network request status + // and whether we're shutting down. The booleans are used to indicate what the + // event signals. + Event thread_notification_event_; + bool is_shutting_down_; + bool is_new_data_available_; + bool is_last_request_complete_; + bool is_new_listener_waiting_; + + // When the last request did not request an address, this stores any new + // listeners which have been added and require an address to be requested. + typedef std::set<LocationProviderBase::ListenerInterface*> ListenerSet; + ListenerSet new_listeners_requiring_address_; + Mutex new_listeners_requiring_address_mutex_; + + // The earliest timestamp at which the next request can be made, in + // milliseconds. + int64 earliest_next_request_time_; + + BrowsingContext *browsing_context_; + + // The cache of positions. + scoped_ptr<PositionCache> position_cache_; + + DISALLOW_EVIL_CONSTRUCTORS(NetworkLocationProvider); +}; + +#endif // if 0 + +#endif // GEARS_GEOLOCATION_NETWORK_LOCATION_PROVIDER_H__ diff --git a/chrome/browser/geolocation/network_location_request.cc b/chrome/browser/geolocation/network_location_request.cc new file mode 100644 index 0000000..47bcffe --- /dev/null +++ b/chrome/browser/geolocation/network_location_request.cc @@ -0,0 +1,561 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// TODO(joth): port to chromium +#if 0 + +#include "gears/geolocation/network_location_request.h" + +#include "gears/blob/blob_utils.h" +#include "gears/blob/buffer_blob.h" +#include "gears/localserver/common/http_constants.h" +#include "third_party/jsoncpp/reader.h" +#include "third_party/jsoncpp/value.h" +#include "third_party/jsoncpp/writer.h" + +static const char *kGearsNetworkLocationProtocolVersion = "1.1.0"; + +static const char *kAccessTokenString = "access_token"; +static const char *kLatitudeString = "latitude"; +static const char *kLongitudeString = "longitude"; +static const char *kAltitudeString = "altitude"; +static const char *kAccuracyString = "accuracy"; +static const char *kAltitudeAccuracyString = "altitude_accuracy"; +// Note that the corresponding JavaScript Position property is 'gearsAddress'. +static const char *kAddressString = "address"; +static const char *kStreetNumberString = "street_number"; +static const char *kStreetString = "street"; +static const char *kPremisesString = "premises"; +static const char *kCityString = "city"; +static const char *kCountyString = "county"; +static const char *kRegionString = "region"; +static const char *kCountryString = "country"; +static const char *kCountryCodeString = "country_code"; +static const char *kPostalCodeString = "postal_code"; + +// Local functions +static const char16* RadioTypeToString(RadioType type); +// Adds a string if it's valid to the JSON object. +static void AddString(const std::string &property_name, + const std::string16 &value, + Json::Value *object); +// Adds an integer if it's valid to the JSON object. +static void AddInteger(const std::string &property_name, + const int &value, + Json::Value *object); +// Returns true if the value is a valid angle. +static bool IsValidAngle(const double &value); +// Parses the server response body. Returns true if parsing was successful. +static bool ParseServerResponse(const std::string &response_body, + int64 timestamp, + bool is_reverse_geocode, + Position *position, + std::string16 *access_token); +static void AddRadioData(const RadioData &radio_data, Json::Value *body_object); +static void AddWifiData(const WifiData &wifi_data, Json::Value *body_object); + +// static +NetworkLocationRequest *NetworkLocationRequest::Create( + BrowsingContext *browsing_context, + const std::string16 &url, + const std::string16 &host_name, + ListenerInterface *listener) { + scoped_ptr<NetworkLocationRequest> request( + new NetworkLocationRequest(browsing_context, url, host_name, listener)); + assert(request.get()); + if (!request.get() || !request->Init() || !request->Start()) { + return NULL; + } + return request.release(); +} + +NetworkLocationRequest::NetworkLocationRequest( + BrowsingContext *browsing_context, + const std::string16 &url, + const std::string16 &host_name, + ListenerInterface *listener) + : AsyncTask(browsing_context), + listener_(listener), + url_(url), + host_name_(host_name), + is_shutting_down_(false) { +} + +bool NetworkLocationRequest::MakeRequest(const std::string16 &access_token, + const RadioData &radio_data, + const WifiData &wifi_data, + bool request_address, + const std::string16 &address_language, + double latitude, + double longitude, + int64 timestamp) { + is_reverse_geocode_ = request_address && + IsValidAngle(latitude) && + IsValidAngle(longitude); + if (!FormRequestBody(host_name_, access_token, radio_data, wifi_data, + request_address, address_language, latitude, longitude, + is_reverse_geocode_, &post_body_)) { + return false; + } + timestamp_ = timestamp; + + thread_event_.Signal(); + return true; +} + +// AsyncTask implementation. +void NetworkLocationRequest::Run() { + while (true) { + thread_event_.Wait(); + if (is_shutting_down_) { + break; + } + MakeRequestImpl(); + } +} + +void NetworkLocationRequest::MakeRequestImpl() { + WebCacheDB::PayloadInfo payload; + // TODO(andreip): remove this once WebCacheDB::PayloadInfo.data is a Blob. + scoped_refptr<BlobInterface> payload_data; + bool result = HttpPost(url_.c_str(), + false, // Not capturing, so follow redirects + NULL, // reason_header_value + HttpConstants::kMimeApplicationJson, // Content-Type + NULL, // mod_since_date + NULL, // required_cookie + true, // disable_browser_cookies + post_body_.get(), + &payload, + &payload_data, + NULL, // was_redirected + NULL, // full_redirect_url + NULL); // error_message + + MutexLock lock(&is_processing_response_mutex_); + // is_aborted_ may be true even if HttpPost succeeded. + if (is_aborted_) { + LOG(("NetworkLocationRequest::Run() : HttpPost request was cancelled.\n")); + return; + } + + if (listener_) { + Position position; + std::string response_body; + if (result) { + // If HttpPost succeeded, payload_data is guaranteed to be non-NULL. + assert(payload_data.get()); + if (!payload_data->Length() || + !BlobToString(payload_data.get(), &response_body)) { + LOG(("NetworkLocationRequest::Run() : Failed to get response body.\n")); + } + } + std::string16 access_token; + GetLocationFromResponse(result, payload.status_code, response_body, + timestamp_, url_, is_reverse_geocode_, + &position, &access_token); + + LOG(("NetworkLocationRequest::Run() : Calling listener with position.\n")); + bool server_error = + !result || (payload.status_code >= 500 && payload.status_code < 600); + listener_->LocationResponseAvailable(position, server_error, access_token); + } +} + +// static +bool NetworkLocationRequest::FormRequestBody( + const std::string16 &host_name, + const std::string16 &access_token, + const RadioData &radio_data, + const WifiData &wifi_data, + bool request_address, + std::string16 address_language, + double latitude, + double longitude, + bool is_reverse_geocode, + scoped_refptr<BlobInterface> *blob) { + assert(blob); + Json::Value body_object; + assert(body_object.isObject()); + // Version and host are required. + if (host_name.empty()) { + return false; + } + body_object["version"] = Json::Value(kGearsNetworkLocationProtocolVersion); + AddString("host", host_name, &body_object); + + AddString("access_token", access_token, &body_object); + + body_object["request_address"] = request_address; + AddString("address_language", address_language, &body_object); + + if (is_reverse_geocode) { + assert(request_address); + assert(IsValidAngle(latitude) && IsValidAngle(longitude)); + Json::Value location; + location["latitude"] = Json::Value(latitude); + location["longitude"] = Json::Value(longitude); + body_object["location"] = location; + } else { + AddRadioData(radio_data, &body_object); + AddWifiData(wifi_data, &body_object); + } + + Json::FastWriter writer; + // We always use the platform independent 'C' locale when writing the JSON + // request, irrespective of the browser's locale. This avoids the need for + // the network location provider to determine the locale of the request and + // parse the JSON accordingly. +#ifdef OS_WINCE + // WinCE does not support setlocale. +#else + char *current_locale = setlocale(LC_NUMERIC, "C"); +#endif + std::string body_string = writer.write(body_object); +#ifdef OS_WINCE + // WinCE does not support setlocale. +#else + setlocale(LC_NUMERIC, current_locale); +#endif + LOG(("NetworkLocationRequest::FormRequestBody(): Formed body %s.\n", + body_string.c_str())); + + blob->reset(new BufferBlob(body_string.c_str(), body_string.size())); + return true; +} + +// static +void NetworkLocationRequest::GetLocationFromResponse( + bool http_post_result, + int status_code, + const std::string &response_body, + int64 timestamp, + const std::string16 &server_url, + bool is_reverse_geocode, + Position *position, + std::string16 *access_token) { + assert(position); + assert(access_token); + + // HttpPost can fail for a number of reasons. Most likely this is because + // we're offline, or there was no response. + if (!http_post_result) { + LOG(("NetworkLocationRequest::GetLocationFromResponse() : HttpPost request " + "failed.\n")); + position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE; + position->error_message = STRING16(L"No response from network provider " + L"at "); + position->error_message += server_url.c_str(); + position->error_message += STRING16(L"."); + } else if (status_code == HttpConstants::HTTP_OK) { + // We use the timestamp from the device data that was used to generate + // this position fix. + if (ParseServerResponse(response_body, timestamp, is_reverse_geocode, + position, access_token)) { + // The response was successfully parsed, but it may not be a valid + // position fix. + if (!position->IsGoodFix()) { + position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE; + position->error_message = STRING16(L"Network provider at "); + position->error_message += server_url.c_str(); + position->error_message += STRING16(L" did not provide a good position " + L"fix."); + } + } else { + // We failed to parse the repsonse. + LOG(("NetworkLocationRequest::GetLocationFromResponse() : Response " + "malformed.\n")); + position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE; + position->error_message = STRING16(L"Response from network provider at "); + position->error_message += server_url.c_str(); + position->error_message += STRING16(L" was malformed."); + } + } else { + // The response was bad. + LOG(("NetworkLocationRequest::GetLocationFromResponse() : HttpPost " + "response was bad.\n")); + position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE; + position->error_message = STRING16(L"Network provider at "); + position->error_message += server_url.c_str(); + position->error_message += STRING16(L" returned error code "); + position->error_message += IntegerToString16(status_code); + position->error_message += STRING16(L"."); + } +} + +void NetworkLocationRequest::StopThreadAndDelete() { + // The FF implementation of AsyncTask::Abort() delivers a message to the UI + // thread to cancel the request. So if we call this method on the UI thread, + // we must return to the OS before the call to Abort() will take effect. In + // particular, we can't call Abort() then block here waiting for HttpPost to + // return. + is_shutting_down_ = true; + thread_event_.Signal(); + is_processing_response_mutex_.Lock(); + Abort(); + is_processing_response_mutex_.Unlock(); + DeleteWhenDone(); +} + +// Local functions. + +static const char16* RadioTypeToString(RadioType type) { + switch (type) { + case RADIO_TYPE_UNKNOWN: + return STRING16(L"unknown"); + case RADIO_TYPE_GSM: + return STRING16(L"gsm"); + case RADIO_TYPE_CDMA: + return STRING16(L"cdma"); + case RADIO_TYPE_WCDMA: + return STRING16(L"wcdma"); + default: + assert(false); + } + return NULL; +} + +static void AddString(const std::string &property_name, + const std::string16 &value, + Json::Value *object) { + assert(object); + assert(object->isObject()); + if (!value.empty()) { + std::string value_utf8; + if (String16ToUTF8(value.c_str(), value.size(), &value_utf8)) { + (*object)[property_name] = Json::Value(value_utf8); + } + } +} + +static void AddInteger(const std::string &property_name, + const int &value, + Json::Value *object) { + assert(object); + assert(object->isObject()); + if (kint32min != value) { + (*object)[property_name] = Json::Value(value); + } +} + +static bool IsValidAngle(const double &value) { + return value >= -180.0 && value <= 180.0; +} + +// Numeric values without a decimal point have type integer and IsDouble() will +// return false. This is convenience function for detecting integer or floating +// point numeric values. Note that isIntegral() includes boolean values, which +// is not what we want. +static bool IsDoubleOrInt(const Json::Value &object, + const std::string &property_name) { + return object[property_name].isDouble() || object[property_name].isInt(); +} + +// The JsValue::asXXX() methods return zero if a property isn't specified. For +// our purposes, zero is a valid value, so we have to test for existence. + +// Gets a double if it's present. +static bool GetAsDouble(const Json::Value &object, + const std::string &property_name, + double *out) { + assert(out); + if (!IsDoubleOrInt(object, property_name)) { + return false; + } + *out = object[property_name].asDouble(); + return true; +} + +// Gets a string if it's present. +static bool GetAsString(const Json::Value &object, + const std::string &property_name, + std::string16 *out) { + assert(out); + if (!object[property_name].isString()) { + return false; + } + std::string out_utf8 = object[property_name].asString(); + return UTF8ToString16(out_utf8.c_str(), out_utf8.size(), out); +} + +static bool ParseServerResponse(const std::string &response_body, + int64 timestamp, + bool is_reverse_geocode, + Position *position, + std::string16 *access_token) { + assert(position); + assert(access_token); + + if (response_body.empty()) { + LOG(("ParseServerResponse() : Response was empty.\n")); + return false; + } + LOG(("ParseServerResponse() : Parsing response %s.\n", + response_body.c_str())); + + // Parse the response, ignoring comments. The JSON reposne from the network + // location provider should always use the 'C' locale. + Json::Reader reader; + Json::Value response_object; +#ifdef OS_WINCE + // WinCE does not support setlocale. +#else + char *current_locale = setlocale(LC_NUMERIC, "C"); +#endif + bool res = reader.parse(response_body, response_object, false); +#ifdef OS_WINCE + // WinCE does not support setlocale. +#else + setlocale(LC_NUMERIC, current_locale); +#endif + if (!res) { + LOG(("ParseServerResponse() : Failed to parse response : %s.\n", + reader.getFormatedErrorMessages().c_str())); + return false; + } + + if (!response_object.isObject()) { + LOG(("ParseServerResponse() : Unexpected response type: %d.\n", + response_object.type())); + return false; + } + + // Get the access token. + GetAsString(response_object, kAccessTokenString, access_token); + + // Get the location + Json::Value location = response_object["location"]; + + // If the network provider was unable to provide a position fix, it should + // return a 200 with location == null. + if (location.type() == Json::nullValue) { + LOG(("ParseServerResponse() : Location is null.\n")); + return true; + } + + // If location is not null, it must be an object. + if (!location.isObject()) { + return false; + } + + // latitude and longitude fields are always required. + if (!GetAsDouble(location, kLatitudeString, &position->latitude) || + !GetAsDouble(location, kLongitudeString, &position->longitude)) { + return false; + } + + // If it's not a reverse geocode request, the accuracy field is also required. + if (is_reverse_geocode) { + position->accuracy = 0.0; + } else { + if (!GetAsDouble(location, kAccuracyString, &position->accuracy)) { + return false; + } + } + + // Other fields are optional. + GetAsDouble(location, kAltitudeString, &position->altitude); + GetAsDouble(location, kAltitudeAccuracyString, &position->altitude_accuracy); + Json::Value address = location[kAddressString]; + if (address.isObject()) { + GetAsString(address, kStreetNumberString, &position->address.street_number); + GetAsString(address, kStreetString, &position->address.street); + GetAsString(address, kPremisesString, &position->address.premises); + GetAsString(address, kCityString, &position->address.city); + GetAsString(address, kCountyString, &position->address.county); + GetAsString(address, kRegionString, &position->address.region); + GetAsString(address, kCountryString, &position->address.country); + GetAsString(address, kCountryCodeString, &position->address.country_code); + GetAsString(address, kPostalCodeString, &position->address.postal_code); + } + + position->timestamp = timestamp; + return true; +} + +static void AddRadioData(const RadioData &radio_data, + Json::Value *body_object) { + assert(body_object); + + AddInteger("home_mobile_country_code", radio_data.home_mobile_country_code, + body_object); + AddInteger("home_mobile_network_code", radio_data.home_mobile_network_code, + body_object); + AddString("radio_type", RadioTypeToString(radio_data.radio_type), + body_object); + AddString("carrier", radio_data.carrier, body_object); + + Json::Value cell_towers; + assert(cell_towers.isArray()); + int num_cell_towers = static_cast<int>(radio_data.cell_data.size()); + for (int i = 0; i < num_cell_towers; ++i) { + Json::Value cell_tower; + assert(cell_tower.isObject()); + AddInteger("cell_id", radio_data.cell_data[i].cell_id, &cell_tower); + AddInteger("location_area_code", radio_data.cell_data[i].location_area_code, + &cell_tower); + AddInteger("mobile_country_code", + radio_data.cell_data[i].mobile_country_code, &cell_tower); + AddInteger("mobile_network_code", + radio_data.cell_data[i].mobile_network_code, &cell_tower); + AddInteger("age", radio_data.cell_data[i].age, &cell_tower); + AddInteger("signal_strength", radio_data.cell_data[i].radio_signal_strength, + &cell_tower); + AddInteger("timing_advance", radio_data.cell_data[i].timing_advance, + &cell_tower); + cell_towers[i] = cell_tower; + } + if (num_cell_towers > 0) { + (*body_object)["cell_towers"] = cell_towers; + } +} + +static void AddWifiData(const WifiData &wifi_data, Json::Value *body_object) { + assert(body_object); + + if (wifi_data.access_point_data.empty()) { + return; + } + + Json::Value wifi_towers; + assert(wifi_towers.isArray()); + for (WifiData::AccessPointDataSet::const_iterator iter = + wifi_data.access_point_data.begin(); + iter != wifi_data.access_point_data.end(); + iter++) { + Json::Value wifi_tower; + assert(wifi_tower.isObject()); + AddString("mac_address", iter->mac_address, &wifi_tower); + AddInteger("signal_strength", iter->radio_signal_strength, &wifi_tower); + AddInteger("age", iter->age, &wifi_tower); + AddInteger("channel", iter->channel, &wifi_tower); + AddInteger("signal_to_noise", iter->signal_to_noise, &wifi_tower); + AddString("ssid", iter->ssid, &wifi_tower); + wifi_towers.append(wifi_tower); + } + (*body_object)["wifi_towers"] = wifi_towers; +} + +#endif // if 0 diff --git a/chrome/browser/geolocation/network_location_request.h b/chrome/browser/geolocation/network_location_request.h new file mode 100644 index 0000000..18a9081 --- /dev/null +++ b/chrome/browser/geolocation/network_location_request.h @@ -0,0 +1,141 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GEARS_GEOLOCATION_NETWORK_LOCATION_REQUEST_H__ +#define GEARS_GEOLOCATION_NETWORK_LOCATION_REQUEST_H__ + +// TODO(joth): port to chromium +#if 0 + +#include <vector> +#include "gears/base/common/basictypes.h" // For int64 +#include "gears/base/common/common.h" +#include "gears/base/common/event.h" +#include "gears/blob/blob.h" +#include "gears/geolocation/geolocation.h" +#include "gears/geolocation/device_data_provider.h" +#include "gears/localserver/common/async_task.h" + +// An implementation of an AsyncTask that takes a set of device data and sends +// it to a server to get a position fix. It performs formatting of the request +// and interpretation of the response. +class NetworkLocationRequest : public AsyncTask { + public: + friend class scoped_ptr<NetworkLocationRequest>; // For use in Create(). + + // Interface for receiving callbacks from a NetworkLocationRequest object. + class ListenerInterface { + public: + // Updates the listener with a new position. server_error indicates whether + // was a server or network error - either no response or a 500 error code. + virtual void LocationResponseAvailable( + const Position &position, + bool server_error, + const std::string16 &access_token) = 0; + }; + + // Creates the object and starts its worker thread running. Returns NULL if + // creation or initialisation fails. + static NetworkLocationRequest* Create(BrowsingContext *browsing_context, + const std::string16 &url, + const std::string16 &host_name, + ListenerInterface *listener); + bool MakeRequest(const std::string16 &access_token, + const RadioData &radio_data, + const WifiData &wifi_data, + bool request_address, + const std::string16 &address_language, + double latitude, + double longitude, + int64 timestamp); + // This method aborts any pending request and instructs the worker thread to + // terminate. The object is destructed once the thread terminates. This + // method blocks until the AsyncTask::Run() implementation is complete, after + // which the thread will not attempt to access external resources such as the + // listener. + void StopThreadAndDelete(); + + private: + // Private constructor and destructor. Callers should use Create() and + // StopThreadAndDelete(). + NetworkLocationRequest(BrowsingContext *browsing_context, + const std::string16 &url, + const std::string16 &host_name, + ListenerInterface *listener); + virtual ~NetworkLocationRequest() {} + + void MakeRequestImpl(); + + // AsyncTask implementation. + virtual void Run(); + + static bool FormRequestBody(const std::string16 &host_name, + const std::string16 &access_token, + const RadioData &radio_data, + const WifiData &wifi_data, + bool request_address, + std::string16 address_language, + double latitude, + double longitude, + bool is_reverse_geocode, + scoped_refptr<BlobInterface> *blob); + + static void GetLocationFromResponse(bool http_post_result, + int status_code, + const std::string &response_body, + int64 timestamp, + const std::string16 &server_url, + bool is_reverse_geocode, + Position *position, + std::string16 *access_token); + + int64 timestamp_; // The timestamp of the data used to make the request. + scoped_refptr<BlobInterface> post_body_; + ListenerInterface *listener_; + std::string16 url_; + std::string16 host_name_; + + Mutex is_processing_response_mutex_; + + bool is_reverse_geocode_; + + Event thread_event_; + bool is_shutting_down_; + +#ifdef USING_CCTESTS + // Uses FormRequestBody for testing. + friend void TestGeolocationFormRequestBody(JsCallContext *context); + // Uses GetLocationFromResponse for testing. + friend void TestGeolocationGetLocationFromResponse( + JsCallContext *context, + JsRunnerInterface *js_runner); +#endif + + DISALLOW_EVIL_CONSTRUCTORS(NetworkLocationRequest); +}; + +#endif // if 0 + +#endif // GEARS_GEOLOCATION_NETWORK_LOCATION_REQUEST_H__ |