shill: cellular: Update status when registration is lost.

BUG=chromium-os:36626
TEST=Unit tests, cellular_ModemControl, network_ModemControl

Change-Id: Ia151d6e22620b3e93789800a8c0666d6bee707bf
Reviewed-on: https://gerrit.chromium.org/gerrit/38671
Reviewed-by: Ben Chan <benchan@chromium.org>
Commit-Ready: Thieu Le <thieule@chromium.org>
Reviewed-by: Thieu Le <thieule@chromium.org>
Tested-by: Thieu Le <thieule@chromium.org>
diff --git a/cellular.cc b/cellular.cc
index 9b3e04b..a244595 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -590,22 +590,21 @@
     return;
   }
   set_modem_state(new_state);
+  if (old_state >= kModemStateRegistered &&
+      new_state < kModemStateRegistered) {
+    capability_->SetUnregistered(new_state == kModemStateSearching);
+    HandleNewRegistrationState();
+  }
   switch (new_state) {
     case kModemStateDisabled:
       SetEnabled(false);
       break;
     case kModemStateEnabled:
-    case kModemStateSearching:
-      // Note: we only handle changes to Enabled from the Registered
-      // state here. Changes from Disabled to Enabled are handled in
-      // the DBusPropertiesChanged handler.
-      if (old_state == kModemStateRegistered) {
-        capability_->SetUnregistered(new_state == kModemStateSearching);
-        HandleNewRegistrationState();
-      } else {
-        SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Enabled";
-      }
+      // Transition from Disabled to Enabled is handled in the
+      // DBusPropertiesChanged handler.
+      SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Enabled";
       // Intentionally falls through.
+    case kModemStateSearching:
     case kModemStateRegistered:
       // If the modem state changes from Connecting/Connected/Disconnecting
       // to Registered/Enabled/Searching, then it's an indication that the
diff --git a/cellular_capability_universal.h b/cellular_capability_universal.h
index ac72355..6059c8d 100644
--- a/cellular_capability_universal.h
+++ b/cellular_capability_universal.h
@@ -147,6 +147,7 @@
   FRIEND_TEST(CellularCapabilityUniversalTest, UpdateOperatorInfoViaOperatorId);
   FRIEND_TEST(CellularTest,
               HandleNewRegistrationStateForServiceRequiringActivation);
+  FRIEND_TEST(CellularTest, ModemStateChangeLostRegistration);
 
   // Methods used in starting a modem
   void EnableModem(Error *error, const ResultCallback &callback);
diff --git a/cellular_unittest.cc b/cellular_unittest.cc
index 8ee3f30..71dc4de 100644
--- a/cellular_unittest.cc
+++ b/cellular_unittest.cc
@@ -799,6 +799,17 @@
   EXPECT_EQ(Cellular::kStateConnected, device_->state());
 }
 
+TEST_F(CellularTest, ModemStateChangeLostRegistration) {
+  SetCellularType(Cellular::kTypeUniversal);
+  CellularCapabilityUniversal *capability = GetCapabilityUniversal();
+  capability->registration_state_ = MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
+  EXPECT_TRUE(capability->IsRegistered());
+  device_->OnModemStateChanged(Cellular::kModemStateRegistered,
+                               Cellular::kModemStateEnabled,
+                               0);
+  EXPECT_FALSE(capability->IsRegistered());
+}
+
 TEST_F(CellularTest, StartModemCallback) {
   EXPECT_CALL(*this, TestCallback(IsSuccess()));
   EXPECT_EQ(device_->state_, Cellular::kStateDisabled);