Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / chromeos / dbus / gsm_sms_client.cc
blob07e84797c244bf19f16f7bfec97c70ffac0f2483
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"
6 #include <map>
7 #include <utility>
8 #include <vector>
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"
25 namespace chromeos {
27 namespace {
29 // A class actually making method calls for SMS services, used by
30 // GsmSMSClientImpl.
31 class SMSProxy {
32 public:
33 typedef GsmSMSClient::SmsReceivedHandler SmsReceivedHandler;
34 typedef GsmSMSClient::DeleteCallback DeleteCallback;
35 typedef GsmSMSClient::GetCallback GetCallback;
36 typedef GsmSMSClient::ListCallback ListCallback;
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()));
51 // Sets SmsReceived signal handler.
52 void SetSmsReceivedHandler(const SmsReceivedHandler& handler) {
53 DCHECK(sms_received_handler_.is_null());
54 sms_received_handler_ = handler;
57 // Resets SmsReceived signal handler.
58 void ResetSmsReceivedHandler() {
59 sms_received_handler_.Reset();
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));
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));
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));
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;
107 if (!sms_received_handler_.is_null())
108 sms_received_handler_.Run(index, complete);
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.";
119 // Handles responses of Delete method calls.
120 void OnDelete(const DeleteCallback& callback, dbus::Response* response) {
121 if (!response)
122 return;
123 callback.Run();
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;
137 callback.Run(*dictionary_value);
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;
151 callback.Run(*list_value);
154 dbus::ObjectProxy* proxy_;
155 SmsReceivedHandler sms_received_handler_;
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_;
161 DISALLOW_COPY_AND_ASSIGN(SMSProxy);
164 // The GsmSMSClient implementation.
165 class GsmSMSClientImpl : public GsmSMSClient {
166 public:
167 explicit GsmSMSClientImpl(dbus::Bus* bus)
168 : bus_(bus),
169 proxies_deleter_(&proxies_) {
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);
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();
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);
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);
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);
210 // GsmSMSClient override.
211 virtual void RequestUpdate(const std::string& service_name,
212 const dbus::ObjectPath& object_path) OVERRIDE {
215 private:
216 typedef std::map<std::pair<std::string, std::string>, SMSProxy*> ProxyMap;
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;
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;
232 dbus::Bus* bus_;
233 ProxyMap proxies_;
234 STLValueDeleter<ProxyMap> proxies_deleter_;
236 DISALLOW_COPY_AND_ASSIGN(GsmSMSClientImpl);
239 // A stub implementaion of GsmSMSClient.
240 class 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");
253 virtual ~GsmSMSClientStubImpl() {}
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;
263 // GsmSMSClient override.
264 virtual void ResetSmsReceivedHandler(
265 const std::string& service_name,
266 const dbus::ObjectPath& object_path) OVERRIDE {
267 handler_.Reset();
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();
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;
289 base::DictionaryValue empty_dictionary;
290 callback.Run(empty_dictionary);
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_);
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()));
317 private:
318 void PushTestMessageChain() {
319 if (PushTestMessage())
320 PushTestMessageDelayed();
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));
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;
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_;
353 DISALLOW_COPY_AND_ASSIGN(GsmSMSClientStubImpl);
356 } // namespace
358 ////////////////////////////////////////////////////////////////////////////////
359 // GsmSMSClient
361 GsmSMSClient::GsmSMSClient() {}
363 GsmSMSClient::~GsmSMSClient() {}
365 // static
366 GsmSMSClient* 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();
374 } // namespace chromeos