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)// Provides wifi scan API binding for chromeos, using proprietary APIs.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/geolocation/wifi_data_provider_chromeos.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/geolocation_handler.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The time periods between successive polls of the wifi data.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDefaultPollingIntervalMilliseconds = 10 * 1000;  // 10s
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kNoChangePollingIntervalMilliseconds = 2 * 60 * 1000;  // 2 mins
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTwoNoChangePollingIntervalMilliseconds = 10 * 60 * 1000;  // 10 mins
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WifiDataProviderChromeOs::WifiDataProviderChromeOs() : started_(false) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WifiDataProviderChromeOs::~WifiDataProviderChromeOs() {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WifiDataProviderChromeOs::StartDataProvider() {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnClientThread());
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(polling_policy_ == NULL);
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  polling_policy_.reset(
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new GenericPollingPolicy<kDefaultPollingIntervalMilliseconds,
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               kNoChangePollingIntervalMilliseconds,
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               kTwoNoChangePollingIntervalMilliseconds,
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               kNoWifiPollingIntervalMilliseconds>);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleStart();
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WifiDataProviderChromeOs::StopDataProvider() {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnClientThread());
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  polling_policy_.reset();
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleStop();
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WifiDataProviderChromeOs::GetData(WifiData* data) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnClientThread());
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(data);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *data = wifi_data_;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_first_scan_complete_;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WifiDataProviderChromeOs::DoStartTaskOnUIThread() {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DoWifiScanTaskOnUIThread();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WifiDataProviderChromeOs::DoWifiScanTaskOnUIThread() {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This method could be scheduled after a ScheduleStop.
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!started_)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WifiData new_data;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetAccessPointData(&new_data.access_point_data)) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_loop()->PostTask(
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&WifiDataProviderChromeOs::DidWifiScanTaskNoResults, this));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_loop()->PostTask(
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&WifiDataProviderChromeOs::DidWifiScanTask, this, new_data));
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WifiDataProviderChromeOs::DidWifiScanTaskNoResults() {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnClientThread());
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedule next scan if started (StopDataProvider could have been called
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in between DoWifiScanTaskOnUIThread and this method).
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (started_)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleNextScan(polling_policy_->NoWifiInterval());
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybeNotifyListeners(false);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WifiDataProviderChromeOs::DidWifiScanTask(const WifiData& new_data) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnClientThread());
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool update_available = wifi_data_.DiffersSignificantly(new_data);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wifi_data_ = new_data;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedule next scan if started (StopDataProvider could have been called
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in between DoWifiScanTaskOnUIThread and this method).
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (started_) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    polling_policy_->UpdatePollingInterval(update_available);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleNextScan(polling_policy_->PollingInterval());
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybeNotifyListeners(update_available);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WifiDataProviderChromeOs::MaybeNotifyListeners(bool update_available) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (update_available || !is_first_scan_complete_) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_first_scan_complete_ = true;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyListeners();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WifiDataProviderChromeOs::ScheduleNextScan(int interval) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnClientThread());
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(started_);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostDelayedTask(
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&WifiDataProviderChromeOs::DoWifiScanTaskOnUIThread, this),
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(interval));
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WifiDataProviderChromeOs::ScheduleStop() {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnClientThread());
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(started_);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  started_ = false;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WifiDataProviderChromeOs::ScheduleStart() {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnClientThread());
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!started_);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  started_ = true;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Perform first scan ASAP regardless of the polling policy. If this scan
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // fails we'll retry at a rate in line with the polling policy.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::UI,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&WifiDataProviderChromeOs::DoStartTaskOnUIThread, this));
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool WifiDataProviderChromeOs::GetAccessPointData(
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WifiData::AccessPointDataSet* result) {
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::WifiAccessPointVector access_points;
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!chromeos::NetworkHandler::Get()->geolocation_handler()->wifi_enabled())
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int64 age_ms = 0;
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!chromeos::NetworkHandler::Get()->geolocation_handler()->
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      GetWifiAccessPoints(&access_points, &age_ms)) {
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (chromeos::WifiAccessPointVector::const_iterator i
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           = access_points.begin();
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       i != access_points.end(); ++i) {
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AccessPointData ap_data;
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ap_data.mac_address = ASCIIToUTF16(i->mac_address);
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ap_data.radio_signal_strength = i->signal_strength;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ap_data.channel = i->channel;
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ap_data.signal_to_noise = i->signal_to_noise;
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ap_data.ssid = UTF8ToUTF16(i->ssid);
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result->insert(ap_data);
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the age is significantly longer than our long polling time, assume the
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // data is stale and return false which will trigger a faster update.
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (age_ms > kTwoNoChangePollingIntervalMilliseconds * 2)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<>
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new WifiDataProviderChromeOs();
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
177