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 // Provides wifi scan API binding for chromeos, using proprietary APIs.
      6 
      7 #include "content/browser/geolocation/wifi_data_provider_chromeos.h"
      8 
      9 #include "base/bind.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "chromeos/network/geolocation_handler.h"
     12 #include "content/public/browser/browser_thread.h"
     13 
     14 namespace content {
     15 
     16 namespace {
     17 
     18 // The time periods between successive polls of the wifi data.
     19 const int kDefaultPollingIntervalMilliseconds = 10 * 1000;  // 10s
     20 const int kNoChangePollingIntervalMilliseconds = 2 * 60 * 1000;  // 2 mins
     21 const int kTwoNoChangePollingIntervalMilliseconds = 10 * 60 * 1000;  // 10 mins
     22 const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s
     23 
     24 }  // namespace
     25 
     26 WifiDataProviderChromeOs::WifiDataProviderChromeOs() : started_(false) {
     27 }
     28 
     29 WifiDataProviderChromeOs::~WifiDataProviderChromeOs() {
     30 }
     31 
     32 bool WifiDataProviderChromeOs::StartDataProvider() {
     33   DCHECK(CalledOnClientThread());
     34 
     35   DCHECK(polling_policy_ == NULL);
     36   polling_policy_.reset(
     37       new GenericPollingPolicy<kDefaultPollingIntervalMilliseconds,
     38                                kNoChangePollingIntervalMilliseconds,
     39                                kTwoNoChangePollingIntervalMilliseconds,
     40                                kNoWifiPollingIntervalMilliseconds>);
     41 
     42   ScheduleStart();
     43   return true;
     44 }
     45 
     46 void WifiDataProviderChromeOs::StopDataProvider() {
     47   DCHECK(CalledOnClientThread());
     48 
     49   polling_policy_.reset();
     50   ScheduleStop();
     51 }
     52 
     53 bool WifiDataProviderChromeOs::GetData(WifiData* data) {
     54   DCHECK(CalledOnClientThread());
     55   DCHECK(data);
     56   *data = wifi_data_;
     57   return is_first_scan_complete_;
     58 }
     59 
     60 void WifiDataProviderChromeOs::DoStartTaskOnUIThread() {
     61   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     62   DoWifiScanTaskOnUIThread();
     63 }
     64 
     65 void WifiDataProviderChromeOs::DoWifiScanTaskOnUIThread() {
     66   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     67 
     68   // This method could be scheduled after a ScheduleStop.
     69   if (!started_)
     70     return;
     71 
     72   WifiData new_data;
     73 
     74   if (!GetAccessPointData(&new_data.access_point_data)) {
     75     client_loop()->PostTask(
     76         FROM_HERE,
     77         base::Bind(&WifiDataProviderChromeOs::DidWifiScanTaskNoResults, this));
     78   } else {
     79     client_loop()->PostTask(
     80         FROM_HERE,
     81         base::Bind(&WifiDataProviderChromeOs::DidWifiScanTask, this, new_data));
     82   }
     83 }
     84 
     85 void WifiDataProviderChromeOs::DidWifiScanTaskNoResults() {
     86   DCHECK(CalledOnClientThread());
     87   // Schedule next scan if started (StopDataProvider could have been called
     88   // in between DoWifiScanTaskOnUIThread and this method).
     89   if (started_)
     90     ScheduleNextScan(polling_policy_->NoWifiInterval());
     91   MaybeNotifyListeners(false);
     92 }
     93 
     94 void WifiDataProviderChromeOs::DidWifiScanTask(const WifiData& new_data) {
     95   DCHECK(CalledOnClientThread());
     96   bool update_available = wifi_data_.DiffersSignificantly(new_data);
     97   wifi_data_ = new_data;
     98   // Schedule next scan if started (StopDataProvider could have been called
     99   // in between DoWifiScanTaskOnUIThread and this method).
    100   if (started_) {
    101     polling_policy_->UpdatePollingInterval(update_available);
    102     ScheduleNextScan(polling_policy_->PollingInterval());
    103   }
    104   MaybeNotifyListeners(update_available);
    105 }
    106 
    107 void WifiDataProviderChromeOs::MaybeNotifyListeners(bool update_available) {
    108   if (update_available || !is_first_scan_complete_) {
    109     is_first_scan_complete_ = true;
    110     NotifyListeners();
    111   }
    112 }
    113 
    114 void WifiDataProviderChromeOs::ScheduleNextScan(int interval) {
    115   DCHECK(CalledOnClientThread());
    116   DCHECK(started_);
    117   BrowserThread::PostDelayedTask(
    118       BrowserThread::UI,
    119       FROM_HERE,
    120       base::Bind(&WifiDataProviderChromeOs::DoWifiScanTaskOnUIThread, this),
    121       base::TimeDelta::FromMilliseconds(interval));
    122 }
    123 
    124 void WifiDataProviderChromeOs::ScheduleStop() {
    125   DCHECK(CalledOnClientThread());
    126   DCHECK(started_);
    127   started_ = false;
    128 }
    129 
    130 void WifiDataProviderChromeOs::ScheduleStart() {
    131   DCHECK(CalledOnClientThread());
    132   DCHECK(!started_);
    133   started_ = true;
    134   // Perform first scan ASAP regardless of the polling policy. If this scan
    135   // fails we'll retry at a rate in line with the polling policy.
    136   BrowserThread::PostTask(
    137       BrowserThread::UI,
    138       FROM_HERE,
    139       base::Bind(&WifiDataProviderChromeOs::DoStartTaskOnUIThread, this));
    140 }
    141 
    142 bool WifiDataProviderChromeOs::GetAccessPointData(
    143     WifiData::AccessPointDataSet* result) {
    144   chromeos::WifiAccessPointVector access_points;
    145   if (!chromeos::NetworkHandler::Get()->geolocation_handler()->wifi_enabled())
    146     return false;
    147   int64 age_ms = 0;
    148   if (!chromeos::NetworkHandler::Get()->geolocation_handler()->
    149       GetWifiAccessPoints(&access_points, &age_ms)) {
    150     return false;
    151   }
    152   for (chromeos::WifiAccessPointVector::const_iterator i
    153            = access_points.begin();
    154        i != access_points.end(); ++i) {
    155     AccessPointData ap_data;
    156     ap_data.mac_address = ASCIIToUTF16(i->mac_address);
    157     ap_data.radio_signal_strength = i->signal_strength;
    158     ap_data.channel = i->channel;
    159     ap_data.signal_to_noise = i->signal_to_noise;
    160     ap_data.ssid = UTF8ToUTF16(i->ssid);
    161     result->insert(ap_data);
    162   }
    163   // If the age is significantly longer than our long polling time, assume the
    164   // data is stale and return false which will trigger a faster update.
    165   if (age_ms > kTwoNoChangePollingIntervalMilliseconds * 2)
    166     return false;
    167   return true;
    168 }
    169 
    170 // static
    171 template<>
    172 WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
    173   return new WifiDataProviderChromeOs();
    174 }
    175 
    176 }  // namespace content
    177