shill: Set Device.Scanning property to |false| after timeout.

In the presence of low (no) network signal, modems sometimes remain in
the SEARCHING state indefinitely, which prevents the UI from getting
updated properly. Shill now sets the Device.Scanning property to |false|
after a 60 second timeout, if the modem hasn't registered with a
cellular network.

BUG=chromium-os:38807
TEST=1. Build and run unittests.
     2. Go to a low (zero) coverage area and enable cellular connectivity
        (either disable/enable through the UI or shut down and start the
        device).
     3. The UI should show the "Initializing..." message.
     4. After 60 seconds, the UI should update to a "No network..."
        message.
     5. Disable/enable device, but this time move to an area with good
        coverage.
     6. If everything else works correctly, the UI should no longer show
        the "Initializing..." message and display the correct cellular
        network.

Change-Id: I8f0f896a92187fc1ba515c47abbd68d7d65c01e6
Reviewed-on: https://gerrit.chromium.org/gerrit/43079
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 7cee6c4..f15f2ef 100644
--- a/cellular.h
+++ b/cellular.h
@@ -234,17 +234,18 @@
   FRIEND_TEST(CellularCapabilityTest, FinishEnable);
   FRIEND_TEST(CellularCapabilityTest, GetModemInfo);
   FRIEND_TEST(CellularCapabilityTest, GetModemStatus);
-  FRIEND_TEST(CellularCapabilityUniversalTest, AllowRoaming);
-  FRIEND_TEST(CellularCapabilityUniversalTest, CreateFriendlyServiceName);
-  FRIEND_TEST(CellularCapabilityUniversalTest, Connect);
-  FRIEND_TEST(CellularCapabilityUniversalTest, IsServiceActivationRequired);
-  FRIEND_TEST(CellularCapabilityUniversalTest, SetHomeProvider);
-  FRIEND_TEST(CellularCapabilityUniversalTest, StopModemConnected);
-  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateOLP);
-  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateOperatorInfoViaOperatorId);
-  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateScanningProperty);
-  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateServiceName);
-  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateStorageIdentifier);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, AllowRoaming);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, CreateFriendlyServiceName);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, Connect);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, IsServiceActivationRequired);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, SetHomeProvider);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, StopModemConnected);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateOLP);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest,
+              UpdateOperatorInfoViaOperatorId);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateScanningProperty);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateServiceName);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateStorageIdentifier);
   FRIEND_TEST(CellularServiceTest, FriendlyName);
   FRIEND_TEST(CellularTest, CreateService);
   FRIEND_TEST(CellularTest, Connect);
diff --git a/cellular_capability_universal.cc b/cellular_capability_universal.cc
index 9c44323..445606a 100644
--- a/cellular_capability_universal.cc
+++ b/cellular_capability_universal.cc
@@ -51,6 +51,9 @@
 const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
     "allow-roaming";
 const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
+const unsigned int
+CellularCapabilityUniversal::kDefaultScanningOrSearchingTimeoutMilliseconds =
+    60000;
 const char CellularCapabilityUniversal::kGenericServiceNamePrefix[] =
     "Mobile Network";
 const char CellularCapabilityUniversal::kStatusProperty[] = "status";
@@ -136,7 +139,9 @@
       scanning_(false),
       scanning_or_searching_(false),
       scan_interval_(0),
-      sim_present_(false) {
+      sim_present_(false),
+      scanning_or_searching_timeout_milliseconds_(
+          kDefaultScanningOrSearchingTimeoutMilliseconds) {
   SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
   PropertyStore *store = cellular->mutable_store();
 
@@ -645,9 +650,29 @@
     scanning_or_searching_ = new_scanning_or_searching;
     cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
                                            new_scanning_or_searching);
+
+    if (!scanning_or_searching_) {
+      SLOG(Cellular, 2) << "Initial network scan ended. Canceling timeout.";
+      scanning_or_searching_timeout_callback_.Cancel();
+    } else if (scanning_or_searching_timeout_callback_.IsCancelled()) {
+      SLOG(Cellular, 2) << "Initial network scan started. Starting timeout.";
+      scanning_or_searching_timeout_callback_.Reset(
+          Bind(&CellularCapabilityUniversal::OnScanningOrSearchingTimeout,
+               weak_ptr_factory_.GetWeakPtr()));
+      cellular()->dispatcher()->PostDelayedTask(
+          scanning_or_searching_timeout_callback_.callback(),
+          scanning_or_searching_timeout_milliseconds_);
+    }
   }
 }
 
+void CellularCapabilityUniversal::OnScanningOrSearchingTimeout() {
+  SLOG(Cellular, 2) << "Initial network scan timed out. Changing "
+                    << "flimflam::kScanningProperty to |false|.";
+  scanning_or_searching_ = false;
+  cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty, false);
+}
+
 void CellularCapabilityUniversal::UpdateOLP() {
   if (!cellular()->cellular_operator_info())
     return;
diff --git a/cellular_capability_universal.h b/cellular_capability_universal.h
index 6799dcd..b11c4f7 100644
--- a/cellular_capability_universal.h
+++ b/cellular_capability_universal.h
@@ -130,36 +130,41 @@
   // unknown.
   static const char kGenericServiceNamePrefix[];
 
+  static const unsigned int kDefaultScanningOrSearchingTimeoutMilliseconds;
+
   friend class CellularTest;
   friend class CellularCapabilityTest;
   friend class CellularCapabilityUniversalTest;
-  FRIEND_TEST(CellularCapabilityUniversalTest, AllowRoaming);
-  FRIEND_TEST(CellularCapabilityUniversalTest, Connect);
-  FRIEND_TEST(CellularCapabilityUniversalTest, ConnectApns);
-  FRIEND_TEST(CellularCapabilityUniversalTest, CreateFriendlyServiceName);
-  FRIEND_TEST(CellularCapabilityUniversalTest, DisconnectNoProxy);
-  FRIEND_TEST(CellularCapabilityUniversalTest, GetTypeString);
-  FRIEND_TEST(CellularCapabilityUniversalTest, IsServiceActivationRequired);
-  FRIEND_TEST(CellularCapabilityUniversalTest, OnListBearersReply);
-  FRIEND_TEST(CellularCapabilityUniversalTest,
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, AllowRoaming);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, Connect);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, ConnectApns);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, CreateFriendlyServiceName);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, DisconnectNoProxy);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, GetTypeString);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, IsServiceActivationRequired);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, OnListBearersReply);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest,
               OnModemCurrentCapabilitiesChanged);
-  FRIEND_TEST(CellularCapabilityUniversalTest, PropertiesChanged);
-  FRIEND_TEST(CellularCapabilityUniversalTest, Reset);
-  FRIEND_TEST(CellularCapabilityUniversalTest, Scan);
-  FRIEND_TEST(CellularCapabilityUniversalTest, ScanFailure);
-  FRIEND_TEST(CellularCapabilityUniversalTest, SetHomeProvider);
-  FRIEND_TEST(CellularCapabilityUniversalTest, SimLockStatusChanged);
-  FRIEND_TEST(CellularCapabilityUniversalTest, SimPathChanged);
-  FRIEND_TEST(CellularCapabilityUniversalTest, SimPropertiesChanged);
-  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);
-  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateOperatorInfoViaOperatorId);
-  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateScanningProperty);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, PropertiesChanged);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, Reset);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, Scan);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, ScanFailure);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, SetHomeProvider);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, SimLockStatusChanged);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, SimPathChanged);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, SimPropertiesChanged);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, StartModem);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, StopModem);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, StopModemConnected);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateServiceName);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateStorageIdentifier);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateOLP);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateOperatorInfo);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest,
+              UpdateOperatorInfoViaOperatorId);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateScanningProperty);
+  FRIEND_TEST(CellularCapabilityUniversalTimerTest,
+              UpdateScanningPropertyTimeout);
   FRIEND_TEST(CellularTest,
               HandleNewRegistrationStateForServiceRequiringActivation);
   FRIEND_TEST(CellularTest, ModemStateChangeLostRegistration);
@@ -290,6 +295,10 @@
   void OnListBearersReply(const std::vector<DBus::Path> &paths,
                           const Error &error);
 
+  // Timeout callback for the network scan initiated when Cellular connectivity
+  // gets enabled.
+  void OnScanningOrSearchingTimeout();
+
   static std::string GenerateNewGenericServiceName();
 
   scoped_ptr<mm1::ModemModem3gppProxyInterface> modem_3gpp_proxy_;
@@ -349,6 +358,13 @@
   // enabling is deferred using this callback.
   base::Closure deferred_enable_modem_callback_;
 
+  // Sometimes modems may be stuck in the SEARCHING state during the lack of
+  // presence of a network. During this indefinite duration of time, keeping
+  // the Device.Scanning property as |true| causes a bad user experience.
+  // This callback sets it to |false| after a timeout period has passed.
+  base::CancelableClosure scanning_or_searching_timeout_callback_;
+  unsigned int scanning_or_searching_timeout_milliseconds_;
+
   static unsigned int friendly_service_name_id_;
 
   DISALLOW_COPY_AND_ASSIGN(CellularCapabilityUniversal);
diff --git a/cellular_capability_universal_unittest.cc b/cellular_capability_universal_unittest.cc
index 8d095e4..e68666f 100644
--- a/cellular_capability_universal_unittest.cc
+++ b/cellular_capability_universal_unittest.cc
@@ -11,6 +11,7 @@
 #include <base/stringprintf.h>
 #include <base/string_util.h>
 #include <chromeos/dbus/service_constants.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <mobile_provider.h>
 #include <ModemManager/ModemManager.h>
@@ -24,6 +25,7 @@
 #include "shill/mock_cellular_operator_info.h"
 #include "shill/mock_cellular_service.h"
 #include "shill/mock_dbus_properties_proxy.h"
+#include "shill/mock_event_dispatcher.h"
 #include "shill/mock_glib.h"
 #include "shill/mock_manager.h"
 #include "shill/mock_metrics.h"
@@ -45,6 +47,7 @@
 using std::vector;
 using testing::InSequence;
 using testing::Invoke;
+using testing::InvokeWithoutArgs;
 using testing::Mock;
 using testing::NiceMock;
 using testing::Return;
@@ -67,11 +70,12 @@
           apn == expected_apn);
 }
 
-class CellularCapabilityUniversalTest : public testing::Test {
+class CellularCapabilityUniversalTest : public testing::TestWithParam<string> {
  public:
-  CellularCapabilityUniversalTest()
-      : metrics_(&dispatcher_),
-        manager_(&control_, &dispatcher_, &metrics_, &glib_),
+  CellularCapabilityUniversalTest(EventDispatcher *dispatcher)
+      : event_dispatcher_(dispatcher),
+        metrics_(dispatcher),
+        manager_(&control_, dispatcher, &metrics_, &glib_),
         bearer_proxy_(new mm1::MockBearerProxy()),
         modem_3gpp_proxy_(new mm1::MockModemModem3gppProxy()),
         modem_cdma_proxy_(new mm1::MockModemModemCdmaProxy()),
@@ -84,7 +88,7 @@
         device_adaptor_(NULL),
         provider_db_(NULL),
         cellular_(new Cellular(&control_,
-                               &dispatcher_,
+                               dispatcher,
                                &metrics_,
                                &manager_,
                                "",
@@ -98,7 +102,7 @@
                                NULL,
                                &proxy_factory_)),
         service_(new MockCellularService(&control_,
-                                         &dispatcher_,
+                                         dispatcher,
                                          &metrics_,
                                          &manager_,
                                          cellular_)) {
@@ -130,7 +134,7 @@
 
   void SetService() {
     cellular_->service_ = new CellularService(
-        &control_, &dispatcher_, &metrics_, NULL, cellular_);
+        &control_, event_dispatcher_, &metrics_, NULL, cellular_);
   }
 
   void InitProviderDB() {
@@ -163,6 +167,11 @@
     error->Populate(Error::kOperationFailed);
   }
 
+  bool InvokeScanningOrSearchingTimeout() {
+    capability_->OnScanningOrSearchingTimeout();
+    return true;
+  }
+
   void Set3gppProxy() {
     capability_->modem_3gpp_proxy_.reset(modem_3gpp_proxy_.release());
   }
@@ -242,7 +251,7 @@
   };
 
   NiceMockControl control_;
-  EventDispatcher dispatcher_;
+  EventDispatcher *event_dispatcher_;
   MockMetrics metrics_;
   MockGLib glib_;
   MockManager manager_;
@@ -264,6 +273,29 @@
   DBusPathCallback connect_callback_;  // saved for testing connect operations
 };
 
+// Most of our tests involve using a real EventDispatcher object.
+class CellularCapabilityUniversalMainTest
+    : public CellularCapabilityUniversalTest {
+ public:
+  CellularCapabilityUniversalMainTest() :
+      CellularCapabilityUniversalTest(&dispatcher_) {}
+
+ protected:
+  EventDispatcher dispatcher_;
+};
+
+// Tests that involve timers will (or may) use a mock of the event dispatcher
+// instead of a real one.
+class CellularCapabilityUniversalTimerTest
+    : public CellularCapabilityUniversalTest {
+ public:
+  CellularCapabilityUniversalTimerTest()
+      : CellularCapabilityUniversalTest(&mock_dispatcher_) {}
+
+ protected:
+  ::testing::StrictMock<MockEventDispatcher> mock_dispatcher_;
+};
+
 const char CellularCapabilityUniversalTest::kActiveBearerPathPrefix[] =
     "/bearer/active";
 const char CellularCapabilityUniversalTest::kImei[] = "999911110000";
@@ -276,7 +308,7 @@
     MM_MODEM_ACCESS_TECHNOLOGY_LTE |
     MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS;
 
-TEST_F(CellularCapabilityUniversalTest, StartModem) {
+TEST_F(CellularCapabilityUniversalMainTest, StartModem) {
   // Set up mock modem properties
   DBusPropertiesMap modem_properties;
   string operator_name = "TestOperator";
@@ -348,7 +380,7 @@
   EXPECT_EQ(kAccessTechnologies, capability_->access_technologies_);
 }
 
-TEST_F(CellularCapabilityUniversalTest, StartModemFail) {
+TEST_F(CellularCapabilityUniversalMainTest, StartModemFail) {
   EXPECT_CALL(*modem_proxy_, State())
           .WillOnce(Return(Cellular::kModemStateDisabled));
   EXPECT_CALL(*modem_proxy_,
@@ -365,7 +397,7 @@
   EXPECT_TRUE(error.IsOngoing());
 }
 
-TEST_F(CellularCapabilityUniversalTest, StopModem) {
+TEST_F(CellularCapabilityUniversalMainTest, StopModem) {
   // Save pointers to proxies before they are lost by the call to InitProxies
   mm1::MockModemProxy *modem_proxy = modem_proxy_.get();
   SetUp();
@@ -388,7 +420,7 @@
   disable_callback.Run(Error(Error::kSuccess));
 }
 
-TEST_F(CellularCapabilityUniversalTest, StopModemConnected) {
+TEST_F(CellularCapabilityUniversalMainTest, StopModemConnected) {
   // Save pointers to proxies before they are lost by the call to InitProxies
   mm1::MockModemProxy *modem_proxy = modem_proxy_.get();
   mm1::MockModemSimpleProxy *modem_simple_proxy = modem_simple_proxy_.get();
@@ -418,7 +450,7 @@
   disable_callback.Run(Error(Error::kSuccess));
 }
 
-TEST_F(CellularCapabilityUniversalTest, DisconnectModemNoBearer) {
+TEST_F(CellularCapabilityUniversalMainTest, DisconnectModemNoBearer) {
   Error error;
   ResultCallback disconnect_callback;
   EXPECT_CALL(*modem_simple_proxy_,
@@ -427,7 +459,7 @@
   capability_->Disconnect(&error, disconnect_callback);
 }
 
-TEST_F(CellularCapabilityUniversalTest, DisconnectNoProxy) {
+TEST_F(CellularCapabilityUniversalMainTest, DisconnectNoProxy) {
   Error error;
   ResultCallback disconnect_callback;
   capability_->bearer_path_ = "/foo";
@@ -438,7 +470,7 @@
   capability_->Disconnect(&error, disconnect_callback);
 }
 
-TEST_F(CellularCapabilityUniversalTest, SimLockStatusChanged) {
+TEST_F(CellularCapabilityUniversalMainTest, SimLockStatusChanged) {
   // Set up mock SIM properties
   const char kImsi[] = "310100000001";
   const char kSimIdentifier[] = "9999888";
@@ -495,7 +527,7 @@
   EXPECT_EQ(kOperatorName, capability_->spn_);
 }
 
-TEST_F(CellularCapabilityUniversalTest, PropertiesChanged) {
+TEST_F(CellularCapabilityUniversalMainTest, PropertiesChanged) {
   // Set up mock modem properties
   DBusPropertiesMap modem_properties;
   modem_properties[MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES].
@@ -578,7 +610,7 @@
                                        vector<string>());
 }
 
-TEST_F(CellularCapabilityUniversalTest, UpdateServiceName) {
+TEST_F(CellularCapabilityUniversalMainTest, UpdateServiceName) {
   ::DBus::Struct<uint32_t, bool> data;
   data._1 = 100;
   data._2 = true;
@@ -626,7 +658,7 @@
   EXPECT_EQ("Test Home Provider", cellular_->service_->friendly_name());
 }
 
-TEST_F(CellularCapabilityUniversalTest, SimPathChanged) {
+TEST_F(CellularCapabilityUniversalMainTest, SimPathChanged) {
   // Set up mock modem SIM properties
   const char kImsi[] = "310100000001";
   const char kSimIdentifier[] = "9999888";
@@ -681,7 +713,7 @@
   EXPECT_EQ("", capability_->spn_);
 }
 
-TEST_F(CellularCapabilityUniversalTest, SimPropertiesChanged) {
+TEST_F(CellularCapabilityUniversalMainTest, SimPropertiesChanged) {
   // Set up mock modem properties
   DBusPropertiesMap modem_properties;
   modem_properties[MM_MODEM_PROPERTY_SIM].writer().append_path(kSimPath);
@@ -746,7 +778,7 @@
   return static_cast<size_t>(value) == arg.size();
 }
 
-TEST_F(CellularCapabilityUniversalTest, Reset) {
+TEST_F(CellularCapabilityUniversalMainTest, Reset) {
   // Save pointers to proxies before they are lost by the call to InitProxies
   mm1::MockModemProxy *modem_proxy = modem_proxy_.get();
   SetUp();
@@ -766,7 +798,7 @@
 }
 
 // Validates that OnScanReply does not crash with a null callback.
-TEST_F(CellularCapabilityUniversalTest, ScanWithNullCallback) {
+TEST_F(CellularCapabilityUniversalMainTest, ScanWithNullCallback) {
   Error error;
   EXPECT_CALL(*modem_3gpp_proxy_, Scan(_, _, CellularCapability::kTimeoutScan))
       .WillOnce(Invoke(this, &CellularCapabilityUniversalTest::InvokeScan));
@@ -779,7 +811,7 @@
 }
 
 // Validates that the scanning property is updated
-TEST_F(CellularCapabilityUniversalTest, Scan) {
+TEST_F(CellularCapabilityUniversalMainTest, Scan) {
   Error error;
 
   EXPECT_CALL(*modem_3gpp_proxy_, Scan(_, _, CellularCapability::kTimeoutScan))
@@ -823,7 +855,7 @@
 }
 
 // Validates expected property updates when scan fails
-TEST_F(CellularCapabilityUniversalTest, ScanFailure) {
+TEST_F(CellularCapabilityUniversalMainTest, ScanFailure) {
   Error error;
 
   // Test immediate error
@@ -868,7 +900,7 @@
 }
 
 // Validates expected behavior of OnListBearersReply function
-TEST_F(CellularCapabilityUniversalTest, OnListBearersReply) {
+TEST_F(CellularCapabilityUniversalMainTest, OnListBearersReply) {
   // Check that bearer_path_ is set correctly when an active bearer
   // is returned.
   const size_t kPathCount = 3;
@@ -914,7 +946,7 @@
 }
 
 // Validates expected behavior of Connect function
-TEST_F(CellularCapabilityUniversalTest, Connect) {
+TEST_F(CellularCapabilityUniversalMainTest, Connect) {
   mm1::MockModemSimpleProxy *modem_simple_proxy = modem_simple_proxy_.get();
   SetSimpleProxy();
   Error error;
@@ -956,7 +988,7 @@
 }
 
 // Validates Connect iterates over APNs
-TEST_F(CellularCapabilityUniversalTest, ConnectApns) {
+TEST_F(CellularCapabilityUniversalMainTest, ConnectApns) {
   mm1::MockModemSimpleProxy *modem_simple_proxy = modem_simple_proxy_.get();
   SetSimpleProxy();
   Error error;
@@ -991,7 +1023,7 @@
 }
 
 // Validates GetTypeString and AccessTechnologyToTechnologyFamily
-TEST_F(CellularCapabilityUniversalTest, GetTypeString) {
+TEST_F(CellularCapabilityUniversalMainTest, GetTypeString) {
   const int gsm_technologies[] = {
     MM_MODEM_ACCESS_TECHNOLOGY_LTE,
     MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS,
@@ -1031,7 +1063,7 @@
   ASSERT_EQ(capability_->GetTypeString(), "");
 }
 
-TEST_F(CellularCapabilityUniversalTest, AllowRoaming) {
+TEST_F(CellularCapabilityUniversalMainTest, AllowRoaming) {
   EXPECT_FALSE(cellular_->allow_roaming_);
   EXPECT_FALSE(capability_->provider_requires_roaming_);
   EXPECT_FALSE(capability_->AllowRoaming());
@@ -1042,7 +1074,7 @@
   EXPECT_TRUE(capability_->AllowRoaming());
 }
 
-TEST_F(CellularCapabilityUniversalTest, SetHomeProvider) {
+TEST_F(CellularCapabilityUniversalMainTest, SetHomeProvider) {
   static const char kTestCarrier[] = "The Cellular Carrier";
   static const char kCountry[] = "us";
   static const char kCode[] = "310160";
@@ -1118,7 +1150,7 @@
   EXPECT_TRUE(capability_->provider_requires_roaming_);
 }
 
-TEST_F(CellularCapabilityUniversalTest, UpdateScanningProperty) {
+TEST_F(CellularCapabilityUniversalMainTest, UpdateScanningProperty) {
   // Save pointers to proxies before they are lost by the call to InitProxies
   // mm1::MockModemProxy *modem_proxy = modem_proxy_.get();
   SetUp();
@@ -1176,7 +1208,62 @@
   EXPECT_FALSE(capability_->scanning_or_searching_);
 }
 
-TEST_F(CellularCapabilityUniversalTest, UpdateStorageIdentifier) {
+TEST_F(CellularCapabilityUniversalTimerTest, UpdateScanningPropertyTimeout) {
+  SetUp();
+  capability_->InitProxies();
+
+  EXPECT_FALSE(capability_->scanning_or_searching_);
+  EXPECT_TRUE(
+      capability_->scanning_or_searching_timeout_callback_.IsCancelled());
+  capability_->UpdateScanningProperty();
+  EXPECT_FALSE(capability_->scanning_or_searching_);
+  EXPECT_TRUE(
+      capability_->scanning_or_searching_timeout_callback_.IsCancelled());
+
+  EXPECT_CALL(mock_dispatcher_,
+              PostDelayedTask(
+                  _,
+                  CellularCapabilityUniversal::
+                      kDefaultScanningOrSearchingTimeoutMilliseconds));
+
+  capability_->scanning_ = true;
+  capability_->UpdateScanningProperty();
+  EXPECT_FALSE(
+      capability_->scanning_or_searching_timeout_callback_.IsCancelled());
+  EXPECT_TRUE(capability_->scanning_or_searching_);
+
+  EXPECT_CALL(mock_dispatcher_,
+              PostDelayedTask(
+                  _,
+                  CellularCapabilityUniversal::
+                      kDefaultScanningOrSearchingTimeoutMilliseconds))
+      .Times(0);
+
+  capability_->scanning_ = false;
+  capability_->UpdateScanningProperty();
+  EXPECT_TRUE(
+      capability_->scanning_or_searching_timeout_callback_.IsCancelled());
+  EXPECT_FALSE(capability_->scanning_or_searching_);
+
+  EXPECT_CALL(mock_dispatcher_,
+              PostDelayedTask(
+                  _,
+                  CellularCapabilityUniversal::
+                      kDefaultScanningOrSearchingTimeoutMilliseconds))
+      .WillOnce(InvokeWithoutArgs(
+          this,
+          &CellularCapabilityUniversalTest::InvokeScanningOrSearchingTimeout));
+
+  capability_->scanning_ = true;
+  capability_->UpdateScanningProperty();
+  // The callback has been scheduled
+  EXPECT_FALSE(
+      capability_->scanning_or_searching_timeout_callback_.IsCancelled());
+  // Our mock invocation worked
+  EXPECT_FALSE(capability_->scanning_or_searching_);
+}
+
+TEST_F(CellularCapabilityUniversalMainTest, UpdateStorageIdentifier) {
   CellularOperatorInfo::CellularOperator provider;
   cellular_->cellular_operator_info_ = &cellular_operator_info_;
 
@@ -1232,7 +1319,7 @@
             cellular_->service()->storage_identifier_);
 }
 
-TEST_F(CellularCapabilityUniversalTest, UpdateOLP) {
+TEST_F(CellularCapabilityUniversalMainTest, UpdateOLP) {
   CellularService::OLP test_olp;
   test_olp.SetURL("http://testurl");
   test_olp.SetMethod("POST");
@@ -1262,7 +1349,7 @@
             olp.GetPostData());
 }
 
-TEST_F(CellularCapabilityUniversalTest, UpdateOperatorInfo) {
+TEST_F(CellularCapabilityUniversalMainTest, UpdateOperatorInfo) {
   static const char kOperatorName[] = "Swisscom";
   InitProviderDB();
   capability_->serving_operator_.SetCode("22801");
@@ -1281,7 +1368,7 @@
   EXPECT_EQ(kTestOperator, cellular_->service()->serving_operator().GetName());
 }
 
-TEST_F(CellularCapabilityUniversalTest, UpdateOperatorInfoViaOperatorId) {
+TEST_F(CellularCapabilityUniversalMainTest, UpdateOperatorInfoViaOperatorId) {
   static const char kOperatorName[] = "Swisscom";
   static const char kOperatorId[] = "22801";
   InitProviderDB();
@@ -1301,7 +1388,7 @@
   EXPECT_EQ(kOperatorName, cellular_->service()->serving_operator().GetName());
 }
 
-TEST_F(CellularCapabilityUniversalTest, CreateFriendlyServiceName) {
+TEST_F(CellularCapabilityUniversalMainTest, CreateFriendlyServiceName) {
   CellularCapabilityUniversal::friendly_service_name_id_ = 0;
   EXPECT_EQ("Mobile Network 0", capability_->CreateFriendlyServiceName());
   EXPECT_EQ("Mobile Network 1", capability_->CreateFriendlyServiceName());
@@ -1328,7 +1415,7 @@
             capability_->CreateFriendlyServiceName());
 }
 
-TEST_F(CellularCapabilityUniversalTest, IsServiceActivationRequired) {
+TEST_F(CellularCapabilityUniversalMainTest, IsServiceActivationRequired) {
   capability_->mdn_ = "0000000000";
   cellular_->cellular_operator_info_ = NULL;
   EXPECT_FALSE(capability_->IsServiceActivationRequired());
@@ -1354,7 +1441,7 @@
   EXPECT_TRUE(capability_->IsServiceActivationRequired());
 }
 
-TEST_F(CellularCapabilityUniversalTest, OnModemCurrentCapabilitiesChanged) {
+TEST_F(CellularCapabilityUniversalMainTest, OnModemCurrentCapabilitiesChanged) {
   EXPECT_FALSE(capability_->scanning_supported_);
   capability_->OnModemCurrentCapabilitiesChanged(MM_MODEM_CAPABILITY_LTE);
   EXPECT_FALSE(capability_->scanning_supported_);
diff --git a/cellular_operator_info.h b/cellular_operator_info.h
index 85acd73..21bd6cf 100644
--- a/cellular_operator_info.h
+++ b/cellular_operator_info.h
@@ -74,7 +74,7 @@
     friend class CellularCapabilityUniversalTest;
     friend class CellularOperatorInfo;
     friend class CellularOperatorInfoTest;
-    FRIEND_TEST(CellularCapabilityUniversalTest, UpdateStorageIdentifier);
+    FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateStorageIdentifier);
     FRIEND_TEST(CellularOperatorInfoTest, HandleMCCMNC);
     FRIEND_TEST(CellularOperatorInfoTest, HandleSID);
 
diff --git a/cellular_service.h b/cellular_service.h
index 6aeb751..4c1a8c1 100644
--- a/cellular_service.h
+++ b/cellular_service.h
@@ -119,8 +119,8 @@
   friend class CellularServiceTest;
   FRIEND_TEST(CellularCapabilityGSMTest, SetupApnTryList);
   FRIEND_TEST(CellularCapabilityTest, TryApns);
-  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateServiceName);
-  FRIEND_TEST(CellularCapabilityUniversalTest, UpdateStorageIdentifier);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateServiceName);
+  FRIEND_TEST(CellularCapabilityUniversalMainTest, UpdateStorageIdentifier);
   FRIEND_TEST(CellularTest, Connect);
   FRIEND_TEST(CellularServiceTest, SetApn);
   FRIEND_TEST(CellularServiceTest, ClearApn);