1 // Copyright (c) 2013 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 #include "chromeos/network/geolocation_handler.h" 6 7 #include "base/bind.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "base/values.h" 10 #include "chromeos/dbus/dbus_thread_manager.h" 11 #include "chromeos/dbus/shill_manager_client.h" 12 #include "third_party/cros_system_api/dbus/service_constants.h" 13 14 namespace chromeos { 15 16 GeolocationHandler::GeolocationHandler() 17 : wifi_enabled_(false), 18 weak_ptr_factory_(this) { 19 } 20 21 GeolocationHandler::~GeolocationHandler() { 22 ShillManagerClient* manager_client = 23 DBusThreadManager::Get()->GetShillManagerClient(); 24 if (manager_client) 25 manager_client->RemovePropertyChangedObserver(this); 26 } 27 28 void GeolocationHandler::Init() { 29 ShillManagerClient* manager_client = 30 DBusThreadManager::Get()->GetShillManagerClient(); 31 manager_client->GetProperties( 32 base::Bind(&GeolocationHandler::ManagerPropertiesCallback, 33 weak_ptr_factory_.GetWeakPtr())); 34 manager_client->AddPropertyChangedObserver(this); 35 } 36 37 bool GeolocationHandler::GetWifiAccessPoints( 38 WifiAccessPointVector* access_points, int64* age_ms) { 39 if (!wifi_enabled_) 40 return false; 41 // Always request updated access points. 42 RequestWifiAccessPoints(); 43 // If no data has been received, return false. 44 if (geolocation_received_time_.is_null()) 45 return false; 46 if (access_points) 47 *access_points = wifi_access_points_; 48 if (age_ms) { 49 base::TimeDelta dtime = base::Time::Now() - geolocation_received_time_; 50 *age_ms = dtime.InMilliseconds(); 51 } 52 return true; 53 } 54 55 void GeolocationHandler::OnPropertyChanged(const std::string& key, 56 const base::Value& value) { 57 HandlePropertyChanged(key, value); 58 } 59 60 //------------------------------------------------------------------------------ 61 // Private methods 62 63 void GeolocationHandler::ManagerPropertiesCallback( 64 DBusMethodCallStatus call_status, 65 const base::DictionaryValue& properties) { 66 const base::Value* value = NULL; 67 if (properties.Get(shill::kEnabledTechnologiesProperty, &value) && value) 68 HandlePropertyChanged(shill::kEnabledTechnologiesProperty, *value); 69 } 70 71 void GeolocationHandler::HandlePropertyChanged(const std::string& key, 72 const base::Value& value) { 73 if (key != shill::kEnabledTechnologiesProperty) 74 return; 75 const base::ListValue* technologies = NULL; 76 if (!value.GetAsList(&technologies) || !technologies) 77 return; 78 bool wifi_was_enabled = wifi_enabled_; 79 wifi_enabled_ = false; 80 for (base::ListValue::const_iterator iter = technologies->begin(); 81 iter != technologies->end(); ++iter) { 82 std::string technology; 83 (*iter)->GetAsString(&technology); 84 if (technology == shill::kTypeWifi) { 85 wifi_enabled_ = true; 86 break; 87 } 88 } 89 if (!wifi_was_enabled && wifi_enabled_) 90 RequestWifiAccessPoints(); // Request initial location data. 91 } 92 93 void GeolocationHandler::RequestWifiAccessPoints() { 94 DBusThreadManager::Get()->GetShillManagerClient()->GetNetworksForGeolocation( 95 base::Bind(&GeolocationHandler::GeolocationCallback, 96 weak_ptr_factory_.GetWeakPtr())); 97 } 98 99 void GeolocationHandler::GeolocationCallback( 100 DBusMethodCallStatus call_status, 101 const base::DictionaryValue& properties) { 102 if (call_status != DBUS_METHOD_CALL_SUCCESS) { 103 LOG(ERROR) << "Failed to get Geolocation data: " << call_status; 104 return; 105 } 106 wifi_access_points_.clear(); 107 if (properties.empty()) 108 return; // No enabled devices, don't update received time. 109 110 // Dictionary<device_type, entry_list> 111 for (base::DictionaryValue::Iterator iter(properties); 112 !iter.IsAtEnd(); iter.Advance()) { 113 const base::ListValue* entry_list = NULL; 114 if (!iter.value().GetAsList(&entry_list)) { 115 LOG(WARNING) << "Geolocation dictionary value not a List: " << iter.key(); 116 continue; 117 } 118 // List[Dictionary<key, value_str>] 119 for (size_t i = 0; i < entry_list->GetSize(); ++i) { 120 const base::DictionaryValue* entry = NULL; 121 if (!entry_list->GetDictionary(i, &entry) || !entry) { 122 LOG(WARNING) << "Geolocation list value not a Dictionary: " << i; 123 continue; 124 } 125 // Docs: developers.google.com/maps/documentation/business/geolocation 126 WifiAccessPoint wap; 127 entry->GetString(shill::kGeoMacAddressProperty, &wap.mac_address); 128 std::string age_str; 129 if (entry->GetString(shill::kGeoAgeProperty, &age_str)) { 130 int64 age_ms; 131 if (base::StringToInt64(age_str, &age_ms)) { 132 wap.timestamp = 133 base::Time::Now() - base::TimeDelta::FromMilliseconds(age_ms); 134 } 135 } 136 std::string strength_str; 137 if (entry->GetString(shill::kGeoSignalStrengthProperty, &strength_str)) 138 base::StringToInt(strength_str, &wap.signal_strength); 139 std::string signal_str; 140 if (entry->GetString(shill::kGeoSignalToNoiseRatioProperty, &signal_str)) 141 base::StringToInt(signal_str, &wap.signal_to_noise); 142 std::string channel_str; 143 if (entry->GetString(shill::kGeoChannelProperty, &channel_str)) 144 base::StringToInt(channel_str, &wap.channel); 145 wifi_access_points_.push_back(wap); 146 } 147 } 148 geolocation_received_time_ = base::Time::Now(); 149 } 150 151 } // namespace chromeos 152