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/browser/geolocation/wifi_data_provider_manager.h" 13 #include "content/public/browser/browser_thread.h" 14 15 namespace content { 16 17 namespace { 18 19 // The time periods between successive polls of the wifi data. 20 const int kDefaultPollingIntervalMilliseconds = 10 * 1000; // 10s 21 const int kNoChangePollingIntervalMilliseconds = 2 * 60 * 1000; // 2 mins 22 const int kTwoNoChangePollingIntervalMilliseconds = 10 * 60 * 1000; // 10 mins 23 const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s 24 25 } // namespace 26 27 WifiDataProviderChromeOs::WifiDataProviderChromeOs() : started_(false) { 28 } 29 30 WifiDataProviderChromeOs::~WifiDataProviderChromeOs() { 31 } 32 33 void WifiDataProviderChromeOs::StartDataProvider() { 34 DCHECK(CalledOnClientThread()); 35 36 DCHECK(polling_policy_ == NULL); 37 polling_policy_.reset( 38 new GenericWifiPollingPolicy<kDefaultPollingIntervalMilliseconds, 39 kNoChangePollingIntervalMilliseconds, 40 kTwoNoChangePollingIntervalMilliseconds, 41 kNoWifiPollingIntervalMilliseconds>); 42 43 ScheduleStart(); 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::DidWifiScanTask, this, new_data)); 78 } else { 79 client_loop()->PostTask( 80 FROM_HERE, 81 base::Bind(&WifiDataProviderChromeOs::DidWifiScanTaskNoResults, this)); 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 } 92 93 void WifiDataProviderChromeOs::DidWifiScanTask(const WifiData& new_data) { 94 DCHECK(CalledOnClientThread()); 95 bool update_available = wifi_data_.DiffersSignificantly(new_data); 96 wifi_data_ = new_data; 97 // Schedule next scan if started (StopDataProvider could have been called 98 // in between DoWifiScanTaskOnUIThread and this method). 99 if (started_) { 100 polling_policy_->UpdatePollingInterval(update_available); 101 ScheduleNextScan(polling_policy_->PollingInterval()); 102 } 103 104 if (update_available || !is_first_scan_complete_) { 105 is_first_scan_complete_ = true; 106 RunCallbacks(); 107 } 108 } 109 110 void WifiDataProviderChromeOs::ScheduleNextScan(int interval) { 111 DCHECK(CalledOnClientThread()); 112 DCHECK(started_); 113 BrowserThread::PostDelayedTask( 114 BrowserThread::UI, 115 FROM_HERE, 116 base::Bind(&WifiDataProviderChromeOs::DoWifiScanTaskOnUIThread, this), 117 base::TimeDelta::FromMilliseconds(interval)); 118 } 119 120 void WifiDataProviderChromeOs::ScheduleStop() { 121 DCHECK(CalledOnClientThread()); 122 DCHECK(started_); 123 started_ = false; 124 } 125 126 void WifiDataProviderChromeOs::ScheduleStart() { 127 DCHECK(CalledOnClientThread()); 128 DCHECK(!started_); 129 started_ = true; 130 // Perform first scan ASAP regardless of the polling policy. If this scan 131 // fails we'll retry at a rate in line with the polling policy. 132 BrowserThread::PostTask( 133 BrowserThread::UI, 134 FROM_HERE, 135 base::Bind(&WifiDataProviderChromeOs::DoStartTaskOnUIThread, this)); 136 } 137 138 bool WifiDataProviderChromeOs::GetAccessPointData( 139 WifiData::AccessPointDataSet* result) { 140 // If wifi isn't enabled, we've effectively completed the task. 141 // Return true to indicate an empty access point list. 142 if (!chromeos::NetworkHandler::Get()->geolocation_handler()->wifi_enabled()) 143 return true; 144 145 chromeos::WifiAccessPointVector access_points; 146 int64 age_ms = 0; 147 if (!chromeos::NetworkHandler::Get()->geolocation_handler()-> 148 GetWifiAccessPoints(&access_points, &age_ms)) { 149 return false; 150 } 151 for (chromeos::WifiAccessPointVector::const_iterator i 152 = access_points.begin(); 153 i != access_points.end(); ++i) { 154 AccessPointData ap_data; 155 ap_data.mac_address = base::ASCIIToUTF16(i->mac_address); 156 ap_data.radio_signal_strength = i->signal_strength; 157 ap_data.channel = i->channel; 158 ap_data.signal_to_noise = i->signal_to_noise; 159 ap_data.ssid = base::UTF8ToUTF16(i->ssid); 160 result->insert(ap_data); 161 } 162 // If the age is significantly longer than our long polling time, assume the 163 // data is stale and return false which will trigger a faster update. 164 if (age_ms > kTwoNoChangePollingIntervalMilliseconds * 2) 165 return false; 166 return true; 167 } 168 169 // static 170 WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() { 171 return new WifiDataProviderChromeOs(); 172 } 173 174 } // namespace content 175