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"
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"
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"
29 // A class actually making method calls for SMS services, used by
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(),
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(),
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(),
97 // Handles SmsReceived signal.
98 void OnSmsReceived(dbus::Signal
* signal
) {
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();
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
,
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
) {
126 // Handles responses of Get method calls.
127 void OnGet(const GetCallback
& callback
, dbus::Response
* response
) {
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();
137 callback
.Run(*dictionary_value
);
140 // Handles responses of List method calls.
141 void OnList(const ListCallback
& callback
, dbus::Response
* response
) {
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();
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
{
167 explicit GsmSMSClientImpl(dbus::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
,
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
,
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
{
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())
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
));
234 STLValueDeleter
<ProxyMap
> proxies_deleter_
;
236 DISALLOW_COPY_AND_ASSIGN(GsmSMSClientImpl
);
239 // A stub implementaion of GsmSMSClient.
240 class GsmSMSClientStubImpl
: public GsmSMSClient
{
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
{
263 // GsmSMSClient override.
264 virtual void ResetSmsReceivedHandler(
265 const std::string
& service_name
,
266 const dbus::ObjectPath
& object_path
) OVERRIDE
{
270 // GsmSMSClient override.
271 virtual void Delete(const std::string
& service_name
,
272 const dbus::ObjectPath
& object_path
,
274 const DeleteCallback
& callback
) OVERRIDE
{
275 message_list_
.Remove(index
, NULL
);
279 // GsmSMSClient override.
280 virtual void Get(const std::string
& service_name
,
281 const dbus::ObjectPath
& object_path
,
283 const GetCallback
& callback
) OVERRIDE
{
284 base::DictionaryValue
* dictionary
= NULL
;
285 if (message_list_
.GetDictionary(index
, &dictionary
)) {
286 callback
.Run(*dictionary
);
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
))
306 if (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(
313 base::Bind(&GsmSMSClientStubImpl::PushTestMessageChain
,
314 weak_ptr_factory_
.GetWeakPtr()));
318 void PushTestMessageChain() {
319 if (PushTestMessage())
320 PushTestMessageDelayed();
323 void PushTestMessageDelayed() {
324 const int kSmsMessageDelaySeconds
= 5;
325 MessageLoop::current()->PostDelayedTask(
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()))
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);
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
);
358 ////////////////////////////////////////////////////////////////////////////////
361 GsmSMSClient::GsmSMSClient() {}
363 GsmSMSClient::~GsmSMSClient() {}
366 GsmSMSClient
* GsmSMSClient::Create(DBusClientImplementationType type
,
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