shill: Update cellular service name, if modem reports a new name.

CellularCapabilityUniversal now updates the cellular service's
|friendly_name_| field when new carrier related information is either
read from the SIM or updated OTA. For the duration of time in which no
valid carrier information is available, the service will be assigned a
generic name as before.

BUG=chrome-os-partner:17310
TEST=1. Build and run unit tests.
     2. Use pseudomodem to generate changes in the OperatorName property
        of interface org.freedesktop.ModemManager1.Modem.Modem3gpp.
        Observe that the UI updates appropriately.

Change-Id: I5b2813731173e8329d191889d4dc58905a6f9e8e
Reviewed-on: https://gerrit.chromium.org/gerrit/42294
Commit-Queue: Arman Uguray <armansito@chromium.org>
Reviewed-by: Arman Uguray <armansito@chromium.org>
Tested-by: Arman Uguray <armansito@chromium.org>
diff --git a/cellular.h b/cellular.h
index c9180c3..7cee6c4 100644
--- a/cellular.h
+++ b/cellular.h
@@ -243,6 +243,7 @@
   FRIEND_TEST(CellularCapabilityUniversalTest, UpdateOLP);
   FRIEND_TEST(CellularCapabilityUniversalTest, UpdateOperatorInfoViaOperatorId);
   FRIEND_TEST(CellularCapabilityUniversalTest, UpdateScanningProperty);
+  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateServiceName);
   FRIEND_TEST(CellularCapabilityUniversalTest, UpdateStorageIdentifier);
   FRIEND_TEST(CellularServiceTest, FriendlyName);
   FRIEND_TEST(CellularTest, CreateService);
diff --git a/cellular_capability_universal.cc b/cellular_capability_universal.cc
index bcf1330..9c44323 100644
--- a/cellular_capability_universal.cc
+++ b/cellular_capability_universal.cc
@@ -51,6 +51,8 @@
 const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
     "allow-roaming";
 const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
+const char CellularCapabilityUniversal::kGenericServiceNamePrefix[] =
+    "Mobile Network";
 const char CellularCapabilityUniversal::kStatusProperty[] = "status";
 const char CellularCapabilityUniversal::kOperatorLongProperty[] =
     "operator-long";
@@ -533,6 +535,13 @@
   OnModem3GPPPropertiesChanged(properties, vector<string>());
 }
 
+// static
+string CellularCapabilityUniversal::GenerateNewGenericServiceName() {
+  return base::StringPrintf("%s %u",
+                            kGenericServiceNamePrefix,
+                            friendly_service_name_id_++);
+}
+
 string CellularCapabilityUniversal::CreateFriendlyServiceName() {
   SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
 
@@ -557,11 +566,10 @@
       !home_provider_name.empty()) {
     return home_provider_name;
   }
-  string serving_operator_code = serving_operator_.GetCode();
-  if (!serving_operator_code.empty()) {
-    return "cellular_" + serving_operator_code;
+  if (!serving_operator_.GetCode().empty()) {
+    return "cellular_" + serving_operator_.GetCode();
   }
-  return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
+  return GenerateNewGenericServiceName();
 }
 
 void CellularCapabilityUniversal::SetHomeProvider() {
@@ -611,6 +619,7 @@
                     << oper.GetName() << ", " << oper.GetCountry()
                     << (provider_requires_roaming_ ? ", roaming required" : "");
   InitAPNList();
+  UpdateServiceName();
 }
 
 void CellularCapabilityUniversal::UpdateScanningProperty() {
@@ -662,8 +671,16 @@
   cellular()->service()->SetOLP(olp);
 }
 
+void CellularCapabilityUniversal::UpdateServiceName() {
+  if (cellular()->service()) {
+    cellular()->service()->SetFriendlyName(CreateFriendlyServiceName());
+  }
+}
+
 void CellularCapabilityUniversal::UpdateOperatorInfo() {
   SLOG(Cellular, 2) << __func__;
+  // TODO(armansito): Use CellularOperatorInfo here instead of
+  // mobile_provider_db.
 
   // Sometimes the modem fails to acquire the operator code OTA, in which case
   // |serving_operator_| may not have an operator ID (sometimes due to service
@@ -1447,8 +1464,14 @@
   registration_state_ = state;
   serving_operator_.SetCode(operator_code);
   serving_operator_.SetName(operator_name);
+
+  // Update the carrier name for |serving_operator_|.
   UpdateOperatorInfo();
+
   cellular()->HandleNewRegistrationState();
+
+  // Update the user facing name of the cellular service.
+  UpdateServiceName();
 }
 
 void CellularCapabilityUniversal::OnModemStateChangedSignal(
diff --git a/cellular_capability_universal.h b/cellular_capability_universal.h
index 747c111..6799dcd 100644
--- a/cellular_capability_universal.h
+++ b/cellular_capability_universal.h
@@ -126,6 +126,10 @@
   // Modem Model ID strings.  From modem firmware via modemmanager.
   static const char kE362ModelId[];
 
+  // Generic service name prefix, shown when the correct carrier name is
+  // unknown.
+  static const char kGenericServiceNamePrefix[];
+
   friend class CellularTest;
   friend class CellularCapabilityTest;
   friend class CellularCapabilityUniversalTest;
@@ -150,6 +154,7 @@
   FRIEND_TEST(CellularCapabilityUniversalTest, StartModem);
   FRIEND_TEST(CellularCapabilityUniversalTest, StopModem);
   FRIEND_TEST(CellularCapabilityUniversalTest, StopModemConnected);
+  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateServiceName);
   FRIEND_TEST(CellularCapabilityUniversalTest, UpdateStorageIdentifier);
   FRIEND_TEST(CellularCapabilityUniversalTest, UpdateOLP);
   FRIEND_TEST(CellularCapabilityUniversalTest, UpdateOperatorInfo);
@@ -171,6 +176,9 @@
   void Stop_DisableCompleted(const ResultCallback &callback,
                              const Error &error);
 
+  // Updates the name property that is exposed by the service to Chrome.
+  void UpdateServiceName();
+
   void UpdateScanningProperty();
 
   // Methods used in acquiring information related to the carrier;
@@ -282,6 +290,8 @@
   void OnListBearersReply(const std::vector<DBus::Path> &paths,
                           const Error &error);
 
+  static std::string GenerateNewGenericServiceName();
+
   scoped_ptr<mm1::ModemModem3gppProxyInterface> modem_3gpp_proxy_;
   scoped_ptr<mm1::ModemModemCdmaProxyInterface> modem_cdma_proxy_;
   scoped_ptr<mm1::ModemProxyInterface> modem_proxy_;
diff --git a/cellular_capability_universal_unittest.cc b/cellular_capability_universal_unittest.cc
index f7bf893..e7c2b31 100644
--- a/cellular_capability_universal_unittest.cc
+++ b/cellular_capability_universal_unittest.cc
@@ -577,6 +577,54 @@
                                        vector<string>());
 }
 
+TEST_F(CellularCapabilityUniversalTest, UpdateServiceName) {
+  ::DBus::Struct<uint32_t, bool> data;
+  data._1 = 100;
+  data._2 = true;
+  EXPECT_CALL(*modem_proxy_, SignalQuality()).WillRepeatedly(Return(data));
+
+  SetUp();
+  InitProviderDB();
+  capability_->InitProxies();
+  cellular_->cellular_operator_info_ = &cellular_operator_info_;
+
+  SetService();
+
+  size_t len = strlen(CellularCapabilityUniversal::kGenericServiceNamePrefix);
+  EXPECT_EQ(CellularCapabilityUniversal::kGenericServiceNamePrefix,
+            cellular_->service_->friendly_name().substr(0, len));
+
+  capability_->imsi_ = "310240123456789";
+  capability_->SetHomeProvider();
+  EXPECT_EQ("", capability_->spn_);
+  EXPECT_EQ("T-Mobile", cellular_->home_provider().GetName());
+  EXPECT_EQ(CellularCapabilityUniversal::kGenericServiceNamePrefix,
+            cellular_->service_->friendly_name().substr(0, len));
+
+  capability_->registration_state_ = MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
+  capability_->SetHomeProvider();
+  EXPECT_EQ("", capability_->spn_);
+  EXPECT_EQ("T-Mobile", cellular_->home_provider().GetName());
+  EXPECT_EQ("T-Mobile", cellular_->service_->friendly_name());
+
+  capability_->spn_ = "Test Home Provider";
+  capability_->SetHomeProvider();
+  EXPECT_EQ("Test Home Provider", cellular_->home_provider().GetName());
+  EXPECT_EQ("Test Home Provider", cellular_->service_->friendly_name());
+
+  capability_->On3GPPRegistrationChanged(
+      MM_MODEM_3GPP_REGISTRATION_STATE_HOME, "", "OTA Name");
+  EXPECT_EQ("OTA Name", cellular_->service_->friendly_name());
+
+  capability_->On3GPPRegistrationChanged(
+      MM_MODEM_3GPP_REGISTRATION_STATE_HOME, "123", "OTA Name 2");
+  EXPECT_EQ("OTA Name 2", cellular_->service_->friendly_name());
+
+  capability_->On3GPPRegistrationChanged(
+      MM_MODEM_3GPP_REGISTRATION_STATE_HOME, "123", "");
+  EXPECT_EQ("Test Home Provider", cellular_->service_->friendly_name());
+}
+
 TEST_F(CellularCapabilityUniversalTest, SimPathChanged) {
   // Set up mock modem SIM properties
   const char kImsi[] = "310100000001";
@@ -1134,7 +1182,12 @@
   SetService();
 
   const string prefix = "cellular_" + string(kMachineAddress) + "_";
-  const string default_identifier_pattern = prefix + "GSMNetwork*";
+  string default_identifier_pattern =
+      prefix + string(CellularCapabilityUniversal::kGenericServiceNamePrefix);
+  std::replace_if(default_identifier_pattern.begin(),
+                  default_identifier_pattern.end(),
+                  &Service::IllegalChar, '_');
+  default_identifier_pattern += "*";
 
   // |capability_->operator_id_| is "".
   capability_->UpdateStorageIdentifier();
@@ -1249,8 +1302,8 @@
 
 TEST_F(CellularCapabilityUniversalTest, CreateFriendlyServiceName) {
   CellularCapabilityUniversal::friendly_service_name_id_ = 0;
-  EXPECT_EQ("GSMNetwork0", capability_->CreateFriendlyServiceName());
-  EXPECT_EQ("GSMNetwork1", capability_->CreateFriendlyServiceName());
+  EXPECT_EQ("Mobile Network 0", capability_->CreateFriendlyServiceName());
+  EXPECT_EQ("Mobile Network 1", capability_->CreateFriendlyServiceName());
 
   capability_->operator_id_ = "0123";
   EXPECT_EQ("cellular_0123", capability_->CreateFriendlyServiceName());
diff --git a/cellular_service.cc b/cellular_service.cc
index c916b9e..e3c2aa5 100644
--- a/cellular_service.cc
+++ b/cellular_service.cc
@@ -339,7 +339,7 @@
                                   olp.ToDict());
 }
 
-void CellularService::SetUsageURL(const std::string &url) {
+void CellularService::SetUsageURL(const string &url) {
   if (url == usage_url_) {
     return;
   }
diff --git a/cellular_service.h b/cellular_service.h
index e665e56..6aeb751 100644
--- a/cellular_service.h
+++ b/cellular_service.h
@@ -119,6 +119,7 @@
   friend class CellularServiceTest;
   FRIEND_TEST(CellularCapabilityGSMTest, SetupApnTryList);
   FRIEND_TEST(CellularCapabilityTest, TryApns);
+  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateServiceName);
   FRIEND_TEST(CellularCapabilityUniversalTest, UpdateStorageIdentifier);
   FRIEND_TEST(CellularTest, Connect);
   FRIEND_TEST(CellularServiceTest, SetApn);
diff --git a/service.cc b/service.cc
index 0863c07..5389838 100644
--- a/service.cc
+++ b/service.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2013 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.
 
@@ -1367,6 +1367,13 @@
   }
 }
 
+void Service::SetFriendlyName(const string &friendly_name) {
+  if (friendly_name == friendly_name_)
+    return;
+  friendly_name_ = friendly_name;
+  adaptor()->EmitStringChanged(flimflam::kNameProperty, friendly_name_);
+}
+
 void Service::SetStrength(uint8 strength) {
   if (strength == strength_) {
     return;
diff --git a/service.h b/service.h
index eb72a29..e63a013 100644
--- a/service.h
+++ b/service.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2013 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.
 
@@ -347,6 +347,8 @@
   bool favorite() const { return favorite_; }
   // Setter is deliberately omitted; use MakeFavorite.
 
+  // Sets the flimflam::kNameProperty
+  void SetFriendlyName(const std::string &friendly_name);
   void set_friendly_name(const std::string &n) { friendly_name_ = n; }
 
   const std::string &guid() const { return guid_; }
@@ -558,9 +560,10 @@
   FRIEND_TEST(ServiceTest, SaveStringCrypted);
   FRIEND_TEST(ServiceTest, SaveStringDontSave);
   FRIEND_TEST(ServiceTest, SaveStringEmpty);
-  FRIEND_TEST(ServiceTest, SetProperty);
   FRIEND_TEST(ServiceTest, SetCheckPortal);
   FRIEND_TEST(ServiceTest, SetConnectable);
+  FRIEND_TEST(ServiceTest, SetFriendlyName);
+  FRIEND_TEST(ServiceTest, SetProperty);
   FRIEND_TEST(ServiceTest, State);
   FRIEND_TEST(ServiceTest, Unload);
   FRIEND_TEST(WiFiMainTest, NoScansWhileConnecting);
diff --git a/service_unittest.cc b/service_unittest.cc
index 6bbc033..b43e5c4 100644
--- a/service_unittest.cc
+++ b/service_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2013 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.
 
@@ -917,6 +917,30 @@
   }
 }
 
+TEST_F(ServiceTest, SetFriendlyName) {
+  EXPECT_EQ(service_->unique_name_, service_->friendly_name_);
+  ServiceMockAdaptor *adaptor =
+      dynamic_cast<ServiceMockAdaptor *>(service_->adaptor());
+
+  EXPECT_CALL(*adaptor, EmitStringChanged(_, _)).Times(0);
+  service_->SetFriendlyName(service_->unique_name_);
+  EXPECT_EQ(service_->unique_name_, service_->friendly_name_);
+
+  EXPECT_CALL(*adaptor, EmitStringChanged(flimflam::kNameProperty,
+                                          "Test Name 1"));
+  service_->SetFriendlyName("Test Name 1");
+  EXPECT_EQ("Test Name 1", service_->friendly_name_);
+
+  EXPECT_CALL(*adaptor, EmitStringChanged(_, _)).Times(0);
+  service_->SetFriendlyName("Test Name 1");
+  EXPECT_EQ("Test Name 1", service_->friendly_name_);
+
+  EXPECT_CALL(*adaptor, EmitStringChanged(flimflam::kNameProperty,
+                                          "Test Name 2"));
+  service_->SetFriendlyName("Test Name 2");
+  EXPECT_EQ("Test Name 2", service_->friendly_name_);
+}
+
 TEST_F(ServiceTest, SetConnectable) {
   EXPECT_FALSE(service_->connectable());