Home | History | Annotate | Download | only in dbus
      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/modem_messaging_client.h"
      5 
      6 #include <map>
      7 #include <utility>
      8 
      9 #include "base/bind.h"
     10 #include "base/memory/weak_ptr.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/stl_util.h"
     13 #include "base/values.h"
     14 #include "dbus/bus.h"
     15 #include "dbus/message.h"
     16 #include "dbus/object_proxy.h"
     17 #include "third_party/cros_system_api/dbus/service_constants.h"
     18 
     19 namespace chromeos {
     20 
     21 namespace {
     22 
     23 // A class which makes method calls for SMS services via the
     24 // org.freedesktop.ModemManager1.Messaging object.
     25 class ModemMessagingProxy {
     26  public:
     27   typedef ModemMessagingClient::SmsReceivedHandler SmsReceivedHandler;
     28   typedef ModemMessagingClient::ListCallback ListCallback;
     29   typedef ModemMessagingClient::DeleteCallback DeleteCallback;
     30 
     31   ModemMessagingProxy(dbus::Bus* bus,
     32            const std::string& service_name,
     33            const dbus::ObjectPath& object_path)
     34       : bus_(bus),
     35         proxy_(bus->GetObjectProxy(service_name, object_path)),
     36         service_name_(service_name),
     37         weak_ptr_factory_(this) {
     38     proxy_->ConnectToSignal(
     39         modemmanager::kModemManager1MessagingInterface,
     40         modemmanager::kSMSAddedSignal,
     41         base::Bind(&ModemMessagingProxy::OnSmsAdded,
     42                    weak_ptr_factory_.GetWeakPtr()),
     43         base::Bind(&ModemMessagingProxy::OnSignalConnected,
     44                    weak_ptr_factory_.GetWeakPtr()));
     45   }
     46   virtual ~ModemMessagingProxy() {}
     47 
     48   // Sets SmsReceived signal handler.
     49   void SetSmsReceivedHandler(const SmsReceivedHandler& handler) {
     50     DCHECK(sms_received_handler_.is_null());
     51     sms_received_handler_ = handler;
     52   }
     53 
     54   // Resets SmsReceived signal handler.
     55   void ResetSmsReceivedHandler() {
     56     sms_received_handler_.Reset();
     57   }
     58 
     59   // Calls Delete method.
     60   void Delete(const dbus::ObjectPath& message_path,
     61               const DeleteCallback& callback) {
     62     dbus::MethodCall method_call(modemmanager::kModemManager1MessagingInterface,
     63                                  modemmanager::kSMSDeleteFunction);
     64     dbus::MessageWriter writer(&method_call);
     65     writer.AppendObjectPath(message_path);
     66     proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
     67                        base::Bind(&ModemMessagingProxy::OnDelete,
     68                                   weak_ptr_factory_.GetWeakPtr(),
     69                                   callback));
     70   }
     71 
     72   // Calls List method.
     73   virtual void List(const ListCallback& callback) {
     74     dbus::MethodCall method_call(modemmanager::kModemManager1MessagingInterface,
     75                                  modemmanager::kSMSListFunction);
     76     proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
     77                        base::Bind(&ModemMessagingProxy::OnList,
     78                                   weak_ptr_factory_.GetWeakPtr(),
     79                                   callback));
     80   }
     81 
     82  private:
     83   // Handles SmsAdded signal.
     84   void OnSmsAdded(dbus::Signal* signal) {
     85     dbus::ObjectPath message_path;
     86     bool complete = false;
     87     dbus::MessageReader reader(signal);
     88     if (!reader.PopObjectPath(&message_path) ||
     89         !reader.PopBool(&complete)) {
     90       LOG(ERROR) << "Invalid signal: " << signal->ToString();
     91       return;
     92     }
     93     if (!sms_received_handler_.is_null()) {
     94       sms_received_handler_.Run(message_path, complete);
     95     }
     96   }
     97 
     98   // Handles responses of Delete method calls.
     99   void OnDelete(const DeleteCallback& callback, dbus::Response* response) {
    100     if (!response)
    101       return;
    102     callback.Run();
    103   }
    104 
    105   // Handles responses of List method calls.
    106   void OnList(const ListCallback& callback, dbus::Response* response) {
    107     if (!response)
    108       return;
    109     dbus::MessageReader reader(response);
    110     std::vector<dbus::ObjectPath> sms_paths;
    111     if (!reader.PopArrayOfObjectPaths(&sms_paths))
    112       LOG(WARNING) << "Invalid response: " << response->ToString();
    113     callback.Run(sms_paths);
    114   }
    115 
    116   // Handles the result of signal connection setup.
    117   void OnSignalConnected(const std::string& interface,
    118                          const std::string& signal,
    119                          bool succeeded) {
    120     LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " "
    121                               << signal << " failed.";
    122   }
    123 
    124   dbus::Bus* bus_;
    125   dbus::ObjectProxy* proxy_;
    126   std::string service_name_;
    127   SmsReceivedHandler sms_received_handler_;
    128 
    129   // Note: This should remain the last member so it'll be destroyed and
    130   // invalidate its weak pointers before any other members are destroyed.
    131   base::WeakPtrFactory<ModemMessagingProxy> weak_ptr_factory_;
    132 
    133   DISALLOW_COPY_AND_ASSIGN(ModemMessagingProxy);
    134 };
    135 
    136 class CHROMEOS_EXPORT ModemMessagingClientImpl : public ModemMessagingClient {
    137  public:
    138   explicit ModemMessagingClientImpl(dbus::Bus *bus)
    139       : bus_(bus),
    140         proxies_deleter_(&proxies_) {
    141   }
    142 
    143   // ModemMessagingClient override.
    144   virtual void SetSmsReceivedHandler(
    145       const std::string& service_name,
    146       const dbus::ObjectPath& object_path,
    147       const SmsReceivedHandler& handler) OVERRIDE {
    148     GetProxy(service_name, object_path)->SetSmsReceivedHandler(handler);
    149   }
    150 
    151   // ModemMessagingClient override.
    152   virtual void ResetSmsReceivedHandler(
    153       const std::string& service_name,
    154       const dbus::ObjectPath& object_path) OVERRIDE {
    155     GetProxy(service_name, object_path)->ResetSmsReceivedHandler();
    156   }
    157 
    158   // ModemMessagingClient override.
    159   virtual void Delete(const std::string& service_name,
    160                       const dbus::ObjectPath& object_path,
    161                       const dbus::ObjectPath& sms_path,
    162                       const DeleteCallback& callback) OVERRIDE {
    163     GetProxy(service_name, object_path)->Delete(sms_path, callback);
    164   }
    165 
    166   // ModemMessagingClient override.
    167   virtual void List(const std::string& service_name,
    168                     const dbus::ObjectPath& object_path,
    169                     const ListCallback& callback) OVERRIDE {
    170     GetProxy(service_name, object_path)->List(callback);
    171   }
    172 
    173  private:
    174   typedef std::map<std::pair<std::string, std::string>, ModemMessagingProxy*>
    175       ProxyMap;
    176 
    177   // Returns a SMSProxy for the given service name and object path.
    178   ModemMessagingProxy* GetProxy(const std::string& service_name,
    179                                 const dbus::ObjectPath& object_path) {
    180     const ProxyMap::key_type key(service_name, object_path.value());
    181     ProxyMap::iterator it = proxies_.find(key);
    182     if (it != proxies_.end())
    183       return it->second;
    184 
    185     // There is no proxy for the service_name and object_path, create it.
    186     ModemMessagingProxy* proxy
    187         = new ModemMessagingProxy(bus_, service_name, object_path);
    188     proxies_.insert(ProxyMap::value_type(key, proxy));
    189     return proxy;
    190   }
    191 
    192   dbus::Bus* bus_;
    193   ProxyMap proxies_;
    194   STLValueDeleter<ProxyMap> proxies_deleter_;
    195 
    196   DISALLOW_COPY_AND_ASSIGN(ModemMessagingClientImpl);
    197 };
    198 
    199 class CHROMEOS_EXPORT ModemMessagingClientStubImpl
    200     : public ModemMessagingClient {
    201  public:
    202   ModemMessagingClientStubImpl() {}
    203   virtual ~ModemMessagingClientStubImpl() {}
    204 
    205   // ModemMessagingClient override.
    206   virtual void SetSmsReceivedHandler(
    207       const std::string& service_name,
    208       const dbus::ObjectPath& object_path,
    209       const SmsReceivedHandler& handler) OVERRIDE {
    210     DCHECK(sms_received_handler_.is_null());
    211     sms_received_handler_ = handler;
    212   }
    213 
    214   // ModemMessagingClient override.
    215   virtual void ResetSmsReceivedHandler(
    216       const std::string& service_name,
    217       const dbus::ObjectPath& object_path) OVERRIDE {
    218     sms_received_handler_.Reset();
    219   }
    220 
    221   // ModemMessagingClient override.
    222   virtual void Delete(const std::string& service_name,
    223                       const dbus::ObjectPath& object_path,
    224                       const dbus::ObjectPath& sms_path,
    225                       const DeleteCallback& callback) OVERRIDE {
    226     std::vector<dbus::ObjectPath>::iterator it(
    227         find(message_paths_.begin(), message_paths_.end(), sms_path));
    228     if (it != message_paths_.end())
    229       message_paths_.erase(it);
    230     callback.Run();
    231   }
    232 
    233   // ModemMessagingClient override.
    234   virtual void List(const std::string& service_name,
    235                     const dbus::ObjectPath& object_path,
    236                     const ListCallback& callback) OVERRIDE {
    237     // This entire ModemMessagingClientStubImpl is for testing.
    238     // Calling List with |service_name| equal to "AddSMS" allows unit
    239     // tests to confirm that the sms_received_handler is functioning.
    240     if (service_name == "AddSMS") {
    241       std::vector<dbus::ObjectPath> no_paths;
    242       const dbus::ObjectPath kSmsPath("/SMS/0");
    243       message_paths_.push_back(kSmsPath);
    244       if (!sms_received_handler_.is_null())
    245         sms_received_handler_.Run(kSmsPath, true);
    246       callback.Run(no_paths);
    247     } else {
    248       callback.Run(message_paths_);
    249     }
    250   }
    251 
    252  private:
    253   SmsReceivedHandler sms_received_handler_;
    254   std::vector<dbus::ObjectPath> message_paths_;
    255 
    256   DISALLOW_COPY_AND_ASSIGN(ModemMessagingClientStubImpl);
    257 };
    258 
    259 }  // namespace
    260 
    261 ////////////////////////////////////////////////////////////////////////////////
    262 // ModemMessagingClient
    263 
    264 ModemMessagingClient::ModemMessagingClient() {}
    265 
    266 ModemMessagingClient::~ModemMessagingClient() {}
    267 
    268 
    269 // static
    270 ModemMessagingClient* ModemMessagingClient::Create(
    271     DBusClientImplementationType type,
    272     dbus::Bus* bus) {
    273   if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) {
    274     return new ModemMessagingClientImpl(bus);
    275   }
    276   DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
    277   return new ModemMessagingClientStubImpl();
    278 }
    279 
    280 
    281 }  // namespace chromeos
    282