Bug 1018320 - RequestSync API - Patch 2 - Wifi Only. r=ehsan, a=bajaj
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 13 Jan 2015 09:53:16 +0000
changeset 237136 32d904a7d04c836568a1e915198f449ae1ea5306
parent 237135 7ea79cc34e617b0ad23d7a2de5b45041d5946389
child 237137 0fd5710ce15e3c46b228a6e4c47dc3277923508a
push id213
push userryanvm@gmail.com
push dateTue, 24 Feb 2015 00:59:48 +0000
treeherdermozilla-b2g37_v2_2@b5a532c7f606 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan, bajaj
bugs1018320
milestone37.0
Bug 1018320 - RequestSync API - Patch 2 - Wifi Only. r=ehsan, a=bajaj
dom/requestsync/RequestSyncService.jsm
dom/requestsync/RequestSyncWifiService.cpp
dom/requestsync/RequestSyncWifiService.h
dom/requestsync/moz.build
layout/build/nsLayoutStatics.cpp
--- a/dom/requestsync/RequestSyncService.jsm
+++ b/dom/requestsync/RequestSyncService.jsm
@@ -1,18 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 'use strict'
 
-/* TODO:
- - wifi
-*/
-
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 function debug(s) {
   //dump('DEBUG RequestSyncService: ' + s + '\n');
 }
 
 const RSYNCDB_VERSION = 1;
 const RSYNCDB_NAME = "requestSync";
@@ -53,26 +49,29 @@ this.RequestSyncService = {
                "RequestSync:Registrations", "RequestSync:Registration",
                "RequestSyncManager:Registrations" ],
 
   _pendingOperation: false,
   _pendingMessages: [],
 
   _registrations: {},
 
+  _wifi: false,
+
   // Initialization of the RequestSyncService.
   init: function() {
     debug("init");
 
     this._messages.forEach((function(msgName) {
       ppmm.addMessageListener(msgName, this);
     }).bind(this));
 
     Services.obs.addObserver(this, 'xpcom-shutdown', false);
     Services.obs.addObserver(this, 'webapps-clear-data', false);
+    Services.obs.addObserver(this, 'wifi-state-changed', false);
 
     this.initDBHelper("requestSync", RSYNCDB_VERSION, [RSYNCDB_NAME]);
 
     // Loading all the data from the database into the _registrations map.
     // Any incoming message will be stored and processed when the async
     // operation is completed.
 
     let self = this;
@@ -98,38 +97,43 @@ this.RequestSyncService = {
     debug("shutdown");
 
     this._messages.forEach((function(msgName) {
       ppmm.removeMessageListener(msgName, this);
     }).bind(this));
 
     Services.obs.removeObserver(this, 'xpcom-shutdown');
     Services.obs.removeObserver(this, 'webapps-clear-data');
+    Services.obs.removeObserver(this, 'wifi-state-changed');
 
     this.close();
 
     // Removing all the registrations will delete the pending timers.
-    for (let key  in this._registrations) {
-      for (let task in this._registrations[key]) {
-        this.removeRegistrationInternal(task, key);
-      }
-    }
+    let self = this;
+    this.forEachRegistration(function(aObj) {
+      let key = self.principalToKey(aObj.principal);
+      self.removeRegistrationInternal(aObj.data.task, key);
+    });
   },
 
   observe: function(aSubject, aTopic, aData) {
     debug("observe");
 
     switch (aTopic) {
       case 'xpcom-shutdown':
         this.shutdown();
         break;
 
       case 'webapps-clear-data':
-       this.clearData(aSubject);
-       break;
+        this.clearData(aSubject);
+        break;
+
+      case 'wifi-state-changed':
+        this.wifiStateChanged(aSubject == 'enabled');
+        break;
 
       default:
         debug("Wrong observer topic: " + aTopic);
         break;
     }
   },
 
   // When an app is uninstalled, we have to clean all its tasks.
@@ -439,22 +443,20 @@ this.RequestSyncService = {
                                results: results });
   },
 
   // Get the list of the registered tasks.
   managerRegistrations: function(aTarget, aData, aPrincipal) {
     debug("managerRegistrations");
 
     let results = [];
-    for (var key in this._registrations) {
-      for (var task in this._registrations[key]) {
-        results.push(
-          this.createFullTaskObject(this._registrations[key][task].data));
-      }
-    }
+    let self = this;
+    this.forEachRegistration(function(aObj) {
+      results.push(self.createFullTaskObject(aObj.data));
+    });
 
     aTarget.sendAsyncMessage("RequestSyncManager:Registrations:Return",
                              { requestID: aData.requestID,
                                results: results });
   },
 
   // We cannot expose the full internal object to content but just a subset.
   // This method creates this subset.
@@ -483,24 +485,31 @@ this.RequestSyncService = {
     return obj;
   },
 
   // Creation of the timer for a particular task object.
   scheduleTimer: function(aObj) {
     debug("scheduleTimer");
 
     // A  registration can be already inactive if it was 1 shot.
-    if (aObj.active) {
-      aObj.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    if (!aObj.active) {
+      return;
+    }
 
-      let self = this;
-      aObj.timer.initWithCallback(function() { self.timeout(aObj); },
-                                  aObj.data.minInterval * 1000,
-                                  Ci.nsITimer.TYPE_ONE_SHOT);
+    // WifiOnly check.
+    if (aObj.data.wifiOnly && !this._wifi) {
+      return;
     }
+
+    aObj.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+
+    let self = this;
+    aObj.timer.initWithCallback(function() { self.timeout(aObj); },
+                                aObj.data.minInterval * 1000,
+                                Ci.nsITimer.TYPE_ONE_SHOT);
   },
 
   timeout: function(aObj) {
     debug("timeout");
 
     let app = appsService.getAppByLocalId(aObj.principal.appId);
     if (!app) {
       dump("ERROR!! RequestSyncService - Failed to retrieve app data from a principal.\n");
@@ -612,14 +621,57 @@ this.RequestSyncService = {
     function() {
       self.pendingOperationDone();
       aSuccessCb();
     },
     function() {
       self.pendingOperationDone();
       aErrorCb();
     });
+  },
+
+  forEachRegistration: function(aCb) {
+    // This method is used also to remove registations from the map, so we have
+    // to make a new list and let _registations free to be used.
+    let list = [];
+    for (var key in this._registrations) {
+      for (var task in this._registrations[key]) {
+        list.push(this._registrations[key][task]);
+      }
+    }
+
+    for (var i = 0; i < list.length; ++i) {
+      aCb(list[i]);
+    }
+  },
+
+  wifiStateChanged: function(aEnabled) {
+    debug("onWifiStateChanged");
+    this._wifi = aEnabled;
+
+    if (!this._wifi) {
+      // Disable all the wifiOnly tasks.
+      this.forEachRegistration(function(aObj) {
+        if (aObj.data.wifiOnly && aObj.timer) {
+          aObj.timer.cancel();
+          aObj.timer = null;
+        }
+      });
+      return;
+    }
+
+    // Enable all the tasks.
+    let self = this;
+    this.forEachRegistration(function(aObj) {
+      if (aObj.active && !aObj.timer) {
+        if (!aObj.data.wifiOnly) {
+          dump("ERROR - Found a disabled task that is not wifiOnly.");
+        }
+
+        self.scheduleTimer(aObj);
+      }
+    });
   }
 }
 
 RequestSyncService.init();
 
 this.EXPORTED_SYMBOLS = [""];
new file mode 100644
--- /dev/null
+++ b/dom/requestsync/RequestSyncWifiService.cpp
@@ -0,0 +1,67 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RequestSyncWifiService.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+#include "nsIObserverService.h"
+
+namespace mozilla {
+namespace dom {
+
+using namespace hal;
+
+NS_IMPL_ISUPPORTS0(RequestSyncWifiService)
+
+namespace {
+
+StaticRefPtr<RequestSyncWifiService> sService;
+
+} // anonymous namespace
+
+/* static */ void
+RequestSyncWifiService::Init()
+{
+  nsRefPtr<RequestSyncWifiService> service = GetInstance();
+  if (!service) {
+    NS_WARNING("Failed to initialize RequestSyncWifiService.");
+  }
+}
+
+/* static */ already_AddRefed<RequestSyncWifiService>
+RequestSyncWifiService::GetInstance()
+{
+  if (!sService) {
+    sService = new RequestSyncWifiService();
+    hal::RegisterNetworkObserver(sService);
+    ClearOnShutdown(&sService);
+  }
+
+  nsRefPtr<RequestSyncWifiService> service = sService.get();
+  return service.forget();
+}
+
+void
+RequestSyncWifiService::Notify(const hal::NetworkInformation& aNetworkInfo)
+{
+  bool isWifi = aNetworkInfo.isWifi();
+  if (isWifi == mIsWifi) {
+    return;
+  }
+
+  mIsWifi = isWifi;
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->NotifyObservers(nullptr, "wifi-state-changed",
+                         mIsWifi ? MOZ_UTF16("enabled") :
+                                   MOZ_UTF16("disabled"));
+  }
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/requestsync/RequestSyncWifiService.h
@@ -0,0 +1,43 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_RequestSyncWifiService_h
+#define mozilla_dom_RequestSyncWifiService_h
+
+#include "mozilla/dom/network/Types.h"
+#include "mozilla/Hal.h"
+#include "nsIObserver.h"
+
+namespace mozilla {
+namespace dom {
+
+class RequestSyncWifiService MOZ_FINAL : public nsISupports
+                                       , public NetworkObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  static void Init();
+
+  static already_AddRefed<RequestSyncWifiService> GetInstance();
+
+  void Notify(const hal::NetworkInformation& aNetworkInfo);
+
+private:
+  RequestSyncWifiService()
+    : mIsWifi(false)
+  {}
+
+  ~RequestSyncWifiService()
+  {}
+
+  bool mIsWifi;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_RequestSyncWifiService_h
--- a/dom/requestsync/moz.build
+++ b/dom/requestsync/moz.build
@@ -1,17 +1,30 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
 
+EXPORTS.mozilla.dom += [
+    'RequestSyncWifiService.h',
+]
+
 EXTRA_COMPONENTS += [
     'RequestSync.manifest',
     'RequestSyncManager.js',
     'RequestSyncScheduler.js',
 ]
 
 EXTRA_JS_MODULES += [
     'RequestSyncService.jsm',
 ]
+
+SOURCES += [
+    'RequestSyncWifiService.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FAIL_ON_WARNINGS = True
+FINAL_LIBRARY = 'xul'
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -59,16 +59,17 @@
 #include "nsMathMLOperators.h"
 #include "Navigator.h"
 #include "DOMStorageObserver.h"
 #include "CacheObserver.h"
 #include "DisplayItemClip.h"
 #include "ActiveLayerTracker.h"
 #include "CounterStyleManager.h"
 #include "FrameLayerBuilder.h"
+#include "mozilla/dom/RequestSyncWifiService.h"
 
 #include "AudioChannelService.h"
 #include "mozilla/dom/DataStoreService.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #include "nsXULContentUtils.h"
 #include "nsXULPrototypeCache.h"
@@ -295,16 +296,20 @@ nsLayoutStatics::Initialize()
   CacheObserver::Init();
 
   CounterStyleManager::InitializeBuiltinCounterStyles();
 
   CameraPreferences::Initialize();
 
   IMEStateManager::Init();
 
+#ifdef MOZ_B2G
+  RequestSyncWifiService::Init();
+#endif
+
   return NS_OK;
 }
 
 void
 nsLayoutStatics::Shutdown()
 {
   // Don't need to shutdown nsWindowMemoryReporter, that will be done by the
   // memory reporter manager.