Don't kill key events even when it's VKEY_UNKNOWN.
[chromium-blink-merge.git] / chromeos / network / network_sms_handler.cc
blobd6e608cd98be3a376bc44cf08b1fd06c66eba4be
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 <string>
10 #include <vector>
12 #include "base/bind.h"
13 #include "base/values.h"
14 #include "chromeos/dbus/dbus_thread_manager.h"
15 #include "chromeos/dbus/shill_device_client.h"
16 #include "chromeos/dbus/shill_manager_client.h"
17 #include "chromeos/dbus/gsm_sms_client.h"
18 #include "chromeos/dbus/modem_messaging_client.h"
19 #include "chromeos/dbus/sms_client.h"
20 #include "dbus/object_path.h"
21 #include "third_party/cros_system_api/dbus/service_constants.h"
23 namespace {
25 // Not exposed/exported:
26 const char kIndexKey[] = "index";
28 // Keys from ModemManager1
29 const char kModemManager1NumberKey[] = "Number";
30 const char kModemManager1TextKey[] = "Text";
31 const char kModemManager1TimestampKey[] = "Timestamp";
33 // Maximum number of messages stored for RequestUpdate(true).
34 const size_t kMaxReceivedMessages = 100;
36 } // namespace
38 namespace chromeos {
40 // static
41 const char NetworkSmsHandler::kNumberKey[] = "number";
42 const char NetworkSmsHandler::kTextKey[] = "text";
43 const char NetworkSmsHandler::kTimestampKey[] = "timestamp";
45 class NetworkSmsHandler::NetworkSmsDeviceHandler {
46 public:
47 NetworkSmsDeviceHandler() {}
48 virtual ~NetworkSmsDeviceHandler() {}
50 virtual void RequestUpdate() = 0;
53 class NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler
54 : public NetworkSmsHandler::NetworkSmsDeviceHandler {
55 public:
56 ModemManagerNetworkSmsDeviceHandler(NetworkSmsHandler* host,
57 const std::string& service_name,
58 const dbus::ObjectPath& object_path);
60 virtual void RequestUpdate() OVERRIDE;
62 private:
63 void ListCallback(const base::ListValue& message_list);
64 void SmsReceivedCallback(uint32 index, bool complete);
65 void GetCallback(uint32 index, const base::DictionaryValue& dictionary);
66 void DeleteMessages();
67 void MessageReceived(const base::DictionaryValue& dictionary);
69 NetworkSmsHandler* host_;
70 std::string service_name_;
71 dbus::ObjectPath object_path_;
72 bool deleting_messages_;
73 base::WeakPtrFactory<ModemManagerNetworkSmsDeviceHandler> weak_ptr_factory_;
74 std::vector<uint32> delete_queue_;
76 DISALLOW_COPY_AND_ASSIGN(ModemManagerNetworkSmsDeviceHandler);
79 NetworkSmsHandler::
80 ModemManagerNetworkSmsDeviceHandler::ModemManagerNetworkSmsDeviceHandler(
81 NetworkSmsHandler* host,
82 const std::string& service_name,
83 const dbus::ObjectPath& object_path)
84 : host_(host),
85 service_name_(service_name),
86 object_path_(object_path),
87 deleting_messages_(false),
88 weak_ptr_factory_(this) {
89 // Set the handler for received Sms messaages.
90 DBusThreadManager::Get()->GetGsmSMSClient()->SetSmsReceivedHandler(
91 service_name_, object_path_,
92 base::Bind(&ModemManagerNetworkSmsDeviceHandler::SmsReceivedCallback,
93 weak_ptr_factory_.GetWeakPtr()));
95 // List the existing messages.
96 DBusThreadManager::Get()->GetGsmSMSClient()->List(
97 service_name_, object_path_,
98 base::Bind(&NetworkSmsHandler::
99 ModemManagerNetworkSmsDeviceHandler::ListCallback,
100 weak_ptr_factory_.GetWeakPtr()));
103 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::RequestUpdate() {
104 DBusThreadManager::Get()->GetGsmSMSClient()->RequestUpdate(
105 service_name_, object_path_);
108 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::ListCallback(
109 const base::ListValue& message_list) {
110 // This receives all messages, so clear any pending deletes.
111 delete_queue_.clear();
112 for (base::ListValue::const_iterator iter = message_list.begin();
113 iter != message_list.end(); ++iter) {
114 base::DictionaryValue* message = NULL;
115 if (!(*iter)->GetAsDictionary(&message))
116 continue;
117 MessageReceived(*message);
118 double index = 0;
119 if (message->GetDoubleWithoutPathExpansion(kIndexKey, &index))
120 delete_queue_.push_back(static_cast<uint32>(index));
122 DeleteMessages();
125 // Messages must be deleted one at a time, since we can not guarantee
126 // the order the deletion will be executed in. Delete messages from
127 // the back of the list so that the indices are valid.
128 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::DeleteMessages() {
129 if (delete_queue_.empty()) {
130 deleting_messages_ = false;
131 return;
133 deleting_messages_ = true;
134 uint32 index = delete_queue_.back();
135 delete_queue_.pop_back();
136 DBusThreadManager::Get()->GetGsmSMSClient()->Delete(
137 service_name_, object_path_, index,
138 base::Bind(&NetworkSmsHandler::
139 ModemManagerNetworkSmsDeviceHandler::DeleteMessages,
140 weak_ptr_factory_.GetWeakPtr()));
143 void NetworkSmsHandler::
144 ModemManagerNetworkSmsDeviceHandler::SmsReceivedCallback(
145 uint32 index,
146 bool complete) {
147 // Only handle complete messages.
148 if (!complete)
149 return;
150 DBusThreadManager::Get()->GetGsmSMSClient()->Get(
151 service_name_, object_path_, index,
152 base::Bind(&NetworkSmsHandler::
153 ModemManagerNetworkSmsDeviceHandler::GetCallback,
154 weak_ptr_factory_.GetWeakPtr(), index));
157 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::GetCallback(
158 uint32 index,
159 const base::DictionaryValue& dictionary) {
160 MessageReceived(dictionary);
161 delete_queue_.push_back(index);
162 if (!deleting_messages_)
163 DeleteMessages();
166 void NetworkSmsHandler::
167 ModemManagerNetworkSmsDeviceHandler::MessageReceived(
168 const base::DictionaryValue& dictionary) {
169 // The keys of the ModemManager.Modem.Gsm.SMS interface match the
170 // exported keys, so the dictionary used as a notification argument
171 // unchanged.
172 host_->MessageReceived(dictionary);
175 class NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler
176 : public NetworkSmsHandler::NetworkSmsDeviceHandler {
177 public:
178 ModemManager1NetworkSmsDeviceHandler(NetworkSmsHandler* host,
179 const std::string& service_name,
180 const dbus::ObjectPath& object_path);
182 virtual void RequestUpdate() OVERRIDE;
184 private:
185 void ListCallback(const std::vector<dbus::ObjectPath>& paths);
186 void SmsReceivedCallback(const dbus::ObjectPath& path, bool complete);
187 void GetCallback(const base::DictionaryValue& dictionary);
188 void DeleteMessages();
189 void GetMessages();
190 void MessageReceived(const base::DictionaryValue& dictionary);
192 NetworkSmsHandler* host_;
193 std::string service_name_;
194 dbus::ObjectPath object_path_;
195 bool deleting_messages_;
196 bool retrieving_messages_;
197 base::WeakPtrFactory<ModemManager1NetworkSmsDeviceHandler> weak_ptr_factory_;
198 std::vector<dbus::ObjectPath> delete_queue_;
199 std::deque<dbus::ObjectPath> retrieval_queue_;
201 DISALLOW_COPY_AND_ASSIGN(ModemManager1NetworkSmsDeviceHandler);
204 NetworkSmsHandler::
205 ModemManager1NetworkSmsDeviceHandler::ModemManager1NetworkSmsDeviceHandler(
206 NetworkSmsHandler* host,
207 const std::string& service_name,
208 const dbus::ObjectPath& object_path)
209 : host_(host),
210 service_name_(service_name),
211 object_path_(object_path),
212 deleting_messages_(false),
213 retrieving_messages_(false),
214 weak_ptr_factory_(this) {
215 // Set the handler for received Sms messaages.
216 DBusThreadManager::Get()->GetModemMessagingClient()->SetSmsReceivedHandler(
217 service_name_, object_path_,
218 base::Bind(
219 &NetworkSmsHandler::
220 ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback,
221 weak_ptr_factory_.GetWeakPtr()));
223 // List the existing messages.
224 DBusThreadManager::Get()->GetModemMessagingClient()->List(
225 service_name_, object_path_,
226 base::Bind(&NetworkSmsHandler::
227 ModemManager1NetworkSmsDeviceHandler::ListCallback,
228 weak_ptr_factory_.GetWeakPtr()));
231 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::RequestUpdate() {
232 // Calling List using the service "AddSMS" causes the stub
233 // implementation to deliver new sms messages.
234 DBusThreadManager::Get()->GetModemMessagingClient()->List(
235 std::string("AddSMS"), dbus::ObjectPath("/"),
236 base::Bind(&NetworkSmsHandler::
237 ModemManager1NetworkSmsDeviceHandler::ListCallback,
238 weak_ptr_factory_.GetWeakPtr()));
241 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::ListCallback(
242 const std::vector<dbus::ObjectPath>& paths) {
243 // This receives all messages, so clear any pending gets and deletes.
244 retrieval_queue_.clear();
245 delete_queue_.clear();
247 retrieval_queue_.resize(paths.size());
248 std::copy(paths.begin(), paths.end(), retrieval_queue_.begin());
249 if (!retrieving_messages_)
250 GetMessages();
253 // Messages must be deleted one at a time, since we can not guarantee
254 // the order the deletion will be executed in. Delete messages from
255 // the back of the list so that the indices are valid.
256 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::DeleteMessages() {
257 if (delete_queue_.empty()) {
258 deleting_messages_ = false;
259 return;
261 deleting_messages_ = true;
262 dbus::ObjectPath sms_path = delete_queue_.back();
263 delete_queue_.pop_back();
264 DBusThreadManager::Get()->GetModemMessagingClient()->Delete(
265 service_name_, object_path_, sms_path,
266 base::Bind(&NetworkSmsHandler::
267 ModemManager1NetworkSmsDeviceHandler::DeleteMessages,
268 weak_ptr_factory_.GetWeakPtr()));
271 // Messages must be fetched one at a time, so that we do not queue too
272 // many requests to a single threaded server.
273 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetMessages() {
274 if (retrieval_queue_.empty()) {
275 retrieving_messages_ = false;
276 if (!deleting_messages_)
277 DeleteMessages();
278 return;
280 retrieving_messages_ = true;
281 dbus::ObjectPath sms_path = retrieval_queue_.front();
282 retrieval_queue_.pop_front();
283 DBusThreadManager::Get()->GetSMSClient()->GetAll(
284 service_name_, sms_path,
285 base::Bind(&NetworkSmsHandler::
286 ModemManager1NetworkSmsDeviceHandler::GetCallback,
287 weak_ptr_factory_.GetWeakPtr()));
288 delete_queue_.push_back(sms_path);
291 void NetworkSmsHandler::
292 ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback(
293 const dbus::ObjectPath& sms_path,
294 bool complete) {
295 // Only handle complete messages.
296 if (!complete)
297 return;
298 retrieval_queue_.push_back(sms_path);
299 if (!retrieving_messages_)
300 GetMessages();
303 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetCallback(
304 const base::DictionaryValue& dictionary) {
305 MessageReceived(dictionary);
306 GetMessages();
309 void NetworkSmsHandler::
310 ModemManager1NetworkSmsDeviceHandler::MessageReceived(
311 const base::DictionaryValue& dictionary) {
312 // The keys of the ModemManager1.SMS interface do not match the
313 // exported keys, so a new dictionary is created with the expected
314 // key namaes.
315 base::DictionaryValue new_dictionary;
316 std::string text, number, timestamp;
317 if (dictionary.GetStringWithoutPathExpansion(kModemManager1NumberKey,
318 &number))
319 new_dictionary.SetString(kNumberKey, number);
320 if (dictionary.GetStringWithoutPathExpansion(kModemManager1TextKey, &text))
321 new_dictionary.SetString(kTextKey, text);
322 // TODO(jglasgow): consider normalizing timestamp.
323 if (dictionary.GetStringWithoutPathExpansion(kModemManager1TimestampKey,
324 &timestamp))
325 new_dictionary.SetString(kTimestampKey, timestamp);
326 host_->MessageReceived(new_dictionary);
329 ///////////////////////////////////////////////////////////////////////////////
330 // NetworkSmsHandler
332 NetworkSmsHandler::NetworkSmsHandler()
333 : weak_ptr_factory_(this) {
336 NetworkSmsHandler::~NetworkSmsHandler() {
337 DBusThreadManager::Get()->GetShillManagerClient()->
338 RemovePropertyChangedObserver(this);
341 void NetworkSmsHandler::Init() {
342 // Add as an observer here so that new devices added after this call are
343 // recognized.
344 DBusThreadManager::Get()->GetShillManagerClient()->AddPropertyChangedObserver(
345 this);
346 // Request network manager properties so that we can get the list of devices.
347 DBusThreadManager::Get()->GetShillManagerClient()->GetProperties(
348 base::Bind(&NetworkSmsHandler::ManagerPropertiesCallback,
349 weak_ptr_factory_.GetWeakPtr()));
352 void NetworkSmsHandler::RequestUpdate(bool request_existing) {
353 // If we already received messages and |request_existing| is true, send
354 // updates for existing messages.
355 for (ScopedVector<base::DictionaryValue>::iterator iter =
356 received_messages_.begin();
357 iter != received_messages_.end(); ++iter) {
358 base::DictionaryValue* message = *iter;
359 NotifyMessageReceived(*message);
361 // Request updates from each device.
362 for (ScopedVector<NetworkSmsDeviceHandler>::iterator iter =
363 device_handlers_.begin(); iter != device_handlers_.end(); ++iter) {
364 (*iter)->RequestUpdate();
368 void NetworkSmsHandler::AddObserver(Observer* observer) {
369 observers_.AddObserver(observer);
372 void NetworkSmsHandler::RemoveObserver(Observer* observer) {
373 observers_.RemoveObserver(observer);
376 void NetworkSmsHandler::OnPropertyChanged(const std::string& name,
377 const base::Value& value) {
378 if (name != shill::kDevicesProperty)
379 return;
380 const base::ListValue* devices = NULL;
381 if (!value.GetAsList(&devices) || !devices)
382 return;
383 UpdateDevices(devices);
386 // Private methods
388 void NetworkSmsHandler::AddReceivedMessage(
389 const base::DictionaryValue& message) {
390 base::DictionaryValue* new_message = message.DeepCopy();
391 if (received_messages_.size() >= kMaxReceivedMessages)
392 received_messages_.erase(received_messages_.begin());
393 received_messages_.push_back(new_message);
396 void NetworkSmsHandler::NotifyMessageReceived(
397 const base::DictionaryValue& message) {
398 FOR_EACH_OBSERVER(Observer, observers_, MessageReceived(message));
401 void NetworkSmsHandler::MessageReceived(const base::DictionaryValue& message) {
402 AddReceivedMessage(message);
403 NotifyMessageReceived(message);
406 void NetworkSmsHandler::ManagerPropertiesCallback(
407 DBusMethodCallStatus call_status,
408 const base::DictionaryValue& properties) {
409 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
410 LOG(ERROR) << "NetworkSmsHandler: Failed to get manager properties.";
411 return;
413 const base::Value* value;
414 if (!properties.GetWithoutPathExpansion(shill::kDevicesProperty, &value) ||
415 value->GetType() != base::Value::TYPE_LIST) {
416 LOG(ERROR) << "NetworkSmsHandler: No list value for: "
417 << shill::kDevicesProperty;
418 return;
420 const base::ListValue* devices = static_cast<const base::ListValue*>(value);
421 UpdateDevices(devices);
424 void NetworkSmsHandler::UpdateDevices(const base::ListValue* devices) {
425 for (base::ListValue::const_iterator iter = devices->begin();
426 iter != devices->end(); ++iter) {
427 std::string device_path;
428 (*iter)->GetAsString(&device_path);
429 if (!device_path.empty()) {
430 // Request device properties.
431 VLOG(1) << "GetDeviceProperties: " << device_path;
432 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
433 dbus::ObjectPath(device_path),
434 base::Bind(&NetworkSmsHandler::DevicePropertiesCallback,
435 weak_ptr_factory_.GetWeakPtr(),
436 device_path));
441 void NetworkSmsHandler::DevicePropertiesCallback(
442 const std::string& device_path,
443 DBusMethodCallStatus call_status,
444 const base::DictionaryValue& properties) {
445 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
446 LOG(ERROR) << "NetworkSmsHandler: ERROR: " << call_status
447 << " For: " << device_path;
448 return;
451 std::string device_type;
452 if (!properties.GetStringWithoutPathExpansion(
453 shill::kTypeProperty, &device_type)) {
454 LOG(ERROR) << "NetworkSmsHandler: No type for: " << device_path;
455 return;
457 if (device_type != shill::kTypeCellular)
458 return;
460 std::string service_name;
461 if (!properties.GetStringWithoutPathExpansion(
462 shill::kDBusServiceProperty, &service_name)) {
463 LOG(ERROR) << "Device has no DBusService Property: " << device_path;
464 return;
467 std::string object_path_string;
468 if (!properties.GetStringWithoutPathExpansion(
469 shill::kDBusObjectProperty, &object_path_string)) {
470 LOG(ERROR) << "Device has no DBusObject Property: " << device_path;
471 return;
473 dbus::ObjectPath object_path(object_path_string);
474 if (service_name == modemmanager::kModemManager1) {
475 device_handlers_.push_back(
476 new ModemManager1NetworkSmsDeviceHandler(
477 this, service_name, object_path));
478 } else {
479 device_handlers_.push_back(
480 new ModemManagerNetworkSmsDeviceHandler(
481 this, service_name, object_path));
485 } // namespace chromeos