diff options
Diffstat (limited to 'chrome/browser/geolocation')
-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/device_data_provider.h | 32 | ||||
-rw-r--r-- | chrome/browser/geolocation/geoposition.cc | 55 | ||||
-rw-r--r-- | chrome/browser/geolocation/geoposition.h | 60 | ||||
-rw-r--r-- | chrome/browser/geolocation/location_provider.cc | 105 | ||||
-rw-r--r-- | chrome/browser/geolocation/location_provider.h | 151 | ||||
-rw-r--r-- | chrome/browser/geolocation/location_provider_pool.cc | 101 | ||||
-rw-r--r-- | chrome/browser/geolocation/location_provider_pool.h | 61 | ||||
-rw-r--r-- | chrome/browser/geolocation/network_location_provider.cc | 547 | ||||
-rw-r--r-- | chrome/browser/geolocation/network_location_provider.h | 157 | ||||
-rw-r--r-- | chrome/browser/geolocation/network_location_request.cc | 741 | ||||
-rw-r--r-- | chrome/browser/geolocation/network_location_request.h | 180 | ||||
-rw-r--r-- | chrome/browser/geolocation/wifi_data_provider_unittest_win.cc | 7 | ||||
-rw-r--r-- | chrome/browser/geolocation/wifi_data_provider_win.cc | 61 |
15 files changed, 913 insertions, 1491 deletions
diff --git a/chrome/browser/geolocation/backoff_manager.cc b/chrome/browser/geolocation/backoff_manager.cc deleted file mode 100644 index bbdae739..0000000 --- a/chrome/browser/geolocation/backoff_manager.cc +++ /dev/null @@ -1,83 +0,0 @@ -// 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 deleted file mode 100644 index 395d0e9..0000000 --- a/chrome/browser/geolocation/backoff_manager.h +++ /dev/null @@ -1,63 +0,0 @@ -// 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/device_data_provider.h b/chrome/browser/geolocation/device_data_provider.h index cef140c..9463636 100644 --- a/chrome/browser/geolocation/device_data_provider.h +++ b/chrome/browser/geolocation/device_data_provider.h @@ -124,7 +124,7 @@ struct AccessPointData { age(kint32min), channel(kint32min), signal_to_noise(kint32min) {} - + // MAC address, formatted as per MacAddressAsString16. string16 mac_address; int radio_signal_strength; // Measured in dBm int age; // Milliseconds since this access point was detected @@ -145,10 +145,17 @@ struct AccessPointDataLess : public std::less<AccessPointData> { // All data for wifi. struct WifiData { // Determines whether a new set of WiFi data differs significantly from this. - bool DiffersSignificantly(const WifiData &other) const { - // At least 5 or 50% of access points added or removed is significant. - static const size_t kMinChangedAccessPoints = 5; - + bool DiffersSignificantly(const WifiData& other) const { + // More than 4 or 50% of access points added or removed is significant. + static const size_t kMinChangedAccessPoints = 4; + const size_t min_ap_count = + std::min(access_point_data.size(), other.access_point_data.size()); + const size_t max_ap_count = + std::max(access_point_data.size(), other.access_point_data.size()); + const size_t difference_threadhold = std::min(kMinChangedAccessPoints, + min_ap_count / 2); + if (max_ap_count > min_ap_count + difference_threadhold) + return true; // Compute size of interesction of old and new sets. size_t num_common = 0; for (AccessPointDataSet::const_iterator iter = access_point_data.begin(); @@ -159,15 +166,10 @@ struct WifiData { ++num_common; } } - assert(num_common <= access_point_data.size()); - assert(num_common <= other.access_point_data.size()); + DCHECK(num_common <= min_ap_count); // Test how many have changed. - size_t added_or_removed = std::max( - other.access_point_data.size() - num_common, - access_point_data.size() - num_common); - return added_or_removed >= - std::min(kMinChangedAccessPoints, access_point_data.size() / 2); + return max_ap_count > num_common + difference_threadhold; } // Store access points as a set, sorted by MAC address. This allows quick @@ -291,7 +293,7 @@ class DeviceDataProvider { if (!instance_) { instance_ = new DeviceDataProvider(); } - assert(instance_); + DCHECK(instance_); instance_->Ref(); instance_->AddListener(listener); return instance_; @@ -322,11 +324,11 @@ class DeviceDataProvider { // Private constructor and destructor, callers access singleton through // Register and Unregister. DeviceDataProvider() : count_(0) { - assert(factory_function_); + DCHECK(factory_function_); impl_.reset((*factory_function_)()); impl_->SetContainer(this); bool started = impl_->StartDataProvider(); - assert(started); + DCHECK(started); } virtual ~DeviceDataProvider() {} diff --git a/chrome/browser/geolocation/geoposition.cc b/chrome/browser/geolocation/geoposition.cc new file mode 100644 index 0000000..8618431 --- /dev/null +++ b/chrome/browser/geolocation/geoposition.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/geolocation/geoposition.h" + +namespace { +// Sentinel values to mark invalid data. (WebKit carries companion is_valid +// bools for this purpose; we may eventually follow that approach, but +// sentinels worked OK in the gears code this is based on.) +const double kBadLatLng = 200; +// Lowest point on land is at approximately -400 metres. +const int kBadAltitude = -1000; +const int kBadAccuracy = -1; // Accuracy must be non-negative. +const int64 kBadTimestamp = kint64min; +} + +Position::Position() + : latitude(kBadLatLng), + longitude(kBadLatLng), + altitude(kBadAltitude), + accuracy(kBadAccuracy), + altitude_accuracy(kBadAccuracy), + timestamp(kBadTimestamp), + error_code(ERROR_CODE_NONE) { +} + +bool Position::is_valid_latlong() const { + return latitude >= -90.0 && latitude <= 90.0 && + longitude >= -180.0 && longitude <= 180.0; +} + +bool Position::is_valid_altitude() const { + return altitude > kBadAltitude; +} + +bool Position::is_valid_accuracy() const { + return accuracy >= 0.0; +} + +bool Position::is_valid_altitude_accuracy() const { + return altitude_accuracy >= 0.0; +} + +bool Position::is_valid_timestamp() const { + return timestamp != kBadTimestamp; +} + +bool Position::IsValidFix() const { + return is_valid_latlong() && is_valid_accuracy() && is_valid_timestamp(); +} + +bool Position::IsInitialized() const { + return error_code != ERROR_CODE_NONE || IsValidFix(); +} diff --git a/chrome/browser/geolocation/geoposition.h b/chrome/browser/geolocation/geoposition.h new file mode 100644 index 0000000..31e5d55 --- /dev/null +++ b/chrome/browser/geolocation/geoposition.h @@ -0,0 +1,60 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file declares the Position structure, which is used to represent a +// position fix. Originally derived from +// http://gears.googlecode.com/svn/trunk/gears/geolocation/geolocation.h + +#ifndef CHROME_BROWSER_GEOLOCATION_GEOPOSITION_H_ +#define CHROME_BROWSER_GEOLOCATION_GEOPOSITION_H_ + +#include "base/string16.h" + +// The internal representation of a position. Some properties use different +// types when passed to JavaScript. +struct Position { + public: + // Error codes for returning to JavaScript. These values are defined by the + // W3C spec. Note that Gears does not use all of these codes, but we need + // values for all of them to allow us to provide the constants on the error + // object. + enum ErrorCode { + ERROR_CODE_NONE = -1, // Gears addition + ERROR_CODE_UNKNOWN_ERROR = 0, // Not used by Gears + ERROR_CODE_PERMISSION_DENIED = 1, // Not used by Gears - Geolocation + // methods throw an exception if + // permission has not been granted. + ERROR_CODE_POSITION_UNAVAILABLE = 2, + ERROR_CODE_TIMEOUT = 3, + }; + + Position(); + + bool is_valid_latlong() const; + bool is_valid_altitude() const; + bool is_valid_accuracy() const; + bool is_valid_altitude_accuracy() const; + bool is_valid_timestamp() const; + + // A valid fix has a valid latitude, longitude, accuracy and timestamp. + bool IsValidFix() const; + + // A position is considered initialized if it has either a valid fix or + // an error code other than NONE. + bool IsInitialized() const; + + // These properties correspond to the JavaScript Position object. + double latitude; // In degrees + double longitude; // In degrees + double altitude; // In metres + double accuracy; // In metres + double altitude_accuracy; // In metres + int64 timestamp; // Milliseconds since 1st Jan 1970 + + // These properties are returned to JavaScript as a PositionError object. + ErrorCode error_code; + std::wstring error_message; // Human-readable error message +}; + +#endif // CHROME_BROWSER_GEOLOCATION_GEOPOSITION_H_ diff --git a/chrome/browser/geolocation/location_provider.cc b/chrome/browser/geolocation/location_provider.cc index 71bf33a..34d1084 100644 --- a/chrome/browser/geolocation/location_provider.cc +++ b/chrome/browser/geolocation/location_provider.cc @@ -1,73 +1,54 @@ -// 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. -// +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + // 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 "chrome/browser/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_); +LocationProviderBase::LocationProviderBase() + : client_loop_(MessageLoop::current()) { +} + +LocationProviderBase::~LocationProviderBase() { + DCHECK_EQ(client_loop_, MessageLoop::current()); +} + +void LocationProviderBase::RegisterListener(ListenerInterface* listener) { + DCHECK(listener); + if (RunInClientThread(FROM_HERE, + &LocationProviderBase::RegisterListener, listener)) + return; 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); + listeners_.insert(std::make_pair(listener, 0)); + DCHECK(result.second); iter = result.first; } - RefCount *count = iter->second.second; - assert(count); - count->Ref(); + ++iter->second; } void LocationProviderBase::UnregisterListener(ListenerInterface *listener) { - assert(listener); - MutexLock lock(&listeners_mutex_); + DCHECK(listener); + if (RunInClientThread(FROM_HERE, + &LocationProviderBase::UnregisterListener, listener)) + return; ListenerMap::iterator iter = listeners_.find(listener); if (iter != listeners_.end()) { - RefCount *count = iter->second.second; - assert(count); - if (count->Unref()) { - delete count; + if (--iter->second == 0) { listeners_.erase(iter); } } } void LocationProviderBase::UpdateListeners() { - MutexLock lock(&listeners_mutex_); + // Currently we required location provider implementations to make + // notifications from the client thread. This could be relaxed if needed. + CheckRunningInClientLoop(); for (ListenerMap::const_iterator iter = listeners_.begin(); iter != listeners_.end(); ++iter) { @@ -76,7 +57,9 @@ void LocationProviderBase::UpdateListeners() { } void LocationProviderBase::InformListenersOfMovement() { - MutexLock lock(&listeners_mutex_); + // Currently we required location provider implementations to make + // notifications from the client thread. This could be relaxed if needed. + CheckRunningInClientLoop(); for (ListenerMap::const_iterator iter = listeners_.begin(); iter != listeners_.end(); ++iter) { @@ -84,27 +67,11 @@ void LocationProviderBase::InformListenersOfMovement() { } } -LocationProviderBase::ListenerMap *LocationProviderBase::GetListeners() { - return &listeners_; +void LocationProviderBase::CheckRunningInClientLoop() { + DCHECK_EQ(MessageLoop::current(), client_loop()); } -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) { +// Currently no platforms have a GPS location provider. +LocationProviderBase* NewGpsLocationProvider() { return NULL; } - -#endif - -#endif // if 0 diff --git a/chrome/browser/geolocation/location_provider.h b/chrome/browser/geolocation/location_provider.h index 5383dd8..762ccb1 100644 --- a/chrome/browser/geolocation/location_provider.h +++ b/chrome/browser/geolocation/location_provider.h @@ -1,28 +1,7 @@ -// 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. -// +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + // 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. @@ -31,95 +10,135 @@ // 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 +#ifndef CHROME_BROWSER_GEOLOCATION_LOCATION_PROVIDER_H_ +#define CHROME_BROWSER_GEOLOCATION_LOCATION_PROVIDER_H_ #include <map> -#include "gears/base/common/base_class.h" -#include "gears/base/common/mutex.h" -#include "gears/base/common/string16.h" +#include "base/lock.h" +#include "base/message_loop.h" +#include "base/ref_counted.h" +#include "base/string16.h" +#include "base/task.h" +class GURL; struct Position; -class RefCount; +class URLRequestContextGetter; // The base class used by all location providers. -class LocationProviderBase { +class LocationProviderBase + : public base::RefCountedThreadSafe<LocationProviderBase> { public: + // Provides storage for the access token used in the network request. + // Normally the client (i.e. geolocation controller) implements this, but + // also allows mocking for testing. + class AccessTokenStore { + public: + virtual bool SetAccessToken(const GURL& url, + const string16& access_token) = 0; + virtual bool GetAccessToken(const GURL& url, string16* access_token) = 0; + + protected: + virtual ~AccessTokenStore() {} + }; + + // Clients of the location provider must implement this interface. All call- + // backs to this interface will happen in the context of the thread on which + // the location provider was created. 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; + 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 bool MovementDetected(LocationProviderBase* provider) = 0; + + protected: virtual ~ListenerInterface() {} }; - virtual ~LocationProviderBase() {} - + // TODO(joth): Make register / unregister non-virtual. // 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); + virtual void RegisterListener(ListenerInterface* listener); // 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); + virtual void UnregisterListener(ListenerInterface* listener); // Interface methods + // Returns false if the provider failed to start. + virtual bool StartProvider() = 0; // Gets the current best position estimate. - virtual void GetPosition(Position *position) = 0; + 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: + // Instances should only be destroyed via the thread safe ref count; derived + // classes should not have a public destructor. + friend class base::RefCountedThreadSafe<LocationProviderBase>; + LocationProviderBase(); + virtual ~LocationProviderBase(); + // 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(); + MessageLoop* client_loop() { return client_loop_; } + void CheckRunningInClientLoop(); + private: + // Utility methods to delegate method calls into the client thread + template <class Method> + bool RunInClientThread(const tracked_objects::Location& from_here, + Method method) { + if (MessageLoop::current() == client_loop_) { + return false; + } + client_loop_->PostTask(from_here, NewRunnableMethod(this, method)); + return true; + } + template <class Method, class A> + bool RunInClientThread(const tracked_objects::Location& from_here, + Method method, const A& a) { + if (MessageLoop::current() == client_loop_) { + return false; + } + client_loop_->PostTask(from_here, NewRunnableMethod(this, method, a)); + return true; + } + // The listeners registered to this provider. For each listener, we store a - // ref count and whether it requires an address. + // ref count. + typedef std::map<ListenerInterface*, int> ListenerMap; ListenerMap listeners_; - Mutex listeners_mutex_; + + // Reference to the client's message loop, all callbacks and access to + // the listeners_ member should happen in this context. + MessageLoop* client_loop_; }; // 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__ +LocationProviderBase* NewMockLocationProvider(); +LocationProviderBase* NewGpsLocationProvider(); +LocationProviderBase* NewNetworkLocationProvider( + LocationProviderBase::AccessTokenStore* access_token_store, + URLRequestContextGetter* context, + const GURL& url, + const string16& host_name); + +#endif // CHROME_BROWSER_GEOLOCATION_LOCATION_PROVIDER_H_ diff --git a/chrome/browser/geolocation/location_provider_pool.cc b/chrome/browser/geolocation/location_provider_pool.cc index 32d6f92..8ca57ba 100644 --- a/chrome/browser/geolocation/location_provider_pool.cc +++ b/chrome/browser/geolocation/location_provider_pool.cc @@ -1,27 +1,6 @@ -// 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. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // TODO(joth): port to chromium #if 0 @@ -35,10 +14,10 @@ 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 string16 MakeKey(const string16& type, + const string16& url, + const string16& host, + const string16& language); // static member variables LocationProviderPool LocationProviderPool::instance_; @@ -52,7 +31,7 @@ LocationProviderPool::~LocationProviderPool() { // The lack of unload monitoring on IE Mobile on WinCE means that we may leak // providers. #else - assert(providers_.empty()); + DCHECK(providers_.empty()); #endif // BROWSER_IEMOBILE } @@ -61,17 +40,17 @@ LocationProviderPool *LocationProviderPool::GetInstance() { return &instance_; } -LocationProviderBase *LocationProviderPool::Register( - BrowsingContext *browsing_context, - const std::string16 &type, - const std::string16 &url, - const std::string16 &host, +LocationProviderBase* LocationProviderPool::Register( + BrowsingContext* browsing_context, + const string16& type, + const string16& url, + const string16& host, bool request_address, - const std::string16 &language, - LocationProviderBase::ListenerInterface *listener) { - assert(listener); + const string16& language, + LocationProviderBase::ListenerInterface* listener) { + DCHECK(listener); MutexLock lock(&providers_mutex_); - std::string16 key = MakeKey(type, url, host, language); + string16 key = MakeKey(type, url, host, language); ProviderMap::iterator iter = providers_.find(key); if (iter == providers_.end()) { LocationProviderBase *provider = NewProvider(browsing_context, type, url, @@ -83,32 +62,32 @@ LocationProviderBase *LocationProviderPool::Register( providers_.insert( std::make_pair(key, std::make_pair(provider, new RefCount()))); - assert(result.second); + DCHECK(result.second); iter = result.first; } LocationProviderBase *provider = iter->second.first; - assert(provider); + DCHECK(provider); provider->RegisterListener(listener, request_address); - RefCount *count = iter->second.second; - assert(count); + RefCount* count = iter->second.second; + DCHECK(count); count->Ref(); return provider; } bool LocationProviderPool::Unregister( - LocationProviderBase *provider, - LocationProviderBase::ListenerInterface *listener) { - assert(provider); - assert(listener); + LocationProviderBase* provider, + LocationProviderBase::ListenerInterface* listener) { + DCHECK(provider); + DCHECK(listener); MutexLock lock(&providers_mutex_); for (ProviderMap::iterator iter = providers_.begin(); iter != providers_.end(); ++iter) { - LocationProviderBase *current_provider = iter->second.first; + LocationProviderBase* current_provider = iter->second.first; if (current_provider == provider) { current_provider->UnregisterListener(listener); RefCount *count = iter->second.second; - assert(count); + DCHECK(count); if (count->Unref()) { delete current_provider; delete count; @@ -125,12 +104,12 @@ void LocationProviderPool::UseMockLocationProvider( 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) { +LocationProviderBase* LocationProviderPool::NewProvider( + BrowsingContext* browsing_context, + const string16& type, + const string16& url, + const string16& host, + const string16& language) { if (type == kMockString) { // use_mock_location_provider_ can only be set to true in a build that uses // USING_CCTESTS. @@ -148,22 +127,22 @@ LocationProviderBase *LocationProviderPool::NewProvider( } else if (type == kNetworkString) { return NewNetworkLocationProvider(browsing_context, url, host, language); } - assert(false); + DCHECK(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) { +static string16 MakeKey(const string16& type, + const string16& url, + const string16& host, + const 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; + string16 key = type; if (!url.empty()) { key += STRING16(L" url=") + url; } @@ -175,7 +154,7 @@ static std::string16 MakeKey(const std::string16 &type, } return key; } - assert(false); + DCHECK(false); return STRING16(L""); } diff --git a/chrome/browser/geolocation/location_provider_pool.h b/chrome/browser/geolocation/location_provider_pool.h index c15e54f..4ba09d5 100644 --- a/chrome/browser/geolocation/location_provider_pool.h +++ b/chrome/browser/geolocation/location_provider_pool.h @@ -1,30 +1,9 @@ -// 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. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef GEARS_GEOLOCATION_LOCATION_PROVIDER_POOL_H__ -#define GEARS_GEOLOCATION_LOCATION_PROVIDER_POOL_H__ +#ifndef CHROME_BROWSER_GEOLOCATION_LOCATION_PROVIDER_POOL_H_ +#define CHROME_BROWSER_GEOLOCATION_LOCATION_PROVIDER_POOL_H_ // TODO(joth): port to chromium #if 0 @@ -46,36 +25,36 @@ class LocationProviderPool { // 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, + LocationProviderBase* Register( + BrowsingContext* browsing_context, + const string16& type, + const string16& url, + const string16& host, bool request_address, - const std::string16 &language, + const 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); + 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); + LocationProviderBase *NewProvider(BrowsingContext* browsing_context, + const string16& type, + const string16& url, + const string16& host, + const string16& language); private: static LocationProviderPool instance_; typedef std::pair<LocationProviderBase*, RefCount*> ProviderPair; - typedef std::map<std::string16, ProviderPair> ProviderMap; + typedef std::map<string16, ProviderPair> ProviderMap; ProviderMap providers_; Mutex providers_mutex_; @@ -86,4 +65,4 @@ class LocationProviderPool { #endif // if 0 -#endif // GEARS_GEOLOCATION_LOCATION_PROVIDER_POOL_H__ +#endif // CHROME_BROWSER_GEOLOCATION_LOCATION_PROVIDER_POOL_H_ diff --git a/chrome/browser/geolocation/network_location_provider.cc b/chrome/browser/geolocation/network_location_provider.cc index df4c8cb..948207d 100644 --- a/chrome/browser/geolocation/network_location_provider.cc +++ b/chrome/browser/geolocation/network_location_provider.cc @@ -1,77 +1,56 @@ -// 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" +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "chrome/browser/geolocation/network_location_provider.h" + +#include "base/time.h" + +namespace { // 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 +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; +const size_t kMaximumCacheSize = 10; +// TODO(joth): Share, or remove usage by porting callers to Time et al. +int64 GetCurrentTimeMillis() { + return static_cast<int64>(base::Time::Now().ToDoubleT() * 1000); +} +} // namespace // 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 { +class NetworkLocationProvider::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) { + 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; + 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); + DCHECK(cache_times_.size() == kMaximumCacheSize); CacheTimesMap::iterator oldest_entry = cache_times_.begin(); - assert(oldest_entry != cache_times_.end()); + DCHECK(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); + DCHECK(result.second); cache_times_[position.timestamp] = result.first; - assert(cache_.size() == cache_times_.size()); + DCHECK(cache_.size() == cache_times_.size()); return true; } @@ -79,7 +58,7 @@ class PositionCache { // WiFi data. Returns the cached position if available, NULL otherwise. const Position *FindPosition(const RadioData &radio_data, const WifiData &wifi_data) { - std::string16 key; + string16 key; if (!MakeKey(radio_data, wifi_data, &key)) { return NULL; } @@ -90,419 +69,225 @@ class PositionCache { // 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) { + const WifiData& wifi_data, + 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. + DCHECK(key); key->clear(); + key->reserve(wifi_data.access_point_data.size() * 19); + const string16 separator(ASCIIToUTF16("|")); 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"|")); + *key += separator; + *key += iter->mac_address; + *key += separator; } // 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: + 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; + typedef std::map<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); +LocationProviderBase* NewNetworkLocationProvider( + LocationProviderBase::AccessTokenStore* access_token_store, + URLRequestContextGetter* context, + const GURL& url, + const string16& host_name) { + return new NetworkLocationProvider(access_token_store, context, + url, host_name); } - // 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), + AccessTokenStore* access_token_store, + URLRequestContextGetter* url_context_getter, + const GURL& url, + const string16& host_name) + : access_token_store_(access_token_store), + radio_data_provider_(NULL), + wifi_data_provider_(NULL), + is_radio_data_complete_(false), + is_wifi_data_complete_(false), + device_data_updated_timestamp_(kint64min), 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_); - + ALLOW_THIS_IN_INITIALIZER_LIST(delayed_start_task_(this)) { // 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); - } + request_.reset(new NetworkLocationRequest(url_context_getter, url, + host_name, this)); } 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; - } + if (radio_data_provider_) + radio_data_provider_->Unregister(this); + if (wifi_data_provider_) + wifi_data_provider_->Unregister(this); } // LocationProviderBase implementation void NetworkLocationProvider::GetPosition(Position *position) { - assert(position); - MutexLock lock(&position_mutex_); + DCHECK(position); + AutoLock lock(position_mutex_); *position = position_; } +void NetworkLocationProvider::UpdatePosition() { + if (is_new_data_available_) { + RequestPosition(); + } +} + // 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(); + RadioDataProvider* provider) { + { + AutoLock lock(data_mutex_); + DCHECK(provider == radio_data_provider_); + is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_); + } + OnDeviceDataUpdated(); } 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(); + WifiDataProvider* provider) { + { + AutoLock lock(data_mutex_); + DCHECK(provider == wifi_data_provider_); + is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_); + } + OnDeviceDataUpdated(); } // NetworkLocationRequest::ListenerInterface implementation. void NetworkLocationProvider::LocationResponseAvailable( - const Position &position, + const Position& position, bool server_error, - const std::string16 &access_token) { + const string16& access_token) { + CheckRunningInClientLoop(); // 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_); + { + AutoLock position_lock(position_mutex_); + position_ = position; + } + if (position.IsValidFix()) { + AutoLock 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); + if (!access_token.empty() && access_token_ != access_token) { + access_token_ = access_token; + access_token_store_->SetAccessToken(request_->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(); - + // If new data arrived whilst request was pending reissue the request. + UpdatePosition(); // 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; +bool NetworkLocationProvider::StartProvider() { + CheckRunningInClientLoop(); + DCHECK(radio_data_provider_ == NULL); + DCHECK(wifi_data_provider_ == NULL); + if (!request_->url().is_valid()) { + LOG(WARNING) << "StartProvider() : Failed, Bad URL: " + << request_->url().possibly_invalid_spec(); + return false; } + // 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); + + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + delayed_start_task_.NewRunnableMethod( + &NetworkLocationProvider::RequestPosition), + kDataCompleteWaitPeriod); + { // Get the device data. - data_mutex_.Lock(); + AutoLock lock(data_mutex_); 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; - } } + if (is_radio_data_complete_ || is_wifi_data_complete_) + OnDeviceDataUpdated(); + return true; } // 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); +void NetworkLocationProvider::RequestPosition() { + CheckRunningInClientLoop(); + + delayed_start_task_.RevokeAll(); + const Position* cached_position; + { + AutoLock lock(data_mutex_); + cached_position = position_cache_->FindPosition(radio_data_, wifi_data_); } - 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(); + DCHECK_NE(device_data_updated_timestamp_, kint64min) << + "Timestamp must be set before looking up position"; if (cached_position) { - assert(cached_position->IsGoodFix()); + DCHECK(cached_position->IsValidFix()); // Record the position and update its timestamp. - position_mutex_.Lock(); - position_ = *cached_position; - position_.timestamp = timestamp_; - position_mutex_.Unlock(); - + { + AutoLock lock(position_mutex_); + position_ = *cached_position; + // The timestamp of a position fix is determined by the timestamp + // of the source data update. (The value of position_.timestamp from + // the cache could be from weeks ago!) + position_.timestamp = device_data_updated_timestamp_; + } + is_new_data_available_ = false; // Let listeners know that we now have a position available. UpdateListeners(); - return true; + return; } - 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_); -} + DCHECK(request_ != NULL); + + // TODO(joth): Consider timing out any pending request. + if (request_->is_request_pending()) + return; + + is_new_data_available_ = false; -void NetworkLocationProvider::DeviceDataUpdateAvailableImpl() { - timestamp_ = GetCurrentTimeMillis(); + if (access_token_.empty()) + access_token_store_->GetAccessToken(request_->url(), &access_token_); - // Signal to the worker thread that new data is available. - is_new_data_available_ = true; - thread_notification_event_.Signal(); + AutoLock data_lock(data_mutex_); + request_->MakeRequest(access_token_, radio_data_, wifi_data_, + device_data_updated_timestamp_); } -#endif // if 0 +void NetworkLocationProvider::OnDeviceDataUpdated() { + if (MessageLoop::current() != client_loop()) { + client_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &NetworkLocationProvider::OnDeviceDataUpdated)); + return; + } + device_data_updated_timestamp_ = GetCurrentTimeMillis(); + + is_new_data_available_ = is_radio_data_complete_ || is_radio_data_complete_; + if (delayed_start_task_.empty() || + (is_radio_data_complete_ && is_radio_data_complete_)) { + UpdatePosition(); + } +} diff --git a/chrome/browser/geolocation/network_location_provider.h b/chrome/browser/geolocation/network_location_provider.h index fed0001..94e5b5b 100644 --- a/chrome/browser/geolocation/network_location_provider.h +++ b/chrome/browser/geolocation/network_location_provider.h @@ -1,95 +1,64 @@ -// 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; +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_GEOLOCATION_NETWORK_LOCATION_PROVIDER_H_ +#define CHROME_BROWSER_GEOLOCATION_NETWORK_LOCATION_PROVIDER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/lock.h" +#include "base/string16.h" +#include "base/thread.h" +#include "chrome/browser/geolocation/device_data_provider.h" +#include "chrome/browser/geolocation/geoposition.h" +#include "chrome/browser/geolocation/location_provider.h" +#include "chrome/browser/geolocation/network_location_request.h" + +class URLFetcherProtectEntry; class NetworkLocationProvider : public LocationProviderBase, public RadioDataProvider::ListenerInterface, public WifiDataProvider::ListenerInterface, - public NetworkLocationRequest::ListenerInterface, - public Thread { + public NetworkLocationRequest::ListenerInterface { public: - NetworkLocationProvider(BrowsingContext *browsing_context, - const std::string16 &url, - const std::string16 &host_name, - const std::string16 &language); + NetworkLocationProvider(AccessTokenStore* access_token_store, + URLRequestContextGetter* context, + const GURL& url, + const string16& host_name); virtual ~NetworkLocationProvider(); - // Override LocationProviderBase implementation. - virtual void RegisterListener( - LocationProviderBase::ListenerInterface *listener, - bool request_address); - virtual void UnregisterListener( - LocationProviderBase::ListenerInterface *listener); - // LocationProviderBase implementation + virtual bool StartProvider(); virtual void GetPosition(Position *position); + virtual void UpdatePosition(); private: - // DeviceDataProvider::ListenerInterface implementation. - virtual void DeviceDataUpdateAvailable(RadioDataProvider *provider); - virtual void DeviceDataUpdateAvailable(WifiDataProvider *provider); + // PositionCache is an implementation detail of NetworkLocationProvider. + class PositionCache; - // NetworkLocationRequest::ListenerInterface implementation. - virtual void LocationResponseAvailable(const Position &position, - bool server_error, - const std::string16 &access_token); + // Satisfies a position request from cache or network. + void RequestPosition(); - // Thread implementation - virtual void Run(); + // Internal helper used by DeviceDataUpdateAvailable + void OnDeviceDataUpdated(); - // Internal helper used by worker thread to make a network request - bool MakeRequest(); + // DeviceDataProvider::ListenerInterface implementation. + virtual void DeviceDataUpdateAvailable(RadioDataProvider* provider); + virtual void DeviceDataUpdateAvailable(WifiDataProvider* provider); - // Internal helper used by DeviceDataUpdateAvailable - void DeviceDataUpdateAvailableImpl(); + // NetworkLocationRequest::ListenerInterface implementation. + virtual void LocationResponseAvailable(const Position& position, + bool server_error, + const string16& access_token); - // The network location request object and the url and host name it will use. - NetworkLocationRequest *request_; - std::string16 url_; - std::string16 host_name_; + AccessTokenStore* access_token_store_; - // The device data providers - RadioDataProvider *radio_data_provider_; - WifiDataProvider *wifi_data_provider_; + // The device data providers, acquired via global factories. + 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. @@ -97,48 +66,28 @@ class NetworkLocationProvider WifiData wifi_data_; bool is_radio_data_complete_; bool is_wifi_data_complete_; - Mutex data_mutex_; + Lock data_mutex_; // The timestamp for the latest device data update. - int64 timestamp_; + int64 device_data_updated_timestamp_; - // Parameters for the network request - bool request_address_; - bool request_address_from_last_request_; - std::string16 address_language_; + string16 access_token_; // 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_; + Lock position_mutex_; - // 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_; + bool is_new_data_available_; - // The earliest timestamp at which the next request can be made, in - // milliseconds. - int64 earliest_next_request_time_; - BrowsingContext *browsing_context_; + // The network location request object, and the url it uses. + scoped_ptr<NetworkLocationRequest> request_; + ScopedRunnableMethodFactory<NetworkLocationProvider> delayed_start_task_; // The cache of positions. scoped_ptr<PositionCache> position_cache_; - DISALLOW_EVIL_CONSTRUCTORS(NetworkLocationProvider); + DISALLOW_COPY_AND_ASSIGN(NetworkLocationProvider); }; -#endif // if 0 - -#endif // GEARS_GEOLOCATION_NETWORK_LOCATION_PROVIDER_H__ +#endif // CHROME_BROWSER_GEOLOCATION_NETWORK_LOCATION_PROVIDER_H_ diff --git a/chrome/browser/geolocation/network_location_request.cc b/chrome/browser/geolocation/network_location_request.cc index 47bcffe..7fff715 100644 --- a/chrome/browser/geolocation/network_location_request.cc +++ b/chrome/browser/geolocation/network_location_request.cc @@ -1,561 +1,404 @@ -// 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"; +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/geolocation/network_location_request.h" + +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/browser/geolocation/geoposition.h" +#include "chrome/browser/net/url_request_context_getter.h" +#include "net/url_request/url_request_status.h" + +namespace { +const char* const kMimeApplicationJson = "application/json"; + +// See http://code.google.com/apis/gears/geolocation_network_protocol.html +const char* kGeoLocationNetworkProtocolVersion = "1.1.0"; + +const wchar_t* kAccessTokenString = L"access_token"; +const wchar_t* kLocationString = L"location"; +const wchar_t* kLatitudeString = L"latitude"; +const wchar_t* kLongitudeString = L"longitude"; +const wchar_t* kAltitudeString = L"altitude"; +const wchar_t* kAccuracyString = L"accuracy"; +const wchar_t* kAltitudeAccuracyString = L"altitude_accuracy"; // Local functions -static const char16* RadioTypeToString(RadioType type); +// Creates the request payload to send to the server. +bool FormRequestBody(const string16& host_name, + const string16& access_token, + const RadioData& radio_data, + const WifiData& wifi_data, + std::string* data); +// Parsers the server response. +void GetLocationFromResponse(bool http_post_result, + int status_code, + const std::string& response_body, + int64 timestamp, + const GURL& server_url, + Position* position, + string16* access_token); + +const char* 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); +void AddString(const std::wstring& property_name, + const string16& value, + DictionaryValue* 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); +void AddInteger(const std::wstring& property_name, + int value, + DictionaryValue* object); // 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(); +bool ParseServerResponse(const std::string& response_body, + int64 timestamp, + Position* position, + string16* access_token); +void AddRadioData(const RadioData& radio_data, DictionaryValue* body_object); +void AddWifiData(const WifiData& wifi_data, DictionaryValue* body_object); +} // namespace + +NetworkLocationRequest::NetworkLocationRequest(URLRequestContextGetter* context, + const GURL& url, + const string16& host_name, + ListenerInterface* listener) + : url_context_(context), timestamp_(kint64min), listener_(listener), + url_(url), host_name_(host_name) { +// DCHECK(url_context_); + DCHECK(listener); } -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) { +NetworkLocationRequest::~NetworkLocationRequest() { } -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, +bool NetworkLocationRequest::MakeRequest(const string16& access_token, + const RadioData& radio_data, + const WifiData& wifi_data, int64 timestamp) { - is_reverse_geocode_ = request_address && - IsValidAngle(latitude) && - IsValidAngle(longitude); + if (url_fetcher_ != NULL) { + DLOG(INFO) << "NetworkLocationRequest : Cancelling pending request"; + url_fetcher_.reset(); + } + std::string post_body; if (!FormRequestBody(host_name_, access_token, radio_data, wifi_data, - request_address, address_language, latitude, longitude, - is_reverse_geocode_, &post_body_)) { + &post_body)) { return false; } timestamp_ = timestamp; - thread_event_.Signal(); + url_fetcher_.reset(URLFetcher::Create( + host_name_.size(), // Used for testing + url_, URLFetcher::POST, this)); + url_fetcher_->set_upload_data(kMimeApplicationJson, post_body); + url_fetcher_->set_request_context(url_context_); + url_fetcher_->Start(); return true; } -// AsyncTask implementation. -void NetworkLocationRequest::Run() { - while (true) { - thread_event_.Wait(); - if (is_shutting_down_) { - break; - } - MakeRequestImpl(); - } +void NetworkLocationRequest::OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + DCHECK_EQ(url_fetcher_.get(), source); + DCHECK(url_.possibly_invalid_spec() == url.possibly_invalid_spec()); + + Position position; + string16 access_token; + GetLocationFromResponse(status.is_success(), response_code, data, + timestamp_, url, &position, &access_token); + const bool server_error = + !status.is_success() || (response_code >= 500 && response_code < 600); + url_fetcher_.reset(); + + DCHECK(listener_); + DLOG(INFO) << "NetworkLocationRequest::Run() : " + "Calling listener with position.\n"; + listener_->LocationResponseAvailable(position, server_error, access_token); } -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; - } +// Local functions. +namespace { - 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); - } -} +bool FormRequestBody(const string16& host_name, + const string16& access_token, + const RadioData& radio_data, + const WifiData& wifi_data, + std::string* data) { + DCHECK(data); -// 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()); + DictionaryValue body_object; // 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); - } + body_object.SetString(L"version", kGeoLocationNetworkProtocolVersion); + AddString(L"host", host_name, &body_object); + + AddString(L"access_token", access_token, &body_object); + + body_object.SetBoolean(L"request_address", false); - Json::FastWriter writer; + AddRadioData(radio_data, &body_object); + AddWifiData(wifi_data, &body_object); + + // TODO(joth): Do we need to mess with locales? // 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())); +// char* current_locale = setlocale(LC_NUMERIC, "C"); + + base::JSONWriter::Write(&body_object, false, data); + +// setlocale(LC_NUMERIC, current_locale); + + DLOG(INFO) << "NetworkLocationRequest::FormRequestBody(): Formed body " + << data << ".\n"; 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); +void FormatPositionError(const GURL& server_url, + const std::wstring& message, + Position* position) { + position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE; + position->error_message = L"Network location provider at '"; + position->error_message += ASCIIToWide(server_url.possibly_invalid_spec()); + position->error_message += L"' : "; + position->error_message += message; + position->error_message += L"."; + LOG(INFO) << "NetworkLocationRequest::GetLocationFromResponse() : " + << position->error_message; +} + +void GetLocationFromResponse(bool http_post_result, + int status_code, + const std::string& response_body, + int64 timestamp, + const GURL& server_url, + Position* position, + string16* access_token) { + DCHECK(position); + DCHECK(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 { + FormatPositionError(server_url, L"No response received", position); + return; + } + if (status_code != 200) { // XXX is '200' in a constant? Can't see it // 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"."); + std::wstring message = L"Returned error code "; + message += IntToWString(status_code); + FormatPositionError(server_url, message, position); + return; + } + // We use the timestamp from the device data that was used to generate + // this position fix. + if (!ParseServerResponse(response_body, timestamp, position, access_token)) { + // We failed to parse the repsonse. + FormatPositionError(server_url, L"Response was malformed", position); + return; + } + // The response was successfully parsed, but it may not be a valid + // position fix. + if (!position->IsValidFix()) { + FormatPositionError(server_url, + L"Did not provide a good position fix", position); + return; } } -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) { +const char* RadioTypeToString(RadioType type) { switch (type) { case RADIO_TYPE_UNKNOWN: - return STRING16(L"unknown"); + break; case RADIO_TYPE_GSM: - return STRING16(L"gsm"); + return "gsm"; case RADIO_TYPE_CDMA: - return STRING16(L"cdma"); + return "cdma"; case RADIO_TYPE_WCDMA: - return STRING16(L"wcdma"); + return "wcdma"; default: - assert(false); + LOG(DFATAL) << "Bad RadioType"; } - return NULL; + return "unknown"; } -static void AddString(const std::string &property_name, - const std::string16 &value, - Json::Value *object) { - assert(object); - assert(object->isObject()); +void AddString(const std::wstring& property_name, + const string16& value, + DictionaryValue* object) { + DCHECK(object); if (!value.empty()) { - std::string value_utf8; - if (String16ToUTF8(value.c_str(), value.size(), &value_utf8)) { - (*object)[property_name] = Json::Value(value_utf8); - } + object->SetStringFromUTF16(property_name, value); } } -static void AddInteger(const std::string &property_name, - const int &value, - Json::Value *object) { - assert(object); - assert(object->isObject()); +void AddInteger(const std::wstring& property_name, + int value, + DictionaryValue* object) { + DCHECK(object); if (kint32min != value) { - (*object)[property_name] = Json::Value(value); + object->SetInteger(property_name, 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()) { +bool GetAsDouble(const DictionaryValue& object, + const std::wstring& property_name, + double* out) { + DCHECK(out); + Value* value = NULL; + if (!object.Get(property_name, &value)) return false; + int value_as_int; + DCHECK(value); + if (value->GetAsInteger(&value_as_int)) { + *out = value_as_int; + return true; } - std::string out_utf8 = object[property_name].asString(); - return UTF8ToString16(out_utf8.c_str(), out_utf8.size(), out); + return value->GetAsReal(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); +bool ParseServerResponse(const std::string& response_body, + int64 timestamp, + Position* position, + string16* access_token) { + DCHECK(position); + DCHECK(access_token); + DCHECK(timestamp != kint64min); if (response_body.empty()) { - LOG(("ParseServerResponse() : Response was empty.\n")); + LOG(WARNING) << "ParseServerResponse() : Response was empty.\n"; return false; } - LOG(("ParseServerResponse() : Parsing response %s.\n", - response_body.c_str())); + DLOG(INFO) << "ParseServerResponse() : Parsing response " + << response_body << ".\n"; - // Parse the response, ignoring comments. The JSON reposne from the network + // Parse the response, ignoring comments. + // TODO(joth): Gears version stated: The JSON reponse 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())); + // Chromium JSON parser works in UTF8 so hopefully we can ignore setlocale? + +// char* current_locale = setlocale(LC_NUMERIC, "C"); + std::string error_msg; + scoped_ptr<Value> response_value(base::JSONReader::ReadAndReturnError( + response_body, false, &error_msg)); + +// setlocale(LC_NUMERIC, current_locale); + + if (response_value == NULL) { + LOG(WARNING) << "ParseServerResponse() : JSONReader failed : " + << error_msg << ".\n"; return false; } - if (!response_object.isObject()) { - LOG(("ParseServerResponse() : Unexpected response type: %d.\n", - response_object.type())); + if (!response_value->IsType(Value::TYPE_DICTIONARY)) { + LOG(INFO) << "ParseServerResponse() : Unexpected resopnse type " + << response_value->GetType() << ".\n"; return false; } + const DictionaryValue* response_object = + static_cast<DictionaryValue*>(response_value.get()); - // Get the access token. - GetAsString(response_object, kAccessTokenString, access_token); + // Get the access token, if any. + response_object->GetStringAsUTF16(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; + DictionaryValue* location_object; + if (!response_object->GetDictionary(kLocationString, &location_object)) { + Value* value = NULL; + // If the network provider was unable to provide a position fix, it should + // return a 200 with location == null. Otherwise it's an error. + return response_object->Get(kLocationString, &value) + && value && value->IsType(Value::TYPE_NULL); } + DCHECK(location_object); // latitude and longitude fields are always required. - if (!GetAsDouble(location, kLatitudeString, &position->latitude) || - !GetAsDouble(location, kLongitudeString, &position->longitude)) { + double latitude, longitude; + if (!GetAsDouble(*location_object, kLatitudeString, &latitude) || + !GetAsDouble(*location_object, kLongitudeString, &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; - } - } + // All error paths covered: now start actually modifying postion. + position->latitude = latitude; + position->longitude = longitude; + position->timestamp = timestamp; // 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); - } + GetAsDouble(*location_object, kAccuracyString, &position->accuracy); + GetAsDouble(*location_object, kAltitudeString, &position->altitude); + GetAsDouble(*location_object, kAltitudeAccuracyString, + &position->altitude_accuracy); - position->timestamp = timestamp; return true; } -static void AddRadioData(const RadioData &radio_data, - Json::Value *body_object) { - assert(body_object); +void AddRadioData(const RadioData& radio_data, DictionaryValue* body_object) { + DCHECK(body_object); - AddInteger("home_mobile_country_code", radio_data.home_mobile_country_code, + AddInteger(L"home_mobile_country_code", radio_data.home_mobile_country_code, body_object); - AddInteger("home_mobile_network_code", radio_data.home_mobile_network_code, + AddInteger(L"home_mobile_network_code", radio_data.home_mobile_network_code, body_object); - AddString("radio_type", RadioTypeToString(radio_data.radio_type), + AddString(L"radio_type", + ASCIIToUTF16(RadioTypeToString(radio_data.radio_type)), body_object); - AddString("carrier", radio_data.carrier, body_object); + AddString(L"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; + const int num_cell_towers = static_cast<int>(radio_data.cell_data.size()); + if (num_cell_towers == 0) { + return; } - if (num_cell_towers > 0) { - (*body_object)["cell_towers"] = cell_towers; + ListValue* cell_towers = new ListValue; + for (int i = 0; i < num_cell_towers; ++i) { + DictionaryValue* cell_tower = new DictionaryValue; + AddInteger(L"cell_id", radio_data.cell_data[i].cell_id, cell_tower); + AddInteger(L"location_area_code", + radio_data.cell_data[i].location_area_code, cell_tower); + AddInteger(L"mobile_country_code", + radio_data.cell_data[i].mobile_country_code, cell_tower); + AddInteger(L"mobile_network_code", + radio_data.cell_data[i].mobile_network_code, cell_tower); + AddInteger(L"age", radio_data.cell_data[i].age, cell_tower); + AddInteger(L"signal_strength", + radio_data.cell_data[i].radio_signal_strength, cell_tower); + AddInteger(L"timing_advance", radio_data.cell_data[i].timing_advance, + cell_tower); + cell_towers->Append(cell_tower); } + body_object->Set(L"cell_towers", cell_towers); } -static void AddWifiData(const WifiData &wifi_data, Json::Value *body_object) { - assert(body_object); +void AddWifiData(const WifiData& wifi_data, DictionaryValue* body_object) { + DCHECK(body_object); if (wifi_data.access_point_data.empty()) { return; } - Json::Value wifi_towers; - assert(wifi_towers.isArray()); + ListValue* wifi_towers = new ListValue; 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); + DictionaryValue* wifi_tower = new DictionaryValue; + AddString(L"mac_address", iter->mac_address, wifi_tower); + AddInteger(L"signal_strength", iter->radio_signal_strength, wifi_tower); + AddInteger(L"age", iter->age, wifi_tower); + AddInteger(L"channel", iter->channel, wifi_tower); + AddInteger(L"signal_to_noise", iter->signal_to_noise, wifi_tower); + AddString(L"ssid", iter->ssid, wifi_tower); + wifi_towers->Append(wifi_tower); } - (*body_object)["wifi_towers"] = wifi_towers; + body_object->Set(L"wifi_towers", wifi_towers); } - -#endif // if 0 +} // namespace diff --git a/chrome/browser/geolocation/network_location_request.h b/chrome/browser/geolocation/network_location_request.h index 18a9081..4bf77fc 100644 --- a/chrome/browser/geolocation/network_location_request.h +++ b/chrome/browser/geolocation/network_location_request.h @@ -1,141 +1,75 @@ -// 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 { +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_GEOLOCATION_NETWORK_LOCATION_REQUEST_H_ +#define CHROME_BROWSER_GEOLOCATION_NETWORK_LOCATION_REQUEST_H_ + +#include <string> +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "chrome/browser/geolocation/device_data_provider.h" +#include "chrome/browser/net/url_fetcher.h" +#include "googleurl/src/gurl.h" + +struct Position; +class URLRequestContextGetter; +class URLFetcher; + +// 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 : private URLFetcher::Delegate { 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, + const Position& position, bool server_error, - const std::string16 &access_token) = 0; + const string16& access_token) = 0; + + protected: + virtual ~ListenerInterface() {} }; - // 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, + // |url| is the server address to which the request wil be sent, |host_name| + // is the host of the webpage that caused this request. + // TODO(joth): is host needed? What to do when we reuse cached locations? + NetworkLocationRequest(URLRequestContextGetter* context, + const GURL& url, + const string16& host_name, + ListenerInterface* listener); + virtual ~NetworkLocationRequest(); + + // Makes a new request. Returns true if the new request was successfully + // started. In all cases, any currently pending request will be canceled. + bool MakeRequest(const string16& access_token, + const RadioData& radio_data, + const WifiData& wifi_data, 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); + bool is_request_pending() const { return url_fetcher_ != NULL; } + const GURL& url() const { return url_; } + private: + // URLFetcher::Delegate + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); + + scoped_refptr<URLRequestContextGetter> url_context_; 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 + ListenerInterface* listener_; + const GURL url_; + string16 host_name_; + scoped_ptr<URLFetcher> url_fetcher_; DISALLOW_EVIL_CONSTRUCTORS(NetworkLocationRequest); }; -#endif // if 0 - -#endif // GEARS_GEOLOCATION_NETWORK_LOCATION_REQUEST_H__ +#endif // CHROME_BROWSER_GEOLOCATION_NETWORK_LOCATION_REQUEST_H_ diff --git a/chrome/browser/geolocation/wifi_data_provider_unittest_win.cc b/chrome/browser/geolocation/wifi_data_provider_unittest_win.cc index 3710e76..8f7571b 100644 --- a/chrome/browser/geolocation/wifi_data_provider_unittest_win.cc +++ b/chrome/browser/geolocation/wifi_data_provider_unittest_win.cc @@ -9,7 +9,6 @@ #include "base/scoped_ptr.h" #include "base/string_util.h" #include "chrome/browser/geolocation/wifi_data_provider_common.h" -#include "chrome/test/ui_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -42,7 +41,7 @@ class MessageLoopQuitListener public: explicit MessageLoopQuitListener(MessageLoop* message_loop) : message_loop_to_quit_(message_loop) { - assert(message_loop_to_quit_ != NULL); + DCHECK(message_loop_to_quit_ != NULL); } // ListenerInterface virtual void DeviceDataUpdateAvailable( @@ -74,7 +73,7 @@ class Win32WifiDataProviderTest : public testing::Test { provider_.reset(CreateWin32WifiDataProvider(&wlan_api_)); } virtual void TearDown() { - provider_.reset(NULL); + provider_.reset(); } protected: @@ -98,7 +97,7 @@ TEST_F(Win32WifiDataProviderTest, CreateDestroy) { TEST_F(Win32WifiDataProviderTest, StartThread) { EXPECT_TRUE(provider_->StartDataProvider()); - provider_.reset(NULL); // Stop()s the thread. + provider_.reset(); // Stop()s the thread. SUCCEED(); } diff --git a/chrome/browser/geolocation/wifi_data_provider_win.cc b/chrome/browser/geolocation/wifi_data_provider_win.cc index e7d52e2..c8f9ff9 100644 --- a/chrome/browser/geolocation/wifi_data_provider_win.cc +++ b/chrome/browser/geolocation/wifi_data_provider_win.cc @@ -30,10 +30,6 @@ #include "chrome/browser/geolocation/wifi_data_provider_common.h" #include "chrome/browser/geolocation/wifi_data_provider_common_win.h" -#ifdef _MSC_VER -#pragma warning(disable:4355) // 'this' : used in base member initializer list -#endif - // Taken from ndis.h for WinCE. #define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L) #define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L) @@ -166,7 +162,7 @@ WifiDataProviderImplBase *WifiDataProvider::DefaultFactoryFunction() { Win32WifiDataProvider::Win32WifiDataProvider() : Thread(__FILE__), is_first_scan_complete_(false), - task_factory_(this) { + ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) { } Win32WifiDataProvider::~Win32WifiDataProvider() { @@ -176,15 +172,15 @@ Win32WifiDataProvider::~Win32WifiDataProvider() { } void Win32WifiDataProvider::inject_mock_wlan_api(WlanApiInterface* wlan_api) { - assert(wlan_api_ == NULL); - assert(wlan_api); + DCHECK(wlan_api_ == NULL); + DCHECK(wlan_api); wlan_api_.reset(wlan_api); } void Win32WifiDataProvider::inject_mock_polling_policy( PollingPolicyInterface* policy) { - assert(polling_policy_ == NULL); - assert(policy); + DCHECK(polling_policy_ == NULL); + DCHECK(policy); polling_policy_.reset(policy); } @@ -193,7 +189,7 @@ bool Win32WifiDataProvider::StartDataProvider() { } bool Win32WifiDataProvider::GetData(WifiData *data) { - assert(data); + DCHECK(data); AutoLock lock(data_mutex_); *data = wifi_data_; // If we've successfully completed a scan, indicate that we have all of the @@ -223,17 +219,18 @@ void Win32WifiDataProvider::Init() { kNoChangePollingInterval, kTwoNoChangePollingInterval>); } - assert(polling_policy_ != NULL); + DCHECK(polling_policy_ != NULL); ScheduleNextScan(); } void Win32WifiDataProvider::CleanUp() { // Destroy the wlan api instance in the thread in which it was created. - wlan_api_.reset(NULL); + wlan_api_.reset(); } void Win32WifiDataProvider::DoWifiScanTask() { + // TODO(joth): Almost all of this is shareable across platforms. WifiData new_data; if (wlan_api_->GetAccessPointData(&new_data.access_point_data)) { bool update_available; @@ -242,7 +239,7 @@ void Win32WifiDataProvider::DoWifiScanTask() { wifi_data_ = new_data; data_mutex_.Release(); polling_policy_->UpdatePollingInterval(update_available); - if (update_available) { + if (update_available || !is_first_scan_complete_) { is_first_scan_complete_ = true; NotifyListeners(); } @@ -278,7 +275,7 @@ WindowsWlanApi* WindowsWlanApi::Create() { if (!GetSystemDirectory(&system_directory)) { return NULL; } - assert(!system_directory.empty()); + DCHECK(!system_directory.empty()); string16 dll_path = system_directory + L"wlanapi.dll"; HINSTANCE library = LoadLibraryEx(dll_path.c_str(), NULL, @@ -290,7 +287,7 @@ WindowsWlanApi* WindowsWlanApi::Create() { } void WindowsWlanApi::GetWLANFunctions(HINSTANCE wlan_library) { - assert(wlan_library); + DCHECK(wlan_library); WlanOpenHandle_function_ = reinterpret_cast<WlanOpenHandleFunction>( GetProcAddress(wlan_library, "WlanOpenHandle")); WlanEnumInterfaces_function_ = reinterpret_cast<WlanEnumInterfacesFunction>( @@ -302,7 +299,7 @@ void WindowsWlanApi::GetWLANFunctions(HINSTANCE wlan_library) { GetProcAddress(wlan_library, "WlanFreeMemory")); WlanCloseHandle_function_ = reinterpret_cast<WlanCloseHandleFunction>( GetProcAddress(wlan_library, "WlanCloseHandle")); - assert(WlanOpenHandle_function_ && + DCHECK(WlanOpenHandle_function_ && WlanEnumInterfaces_function_ && WlanGetNetworkBssList_function_ && WlanFreeMemory_function_ && @@ -311,7 +308,7 @@ void WindowsWlanApi::GetWLANFunctions(HINSTANCE wlan_library) { bool WindowsWlanApi::GetAccessPointData( WifiData::AccessPointDataSet *data) { - assert(data); + DCHECK(data); // Get the handle to the WLAN API. DWORD negotiated_version; @@ -326,7 +323,7 @@ bool WindowsWlanApi::GetAccessPointData( &wlan_handle) != ERROR_SUCCESS) { return false; } - assert(wlan_handle); + DCHECK(wlan_handle); // Get the list of interfaces. WlanEnumInterfaces allocates interface_list. WLAN_INTERFACE_INFO_LIST *interface_list = NULL; @@ -334,7 +331,7 @@ bool WindowsWlanApi::GetAccessPointData( ERROR_SUCCESS) { return false; } - assert(interface_list); + DCHECK(interface_list); // Go through the list of interfaces and get the data for each. for (int i = 0; i < static_cast<int>(interface_list->dwNumberOfItems); ++i) { @@ -360,7 +357,7 @@ int WindowsWlanApi::GetInterfaceDataWLAN( const HANDLE wlan_handle, const GUID &interface_id, WifiData::AccessPointDataSet *data) { - assert(data); + DCHECK(data); // WlanGetNetworkBssList allocates bss_list. WLAN_BSS_LIST *bss_list; if ((*WlanGetNetworkBssList_function_)(wlan_handle, @@ -391,7 +388,7 @@ int WindowsWlanApi::GetInterfaceDataWLAN( WindowsNdisApi::WindowsNdisApi( std::vector<string16>* interface_service_names) : oid_buffer_size_(kInitialBufferSize) { - assert(!interface_service_names->empty()); + DCHECK(!interface_service_names->empty()); interface_service_names_.swap(*interface_service_names); } @@ -407,7 +404,7 @@ WindowsNdisApi* WindowsNdisApi::Create() { } bool WindowsNdisApi::GetAccessPointData(WifiData::AccessPointDataSet *data) { - assert(data); + DCHECK(data); int interfaces_failed = 0; int interfaces_succeeded = 0; @@ -452,7 +449,7 @@ bool WindowsNdisApi::GetInterfacesNDIS( &network_cards_key) != ERROR_SUCCESS) { return false; } - assert(network_cards_key); + DCHECK(network_cards_key); for (int i = 0; ; ++i) { TCHAR name[kStringLength]; @@ -473,7 +470,7 @@ bool WindowsNdisApi::GetInterfacesNDIS( ERROR_SUCCESS) { break; } - assert(hardware_key); + DCHECK(hardware_key); TCHAR service_name[kStringLength]; DWORD service_name_size = kStringLength; @@ -496,7 +493,7 @@ bool WindowsNdisApi::GetInterfacesNDIS( bool WindowsNdisApi::GetInterfaceDataNDIS(HANDLE adapter_handle, WifiData::AccessPointDataSet *data) { - assert(data); + DCHECK(data); scoped_ptr_malloc<BYTE> buffer( reinterpret_cast<BYTE*>(malloc(oid_buffer_size_))); @@ -532,7 +529,7 @@ bool WindowsNdisApi::GetInterfaceDataNDIS(HANDLE adapter_handle, break; } } - assert(buffer.get()); + DCHECK(buffer.get()); if (result == ERROR_SUCCESS) { NDIS_802_11_BSSID_LIST* bssid_list = @@ -553,7 +550,7 @@ bool IsRunningOnVistaOrNewer() { bool GetNetworkData(const WLAN_BSS_ENTRY &bss_entry, AccessPointData *access_point_data) { // Currently we get only MAC address, signal strength and SSID. - assert(access_point_data); + DCHECK(access_point_data); access_point_data->mac_address = MacAddressAsString16(bss_entry.dot11Bssid); access_point_data->radio_signal_strength = bss_entry.lRssi; // bss_entry.dot11Ssid.ucSSID is not null-terminated. @@ -635,10 +632,10 @@ int PerformQuery(HANDLE adapter_handle, } bool ResizeBuffer(int requested_size, scoped_ptr_malloc<BYTE>* buffer) { - assert(requested_size > 0); - assert(buffer); + DCHECK(requested_size > 0); + DCHECK(buffer); if (requested_size > kMaximumBufferSize) { - buffer->reset(NULL); + buffer->reset(); return false; } @@ -648,7 +645,7 @@ bool ResizeBuffer(int requested_size, scoped_ptr_malloc<BYTE>* buffer) { } bool GetSystemDirectory(string16 *path) { - assert(path); + DCHECK(path); // Return value includes terminating NULL. int buffer_size = ::GetSystemDirectory(NULL, 0); if (buffer_size == 0) { @@ -661,7 +658,7 @@ bool GetSystemDirectory(string16 *path) { if (characters_written == 0) { return false; } - assert(characters_written == buffer_size - 1); + DCHECK(characters_written == buffer_size - 1); path->assign(buffer); delete[] buffer; |