gsm_sms_client.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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. 4#include "chromeos/dbus/gsm_sms_client.h" 5 6#include <map> 7#include <utility> 8#include <vector> 9 10#include "base/bind.h" 11#include "base/command_line.h" 12#include "base/memory/scoped_ptr.h" 13#include "base/memory/weak_ptr.h" 14#include "base/message_loop.h" 15#include "base/stringprintf.h" 16#include "base/stl_util.h" 17#include "base/values.h" 18#include "chromeos/chromeos_switches.h" 19#include "dbus/bus.h" 20#include "dbus/message.h" 21#include "dbus/object_proxy.h" 22#include "dbus/values_util.h" 23#include "third_party/cros_system_api/dbus/service_constants.h" 24 25namespace chromeos { 26 27namespace { 28 29// A class actually making method calls for SMS services, used by 30// GsmSMSClientImpl. 31class SMSProxy { 32 public: 33 typedef GsmSMSClient::SmsReceivedHandler SmsReceivedHandler; 34 typedef GsmSMSClient::DeleteCallback DeleteCallback; 35 typedef GsmSMSClient::GetCallback GetCallback; 36 typedef GsmSMSClient::ListCallback ListCallback; 37 38 SMSProxy(dbus::Bus* bus, 39 const std::string& service_name, 40 const dbus::ObjectPath& object_path) 41 : proxy_(bus->GetObjectProxy(service_name, object_path)), 42 weak_ptr_factory_(this) { 43 proxy_->ConnectToSignal( 44 modemmanager::kModemManagerSMSInterface, 45 modemmanager::kSMSReceivedSignal, 46 base::Bind(&SMSProxy::OnSmsReceived, weak_ptr_factory_.GetWeakPtr()), 47 base::Bind(&SMSProxy::OnSignalConnected, 48 weak_ptr_factory_.GetWeakPtr())); 49 } 50 51 // Sets SmsReceived signal handler. 52 void SetSmsReceivedHandler(const SmsReceivedHandler& handler) { 53 DCHECK(sms_received_handler_.is_null()); 54 sms_received_handler_ = handler; 55 } 56 57 // Resets SmsReceived signal handler. 58 void ResetSmsReceivedHandler() { 59 sms_received_handler_.Reset(); 60 } 61 62 // Calls Delete method. 63 void Delete(uint32 index, const DeleteCallback& callback) { 64 dbus::MethodCall method_call(modemmanager::kModemManagerSMSInterface, 65 modemmanager::kSMSDeleteFunction); 66 dbus::MessageWriter writer(&method_call); 67 writer.AppendUint32(index); 68 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 69 base::Bind(&SMSProxy::OnDelete, 70 weak_ptr_factory_.GetWeakPtr(), 71 callback)); 72 } 73 74 // Calls Get method. 75 void Get(uint32 index, const GetCallback& callback) { 76 dbus::MethodCall method_call(modemmanager::kModemManagerSMSInterface, 77 modemmanager::kSMSGetFunction); 78 dbus::MessageWriter writer(&method_call); 79 writer.AppendUint32(index); 80 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 81 base::Bind(&SMSProxy::OnGet, 82 weak_ptr_factory_.GetWeakPtr(), 83 callback)); 84 } 85 86 // Calls List method. 87 void List(const ListCallback& callback) { 88 dbus::MethodCall method_call(modemmanager::kModemManagerSMSInterface, 89 modemmanager::kSMSListFunction); 90 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 91 base::Bind(&SMSProxy::OnList, 92 weak_ptr_factory_.GetWeakPtr(), 93 callback)); 94 } 95 96 private: 97 // Handles SmsReceived signal. 98 void OnSmsReceived(dbus::Signal* signal) { 99 uint32 index = 0; 100 bool complete = false; 101 dbus::MessageReader reader(signal); 102 if (!reader.PopUint32(&index) || 103 !reader.PopBool(&complete)) { 104 LOG(ERROR) << "Invalid signal: " << signal->ToString(); 105 return; 106 } 107 if (!sms_received_handler_.is_null()) 108 sms_received_handler_.Run(index, complete); 109 } 110 111 // Handles the result of signal connection setup. 112 void OnSignalConnected(const std::string& interface, 113 const std::string& signal, 114 bool succeeded) { 115 LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " " << 116 signal << " failed."; 117 } 118 119 // Handles responses of Delete method calls. 120 void OnDelete(const DeleteCallback& callback, dbus::Response* response) { 121 if (!response) 122 return; 123 callback.Run(); 124 } 125 126 // Handles responses of Get method calls. 127 void OnGet(const GetCallback& callback, dbus::Response* response) { 128 if (!response) 129 return; 130 dbus::MessageReader reader(response); 131 scoped_ptr<base::Value> value(dbus::PopDataAsValue(&reader)); 132 base::DictionaryValue* dictionary_value = NULL; 133 if (!value.get() || !value->GetAsDictionary(&dictionary_value)) { 134 LOG(WARNING) << "Invalid response: " << response->ToString(); 135 return; 136 } 137 callback.Run(*dictionary_value); 138 } 139 140 // Handles responses of List method calls. 141 void OnList(const ListCallback& callback, dbus::Response* response) { 142 if (!response) 143 return; 144 dbus::MessageReader reader(response); 145 scoped_ptr<base::Value> value(dbus::PopDataAsValue(&reader)); 146 base::ListValue* list_value = NULL; 147 if (!value.get() || !value->GetAsList(&list_value)) { 148 LOG(WARNING) << "Invalid response: " << response->ToString(); 149 return; 150 } 151 callback.Run(*list_value); 152 } 153 154 dbus::ObjectProxy* proxy_; 155 SmsReceivedHandler sms_received_handler_; 156 157 // Note: This should remain the last member so it'll be destroyed and 158 // invalidate its weak pointers before any other members are destroyed. 159 base::WeakPtrFactory<SMSProxy> weak_ptr_factory_; 160 161 DISALLOW_COPY_AND_ASSIGN(SMSProxy); 162}; 163 164// The GsmSMSClient implementation. 165class GsmSMSClientImpl : public GsmSMSClient { 166 public: 167 explicit GsmSMSClientImpl(dbus::Bus* bus) 168 : bus_(bus), 169 proxies_deleter_(&proxies_) { 170 } 171 172 // GsmSMSClient override. 173 virtual void SetSmsReceivedHandler( 174 const std::string& service_name, 175 const dbus::ObjectPath& object_path, 176 const SmsReceivedHandler& handler) OVERRIDE { 177 GetProxy(service_name, object_path)->SetSmsReceivedHandler(handler); 178 } 179 180 // GsmSMSClient override. 181 virtual void ResetSmsReceivedHandler( 182 const std::string& service_name, 183 const dbus::ObjectPath& object_path) OVERRIDE { 184 GetProxy(service_name, object_path)->ResetSmsReceivedHandler(); 185 } 186 187 // GsmSMSClient override. 188 virtual void Delete(const std::string& service_name, 189 const dbus::ObjectPath& object_path, 190 uint32 index, 191 const DeleteCallback& callback) OVERRIDE { 192 GetProxy(service_name, object_path)->Delete(index, callback); 193 } 194 195 // GsmSMSClient override. 196 virtual void Get(const std::string& service_name, 197 const dbus::ObjectPath& object_path, 198 uint32 index, 199 const GetCallback& callback) OVERRIDE { 200 GetProxy(service_name, object_path)->Get(index, callback); 201 } 202 203 // GsmSMSClient override. 204 virtual void List(const std::string& service_name, 205 const dbus::ObjectPath& object_path, 206 const ListCallback& callback) OVERRIDE { 207 GetProxy(service_name, object_path)->List(callback); 208 } 209 210 // GsmSMSClient override. 211 virtual void RequestUpdate(const std::string& service_name, 212 const dbus::ObjectPath& object_path) OVERRIDE { 213 } 214 215 private: 216 typedef std::map<std::pair<std::string, std::string>, SMSProxy*> ProxyMap; 217 218 // Returns a SMSProxy for the given service name and object path. 219 SMSProxy* GetProxy(const std::string& service_name, 220 const dbus::ObjectPath& object_path) { 221 const ProxyMap::key_type key(service_name, object_path.value()); 222 ProxyMap::iterator it = proxies_.find(key); 223 if (it != proxies_.end()) 224 return it->second; 225 226 // There is no proxy for the service_name and object_path, create it. 227 SMSProxy* proxy = new SMSProxy(bus_, service_name, object_path); 228 proxies_.insert(ProxyMap::value_type(key, proxy)); 229 return proxy; 230 } 231 232 dbus::Bus* bus_; 233 ProxyMap proxies_; 234 STLValueDeleter<ProxyMap> proxies_deleter_; 235 236 DISALLOW_COPY_AND_ASSIGN(GsmSMSClientImpl); 237}; 238 239// A stub implementaion of GsmSMSClient. 240class GsmSMSClientStubImpl : public GsmSMSClient { 241 public: 242 GsmSMSClientStubImpl() : test_index_(-1), weak_ptr_factory_(this) { 243 test_messages_.push_back("Test Message 0"); 244 test_messages_.push_back("Test Message 1"); 245 test_messages_.push_back("Test a relatively long message 2"); 246 test_messages_.push_back("Test a very, the quick brown fox jumped" 247 " over the lazy dog, long message 3"); 248 test_messages_.push_back("Test Message 4"); 249 test_messages_.push_back("Test Message 5"); 250 test_messages_.push_back("Test Message 6"); 251 } 252 253 virtual ~GsmSMSClientStubImpl() {} 254 255 // GsmSMSClient override. 256 virtual void SetSmsReceivedHandler( 257 const std::string& service_name, 258 const dbus::ObjectPath& object_path, 259 const SmsReceivedHandler& handler) OVERRIDE { 260 handler_ = handler; 261 } 262 263 // GsmSMSClient override. 264 virtual void ResetSmsReceivedHandler( 265 const std::string& service_name, 266 const dbus::ObjectPath& object_path) OVERRIDE { 267 handler_.Reset(); 268 } 269 270 // GsmSMSClient override. 271 virtual void Delete(const std::string& service_name, 272 const dbus::ObjectPath& object_path, 273 uint32 index, 274 const DeleteCallback& callback) OVERRIDE { 275 message_list_.Remove(index, NULL); 276 callback.Run(); 277 } 278 279 // GsmSMSClient override. 280 virtual void Get(const std::string& service_name, 281 const dbus::ObjectPath& object_path, 282 uint32 index, 283 const GetCallback& callback) OVERRIDE { 284 base::DictionaryValue* dictionary = NULL; 285 if (message_list_.GetDictionary(index, &dictionary)) { 286 callback.Run(*dictionary); 287 return; 288 } 289 base::DictionaryValue empty_dictionary; 290 callback.Run(empty_dictionary); 291 } 292 293 // GsmSMSClient override. 294 virtual void List(const std::string& service_name, 295 const dbus::ObjectPath& object_path, 296 const ListCallback& callback) OVERRIDE { 297 callback.Run(message_list_); 298 } 299 300 // GsmSMSClient override. 301 virtual void RequestUpdate(const std::string& service_name, 302 const dbus::ObjectPath& object_path) OVERRIDE { 303 if (!CommandLine::ForCurrentProcess()->HasSwitch( 304 chromeos::switches::kSmsTestMessages)) 305 return; 306 if (test_index_ >= 0) 307 return; 308 test_index_ = 0; 309 // Call PushTestMessageChain asynchronously so that the handler_ callback 310 // does not get called from the update request. 311 MessageLoop::current()->PostTask( 312 FROM_HERE, 313 base::Bind(&GsmSMSClientStubImpl::PushTestMessageChain, 314 weak_ptr_factory_.GetWeakPtr())); 315 } 316 317 private: 318 void PushTestMessageChain() { 319 if (PushTestMessage()) 320 PushTestMessageDelayed(); 321 } 322 323 void PushTestMessageDelayed() { 324 const int kSmsMessageDelaySeconds = 5; 325 MessageLoop::current()->PostDelayedTask( 326 FROM_HERE, 327 base::Bind(&GsmSMSClientStubImpl::PushTestMessageChain, 328 weak_ptr_factory_.GetWeakPtr()), 329 base::TimeDelta::FromSeconds(kSmsMessageDelaySeconds)); 330 } 331 332 bool PushTestMessage() { 333 if (test_index_ >= static_cast<int>(test_messages_.size())) 334 return false; 335 base::DictionaryValue* message = new base::DictionaryValue; 336 message->SetString("number", "000-000-0000"); 337 message->SetString("text", test_messages_[test_index_]); 338 message->SetInteger("index", test_index_); 339 int msg_index = message_list_.GetSize(); 340 message_list_.Append(message); 341 if (!handler_.is_null()) 342 handler_.Run(msg_index, true); 343 ++test_index_; 344 return true; 345 } 346 347 int test_index_; 348 std::vector<std::string> test_messages_; 349 base::ListValue message_list_; 350 SmsReceivedHandler handler_; 351 base::WeakPtrFactory<GsmSMSClientStubImpl> weak_ptr_factory_; 352 353 DISALLOW_COPY_AND_ASSIGN(GsmSMSClientStubImpl); 354}; 355 356} // namespace 357 358//////////////////////////////////////////////////////////////////////////////// 359// GsmSMSClient 360 361GsmSMSClient::GsmSMSClient() {} 362 363GsmSMSClient::~GsmSMSClient() {} 364 365// static 366GsmSMSClient* GsmSMSClient::Create(DBusClientImplementationType type, 367 dbus::Bus* bus) { 368 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) 369 return new GsmSMSClientImpl(bus); 370 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); 371 return new GsmSMSClientStubImpl(); 372} 373 374} // namespace chromeos 375