12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/geolocation_handler.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/dbus/dbus_thread_manager.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/dbus/shill_manager_client.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos { 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)GeolocationHandler::GeolocationHandler() 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : wifi_enabled_(false), 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_ptr_factory_(this) { 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)GeolocationHandler::~GeolocationHandler() { 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ShillManagerClient* manager_client = 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DBusThreadManager::Get()->GetShillManagerClient(); 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (manager_client) 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) manager_client->RemovePropertyChangedObserver(this); 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GeolocationHandler::Init() { 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ShillManagerClient* manager_client = 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DBusThreadManager::Get()->GetShillManagerClient(); 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) manager_client->GetProperties( 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&GeolocationHandler::ManagerPropertiesCallback, 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) manager_client->AddPropertyChangedObserver(this); 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GeolocationHandler::GetWifiAccessPoints( 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WifiAccessPointVector* access_points, int64* age_ms) { 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!wifi_enabled_) 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Always request updated access points. 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RequestWifiAccessPoints(); 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If no data has been received, return false. 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (geolocation_received_time_.is_null()) 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (access_points) 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *access_points = wifi_access_points_; 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (age_ms) { 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta dtime = base::Time::Now() - geolocation_received_time_; 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *age_ms = dtime.InMilliseconds(); 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GeolocationHandler::OnPropertyChanged(const std::string& key, 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Value& value) { 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HandlePropertyChanged(key, value); 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//------------------------------------------------------------------------------ 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Private methods 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GeolocationHandler::ManagerPropertiesCallback( 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DBusMethodCallStatus call_status, 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::DictionaryValue& properties) { 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Value* value = NULL; 6768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (properties.Get(shill::kEnabledTechnologiesProperty, &value) && value) 6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) HandlePropertyChanged(shill::kEnabledTechnologiesProperty, *value); 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GeolocationHandler::HandlePropertyChanged(const std::string& key, 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Value& value) { 7368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (key != shill::kEnabledTechnologiesProperty) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::ListValue* technologies = NULL; 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!value.GetAsList(&technologies) || !technologies) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool wifi_was_enabled = wifi_enabled_; 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) wifi_enabled_ = false; 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (base::ListValue::const_iterator iter = technologies->begin(); 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) iter != technologies->end(); ++iter) { 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string technology; 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (*iter)->GetAsString(&technology); 8468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (technology == shill::kTypeWifi) { 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) wifi_enabled_ = true; 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!wifi_was_enabled && wifi_enabled_) 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RequestWifiAccessPoints(); // Request initial location data. 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GeolocationHandler::RequestWifiAccessPoints() { 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DBusThreadManager::Get()->GetShillManagerClient()->GetNetworksForGeolocation( 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&GeolocationHandler::GeolocationCallback, 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GeolocationHandler::GeolocationCallback( 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DBusMethodCallStatus call_status, 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::DictionaryValue& properties) { 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (call_status != DBUS_METHOD_CALL_SUCCESS) { 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Failed to get Geolocation data: " << call_status; 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) wifi_access_points_.clear(); 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (properties.empty()) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; // No enabled devices, don't update received time. 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Dictionary<device_type, entry_list> 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (base::DictionaryValue::Iterator iter(properties); 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) !iter.IsAtEnd(); iter.Advance()) { 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::ListValue* entry_list = NULL; 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!iter.value().GetAsList(&entry_list)) { 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(WARNING) << "Geolocation dictionary value not a List: " << iter.key(); 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // List[Dictionary<key, value_str>] 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < entry_list->GetSize(); ++i) { 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::DictionaryValue* entry = NULL; 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!entry_list->GetDictionary(i, &entry) || !entry) { 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(WARNING) << "Geolocation list value not a Dictionary: " << i; 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Docs: developers.google.com/maps/documentation/business/geolocation 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WifiAccessPoint wap; 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entry->GetString(shill::kGeoMacAddressProperty, &wap.mac_address); 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string age_str; 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (entry->GetString(shill::kGeoAgeProperty, &age_str)) { 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int64 age_ms; 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (base::StringToInt64(age_str, &age_ms)) { 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) wap.timestamp = 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Time::Now() - base::TimeDelta::FromMilliseconds(age_ms); 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string strength_str; 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (entry->GetString(shill::kGeoSignalStrengthProperty, &strength_str)) 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringToInt(strength_str, &wap.signal_strength); 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string signal_str; 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (entry->GetString(shill::kGeoSignalToNoiseRatioProperty, &signal_str)) 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringToInt(signal_str, &wap.signal_to_noise); 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string channel_str; 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (entry->GetString(shill::kGeoChannelProperty, &channel_str)) 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringToInt(channel_str, &wap.channel); 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) wifi_access_points_.push_back(wap); 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) geolocation_received_time_ = base::Time::Now(); 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace chromeos 152