Bug 1018320 - RequestSync API - patch 2 - Wifi Only, r=ehsan
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 13 Jan 2015 09:53:16 +0000
changeset 223537 2103910871480ce2a8c86ca5f997657b639ce709
parent 223536 7778319fce3211823402002f9aeb80a2a9868dfe
child 223538 b729cdfd5a8cabafbf6ec894fdfc33b47cf81687
push id53943
push useramarchesini@mozilla.com
push dateTue, 13 Jan 2015 09:53:46 +0000
treeherdermozilla-inbound@f15ef701bdf2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1018320
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1018320 - RequestSync API - patch 2 - Wifi Only, r=ehsan
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.