Home | History | Annotate | Download | only in network
      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