Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chromeos / network / network_sms_handler.cc
blob9c95c7b2e691b82a9203649e2d41d55a1137d931
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.
5 #include "chromeos/network/network_sms_handler.h"
7 #include <algorithm>
8 #include <deque>
9 #include <vector>
11 #include "base/bind.h"
12 #include "base/values.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_device_client.h"
15 #include "chromeos/dbus/shill_manager_client.h"
16 #include "chromeos/dbus/gsm_sms_client.h"
17 #include "chromeos/dbus/modem_messaging_client.h"
18 #include "chromeos/dbus/sms_client.h"
19 #include "dbus/object_path.h"
20 #include "third_party/cros_system_api/dbus/service_constants.h"
22 namespace {
24 // Not exposed/exported:
25 const char kIndexKey[] = "index";
27 // Keys from ModemManager1
28 const char kModemManager1NumberKey[] = "Number";
29 const char kModemManager1TextKey[] = "Text";
30 const char kModemManager1TimestampKey[] = "Timestamp";
32 // Maximum number of messages stored for RequestUpdate(true).
33 const size_t kMaxReceivedMessages = 100;
35 } // namespace
37 namespace chromeos {
39 // static
40 const char NetworkSmsHandler::kNumberKey[] = "number";
41 const char NetworkSmsHandler::kTextKey[] = "text";
42 const char NetworkSmsHandler::kTimestampKey[] = "timestamp";
44 class NetworkSmsHandler::NetworkSmsDeviceHandler {
45 public:
46 NetworkSmsDeviceHandler() {}
47 virtual ~NetworkSmsDeviceHandler() {}
49 virtual void RequestUpdate() = 0;
52 class NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler
53 : public NetworkSmsHandler::NetworkSmsDeviceHandler {
54 public:
55 ModemManagerNetworkSmsDeviceHandler(NetworkSmsHandler* host,
56 const std::string& service_name,
57 const dbus::ObjectPath& object_path);
59 void RequestUpdate() override;
61 private:
62 void ListCallback(const base::ListValue& message_list);
63 void SmsReceivedCallback(uint32 index, bool complete);
64 void GetCallback(uint32 index, const base::DictionaryValue& dictionary);
65 void DeleteMessages();
66 void MessageReceived(const base::DictionaryValue& dictionary);
68 NetworkSmsHandler* host_;
69 std::string service_name_;
70 dbus::ObjectPath object_path_;
71 bool deleting_messages_;
72 std::vector<uint32> delete_queue_;
73 base::WeakPtrFactory<ModemManagerNetworkSmsDeviceHandler> weak_ptr_factory_;
75 DISALLOW_COPY_AND_ASSIGN(ModemManagerNetworkSmsDeviceHandler);
78 NetworkSmsHandler::
79 ModemManagerNetworkSmsDeviceHandler::ModemManagerNetworkSmsDeviceHandler(
80 NetworkSmsHandler* host,
81 const std::string& service_name,
82 const dbus::ObjectPath& object_path)
83 : host_(host),
84 service_name_(service_name),
85 object_path_(object_path),
86 deleting_messages_(false),
87 weak_ptr_factory_(this) {
88 // Set the handler for received Sms messaages.
89 DBusThreadManager::Get()->GetGsmSMSClient()->SetSmsReceivedHandler(
90 service_name_, object_path_,
91 base::Bind(&ModemManagerNetworkSmsDeviceHandler::SmsReceivedCallback,
92 weak_ptr_factory_.GetWeakPtr()));
94 // List the existing messages.
95 DBusThreadManager::Get()->GetGsmSMSClient()->List(
96 service_name_, object_path_,
97 base::Bind(&NetworkSmsHandler::
98 ModemManagerNetworkSmsDeviceHandler::ListCallback,
99 weak_ptr_factory_.GetWeakPtr()));
102 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::RequestUpdate() {
103 DBusThreadManager::Get()->GetGsmSMSClient()->RequestUpdate(
104 service_name_, object_path_);
107 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::ListCallback(
108 const base::ListValue& message_list) {
109 // This receives all messages, so clear any pending deletes.
110 delete_queue_.clear();
111 for (base::ListValue::const_iterator iter = message_list.begin();
112 iter != message_list.end(); ++iter) {
113 base::DictionaryValue* message = NULL;
114 if (!(*iter)->GetAsDictionary(&message))
115 continue;
116 MessageReceived(*message);
117 double index = 0;
118 if (message->GetDoubleWithoutPathExpansion(kIndexKey, &index))
119 delete_queue_.push_back(static_cast<uint32>(index));
121 DeleteMessages();
124 // Messages must be deleted one at a time, since we can not guarantee
125 // the order the deletion will be executed in. Delete messages from
126 // the back of the list so that the indices are valid.
127 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::DeleteMessages() {
128 if (delete_queue_.empty()) {
129 deleting_messages_ = false;
130 return;
132 deleting_messages_ = true;
133 uint32 index = delete_queue_.back();
134 delete_queue_.pop_back();
135 DBusThreadManager::Get()->GetGsmSMSClient()->Delete(
136 service_name_, object_path_, index,
137 base::Bind(&NetworkSmsHandler::
138 ModemManagerNetworkSmsDeviceHandler::DeleteMessages,
139 weak_ptr_factory_.GetWeakPtr()));
142 void NetworkSmsHandler::
143 ModemManagerNetworkSmsDeviceHandler::SmsReceivedCallback(
144 uint32 index,
145 bool complete) {
146 // Only handle complete messages.
147 if (!complete)
148 return;
149 DBusThreadManager::Get()->GetGsmSMSClient()->Get(
150 service_name_, object_path_, index,
151 base::Bind(&NetworkSmsHandler::
152 ModemManagerNetworkSmsDeviceHandler::GetCallback,
153 weak_ptr_factory_.GetWeakPtr(), index));
156 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::GetCallback(
157 uint32 index,
158 const base::DictionaryValue& dictionary) {
159 MessageReceived(dictionary);
160 delete_queue_.push_back(index);
161 if (!deleting_messages_)
162 DeleteMessages();
165 void NetworkSmsHandler::
166 ModemManagerNetworkSmsDeviceHandler::MessageReceived(
167 const base::DictionaryValue& dictionary) {
168 // The keys of the ModemManager.Modem.Gsm.SMS interface match the
169 // exported keys, so the dictionary used as a notification argument
170 // unchanged.
171 host_->MessageReceived(dictionary);
174 class NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler
175 : public NetworkSmsHandler::NetworkSmsDeviceHandler {
176 public:
177 ModemManager1NetworkSmsDeviceHandler(NetworkSmsHandler* host,
178 const std::string& service_name,
179 const dbus::ObjectPath& object_path);
181 void RequestUpdate() override;
183 private:
184 void ListCallback(const std::vector<dbus::ObjectPath>& paths);
185 void SmsReceivedCallback(const dbus::ObjectPath& path, bool complete);
186 void GetCallback(const base::DictionaryValue& dictionary);
187 void DeleteMessages();
188 void GetMessages();
189 void MessageReceived(const base::DictionaryValue& dictionary);
191 NetworkSmsHandler* host_;
192 std::string service_name_;
193 dbus::ObjectPath object_path_;
194 bool deleting_messages_;
195 bool retrieving_messages_;
196 std::vector<dbus::ObjectPath> delete_queue_;
197 std::deque<dbus::ObjectPath> retrieval_queue_;
198 base::WeakPtrFactory<ModemManager1NetworkSmsDeviceHandler> weak_ptr_factory_;
200 DISALLOW_COPY_AND_ASSIGN(ModemManager1NetworkSmsDeviceHandler);
203 NetworkSmsHandler::
204 ModemManager1NetworkSmsDeviceHandler::ModemManager1NetworkSmsDeviceHandler(
205 NetworkSmsHandler* host,
206 const std::string& service_name,
207 const dbus::ObjectPath& object_path)
208 : host_(host),
209 service_name_(service_name),
210 object_path_(object_path),
211 deleting_messages_(false),
212 retrieving_messages_(false),
213 weak_ptr_factory_(this) {
214 // Set the handler for received Sms messaages.
215 DBusThreadManager::Get()->GetModemMessagingClient()->SetSmsReceivedHandler(
216 service_name_, object_path_,
217 base::Bind(
218 &NetworkSmsHandler::
219 ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback,
220 weak_ptr_factory_.GetWeakPtr()));
222 // List the existing messages.
223 DBusThreadManager::Get()->GetModemMessagingClient()->List(
224 service_name_, object_path_,
225 base::Bind(&NetworkSmsHandler::
226 ModemManager1NetworkSmsDeviceHandler::ListCallback,
227 weak_ptr_factory_.GetWeakPtr()));
230 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::RequestUpdate() {
231 // Calling List using the service "AddSMS" causes the stub
232 // implementation to deliver new sms messages.
233 DBusThreadManager::Get()->GetModemMessagingClient()->List(
234 std::string("AddSMS"), dbus::ObjectPath("/"),
235 base::Bind(&NetworkSmsHandler::
236 ModemManager1NetworkSmsDeviceHandler::ListCallback,
237 weak_ptr_factory_.GetWeakPtr()));
240 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::ListCallback(
241 const std::vector<dbus::ObjectPath>& paths) {
242 // This receives all messages, so clear any pending gets and deletes.
243 retrieval_queue_.clear();
244 delete_queue_.clear();
246 retrieval_queue_.resize(paths.size());
247 std::copy(paths.begin(), paths.end(), retrieval_queue_.begin());
248 if (!retrieving_messages_)
249 GetMessages();
252 // Messages must be deleted one at a time, since we can not guarantee
253 // the order the deletion will be executed in. Delete messages from
254 // the back of the list so that the indices are valid.
255 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::DeleteMessages() {
256 if (delete_queue_.empty()) {
257 deleting_messages_ = false;
258 return;
260 deleting_messages_ = true;
261 dbus::ObjectPath sms_path = delete_queue_.back();
262 delete_queue_.pop_back();
263 DBusThreadManager::Get()->GetModemMessagingClient()->Delete(
264 service_name_, object_path_, sms_path,
265 base::Bind(&NetworkSmsHandler::
266 ModemManager1NetworkSmsDeviceHandler::DeleteMessages,
267 weak_ptr_factory_.GetWeakPtr()));
270 // Messages must be fetched one at a time, so that we do not queue too
271 // many requests to a single threaded server.
272 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetMessages() {
273 if (retrieval_queue_.empty()) {
274 retrieving_messages_ = false;
275 if (!deleting_messages_)
276 DeleteMessages();
277 return;
279 retrieving_messages_ = true;
280 dbus::ObjectPath sms_path = retrieval_queue_.front();
281 retrieval_queue_.pop_front();
282 DBusThreadManager::Get()->GetSMSClient()->GetAll(
283 service_name_, sms_path,
284 base::Bind(&NetworkSmsHandler::
285 ModemManager1NetworkSmsDeviceHandler::GetCallback,
286 weak_ptr_factory_.GetWeakPtr()));
287 delete_queue_.push_back(sms_path);
290 void NetworkSmsHandler::
291 ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback(
292 const dbus::ObjectPath& sms_path,
293 bool complete) {
294 // Only handle complete messages.
295 if (!complete)
296 return;
297 retrieval_queue_.push_back(sms_path);
298 if (!retrieving_messages_)
299 GetMessages();
302 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetCallback(
303 const base::DictionaryValue& dictionary) {
304 MessageReceived(dictionary);
305 GetMessages();
308 void NetworkSmsHandler::
309 ModemManager1NetworkSmsDeviceHandler::MessageReceived(
310 const base::DictionaryValue& dictionary) {
311 // The keys of the ModemManager1.SMS interface do not match the
312 // exported keys, so a new dictionary is created with the expected
313 // key namaes.
314 base::DictionaryValue new_dictionary;
315 std::string text, number, timestamp;
316 if (dictionary.GetStringWithoutPathExpansion(kModemManager1NumberKey,
317 &number))
318 new_dictionary.SetString(kNumberKey, number);
319 if (dictionary.GetStringWithoutPathExpansion(kModemManager1TextKey, &text))
320 new_dictionary.SetString(kTextKey, text);
321 // TODO(jglasgow): consider normalizing timestamp.
322 if (dictionary.GetStringWithoutPathExpansion(kModemManager1TimestampKey,
323 &timestamp))
324 new_dictionary.SetString(kTimestampKey, timestamp);
325 host_->MessageReceived(new_dictionary);
328 ///////////////////////////////////////////////////////////////////////////////
329 // NetworkSmsHandler
331 NetworkSmsHandler::NetworkSmsHandler()
332 : weak_ptr_factory_(this) {
335 NetworkSmsHandler::~NetworkSmsHandler() {
336 DBusThreadManager::Get()->GetShillManagerClient()->
337 RemovePropertyChangedObserver(this);
340 void NetworkSmsHandler::Init() {
341 // Add as an observer here so that new devices added after this call are
342 // recognized.
343 DBusThreadManager::Get()->GetShillManagerClient()->AddPropertyChangedObserver(
344 this);
345 // Request network manager properties so that we can get the list of devices.
346 DBusThreadManager::Get()->GetShillManagerClient()->GetProperties(
347 base::Bind(&NetworkSmsHandler::ManagerPropertiesCallback,
348 weak_ptr_factory_.GetWeakPtr()));
351 void NetworkSmsHandler::RequestUpdate(bool request_existing) {
352 // If we already received messages and |request_existing| is true, send
353 // updates for existing messages.
354 for (ScopedVector<base::DictionaryValue>::iterator iter =
355 received_messages_.begin();
356 iter != received_messages_.end(); ++iter) {
357 base::DictionaryValue* message = *iter;
358 NotifyMessageReceived(*message);
360 // Request updates from each device.
361 for (ScopedVector<NetworkSmsDeviceHandler>::iterator iter =
362 device_handlers_.begin(); iter != device_handlers_.end(); ++iter) {
363 (*iter)->RequestUpdate();
367 void NetworkSmsHandler::AddObserver(Observer* observer) {
368 observers_.AddObserver(observer);
371 void NetworkSmsHandler::RemoveObserver(Observer* observer) {
372 observers_.RemoveObserver(observer);
375 void NetworkSmsHandler::OnPropertyChanged(const std::string& name,
376 const base::Value& value) {
377 if (name != shill::kDevicesProperty)
378 return;
379 const base::ListValue* devices = NULL;
380 if (!value.GetAsList(&devices) || !devices)
381 return;
382 UpdateDevices(devices);
385 // Private methods
387 void NetworkSmsHandler::AddReceivedMessage(
388 const base::DictionaryValue& message) {
389 base::DictionaryValue* new_message = message.DeepCopy();
390 if (received_messages_.size() >= kMaxReceivedMessages)
391 received_messages_.erase(received_messages_.begin());
392 received_messages_.push_back(new_message);
395 void NetworkSmsHandler::NotifyMessageReceived(
396 const base::DictionaryValue& message) {
397 FOR_EACH_OBSERVER(Observer, observers_, MessageReceived(message));
400 void NetworkSmsHandler::MessageReceived(const base::DictionaryValue& message) {
401 AddReceivedMessage(message);
402 NotifyMessageReceived(message);
405 void NetworkSmsHandler::ManagerPropertiesCallback(
406 DBusMethodCallStatus call_status,
407 const base::DictionaryValue& properties) {
408 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
409 LOG(ERROR) << "NetworkSmsHandler: Failed to get manager properties.";
410 return;
412 const base::Value* value;
413 if (!properties.GetWithoutPathExpansion(shill::kDevicesProperty, &value) ||
414 value->GetType() != base::Value::TYPE_LIST) {
415 LOG(ERROR) << "NetworkSmsHandler: No list value for: "
416 << shill::kDevicesProperty;
417 return;
419 const base::ListValue* devices = static_cast<const base::ListValue*>(value);
420 UpdateDevices(devices);
423 void NetworkSmsHandler::UpdateDevices(const base::ListValue* devices) {
424 for (base::ListValue::const_iterator iter = devices->begin();
425 iter != devices->end(); ++iter) {
426 std::string device_path;
427 (*iter)->GetAsString(&device_path);
428 if (!device_path.empty()) {
429 // Request device properties.
430 VLOG(1) << "GetDeviceProperties: " << device_path;
431 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
432 dbus::ObjectPath(device_path),
433 base::Bind(&NetworkSmsHandler::DevicePropertiesCallback,
434 weak_ptr_factory_.GetWeakPtr(),
435 device_path));
440 void NetworkSmsHandler::DevicePropertiesCallback(
441 const std::string& device_path,
442 DBusMethodCallStatus call_status,
443 const base::DictionaryValue& properties) {
444 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
445 LOG(ERROR) << "NetworkSmsHandler: ERROR: " << call_status
446 << " For: " << device_path;
447 return;
450 std::string device_type;
451 if (!properties.GetStringWithoutPathExpansion(
452 shill::kTypeProperty, &device_type)) {
453 LOG(ERROR) << "NetworkSmsHandler: No type for: " << device_path;
454 return;
456 if (device_type != shill::kTypeCellular)
457 return;
459 std::string service_name;
460 if (!properties.GetStringWithoutPathExpansion(
461 shill::kDBusServiceProperty, &service_name)) {
462 LOG(ERROR) << "Device has no DBusService Property: " << device_path;
463 return;
466 std::string object_path_string;
467 if (!properties.GetStringWithoutPathExpansion(
468 shill::kDBusObjectProperty, &object_path_string)) {
469 LOG(ERROR) << "Device has no DBusObject Property: " << device_path;
470 return;
472 dbus::ObjectPath object_path(object_path_string);
473 if (service_name == modemmanager::kModemManager1ServiceName) {
474 device_handlers_.push_back(
475 new ModemManager1NetworkSmsDeviceHandler(
476 this, service_name, object_path));
477 } else {
478 device_handlers_.push_back(
479 new ModemManagerNetworkSmsDeviceHandler(
480 this, service_name, object_path));
484 } // namespace chromeos