shill: make access to Service.AutoConnect consistent with flimflam

Service.AutoConnect is writable only if the Favorite property is true.

BUG=chromium-os:23342
TEST=Unit tests, network_WiFiManager (7/9)

Change-Id: Ia76e1bfb39e51b62352b97131d14a672fdc45f6d
Reviewed-on: https://gerrit.chromium.org/gerrit/15156
Commit-Ready: Thieu Le <thieule@chromium.org>
Reviewed-by: Thieu Le <thieule@chromium.org>
Tested-by: Thieu Le <thieule@chromium.org>
diff --git a/service.cc b/service.cc
index f98cb41..4ac4685 100644
--- a/service.cc
+++ b/service.cc
@@ -95,7 +95,9 @@
       metrics_(metrics),
       manager_(manager) {
 
-  store_.RegisterBool(flimflam::kAutoConnectProperty, &auto_connect_);
+  HelpRegisterDerivedBool(flimflam::kAutoConnectProperty,
+                          &Service::GetAutoConnect,
+                          &Service::SetAutoConnect);
 
   // flimflam::kActivationStateProperty: Registered in CellularService
   // flimflam::kCellularApnProperty: Registered in CellularService
@@ -695,6 +697,18 @@
   eap_.key_management = key_management;
 }
 
+bool Service::GetAutoConnect(Error */*error*/) {
+  return auto_connect();
+}
+
+void Service::SetAutoConnect(const bool &connect, Error *error) {
+  if (favorite_) {
+    set_auto_connect(connect);
+  } else {
+    error->Populate(Error::kInvalidArguments, "Property is read-only");
+  }
+}
+
 string Service::GetProfileRpcId(Error *error) {
   if (!profile_) {
     // This happens in some unit tests where profile_ is not set.
diff --git a/service.h b/service.h
index aaf8608..44efa5d 100644
--- a/service.h
+++ b/service.h
@@ -292,6 +292,8 @@
   FRIEND_TEST(DeviceTest, SelectedService);
   FRIEND_TEST(ManagerTest, SortServicesWithConnection);
   FRIEND_TEST(ServiceTest, Constructor);
+  FRIEND_TEST(ServiceTest, Dispatch);
+  FRIEND_TEST(ServiceTest, GetProperties);
   FRIEND_TEST(ServiceTest, IsAutoConnectable);
   FRIEND_TEST(ServiceTest, Save);
   FRIEND_TEST(ServiceTest, SaveString);
@@ -325,6 +327,9 @@
   static const char kStorageType[];
   static const char kStorageUIData[];
 
+  bool GetAutoConnect(Error *error);
+  void SetAutoConnect(const bool &connect, Error *error);
+
   virtual std::string GetDeviceRpcId(Error *error) = 0;
 
   std::string GetProfileRpcId(Error *error);
@@ -337,6 +342,9 @@
   // are, "decision" is populated with the boolean value of "a > b".
   static bool DecideBetween(int a, int b, bool *decision);
 
+  // For unit testing.
+  void set_favorite(bool favorite) { favorite_ = favorite; }
+
   ConnectState state_;
   ConnectFailure failure_;
   bool auto_connect_;
diff --git a/service_unittest.cc b/service_unittest.cc
index be325c4..8f2daab 100644
--- a/service_unittest.cc
+++ b/service_unittest.cc
@@ -79,6 +79,7 @@
   {
     ::DBus::Error dbus_error;
     bool expected = true;
+    service_->set_favorite(true);
     service_->mutable_store()->SetBoolProperty(flimflam::kAutoConnectProperty,
                                                expected,
                                                &error);
@@ -144,6 +145,23 @@
                                              &error));
     EXPECT_EQ(invalid_args(), error.name());
   }
+  {
+    ::DBus::Error error;
+    service_->set_favorite(true);
+    EXPECT_TRUE(DBusAdaptor::DispatchOnType(service_->mutable_store(),
+                                            flimflam::kAutoConnectProperty,
+                                            PropertyStoreTest::kBoolV,
+                                            &error));
+  }
+  {
+    ::DBus::Error error;
+    service_->set_favorite(false);
+    EXPECT_FALSE(DBusAdaptor::DispatchOnType(service_->mutable_store(),
+                                             flimflam::kAutoConnectProperty,
+                                             PropertyStoreTest::kBoolV,
+                                             &error));
+    EXPECT_EQ(invalid_args(), error.name());
+  }
 }
 
 TEST_F(ServiceTest, Load) {