Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(102)

Side by Side Diff: device/geolocation/network_location_provider.cc

Issue 2192683003: Revert of Reland: Geolocation: move from content/browser to device/ (patchset #2 id:20001 of https:… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2810
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "device/geolocation/network_location_provider.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/threading/thread_task_runner_handle.h"
12 #include "base/time/time.h"
13 #include "device/geolocation/access_token_store.h"
14
15 namespace device {
16 namespace {
17 // The maximum period of time we'll wait for a complete set of wifi data
18 // before sending the request.
19 const int kDataCompleteWaitSeconds = 2;
20 } // namespace
21
22 // static
23 const size_t NetworkLocationProvider::PositionCache::kMaximumSize = 10;
24
25 NetworkLocationProvider::PositionCache::PositionCache() {}
26
27 NetworkLocationProvider::PositionCache::~PositionCache() {}
28
29 bool NetworkLocationProvider::PositionCache::CachePosition(
30 const WifiData& wifi_data,
31 const Geoposition& position) {
32 // Check that we can generate a valid key for the wifi data.
33 base::string16 key;
34 if (!MakeKey(wifi_data, &key)) {
35 return false;
36 }
37 // If the cache is full, remove the oldest entry.
38 if (cache_.size() == kMaximumSize) {
39 DCHECK(cache_age_list_.size() == kMaximumSize);
40 CacheAgeList::iterator oldest_entry = cache_age_list_.begin();
41 DCHECK(oldest_entry != cache_age_list_.end());
42 cache_.erase(*oldest_entry);
43 cache_age_list_.erase(oldest_entry);
44 }
45 DCHECK_LT(cache_.size(), kMaximumSize);
46 // Insert the position into the cache.
47 std::pair<CacheMap::iterator, bool> result =
48 cache_.insert(std::make_pair(key, position));
49 if (!result.second) {
50 NOTREACHED(); // We never try to add the same key twice.
51 CHECK_EQ(cache_.size(), cache_age_list_.size());
52 return false;
53 }
54 cache_age_list_.push_back(result.first);
55 DCHECK_EQ(cache_.size(), cache_age_list_.size());
56 return true;
57 }
58
59 // Searches for a cached position response for the current WiFi data. Returns
60 // the cached position if available, nullptr otherwise.
61 const Geoposition* NetworkLocationProvider::PositionCache::FindPosition(
62 const WifiData& wifi_data) {
63 base::string16 key;
64 if (!MakeKey(wifi_data, &key)) {
65 return nullptr;
66 }
67 CacheMap::const_iterator iter = cache_.find(key);
68 return iter == cache_.end() ? nullptr : &iter->second;
69 }
70
71 // Makes the key for the map of cached positions, using the available data.
72 // Returns true if a good key was generated, false otherwise.
73 //
74 // static
75 bool NetworkLocationProvider::PositionCache::MakeKey(
76 const WifiData& wifi_data,
77 base::string16* key) {
78 // Currently we use only WiFi data and base the key only on the MAC addresses.
79 DCHECK(key);
80 key->clear();
81 const size_t kCharsPerMacAddress = 6 * 3 + 1; // e.g. "11:22:33:44:55:66|"
82 key->reserve(wifi_data.access_point_data.size() * kCharsPerMacAddress);
83 const base::string16 separator(base::ASCIIToUTF16("|"));
84 for (const auto& access_point_data : wifi_data.access_point_data) {
85 *key += separator;
86 *key += access_point_data.mac_address;
87 *key += separator;
88 }
89 // If the key is the empty string, return false, as we don't want to cache a
90 // position for such data.
91 return !key->empty();
92 }
93
94 // NetworkLocationProvider factory function
95 LocationProviderBase* NewNetworkLocationProvider(
96 const scoped_refptr<AccessTokenStore>& access_token_store,
97 const scoped_refptr<net::URLRequestContextGetter>& context,
98 const GURL& url,
99 const base::string16& access_token) {
100 return new NetworkLocationProvider(
101 access_token_store, context, url, access_token);
102 }
103
104 // NetworkLocationProvider
105 NetworkLocationProvider::NetworkLocationProvider(
106 const scoped_refptr<AccessTokenStore>& access_token_store,
107 const scoped_refptr<net::URLRequestContextGetter>& url_context_getter,
108 const GURL& url,
109 const base::string16& access_token)
110 : access_token_store_(access_token_store),
111 wifi_data_provider_manager_(nullptr),
112 wifi_data_update_callback_(
113 base::Bind(&NetworkLocationProvider::OnWifiDataUpdate,
114 base::Unretained(this))),
115 is_wifi_data_complete_(false),
116 access_token_(access_token),
117 is_permission_granted_(false),
118 is_new_data_available_(false),
119 position_cache_(new PositionCache),
120 weak_factory_(this) {
121 request_.reset(new NetworkLocationRequest(
122 url_context_getter,
123 url,
124 base::Bind(&NetworkLocationProvider::OnLocationResponse,
125 base::Unretained(this))));
126 }
127
128 NetworkLocationProvider::~NetworkLocationProvider() {
129 StopProvider();
130 }
131
132 // LocationProvider implementation
133 void NetworkLocationProvider::GetPosition(Geoposition* position) {
134 DCHECK(position);
135 *position = position_;
136 }
137
138 void NetworkLocationProvider::RequestRefresh() {
139 // TODO(joth): When called via the public (base class) interface, this should
140 // poke each data provider to get them to expedite their next scan.
141 // Whilst in the delayed start, only send request if all data is ready.
142 // TODO(mcasas): consider not using HasWeakPtrs() https://crbug.com/629158.
143 if (!weak_factory_.HasWeakPtrs() || is_wifi_data_complete_) {
144 RequestPosition();
145 }
146 }
147
148 void NetworkLocationProvider::OnPermissionGranted() {
149 const bool was_permission_granted = is_permission_granted_;
150 is_permission_granted_ = true;
151 if (!was_permission_granted && IsStarted()) {
152 RequestRefresh();
153 }
154 }
155
156 void NetworkLocationProvider::OnWifiDataUpdate() {
157 DCHECK(wifi_data_provider_manager_);
158 is_wifi_data_complete_ = wifi_data_provider_manager_->GetData(&wifi_data_);
159 OnWifiDataUpdated();
160 }
161
162 void NetworkLocationProvider::OnLocationResponse(
163 const Geoposition& position,
164 bool server_error,
165 const base::string16& access_token,
166 const WifiData& wifi_data) {
167 DCHECK(CalledOnValidThread());
168 // Record the position and update our cache.
169 position_ = position;
170 if (position.Validate()) {
171 position_cache_->CachePosition(wifi_data, position);
172 }
173
174 // Record access_token if it's set.
175 if (!access_token.empty() && access_token_ != access_token) {
176 access_token_ = access_token;
177 access_token_store_->SaveAccessToken(request_->url(), access_token);
178 }
179
180 // Let listeners know that we now have a position available.
181 NotifyCallback(position_);
182 }
183
184 bool NetworkLocationProvider::StartProvider(bool high_accuracy) {
185 DCHECK(CalledOnValidThread());
186 if (IsStarted())
187 return true;
188 DCHECK(!wifi_data_provider_manager_);
189 if (!request_->url().is_valid()) {
190 LOG(WARNING) << "StartProvider() : Failed, Bad URL: "
191 << request_->url().possibly_invalid_spec();
192 return false;
193 }
194
195 // Registers a callback with the data provider. The first call to Register
196 // will create a singleton data provider and it will be deleted when the last
197 // callback is removed with Unregister.
198 wifi_data_provider_manager_ =
199 WifiDataProviderManager::Register(&wifi_data_update_callback_);
200
201 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
202 FROM_HERE, base::Bind(&NetworkLocationProvider::RequestPosition,
203 weak_factory_.GetWeakPtr()),
204 base::TimeDelta::FromSeconds(kDataCompleteWaitSeconds));
205 // Get the wifi data.
206 is_wifi_data_complete_ = wifi_data_provider_manager_->GetData(&wifi_data_);
207 if (is_wifi_data_complete_)
208 OnWifiDataUpdated();
209 return true;
210 }
211
212 void NetworkLocationProvider::OnWifiDataUpdated() {
213 DCHECK(CalledOnValidThread());
214 wifi_timestamp_ = base::Time::Now();
215
216 is_new_data_available_ = is_wifi_data_complete_;
217 RequestRefresh();
218 }
219
220 void NetworkLocationProvider::StopProvider() {
221 DCHECK(CalledOnValidThread());
222 if (IsStarted()) {
223 wifi_data_provider_manager_->Unregister(&wifi_data_update_callback_);
224 }
225 wifi_data_provider_manager_ = nullptr;
226 weak_factory_.InvalidateWeakPtrs();
227 }
228
229 // Other methods
230 void NetworkLocationProvider::RequestPosition() {
231 DCHECK(CalledOnValidThread());
232 if (!is_new_data_available_)
233 return;
234
235 const Geoposition* cached_position =
236 position_cache_->FindPosition(wifi_data_);
237 DCHECK(!wifi_timestamp_.is_null())
238 << "Timestamp must be set before looking up position";
239 if (cached_position) {
240 DCHECK(cached_position->Validate());
241 // Record the position and update its timestamp.
242 position_ = *cached_position;
243 // The timestamp of a position fix is determined by the timestamp
244 // of the source data update. (The value of position_.timestamp from
245 // the cache could be from weeks ago!)
246 position_.timestamp = wifi_timestamp_;
247 is_new_data_available_ = false;
248 // Let listeners know that we now have a position available.
249 NotifyCallback(position_);
250 return;
251 }
252 // Don't send network requests until authorized. http://crbug.com/39171
253 if (!is_permission_granted_)
254 return;
255
256 weak_factory_.InvalidateWeakPtrs();
257 is_new_data_available_ = false;
258
259 // TODO(joth): Rather than cancel pending requests, we should create a new
260 // NetworkLocationRequest for each and hold a set of pending requests.
261 if (request_->is_request_pending()) {
262 DVLOG(1) << "NetworkLocationProvider - pre-empting pending network request "
263 "with new data. Wifi APs: "
264 << wifi_data_.access_point_data.size();
265 }
266 request_->MakeRequest(access_token_, wifi_data_, wifi_timestamp_);
267 }
268
269 bool NetworkLocationProvider::IsStarted() const {
270 return wifi_data_provider_manager_ != nullptr;
271 }
272
273 } // namespace device
OLDNEW
« no previous file with comments | « device/geolocation/network_location_provider.h ('k') | device/geolocation/network_location_provider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698