shill: cellular: Persist the Allow.Roaming property of cellular devices

Persist the Allow.Roaming property of cellular devices

BUG=none
TEST=unit tests and manually testing on the machine. restart shill.

Change-Id: I25c25588ca20e9fb941b0024d558b229e5fcfa90
Reviewed-on: https://gerrit.chromium.org/gerrit/21540
Reviewed-by: Jason Glasgow <jglasgow@chromium.org>
Tested-by: Jason Glasgow <jglasgow@chromium.org>
Commit-Ready: Jason Glasgow <jglasgow@chromium.org>
diff --git a/cellular.cc b/cellular.cc
index 1cac8f7..db6df6e 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -33,6 +33,7 @@
 #include "shill/proxy_factory.h"
 #include "shill/rtnl_handler.h"
 #include "shill/scope_logger.h"
+#include "shill/store_interface.h"
 #include "shill/technology.h"
 
 using base::Bind;
@@ -41,6 +42,9 @@
 
 namespace shill {
 
+// static
+const char Cellular::kAllowRoaming[] = "AllowRoaming";
+
 Cellular::Operator::Operator() {
   SetName("");
   SetCode("");
@@ -104,13 +108,17 @@
       modem_state_(kModemStateUnknown),
       dbus_owner_(owner),
       dbus_path_(path),
-      provider_db_(provider_db) {
+      provider_db_(provider_db),
+      allow_roaming_(false) {
   PropertyStore *store = this->mutable_store();
   store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
   store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
   HelpRegisterDerivedString(flimflam::kTechnologyFamilyProperty,
                             &Cellular::GetTechnologyFamily,
                             NULL);
+  HelpRegisterDerivedBool(flimflam::kCellularAllowRoamingProperty,
+                          &Cellular::GetAllowRoaming,
+                          &Cellular::SetAllowRoaming);
   store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
                                 &home_provider_.ToDict());
   // For now, only a single capability is supported.
@@ -123,6 +131,22 @@
 Cellular::~Cellular() {
 }
 
+bool Cellular::Load(StoreInterface *storage) {
+  const string id = GetStorageIdentifier();
+  if (!storage->ContainsGroup(id)) {
+    LOG(WARNING) << "Device is not available in the persistent store: " << id;
+    return false;
+  }
+  storage->GetBool(id, kAllowRoaming, &allow_roaming_);
+  return Device::Load(storage);
+}
+
+bool Cellular::Save(StoreInterface *storage) {
+  const string id = GetStorageIdentifier();
+  storage->SetBool(id, kAllowRoaming, allow_roaming_);
+  return Device::Save(storage);
+}
+
 // static
 string Cellular::GetStateString(State state) {
   switch (state) {
@@ -146,6 +170,16 @@
   state_ = state;
 }
 
+void Cellular::HelpRegisterDerivedBool(
+    const string &name,
+    bool(Cellular::*get)(Error *error),
+    void(Cellular::*set)(const bool &value, Error *error)) {
+  mutable_store()->RegisterDerivedBool(
+      name,
+      BoolAccessor(
+          new CustomAccessor<Cellular, bool>(this, get, set)));
+}
+
 void Cellular::HelpRegisterDerivedString(
     const string &name,
     string(Cellular::*get)(Error *),
@@ -522,4 +556,24 @@
   }
 }
 
+void Cellular::SetAllowRoaming(const bool &value, Error */*error*/) {
+  SLOG(Cellular, 2) << __func__
+                    << "(" << allow_roaming_ << "->" << value << ")";
+  if (allow_roaming_ == value) {
+    return;
+  }
+  allow_roaming_ = value;
+  manager()->SaveActiveProfile();
+
+  // Use AllowRoaming() instead of allow_roaming_ in order to
+  // incorporate provider preferences when evaluating if a disconnect
+  // is required.
+  if (!capability_->AllowRoaming() &&
+      capability_->GetRoamingStateString() == flimflam::kRoamingStateRoaming) {
+    Error error;
+    Disconnect(&error);
+  }
+  adaptor()->EmitBoolChanged(flimflam::kCellularAllowRoamingProperty, value);
+}
+
 }  // namespace shill