Bug 677166 - Part 7 - Network Information API: DOM implementation. r=sicking
authorMounir Lamouri <mounir.lamouri@gmail.com>
Mon, 16 Jan 2012 18:14:56 +0100
changeset 84742 778597344568aa509f3731056fad9501307977a3
parent 84741 ae007b96ebf087c2b2a38c97532c5e05bbb55531
child 84743 e652d673382fae155a88ef779b2fa3b4e16421f6
push id21873
push usermlamouri@mozilla.com
push dateWed, 18 Jan 2012 10:29:07 +0000
treeherdermozilla-central@7538f4d4697c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs677166
milestone12.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 677166 - Part 7 - Network Information API: DOM implementation. r=sicking
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/network/interfaces/nsIDOMConnection.idl
dom/network/src/Connection.cpp
dom/network/src/Connection.h
dom/network/src/Makefile.in
dom/network/tests/test_network_basics.html
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -170,17 +170,20 @@ Navigator::Invalidate()
   }
 
 #ifdef MOZ_B2G_RIL
   if (mTelephony) {
     mTelephony = nsnull;
   }
 #endif
 
-  mConnection = nsnull;
+  if (mConnection) {
+    mConnection->Shutdown();
+    mConnection = nsnull;
+  }
 }
 
 nsPIDOMWindow *
 Navigator::GetWindow()
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
 
   return win;
@@ -1069,18 +1072,30 @@ Navigator::GetMozTelephony(nsIDOMTelepho
 
 //*****************************************************************************
 //    Navigator::nsIDOMNavigatorNetwork
 //*****************************************************************************
 
 NS_IMETHODIMP
 Navigator::GetMozConnection(nsIDOMMozConnection** aConnection)
 {
+  *aConnection = nsnull;
+
   if (!mConnection) {
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+    NS_ENSURE_TRUE(window && window->GetDocShell(), NS_OK);
+
+    nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
+    NS_ENSURE_TRUE(sgo, NS_OK);
+
+    nsIScriptContext* scx = sgo->GetContext();
+    NS_ENSURE_TRUE(scx, NS_OK);
+
     mConnection = new network::Connection();
+    mConnection->Init(window, scx);
   }
 
   NS_ADDREF(*aConnection = mConnection);
   return NS_OK;
 }
 
 PRInt64
 Navigator::SizeOf() const
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -75,16 +75,20 @@ namespace dom {
 namespace battery {
 class BatteryManager;
 } // namespace battery
 
 namespace sms {
 class SmsManager;
 } // namespace sms
 
+namespace network {
+class Connection;
+} // namespace Connection;
+
 class Navigator : public nsIDOMNavigator
                 , public nsIDOMClientInformation
                 , public nsIDOMNavigatorGeolocation
                 , public nsIDOMNavigatorDesktopNotification
                 , public nsIDOMMozNavigatorBattery
                 , public nsIDOMMozNavigatorSms
 #ifdef MOZ_B2G_RIL
                 , public nsIDOMNavigatorTelephony
@@ -131,17 +135,17 @@ private:
   nsRefPtr<nsPluginArray> mPlugins;
   nsRefPtr<nsGeolocation> mGeolocation;
   nsRefPtr<nsDesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
   nsRefPtr<sms::SmsManager> mSmsManager;
 #ifdef MOZ_B2G_RIL
   nsCOMPtr<nsIDOMTelephony> mTelephony;
 #endif
-  nsCOMPtr<nsIDOMMozConnection> mConnection;
+  nsRefPtr<network::Connection> mConnection;
   nsWeakPtr mWindow;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
 nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
--- a/dom/network/interfaces/nsIDOMConnection.idl
+++ b/dom/network/interfaces/nsIDOMConnection.idl
@@ -31,13 +31,18 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(0bd0bcc8-ca92-43fa-97bd-aec8d79edb24)]
+interface nsIDOMEventListener;
+
+[scriptable, uuid(8c6b574d-1135-4387-a6e3-6d8ba38d79a1)]
 interface nsIDOMMozConnection : nsISupports
 {
+  readonly attribute double  bandwidth;
   readonly attribute boolean metered;
+
+           attribute nsIDOMEventListener onchange;
 };
--- a/dom/network/src/Connection.cpp
+++ b/dom/network/src/Connection.cpp
@@ -30,42 +30,150 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include <limits>
+#include "mozilla/Hal.h"
 #include "Connection.h"
 #include "nsIDOMClassInfo.h"
 #include "mozilla/Preferences.h"
+#include "nsDOMEvent.h"
+#include "Constants.h"
+
+/**
+ * We have to use macros here because our leak analysis tool things we are
+ * leaking strings when we have |static const nsString|. Sad :(
+ */
+#define CHANGE_EVENT_NAME NS_LITERAL_STRING("change")
 
 DOMCI_DATA(MozConnection, mozilla::dom::network::Connection)
 
 namespace mozilla {
 namespace dom {
 namespace network {
 
 const char* Connection::sMeteredPrefName     = "dom.network.metered";
 const bool  Connection::sMeteredDefaultValue = false;
 
-NS_INTERFACE_MAP_BEGIN(Connection)
+NS_IMPL_CYCLE_COLLECTION_CLASS(Connection)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Connection,
+                                                  nsDOMEventTargetWrapperCache)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(change)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Connection,
+                                                nsDOMEventTargetWrapperCache)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(change)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Connection)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozConnection)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozConnection)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozConnection)
-NS_INTERFACE_MAP_END
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache)
+
+NS_IMPL_ADDREF_INHERITED(Connection, nsDOMEventTargetWrapperCache)
+NS_IMPL_RELEASE_INHERITED(Connection, nsDOMEventTargetWrapperCache)
+
+Connection::Connection()
+  : mCanBeMetered(kDefaultCanBeMetered)
+  , mBandwidth(kDefaultBandwidth)
+{
+}
+
+void
+Connection::Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext)
+{
+  // Those vars come from nsDOMEventTargetHelper.
+  mOwner = aWindow;
+  mScriptContext = aScriptContext;
+
+  hal::RegisterNetworkObserver(this);
 
-NS_IMPL_ADDREF(Connection)
-NS_IMPL_RELEASE(Connection)
+  hal::NetworkInformation networkInfo;
+  hal::GetCurrentNetworkInformation(&networkInfo);
+
+  UpdateFromNetworkInfo(networkInfo);
+}
+
+void
+Connection::Shutdown()
+{
+  hal::UnregisterNetworkObserver(this);
+}
+
+NS_IMETHODIMP
+Connection::GetBandwidth(double* aBandwidth)
+{
+  if (mBandwidth == kDefaultBandwidth) {
+    *aBandwidth = std::numeric_limits<double>::infinity();
+    return NS_OK;
+  }
+
+  *aBandwidth = mBandwidth;
+  return NS_OK;
+}
 
 NS_IMETHODIMP
 Connection::GetMetered(bool* aMetered)
 {
+  if (!mCanBeMetered) {
+    *aMetered = false;
+    return NS_OK;
+  }
+
   *aMetered = Preferences::GetBool(sMeteredPrefName,
                                    sMeteredDefaultValue);
   return NS_OK;
 }
 
+NS_IMPL_EVENT_HANDLER(Connection, change)
+
+nsresult
+Connection::DispatchTrustedEventToSelf(const nsAString& aEventName)
+{
+  nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
+  nsresult rv = event->InitEvent(aEventName, false, false);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = event->SetTrusted(PR_TRUE);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool dummy;
+  rv = DispatchEvent(event, &dummy);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+void
+Connection::UpdateFromNetworkInfo(const hal::NetworkInformation& aNetworkInfo)
+{
+  mBandwidth = aNetworkInfo.bandwidth();
+  mCanBeMetered = aNetworkInfo.canBeMetered();
+}
+
+void
+Connection::Notify(const hal::NetworkInformation& aNetworkInfo)
+{
+  double previousBandwidth = mBandwidth;
+  bool previousCanBeMetered = mCanBeMetered;
+
+  UpdateFromNetworkInfo(aNetworkInfo);
+
+  if (previousBandwidth == mBandwidth &&
+      previousCanBeMetered == mCanBeMetered) {
+    return;
+  }
+
+  DispatchTrustedEventToSelf(CHANGE_EVENT_NAME);
+}
+
 } // namespace network
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/network/src/Connection.h
+++ b/dom/network/src/Connection.h
@@ -34,28 +34,75 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_network_Connection_h
 #define mozilla_dom_network_Connection_h
 
 #include "nsIDOMConnection.h"
+#include "nsDOMEventTargetWrapperCache.h"
+#include "nsCycleCollectionParticipant.h"
+#include "mozilla/Observer.h"
+#include "Types.h"
 
 namespace mozilla {
+
+namespace hal {
+class NetworkInformation;
+} // namespace hal
+
 namespace dom {
 namespace network {
 
-class Connection : public nsIDOMMozConnection
+class Connection : public nsDOMEventTargetWrapperCache
+                 , public nsIDOMMozConnection
+                 , public NetworkObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMOZCONNECTION
 
+  NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetWrapperCache::)
+
+  Connection();
+
+  void Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext);
+  void Shutdown();
+
+  // For IObserver
+  void Notify(const hal::NetworkInformation& aNetworkInfo);
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Connection,
+                                           nsDOMEventTargetWrapperCache)
+
 private:
+  /**
+   * Dispatch a trusted non-cancellable and non-bubbling event to itself.
+   */
+  nsresult DispatchTrustedEventToSelf(const nsAString& aEventName);
+
+  /**
+   * Update the connection information stored in the object using a
+   * NetworkInformation object.
+   */
+  void UpdateFromNetworkInfo(const hal::NetworkInformation& aNetworkInfo);
+
+  /**
+   * If the connection is of a type that can be metered.
+   */
+  bool mCanBeMetered;
+
+  /**
+   * The connection bandwidth.
+   */
+  double mBandwidth;
+
+  NS_DECL_EVENT_HANDLER(change)
+
   static const char* sMeteredPrefName;
   static const bool  sMeteredDefaultValue;
 };
 
 } // namespace network
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/network/src/Makefile.in
+++ b/dom/network/src/Makefile.in
@@ -56,11 +56,14 @@ EXPORTS_mozilla/dom/network = \
   $(NULL)
 
 CPPSRCS = \
   Connection.cpp \
   Utils.cpp \
   $(NULL)
 
 LOCAL_INCLUDES = \
+  -I$(topsrcdir)/content/events/src \
   $(NULL)
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
--- a/dom/network/tests/test_network_basics.html
+++ b/dom/network/tests/test_network_basics.html
@@ -23,12 +23,22 @@ ok('mozConnection' in navigator, "naviga
 
 ok(navigator.mozConnection, "navigator.mozConnection returns an object");
 
 ok(navigator.mozConnection instanceof MozConnection,
    "navigator.mozConnection is a MozConnection object");
 
 checkInterface("Connection");
 
+ok('bandwidth' in navigator.mozConnection,
+   "bandwidth should be a Connection attribute");
+is(navigator.mozConnection.bandwidth, Infinity,
+   "By default connection.bandwidth is equals to Infinity");
+
+ok('metered' in navigator.mozConnection,
+   "metered should be a Connection attribute");
+is(navigator.mozConnection.metered, false,
+   "By default the connection is not metered");
+
 </script>
 </pre>
 </body>
 </html>