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