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