15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/geolocation/network_location_provider.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/access_token_store.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
14424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// The maximum period of time we'll wait for a complete set of wifi data
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// before sending the request.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDataCompleteWaitSeconds = 2;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t NetworkLocationProvider::PositionCache::kMaximumSize = 10;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkLocationProvider::PositionCache::PositionCache() {}
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkLocationProvider::PositionCache::~PositionCache() {}
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NetworkLocationProvider::PositionCache::CachePosition(
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WifiData& wifi_data,
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Geoposition& position) {
29424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Check that we can generate a valid key for the wifi data.
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 key;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!MakeKey(wifi_data, &key)) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the cache is full, remove the oldest entry.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cache_.size() == kMaximumSize) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(cache_age_list_.size() == kMaximumSize);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CacheAgeList::iterator oldest_entry = cache_age_list_.begin();
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(oldest_entry != cache_age_list_.end());
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_.erase(*oldest_entry);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_age_list_.erase(oldest_entry);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LT(cache_.size(), kMaximumSize);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Insert the position into the cache.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::pair<CacheMap::iterator, bool> result =
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache_.insert(std::make_pair(key, position));
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result.second) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();  // We never try to add the same key twice.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_EQ(cache_.size(), cache_age_list_.size());
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cache_age_list_.push_back(result.first);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(cache_.size(), cache_age_list_.size());
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Searches for a cached position response for the current WiFi data. Returns
57424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// the cached position if available, NULL otherwise.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const Geoposition* NetworkLocationProvider::PositionCache::FindPosition(
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WifiData& wifi_data) {
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 key;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!MakeKey(wifi_data, &key)) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CacheMap::const_iterator iter = cache_.find(key);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return iter == cache_.end() ? NULL : &iter->second;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
68424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Makes the key for the map of cached positions, using the available data.
69424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Returns true if a good key was generated, false otherwise.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NetworkLocationProvider::PositionCache::MakeKey(
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WifiData& wifi_data,
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16* key) {
75424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Currently we use only WiFi data and base the key only on the MAC addresses.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(key);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key->clear();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t kCharsPerMacAddress = 6 * 3 + 1;  // e.g. "11:22:33:44:55:66|"
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key->reserve(wifi_data.access_point_data.size() * kCharsPerMacAddress);
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::string16 separator(base::ASCIIToUTF16("|"));
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (WifiData::AccessPointDataSet::const_iterator iter =
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       wifi_data.access_point_data.begin();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != wifi_data.access_point_data.end();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter++) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *key += separator;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *key += iter->mac_address;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *key += separator;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the key is the empty string, return false, as we don't want to cache a
90424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // position for such data.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !key->empty();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NetworkLocationProvider factory function
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LocationProviderBase* NewNetworkLocationProvider(
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AccessTokenStore* access_token_store,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLRequestContextGetter* context,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& access_token) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new NetworkLocationProvider(
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      access_token_store, context, url, access_token);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NetworkLocationProvider
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkLocationProvider::NetworkLocationProvider(
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AccessTokenStore* access_token_store,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLRequestContextGetter* url_context_getter,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& access_token)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : access_token_store_(access_token_store),
11103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      wifi_data_provider_manager_(NULL),
112424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      wifi_data_update_callback_(
1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          base::Bind(&NetworkLocationProvider::OnWifiDataUpdate,
114424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                     base::Unretained(this))),
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_wifi_data_complete_(false),
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      access_token_(access_token),
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_permission_granted_(false),
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_new_data_available_(false),
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the position cache.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  position_cache_.reset(new PositionCache());
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  request_.reset(new NetworkLocationRequest(
1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      url_context_getter,
1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      url,
1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      base::Bind(&NetworkLocationProvider::OnLocationResponse,
1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                 base::Unretained(this))));
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NetworkLocationProvider::~NetworkLocationProvider() {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopProvider();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// LocationProvider implementation
135424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void NetworkLocationProvider::GetPosition(Geoposition* position) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(position);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *position = position_;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void NetworkLocationProvider::RequestRefresh() {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(joth): When called via the public (base class) interface, this should
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // poke each data provider to get them to expedite their next scan.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Whilst in the delayed start, only send request if all data is ready.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!weak_factory_.HasWeakPtrs() || is_wifi_data_complete_) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RequestPosition();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkLocationProvider::OnPermissionGranted() {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool was_permission_granted = is_permission_granted_;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_permission_granted_ = true;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!was_permission_granted && IsStarted()) {
1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    RequestRefresh();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void NetworkLocationProvider::OnWifiDataUpdate() {
15803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(wifi_data_provider_manager_);
15903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  is_wifi_data_complete_ = wifi_data_provider_manager_->GetData(&wifi_data_);
160424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  OnWifiDataUpdated();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void NetworkLocationProvider::OnLocationResponse(
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Geoposition& position,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool server_error,
166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& access_token,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WifiData& wifi_data) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record the position and update our cache.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  position_ = position;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (position.Validate()) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    position_cache_->CachePosition(wifi_data, position);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record access_token if it's set.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!access_token.empty() && access_token_ != access_token) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    access_token_ = access_token;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    access_token_store_->SaveAccessToken(request_->url(), access_token);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Let listeners know that we now have a position available.
1827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  NotifyCallback(position_);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NetworkLocationProvider::StartProvider(bool high_accuracy) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsStarted())
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
18903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(wifi_data_provider_manager_ == NULL);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!request_->url().is_valid()) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "StartProvider() : Failed, Bad URL: "
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << request_->url().possibly_invalid_spec();
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
196424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Registers a callback with the data provider. The first call to Register
197424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // will create a singleton data provider and it will be deleted when the last
198424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // callback is removed with Unregister.
19903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  wifi_data_provider_manager_ =
20003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      WifiDataProviderManager::Register(&wifi_data_update_callback_);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&NetworkLocationProvider::RequestPosition,
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_factory_.GetWeakPtr()),
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromSeconds(kDataCompleteWaitSeconds));
207424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Get the wifi data.
20803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  is_wifi_data_complete_ = wifi_data_provider_manager_->GetData(&wifi_data_);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_wifi_data_complete_)
210424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    OnWifiDataUpdated();
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
214424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void NetworkLocationProvider::OnWifiDataUpdated() {
215424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(CalledOnValidThread());
216424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  wifi_data_updated_timestamp_ = base::Time::Now();
217424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
218424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  is_new_data_available_ = is_wifi_data_complete_;
219424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  RequestRefresh();
220424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
221424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkLocationProvider::StopProvider() {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsStarted()) {
22503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    wifi_data_provider_manager_->Unregister(&wifi_data_update_callback_);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
22703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  wifi_data_provider_manager_ = NULL;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Other methods
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NetworkLocationProvider::RequestPosition() {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_new_data_available_)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Geoposition* cached_position =
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      position_cache_->FindPosition(wifi_data_);
239424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(!wifi_data_updated_timestamp_.is_null()) <<
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Timestamp must be set before looking up position";
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cached_position) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(cached_position->Validate());
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Record the position and update its timestamp.
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    position_ = *cached_position;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The timestamp of a position fix is determined by the timestamp
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // of the source data update. (The value of position_.timestamp from
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the cache could be from weeks ago!)
248424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    position_.timestamp = wifi_data_updated_timestamp_;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_new_data_available_ = false;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Let listeners know that we now have a position available.
2517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    NotifyCallback(position_);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't send network requests until authorized. http://crbug.com/39171
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_permission_granted_)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_new_data_available_ = false;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(joth): Rather than cancel pending requests, we should create a new
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NetworkLocationRequest for each and hold a set of pending requests.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request_->is_request_pending()) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "NetworkLocationProvider - pre-empting pending network request "
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                "with new data. Wifi APs: "
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             << wifi_data_.access_point_data.size();
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_->MakeRequest(access_token_, wifi_data_,
269424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        wifi_data_updated_timestamp_);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NetworkLocationProvider::IsStarted() const {
27303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return wifi_data_provider_manager_ != NULL;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
277