shill: Get CDMA registration state.

BUG=chromium-os:18315
TEST=unit tests, tested on device

Change-Id: Ida6d72145eb829a8d47fd23c9d30ded5308aa8cd
Reviewed-on: http://gerrit.chromium.org/gerrit/5115
Reviewed-by: Darin Petkov <petkov@chromium.org>
Tested-by: Darin Petkov <petkov@chromium.org>
diff --git a/Makefile b/Makefile
index 41c3a27..332598e 100644
--- a/Makefile
+++ b/Makefile
@@ -101,6 +101,7 @@
 	manager.o \
 	manager_dbus_adaptor.o \
 	modem.o \
+	modem_cdma_proxy.o \
 	modem_info.o \
 	modem_manager.o \
 	modem_manager_proxy.o \
diff --git a/cellular.cc b/cellular.cc
index 3d29d9f..2ca6951 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -11,12 +11,14 @@
 #include <base/logging.h>
 #include <base/stringprintf.h>
 #include <chromeos/dbus/service_constants.h>
+#include <mm/mm-modem.h>
 
 #include "shill/cellular_service.h"
 #include "shill/control_interface.h"
 #include "shill/device.h"
 #include "shill/device_info.h"
 #include "shill/manager.h"
+#include "shill/modem_cdma_proxy_interface.h"
 #include "shill/modem_proxy_interface.h"
 #include "shill/modem_simple_proxy_interface.h"
 #include "shill/profile.h"
@@ -84,6 +86,11 @@
   return dict_;
 }
 
+Cellular::CDMA::CDMA()
+    : registration_state_evdo(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
+      registration_state_1x(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
+      activation_state(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED) {}
+
 Cellular::Cellular(ControlInterface *control_interface,
                    EventDispatcher *dispatcher,
                    Manager *manager,
@@ -163,13 +170,8 @@
 }
 
 void Cellular::Start() {
-  proxy_.reset(
-      ProxyFactory::factory()->CreateModemProxy(dbus_path_, dbus_owner_));
-  simple_proxy_.reset(
-      ProxyFactory::factory()->CreateModemSimpleProxy(
-          dbus_path_, dbus_owner_));
-
   VLOG(2) << __func__ << ": " << GetStateString();
+  InitProxies();
   EnableModem();
   if (type_ == kTypeGSM) {
     RegisterGSMModem();
@@ -188,11 +190,31 @@
 void Cellular::Stop() {
   proxy_.reset();
   simple_proxy_.reset();
+  cdma_proxy_.reset();
   manager_->DeregisterService(service_);
   service_ = NULL;  // Breaks a reference cycle.
   // TODO(petkov): Device::Stop();
 }
 
+void Cellular::InitProxies() {
+  proxy_.reset(
+      ProxyFactory::factory()->CreateModemProxy(dbus_path_, dbus_owner_));
+  simple_proxy_.reset(
+      ProxyFactory::factory()->CreateModemSimpleProxy(
+          dbus_path_, dbus_owner_));
+  switch (type_) {
+    case kTypeGSM:
+      NOTIMPLEMENTED();
+      break;
+    case kTypeCDMA:
+      cdma_proxy_.reset(
+          ProxyFactory::factory()->CreateModemCDMAProxy(
+              dbus_path_, dbus_owner_));
+      break;
+    default: NOTREACHED();
+  }
+}
+
 void Cellular::EnableModem() {
   CHECK_EQ(kStateDisabled, state_);
   // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
@@ -254,6 +276,27 @@
 }
 
 void Cellular::GetModemRegistrationState() {
+  switch (type_) {
+    case kTypeGSM:
+      GetGSMRegistrationState();
+      break;
+    case kTypeCDMA:
+      GetCDMARegistrationState();
+      break;
+    default: NOTREACHED();
+  }
+}
+
+void Cellular::GetCDMARegistrationState() {
+  CHECK_EQ(kTypeCDMA, type_);
+  cdma_proxy_->GetRegistrationState(&cdma_.registration_state_1x,
+                                    &cdma_.registration_state_evdo);
+  VLOG(2) << "CDMA Registration: 1x(" << cdma_.registration_state_1x
+          << ") EVDO(" << cdma_.registration_state_evdo << ")";
+  // TODO(petkov): handle_reported_connect?
+}
+
+void Cellular::GetGSMRegistrationState() {
   // TODO(petkov): Implement this.
   NOTIMPLEMENTED();
 }
diff --git a/cellular.h b/cellular.h
index 3d82516..a88cb09 100644
--- a/cellular.h
+++ b/cellular.h
@@ -16,6 +16,7 @@
 
 namespace shill {
 
+class ModemCDMAProxyInterface;
 class ModemProxyInterface;
 class ModemSimpleProxyInterface;
 
@@ -61,6 +62,14 @@
     DISALLOW_COPY_AND_ASSIGN(Network);
   };
 
+  struct CDMA {
+    CDMA();
+
+    uint32 registration_state_evdo;
+    uint32 registration_state_1x;
+    uint32 activation_state;
+  };
+
   struct SimLockStatus {
    public:
     SimLockStatus() : retries_left(0) {}
@@ -88,10 +97,13 @@
   virtual bool TechnologyIs(Technology type);
 
  private:
+  FRIEND_TEST(CellularTest, GetCDMARegistrationState);
   FRIEND_TEST(CellularTest, GetModemInfo);
   FRIEND_TEST(CellularTest, GetModemStatus);
   FRIEND_TEST(CellularTest, GetStateString);
   FRIEND_TEST(CellularTest, GetTypeString);
+  FRIEND_TEST(CellularTest, InitProxiesCDMA);
+  FRIEND_TEST(CellularTest, InitProxiesGSM);
   FRIEND_TEST(CellularTest, Start);
 
   Stringmaps EnumerateNetworks();
@@ -103,6 +115,8 @@
                                      StrIntPair(Cellular::*get)(void),
                                      bool(Cellular::*set)(const StrIntPair&));
 
+  void InitProxies();
+
   std::string GetTypeString();
   std::string GetStateString();
 
@@ -110,7 +124,6 @@
   void GetModemStatus();
   void GetGSMProperties();
   void RegisterGSMModem();
-  void GetModemRegistrationState();
   void ReportEnabled();
 
   // Obtains the modem identifiers: MEID for CDMA; IMEI, IMSI, SPN and MSISDN
@@ -120,6 +133,10 @@
   // Obtain modem's manufacturer, model ID, and hardware revision.
   void GetModemInfo();
 
+  void GetModemRegistrationState();
+  void GetCDMARegistrationState();
+  void GetGSMRegistrationState();
+
   Type type_;
   State state_;
 
@@ -127,6 +144,9 @@
   const std::string dbus_path_;  // ModemManager.Modem
   scoped_ptr<ModemProxyInterface> proxy_;
   scoped_ptr<ModemSimpleProxyInterface> simple_proxy_;
+  scoped_ptr<ModemCDMAProxyInterface> cdma_proxy_;
+
+  CDMA cdma_;
 
   ServiceRefPtr service_;
   bool service_registered_;
diff --git a/cellular_unittest.cc b/cellular_unittest.cc
index eb5bb77..6b3e575 100644
--- a/cellular_unittest.cc
+++ b/cellular_unittest.cc
@@ -5,14 +5,18 @@
 #include "shill/cellular.h"
 
 #include <chromeos/dbus/service_constants.h>
+#include <mm/mm-modem.h>
 
+#include "shill/mock_modem_cdma_proxy.h"
 #include "shill/mock_modem_proxy.h"
 #include "shill/mock_modem_simple_proxy.h"
 #include "shill/property_store_unittest.h"
 #include "shill/proxy_factory.h"
 
 using std::string;
+using testing::_;
 using testing::Return;
+using testing::SetArgumentPointee;
 
 namespace shill {
 
@@ -21,6 +25,7 @@
   CellularTest()
       : proxy_(new MockModemProxy()),
         simple_proxy_(new MockModemSimpleProxy()),
+        cdma_proxy_(new MockModemCDMAProxy()),
         proxy_factory_(this),
         device_(new Cellular(&control_interface_,
                              NULL,
@@ -57,6 +62,12 @@
       return test_->simple_proxy_.release();
     }
 
+    virtual ModemCDMAProxyInterface *CreateModemCDMAProxy(
+        const string &path,
+        const string &service) {
+      return test_->cdma_proxy_.release();
+    }
+
    private:
     CellularTest *test_;
   };
@@ -66,6 +77,7 @@
 
   scoped_ptr<MockModemProxy> proxy_;
   scoped_ptr<MockModemSimpleProxy> simple_proxy_;
+  scoped_ptr<MockModemCDMAProxy> cdma_proxy_;
   TestProxyFactory proxy_factory_;
   CellularRefPtr device_;
 };
@@ -150,6 +162,22 @@
   EXPECT_EQ(Cellular::kStateEnabled, device_->state_);
 }
 
+TEST_F(CellularTest, InitProxiesCDMA) {
+  device_->type_ = Cellular::kTypeCDMA;
+  device_->InitProxies();
+  EXPECT_TRUE(device_->proxy_.get());
+  EXPECT_TRUE(device_->simple_proxy_.get());
+  EXPECT_TRUE(device_->cdma_proxy_.get());
+}
+
+TEST_F(CellularTest, InitProxiesGSM) {
+  device_->type_ = Cellular::kTypeGSM;
+  device_->InitProxies();
+  EXPECT_TRUE(device_->proxy_.get());
+  EXPECT_TRUE(device_->simple_proxy_.get());
+  EXPECT_FALSE(device_->cdma_proxy_.get());
+}
+
 TEST_F(CellularTest, GetModemStatus) {
   static const char kCarrier[] = "The Cellular Carrier";
   DBusPropertiesMap props;
@@ -178,4 +206,22 @@
   EXPECT_EQ(kHWRev, device_->hardware_revision_);
 }
 
+TEST_F(CellularTest, GetCDMARegistrationState) {
+  EXPECT_EQ(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN,
+            device_->cdma_.registration_state_1x);
+  EXPECT_EQ(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN,
+            device_->cdma_.registration_state_evdo);
+  device_->type_ = Cellular::kTypeCDMA;
+  EXPECT_CALL(*cdma_proxy_, GetRegistrationState(_, _))
+      .WillOnce(DoAll(
+          SetArgumentPointee<0>(MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED),
+          SetArgumentPointee<1>(MM_MODEM_CDMA_REGISTRATION_STATE_HOME)));
+  device_->cdma_proxy_.reset(cdma_proxy_.release());
+  device_->GetModemRegistrationState();
+  EXPECT_EQ(MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED,
+            device_->cdma_.registration_state_1x);
+  EXPECT_EQ(MM_MODEM_CDMA_REGISTRATION_STATE_HOME,
+            device_->cdma_.registration_state_evdo);
+}
+
 }  // namespace shill
diff --git a/mock_modem_cdma_proxy.h b/mock_modem_cdma_proxy.h
new file mode 100644
index 0000000..afdf183
--- /dev/null
+++ b/mock_modem_cdma_proxy.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_MOCK_MODEM_CDMA_PROXY_H_
+#define SHILL_MOCK_MODEM_CDMA_PROXY_H_
+
+#include <gmock/gmock.h>
+
+#include "shill/modem_cdma_proxy_interface.h"
+
+namespace shill {
+
+class MockModemCDMAProxy : public ModemCDMAProxyInterface {
+ public:
+  MOCK_METHOD2(GetRegistrationState, void(uint32 *cdma_1x_state,
+                                          uint32 *evdo_state));
+};
+
+}  // namespace shill
+
+#endif  // SHILL_MOCK_MODEM_CDMA_PROXY_H_
diff --git a/modem.cc b/modem.cc
index 75a3c28..87e3d3e 100644
--- a/modem.cc
+++ b/modem.cc
@@ -97,6 +97,8 @@
       return;
   }
 
+  // TODO(petkov): Handle the "State" property?
+
   LOG(INFO) << "Creating a cellular device on link " << link_name
             << " interface index " << interface_index << ".";
   device_ = new Cellular(control_interface_,
diff --git a/modem_cdma_proxy.cc b/modem_cdma_proxy.cc
new file mode 100644
index 0000000..aab7c4a
--- /dev/null
+++ b/modem_cdma_proxy.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shill/modem_cdma_proxy.h"
+
+#include <base/logging.h>
+
+using std::string;
+
+namespace shill {
+
+ModemCDMAProxy::ModemCDMAProxy(DBus::Connection *connection,
+                               const string &path,
+                               const string &service)
+    : proxy_(connection, path, service) {}
+
+ModemCDMAProxy::~ModemCDMAProxy() {}
+
+void ModemCDMAProxy::GetRegistrationState(uint32 *cdma_1x_state,
+                                          uint32 *evdo_state) {
+  proxy_.GetRegistrationState(*cdma_1x_state, *evdo_state);
+}
+
+ModemCDMAProxy::Proxy::Proxy(DBus::Connection *connection,
+                             const string &path,
+                             const string &service)
+    : DBus::ObjectProxy(*connection, path, service.c_str()) {}
+
+ModemCDMAProxy::Proxy::~Proxy() {}
+
+void ModemCDMAProxy::Proxy::ActivationStateChanged(
+    const uint32 &activation_state,
+    const uint32 &activation_error,
+    const DBusPropertiesMap &status_changes) {
+  VLOG(2) << __func__;
+  // TODO(petkov): Implement this.
+  NOTIMPLEMENTED();
+}
+
+void ModemCDMAProxy::Proxy::SignalQuality(const uint32 &quality) {
+  VLOG(2) << __func__;
+  // TODO(petkov): Implement this.
+  NOTIMPLEMENTED();
+}
+
+void ModemCDMAProxy::Proxy::RegistrationStateChanged(
+    const uint32_t &cdma_1x_state,
+    const uint32_t &evdo_state) {
+  VLOG(2) << __func__;
+  // TODO(petkov): Implement this.
+  NOTIMPLEMENTED();
+}
+
+}  // namespace shill
diff --git a/modem_cdma_proxy.h b/modem_cdma_proxy.h
new file mode 100644
index 0000000..b1ef84f
--- /dev/null
+++ b/modem_cdma_proxy.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_MODEM_CDMA_PROXY_
+#define SHILL_MODEM_CDMA_PROXY_
+
+#include "shill/dbus_bindings/modem-cdma.h"
+#include "shill/dbus_properties.h"
+#include "shill/modem_cdma_proxy_interface.h"
+
+namespace shill {
+
+class ModemCDMAProxy : public ModemCDMAProxyInterface {
+ public:
+  ModemCDMAProxy(DBus::Connection *connection,
+                 const std::string &path,
+                 const std::string &service);
+  virtual ~ModemCDMAProxy();
+
+  // Inherited from ModemCDMAProxyInterface.
+  virtual void GetRegistrationState(uint32 *cdma_1x_state, uint32 *evdo_state);
+
+ private:
+  class Proxy : public org::freedesktop::ModemManager::Modem::Cdma_proxy,
+                public DBus::ObjectProxy {
+   public:
+    Proxy(DBus::Connection *connection,
+          const std::string &path,
+          const std::string &service);
+    virtual ~Proxy();
+
+   private:
+    // Signal callbacks inherited from ModemManager::Modem::Cdma_proxy.
+    virtual void ActivationStateChanged(
+        const uint32 &activation_state,
+        const uint32 &activation_error,
+        const DBusPropertiesMap &status_changes);
+    virtual void SignalQuality(const uint32 &quality);
+    virtual void RegistrationStateChanged(const uint32_t &cdma_1x_state,
+                                          const uint32_t &evdo_state);
+
+    DISALLOW_COPY_AND_ASSIGN(Proxy);
+  };
+
+  Proxy proxy_;
+
+  DISALLOW_COPY_AND_ASSIGN(ModemCDMAProxy);
+};
+
+}  // namespace shill
+
+#endif  // SHILL_MODEM_CDMA_PROXY_
diff --git a/modem_cdma_proxy_interface.h b/modem_cdma_proxy_interface.h
new file mode 100644
index 0000000..c4f4c9c
--- /dev/null
+++ b/modem_cdma_proxy_interface.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_MODEM_CDMA_PROXY_INTERFACE_
+#define SHILL_MODEM_CDMA_PROXY_INTERFACE_
+
+#include <base/basictypes.h>
+
+namespace shill {
+
+// These are the methods that a ModemManager.Modem.CDMA proxy must support. The
+// interface is provided so that it can be mocked in tests.
+class ModemCDMAProxyInterface {
+ public:
+  virtual ~ModemCDMAProxyInterface() {}
+
+  virtual void GetRegistrationState(uint32 *cdma_1x_state,
+                                    uint32 *evdo_state) = 0;
+};
+
+}  // namespace shill
+
+#endif  // SHILL_MODEM_CDMA_PROXY_INTERFACE_
diff --git a/proxy_factory.cc b/proxy_factory.cc
index 389dde6..3d250ac 100644
--- a/proxy_factory.cc
+++ b/proxy_factory.cc
@@ -8,6 +8,7 @@
 
 #include "shill/dbus_properties_proxy.h"
 #include "shill/dhcpcd_proxy.h"
+#include "shill/modem_cdma_proxy.h"
 #include "shill/modem_manager_proxy.h"
 #include "shill/modem_proxy.h"
 #include "shill/modem_simple_proxy.h"
@@ -55,6 +56,12 @@
   return new ModemSimpleProxy(connection(), path, service);
 }
 
+ModemCDMAProxyInterface *ProxyFactory::CreateModemCDMAProxy(
+    const string &path,
+    const string &service) {
+  return new ModemCDMAProxy(connection(), path, service);
+}
+
 SupplicantProcessProxyInterface *ProxyFactory::CreateSupplicantProcessProxy(
     const char *dbus_path,
     const char *dbus_addr) {
diff --git a/proxy_factory.h b/proxy_factory.h
index 908b699..6c1b0f4 100644
--- a/proxy_factory.h
+++ b/proxy_factory.h
@@ -18,6 +18,7 @@
 class DBusPropertiesProxyInterface;
 class DHCPProxyInterface;
 class Modem;
+class ModemCDMAProxyInterface;
 class ModemManager;
 class ModemManagerProxyInterface;
 class ModemProxyInterface;
@@ -50,6 +51,10 @@
       const std::string &path,
       const std::string &service);
 
+  virtual ModemCDMAProxyInterface *CreateModemCDMAProxy(
+      const std::string &path,
+      const std::string &service);
+
   virtual SupplicantProcessProxyInterface *CreateSupplicantProcessProxy(
       const char *dbus_path,
       const char *dbus_addr);