Home | History | Annotate | Download | only in geolocation
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/geolocation/location_arbitrator_impl.h"
      6 
      7 #include <map>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "content/browser/geolocation/network_location_provider.h"
     12 #include "content/public/browser/access_token_store.h"
     13 #include "content/public/browser/content_browser_client.h"
     14 #include "content/public/common/content_client.h"
     15 #include "url/gurl.h"
     16 
     17 namespace content {
     18 namespace {
     19 
     20 const char* kDefaultNetworkProviderUrl =
     21     "https://www.googleapis.com/geolocation/v1/geolocate";
     22 }  // namespace
     23 
     24 // To avoid oscillations, set this to twice the expected update interval of a
     25 // a GPS-type location provider (in case it misses a beat) plus a little.
     26 const int64 LocationArbitratorImpl::kFixStaleTimeoutMilliseconds =
     27     11 * base::Time::kMillisecondsPerSecond;
     28 
     29 LocationArbitratorImpl::LocationArbitratorImpl(
     30     const LocationUpdateCallback& callback)
     31     : callback_(callback),
     32       provider_callback_(
     33           base::Bind(&LocationArbitratorImpl::LocationUpdateAvailable,
     34                      base::Unretained(this))),
     35       position_provider_(NULL),
     36       is_permission_granted_(false),
     37       is_running_(false) {
     38 }
     39 
     40 LocationArbitratorImpl::~LocationArbitratorImpl() {
     41 }
     42 
     43 GURL LocationArbitratorImpl::DefaultNetworkProviderURL() {
     44   return GURL(kDefaultNetworkProviderUrl);
     45 }
     46 
     47 void LocationArbitratorImpl::OnPermissionGranted() {
     48   is_permission_granted_ = true;
     49   for (ScopedVector<LocationProvider>::iterator i = providers_.begin();
     50       i != providers_.end(); ++i) {
     51     (*i)->OnPermissionGranted();
     52   }
     53 }
     54 
     55 void LocationArbitratorImpl::StartProviders(bool use_high_accuracy) {
     56   // Stash options as OnAccessTokenStoresLoaded has not yet been called.
     57   is_running_ = true;
     58   use_high_accuracy_ = use_high_accuracy;
     59   if (providers_.empty()) {
     60     DCHECK(DefaultNetworkProviderURL().is_valid());
     61     GetAccessTokenStore()->LoadAccessTokens(
     62         base::Bind(&LocationArbitratorImpl::OnAccessTokenStoresLoaded,
     63                    base::Unretained(this)));
     64   } else {
     65     DoStartProviders();
     66   }
     67 }
     68 
     69 void LocationArbitratorImpl::DoStartProviders() {
     70   for (ScopedVector<LocationProvider>::iterator i = providers_.begin();
     71        i != providers_.end(); ++i) {
     72     (*i)->StartProvider(use_high_accuracy_);
     73   }
     74 }
     75 
     76 void LocationArbitratorImpl::StopProviders() {
     77   // Reset the reference location state (provider+position)
     78   // so that future starts use fresh locations from
     79   // the newly constructed providers.
     80   position_provider_ = NULL;
     81   position_ = Geoposition();
     82 
     83   providers_.clear();
     84   is_running_ = false;
     85 }
     86 
     87 void LocationArbitratorImpl::OnAccessTokenStoresLoaded(
     88     AccessTokenStore::AccessTokenSet access_token_set,
     89     net::URLRequestContextGetter* context_getter) {
     90   if (!is_running_ || !providers_.empty()) {
     91     // A second StartProviders() call may have arrived before the first
     92     // completed.
     93     return;
     94   }
     95   // If there are no access tokens, boot strap it with the default server URL.
     96   if (access_token_set.empty())
     97     access_token_set[DefaultNetworkProviderURL()];
     98   for (AccessTokenStore::AccessTokenSet::iterator i =
     99            access_token_set.begin();
    100       i != access_token_set.end(); ++i) {
    101     RegisterProvider(
    102         NewNetworkLocationProvider(
    103             GetAccessTokenStore(), context_getter,
    104             i->first, i->second));
    105   }
    106 
    107   LocationProvider* provider =
    108       GetContentClient()->browser()->OverrideSystemLocationProvider();
    109   if (!provider)
    110     provider = NewSystemLocationProvider();
    111   RegisterProvider(provider);
    112   DoStartProviders();
    113 }
    114 
    115 void LocationArbitratorImpl::RegisterProvider(
    116     LocationProvider* provider) {
    117   if (!provider)
    118     return;
    119   provider->SetUpdateCallback(provider_callback_);
    120   if (is_permission_granted_)
    121     provider->OnPermissionGranted();
    122   providers_.push_back(provider);
    123 }
    124 
    125 void LocationArbitratorImpl::LocationUpdateAvailable(
    126     const LocationProvider* provider,
    127     const Geoposition& new_position) {
    128   DCHECK(new_position.Validate() ||
    129          new_position.error_code != Geoposition::ERROR_CODE_NONE);
    130   if (!IsNewPositionBetter(position_, new_position,
    131                            provider == position_provider_))
    132     return;
    133   position_provider_ = provider;
    134   position_ = new_position;
    135   callback_.Run(position_);
    136 }
    137 
    138 AccessTokenStore* LocationArbitratorImpl::NewAccessTokenStore() {
    139   return GetContentClient()->browser()->CreateAccessTokenStore();
    140 }
    141 
    142 AccessTokenStore* LocationArbitratorImpl::GetAccessTokenStore() {
    143   if (!access_token_store_.get())
    144     access_token_store_ = NewAccessTokenStore();
    145   return access_token_store_.get();
    146 }
    147 
    148 LocationProvider* LocationArbitratorImpl::NewNetworkLocationProvider(
    149     AccessTokenStore* access_token_store,
    150     net::URLRequestContextGetter* context,
    151     const GURL& url,
    152     const base::string16& access_token) {
    153 #if defined(OS_ANDROID)
    154   // Android uses its own SystemLocationProvider.
    155   return NULL;
    156 #else
    157   return new NetworkLocationProvider(access_token_store, context, url,
    158                                      access_token);
    159 #endif
    160 }
    161 
    162 LocationProvider* LocationArbitratorImpl::NewSystemLocationProvider() {
    163 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
    164   return NULL;
    165 #else
    166   return content::NewSystemLocationProvider();
    167 #endif
    168 }
    169 
    170 base::Time LocationArbitratorImpl::GetTimeNow() const {
    171   return base::Time::Now();
    172 }
    173 
    174 bool LocationArbitratorImpl::IsNewPositionBetter(
    175     const Geoposition& old_position, const Geoposition& new_position,
    176     bool from_same_provider) const {
    177   // Updates location_info if it's better than what we currently have,
    178   // or if it's a newer update from the same provider.
    179   if (!old_position.Validate()) {
    180     // Older location wasn't locked.
    181     return true;
    182   }
    183   if (new_position.Validate()) {
    184     // New location is locked, let's check if it's any better.
    185     if (old_position.accuracy >= new_position.accuracy) {
    186       // Accuracy is better.
    187       return true;
    188     } else if (from_same_provider) {
    189       // Same provider, fresher location.
    190       return true;
    191     } else if ((GetTimeNow() - old_position.timestamp).InMilliseconds() >
    192                kFixStaleTimeoutMilliseconds) {
    193       // Existing fix is stale.
    194       return true;
    195     }
    196   }
    197   return false;
    198 }
    199 
    200 bool LocationArbitratorImpl::HasPermissionBeenGranted() const {
    201   return is_permission_granted_;
    202 }
    203 
    204 }  // namespace content
    205