geolocation_handler.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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/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
14namespace chromeos {
15
16GeolocationHandler::GeolocationHandler()
17    : wifi_enabled_(false),
18      weak_ptr_factory_(this) {
19}
20
21GeolocationHandler::~GeolocationHandler() {
22  ShillManagerClient* manager_client =
23      DBusThreadManager::Get()->GetShillManagerClient();
24  if (manager_client)
25    manager_client->RemovePropertyChangedObserver(this);
26}
27
28void 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
37bool 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
55void GeolocationHandler::OnPropertyChanged(const std::string& key,
56                                           const base::Value& value) {
57  HandlePropertyChanged(key, value);
58}
59
60//------------------------------------------------------------------------------
61// Private methods
62
63void GeolocationHandler::ManagerPropertiesCallback(
64    DBusMethodCallStatus call_status,
65    const base::DictionaryValue& properties) {
66  const base::Value* value = NULL;
67  if (properties.Get(flimflam::kEnabledTechnologiesProperty, &value) && value)
68    HandlePropertyChanged(flimflam::kEnabledTechnologiesProperty, *value);
69}
70
71void GeolocationHandler::HandlePropertyChanged(const std::string& key,
72                                               const base::Value& value) {
73  if (key != flimflam::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 == flimflam::kTypeWifi) {
85      wifi_enabled_ = true;
86      break;
87    }
88  }
89  if (!wifi_was_enabled && wifi_enabled_)
90    RequestWifiAccessPoints();  // Request initial location data.
91}
92
93void GeolocationHandler::RequestWifiAccessPoints() {
94  DBusThreadManager::Get()->GetShillManagerClient()->GetNetworksForGeolocation(
95      base::Bind(&GeolocationHandler::GeolocationCallback,
96                 weak_ptr_factory_.GetWeakPtr()));
97}
98
99void 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