Bug 713687 - Part 1 - Network API Android backend: get current information. r=dougt
authorMounir Lamouri <mounir.lamouri@gmail.com>
Mon, 16 Jan 2012 14:44:07 +0100
changeset 87185 e652d673382fae155a88ef779b2fa3b4e16421f6
parent 87184 778597344568aa509f3731056fad9501307977a3
child 87186 b92399819ec4dc53371f336283ed58c21884b9bd
push id674
push userffxbld
push dateTue, 13 Mar 2012 21:17:50 +0000
treeherdermozilla-beta@e3c4c92dec31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdougt
bugs713687
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 713687 - Part 1 - Network API Android backend: get current information. r=dougt
embedding/android/GeckoAppShell.java
embedding/android/GeckoNetworkManager.java
embedding/android/Makefile.in
hal/android/AndroidHal.cpp
mobile/android/base/GeckoAppShell.java
mobile/android/base/GeckoNetworkManager.java
mobile/android/base/Makefile.in
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -1771,9 +1771,13 @@ public class GeckoAppShell
             // and should include most devices ~7in and up.
             // http://developer.android.com/guide/practices/screens_support.html
             if ((config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE) {
                 return true;
             }
         }
         return false;
     }
+
+    public static double[] getCurrentNetworkInformation() {
+        return GeckoNetworkManager.getCurrentInformation();
+    }
 }
new file mode 100644
--- /dev/null
+++ b/embedding/android/GeckoNetworkManager.java
@@ -0,0 +1,206 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * 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 ***** */
+
+package org.mozilla.gecko;
+
+import java.lang.Math;
+
+import android.util.Log;
+
+import android.content.Context;
+
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+
+import android.telephony.TelephonyManager;
+
+/*
+ * A part of the work of GeckoNetworkManager is to give an estimation of the
+ * download speed of the current connection. For known to be fast connection, we
+ * simply use a predefined value (we don't care about being precise). For mobile
+ * connections, we sort them in groups (generations) and estimate the average
+ * real life download speed of that specific generation. This value comes from
+ * researches (eg. Wikipedia articles) or is simply an arbitrary estimation.
+ * Precision isn't important, we mostly need an order of magnitude.
+ *
+ * Each group is composed with networks represented by the constant from
+ * Android's ConnectivityManager and the description comming from the same
+ * class.
+ *
+ * 2G (15 bk/s):
+ * int NETWORK_TYPE_IDEN     Current network is iDen
+ * int NETWORK_TYPE_CDMA     Current network is CDMA: Either IS95A or IS95B
+ *
+ * 2.5G (60 kb/s)
+ * int NETWORK_TYPE_GPRS     Current network is GPRS
+ * int NETWORK_TYPE_1xRTT    Current network is 1xRTT
+ *
+ * 2.75G (200 kb/s)
+ * int NETWORK_TYPE_EDGE     Current network is EDGE
+ *
+ * 3G (300 kb/s)
+ * int NETWORK_TYPE_UMTS     Current network is UMTS
+ * int NETWORK_TYPE_EVDO_0   Current network is EVDO revision 0
+ *
+ * 3.5G (7 Mb/s)
+ * int NETWORK_TYPE_HSPA     Current network is HSPA
+ * int NETWORK_TYPE_HSDPA    Current network is HSDPA
+ * int NETWORK_TYPE_HSUPA    Current network is HSUPA
+ * int NETWORK_TYPE_EVDO_A   Current network is EVDO revision A
+ * int NETWORK_TYPE_EVDO_B   Current network is EVDO revision B
+ * int NETWORK_TYPE_EHRPD    Current network is eHRPD
+ *
+ * 3.75G (20 Mb/s)
+ * int NETWORK_TYPE_HSPAP    Current network is HSPA+
+ *
+ * 3.9G (50 Mb/s)
+ * int NETWORK_TYPE_LTE      Current network is LTE
+ */
+
+public class GeckoNetworkManager
+{
+  static private final double  kDefaultBandwidth    = -1.0;
+  static private final boolean kDefaultCanBeMetered = false;
+
+  static private final double  kMaxBandwidth = 20.0;
+
+  static private final double  kNetworkSpeed_2_G    = 15.0 / 1024.0;  // 15 kb/s
+  static private final double  kNetworkSpeed_2_5_G  = 60.0 / 1024.0;  // 60 kb/s
+  static private final double  kNetworkSpeed_2_75_G = 200.0 / 1024.0; // 200 kb/s
+  static private final double  kNetworkSpeed_3_G    = 300.0 / 1024.0; // 300 kb/s
+  static private final double  kNetworkSpeed_3_5_G  = 7.0;            // 7 Mb/s
+  static private final double  kNetworkSpeed_3_75_G = 20.0;           // 20 Mb/s
+  static private final double  kNetworkSpeed_3_9_G  = 50.0;           // 50 Mb/s
+
+  private enum MobileNetworkType {
+    NETWORK_2_G,    // 2G
+    NETWORK_2_5_G,  // 2.5G
+    NETWORK_2_75_G, // 2.75G
+    NETWORK_3_G,    // 3G
+    NETWORK_3_5_G,  // 3.5G
+    NETWORK_3_75_G, // 3.75G
+    NETWORK_3_9_G,  // 3.9G
+    NETWORK_UNKNOWN
+  }
+
+  private static MobileNetworkType getMobileNetworkType() {
+    TelephonyManager tm =
+      (TelephonyManager)GeckoApp.mAppContext.getSystemService(Context.TELEPHONY_SERVICE);
+
+    switch (tm.getNetworkType()) {
+      case TelephonyManager.NETWORK_TYPE_IDEN:
+      case TelephonyManager.NETWORK_TYPE_CDMA:
+        return MobileNetworkType.NETWORK_2_G;
+      case TelephonyManager.NETWORK_TYPE_GPRS:
+      case TelephonyManager.NETWORK_TYPE_1xRTT:
+        return MobileNetworkType.NETWORK_2_5_G;
+      case TelephonyManager.NETWORK_TYPE_EDGE:
+        return MobileNetworkType.NETWORK_2_75_G;
+      case TelephonyManager.NETWORK_TYPE_UMTS:
+      case TelephonyManager.NETWORK_TYPE_EVDO_0:
+        return MobileNetworkType.NETWORK_3_G;
+      case TelephonyManager.NETWORK_TYPE_HSPA:
+      case TelephonyManager.NETWORK_TYPE_HSDPA:
+      case TelephonyManager.NETWORK_TYPE_HSUPA:
+      case TelephonyManager.NETWORK_TYPE_EVDO_A:
+      case TelephonyManager.NETWORK_TYPE_EVDO_B:
+      case TelephonyManager.NETWORK_TYPE_EHRPD:
+        return MobileNetworkType.NETWORK_3_5_G;
+      case TelephonyManager.NETWORK_TYPE_HSPAP:
+        return MobileNetworkType.NETWORK_3_75_G;
+      case TelephonyManager.NETWORK_TYPE_LTE:
+        return MobileNetworkType.NETWORK_3_9_G;
+      case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+      default:
+        Log.w("GeckoNetworkManager", "Connected to an unknown mobile network!");
+        return MobileNetworkType.NETWORK_UNKNOWN;
+    }
+  }
+
+  public static double getMobileNetworkSpeed(MobileNetworkType aType) {
+    switch (aType) {
+      case NETWORK_2_G:
+        return kNetworkSpeed_2_G;
+      case NETWORK_2_5_G:
+        return kNetworkSpeed_2_5_G;
+      case NETWORK_2_75_G:
+        return kNetworkSpeed_2_75_G;
+      case NETWORK_3_G:
+        return kNetworkSpeed_3_G;
+      case NETWORK_3_5_G:
+        return kNetworkSpeed_3_5_G;
+      case NETWORK_3_75_G:
+        return kNetworkSpeed_3_75_G;
+      case NETWORK_3_9_G:
+        return kNetworkSpeed_3_9_G;
+      case NETWORK_UNKNOWN:
+      default:
+        return kDefaultBandwidth;
+    }
+  }
+
+  public static double[] getCurrentInformation() {
+    ConnectivityManager cm =
+      (ConnectivityManager)GeckoApp.mAppContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+    if (cm.getActiveNetworkInfo() == null) {
+      return new double[] { 0.0, 1.0 };
+    }
+
+    int type = cm.getActiveNetworkInfo().getType();
+    double bandwidth = kDefaultBandwidth;
+    boolean canBeMetered = kDefaultCanBeMetered;
+
+    switch (type) {
+      case ConnectivityManager.TYPE_ETHERNET:
+      case ConnectivityManager.TYPE_WIFI:
+      case ConnectivityManager.TYPE_WIMAX:
+        bandwidth = kMaxBandwidth;
+        canBeMetered = false;
+        break;
+      case ConnectivityManager.TYPE_MOBILE:
+        bandwidth = Math.min(getMobileNetworkSpeed(getMobileNetworkType()), kMaxBandwidth);
+        canBeMetered = true;
+        break;
+      default:
+        Log.w("GeckoNetworkManager", "Ignoring the current network type.");
+        break;
+    }
+
+    return new double[] { bandwidth, canBeMetered ? 1.0 : 0.0 };
+  }
+}
--- a/embedding/android/Makefile.in
+++ b/embedding/android/Makefile.in
@@ -51,16 +51,17 @@ JAVAFILES = \
   GeckoConnectivityReceiver.java \
   GeckoEvent.java \
   GeckoSurfaceView.java \
   GeckoInputConnection.java \
   AlertNotification.java \
   SurfaceInfo.java \
   GeckoBatteryManager.java \
   VideoPlayer.java \
+  GeckoNetworkManager.java \
   $(NULL)
 
 ifdef MOZ_WEBSMS_BACKEND
 JAVAFILES += GeckoSmsManager.java
 endif
 
 PROCESSEDJAVAFILES = \
   App.java \
--- a/hal/android/AndroidHal.cpp
+++ b/hal/android/AndroidHal.cpp
@@ -146,15 +146,19 @@ EnableNetworkNotifications()
 
 void
 DisableNetworkNotifications()
 {}
 
 void
 GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
 {
-  aNetworkInfo->bandwidth() = dom::network::kDefaultBandwidth;
-  aNetworkInfo->canBeMetered() = dom::network::kDefaultCanBeMetered;
+  AndroidBridge* bridge = AndroidBridge::Bridge();
+  if (!bridge) {
+    return;
+  }
+
+  bridge->GetCurrentNetworkInformation(aNetworkInfo);
 }
 
 } // hal_impl
 } // mozilla
 
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -1742,9 +1742,13 @@ public class GeckoAppShell
         accessibilityManager.sendAccessibilityEvent(event);
     }
 
     public static void viewSizeChanged() {
         if (mInputConnection != null && mInputConnection.isIMEEnabled()) {
             sendEventToGecko(new GeckoEvent("ScrollTo:FocusedInput", ""));
         }
     }
+
+    public static double[] getCurrentNetworkInformation() {
+        return GeckoNetworkManager.getCurrentInformation();
+    }
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/GeckoNetworkManager.java
@@ -0,0 +1,206 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * 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 ***** */
+
+package org.mozilla.gecko;
+
+import java.lang.Math;
+
+import android.util.Log;
+
+import android.content.Context;
+
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+
+import android.telephony.TelephonyManager;
+
+/*
+ * A part of the work of GeckoNetworkManager is to give an estimation of the
+ * download speed of the current connection. For known to be fast connection, we
+ * simply use a predefined value (we don't care about being precise). For mobile
+ * connections, we sort them in groups (generations) and estimate the average
+ * real life download speed of that specific generation. This value comes from
+ * researches (eg. Wikipedia articles) or is simply an arbitrary estimation.
+ * Precision isn't important, we mostly need an order of magnitude.
+ *
+ * Each group is composed with networks represented by the constant from
+ * Android's ConnectivityManager and the description comming from the same
+ * class.
+ *
+ * 2G (15 bk/s):
+ * int NETWORK_TYPE_IDEN     Current network is iDen
+ * int NETWORK_TYPE_CDMA     Current network is CDMA: Either IS95A or IS95B
+ *
+ * 2.5G (60 kb/s)
+ * int NETWORK_TYPE_GPRS     Current network is GPRS
+ * int NETWORK_TYPE_1xRTT    Current network is 1xRTT
+ *
+ * 2.75G (200 kb/s)
+ * int NETWORK_TYPE_EDGE     Current network is EDGE
+ *
+ * 3G (300 kb/s)
+ * int NETWORK_TYPE_UMTS     Current network is UMTS
+ * int NETWORK_TYPE_EVDO_0   Current network is EVDO revision 0
+ *
+ * 3.5G (7 Mb/s)
+ * int NETWORK_TYPE_HSPA     Current network is HSPA
+ * int NETWORK_TYPE_HSDPA    Current network is HSDPA
+ * int NETWORK_TYPE_HSUPA    Current network is HSUPA
+ * int NETWORK_TYPE_EVDO_A   Current network is EVDO revision A
+ * int NETWORK_TYPE_EVDO_B   Current network is EVDO revision B
+ * int NETWORK_TYPE_EHRPD    Current network is eHRPD
+ *
+ * 3.75G (20 Mb/s)
+ * int NETWORK_TYPE_HSPAP    Current network is HSPA+
+ *
+ * 3.9G (50 Mb/s)
+ * int NETWORK_TYPE_LTE      Current network is LTE
+ */
+
+public class GeckoNetworkManager
+{
+  static private final double  kDefaultBandwidth    = -1.0;
+  static private final boolean kDefaultCanBeMetered = false;
+
+  static private final double  kMaxBandwidth = 20.0;
+
+  static private final double  kNetworkSpeed_2_G    = 15.0 / 1024.0;  // 15 kb/s
+  static private final double  kNetworkSpeed_2_5_G  = 60.0 / 1024.0;  // 60 kb/s
+  static private final double  kNetworkSpeed_2_75_G = 200.0 / 1024.0; // 200 kb/s
+  static private final double  kNetworkSpeed_3_G    = 300.0 / 1024.0; // 300 kb/s
+  static private final double  kNetworkSpeed_3_5_G  = 7.0;            // 7 Mb/s
+  static private final double  kNetworkSpeed_3_75_G = 20.0;           // 20 Mb/s
+  static private final double  kNetworkSpeed_3_9_G  = 50.0;           // 50 Mb/s
+
+  private enum MobileNetworkType {
+    NETWORK_2_G,    // 2G
+    NETWORK_2_5_G,  // 2.5G
+    NETWORK_2_75_G, // 2.75G
+    NETWORK_3_G,    // 3G
+    NETWORK_3_5_G,  // 3.5G
+    NETWORK_3_75_G, // 3.75G
+    NETWORK_3_9_G,  // 3.9G
+    NETWORK_UNKNOWN
+  }
+
+  private static MobileNetworkType getMobileNetworkType() {
+    TelephonyManager tm =
+      (TelephonyManager)GeckoApp.mAppContext.getSystemService(Context.TELEPHONY_SERVICE);
+
+    switch (tm.getNetworkType()) {
+      case TelephonyManager.NETWORK_TYPE_IDEN:
+      case TelephonyManager.NETWORK_TYPE_CDMA:
+        return MobileNetworkType.NETWORK_2_G;
+      case TelephonyManager.NETWORK_TYPE_GPRS:
+      case TelephonyManager.NETWORK_TYPE_1xRTT:
+        return MobileNetworkType.NETWORK_2_5_G;
+      case TelephonyManager.NETWORK_TYPE_EDGE:
+        return MobileNetworkType.NETWORK_2_75_G;
+      case TelephonyManager.NETWORK_TYPE_UMTS:
+      case TelephonyManager.NETWORK_TYPE_EVDO_0:
+        return MobileNetworkType.NETWORK_3_G;
+      case TelephonyManager.NETWORK_TYPE_HSPA:
+      case TelephonyManager.NETWORK_TYPE_HSDPA:
+      case TelephonyManager.NETWORK_TYPE_HSUPA:
+      case TelephonyManager.NETWORK_TYPE_EVDO_A:
+      case TelephonyManager.NETWORK_TYPE_EVDO_B:
+      case TelephonyManager.NETWORK_TYPE_EHRPD:
+        return MobileNetworkType.NETWORK_3_5_G;
+      case TelephonyManager.NETWORK_TYPE_HSPAP:
+        return MobileNetworkType.NETWORK_3_75_G;
+      case TelephonyManager.NETWORK_TYPE_LTE:
+        return MobileNetworkType.NETWORK_3_9_G;
+      case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+      default:
+        Log.w("GeckoNetworkManager", "Connected to an unknown mobile network!");
+        return MobileNetworkType.NETWORK_UNKNOWN;
+    }
+  }
+
+  public static double getMobileNetworkSpeed(MobileNetworkType aType) {
+    switch (aType) {
+      case NETWORK_2_G:
+        return kNetworkSpeed_2_G;
+      case NETWORK_2_5_G:
+        return kNetworkSpeed_2_5_G;
+      case NETWORK_2_75_G:
+        return kNetworkSpeed_2_75_G;
+      case NETWORK_3_G:
+        return kNetworkSpeed_3_G;
+      case NETWORK_3_5_G:
+        return kNetworkSpeed_3_5_G;
+      case NETWORK_3_75_G:
+        return kNetworkSpeed_3_75_G;
+      case NETWORK_3_9_G:
+        return kNetworkSpeed_3_9_G;
+      case NETWORK_UNKNOWN:
+      default:
+        return kDefaultBandwidth;
+    }
+  }
+
+  public static double[] getCurrentInformation() {
+    ConnectivityManager cm =
+      (ConnectivityManager)GeckoApp.mAppContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+    if (cm.getActiveNetworkInfo() == null) {
+      return new double[] { 0.0, 1.0 };
+    }
+
+    int type = cm.getActiveNetworkInfo().getType();
+    double bandwidth = kDefaultBandwidth;
+    boolean canBeMetered = kDefaultCanBeMetered;
+
+    switch (type) {
+      case ConnectivityManager.TYPE_ETHERNET:
+      case ConnectivityManager.TYPE_WIFI:
+      case ConnectivityManager.TYPE_WIMAX:
+        bandwidth = kMaxBandwidth;
+        canBeMetered = false;
+        break;
+      case ConnectivityManager.TYPE_MOBILE:
+        bandwidth = Math.min(getMobileNetworkSpeed(getMobileNetworkType()), kMaxBandwidth);
+        canBeMetered = true;
+        break;
+      default:
+        Log.w("GeckoNetworkManager", "Ignoring the current network type.");
+        break;
+    }
+
+    return new double[] { bandwidth, canBeMetered ? 1.0 : 0.0 };
+  }
+}
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -118,16 +118,17 @@ FENNEC_JAVA_FILES = \
   gfx/TextLayer.java \
   gfx/TextureReaper.java \
   gfx/TileLayer.java \
   gfx/ViewportMetrics.java \
   gfx/WidgetTileLayer.java \
   ui/Axis.java \
   ui/PanZoomController.java \
   ui/SubdocumentScrollHelper.java \
+  GeckoNetworkManager.java \
   $(NULL)
 
 ifdef MOZ_WEBSMS_BACKEND
 FENNEC_JAVA_FILES += GeckoSmsManager.java
 endif
 
 FENNEC_PP_JAVA_FILES = \
   App.java \
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -171,16 +171,18 @@ AndroidBridge::Init(JNIEnv *jEnv,
     jSendMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "sendMessage", "(Ljava/lang/String;Ljava/lang/String;IJ)V");
     jSaveSentMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "saveSentMessage", "(Ljava/lang/String;Ljava/lang/String;J)I");
     jGetMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getMessage", "(IIJ)V");
     jDeleteMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "deleteMessage", "(IIJ)V");
     jCreateMessageList = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "createMessageList", "(JJ[Ljava/lang/String;IIZIJ)V");
     jGetNextMessageinList = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getNextMessageInList", "(IIJ)V");
     jClearMessageList = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "clearMessageList", "(I)V");
 
+    jGetCurrentNetworkInformation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getCurrentNetworkInformation", "()[D");
+
     jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
     jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10"));
     jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl"));
     jEGLContextImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLContextImpl"));
     jEGLConfigImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLConfigImpl"));
     jEGLDisplayImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLDisplayImpl"));
 
     InitAndroidJavaWrappers(jEnv);
@@ -1424,16 +1426,39 @@ AndroidBridge::GetNextMessageInList(PRIn
 void
 AndroidBridge::ClearMessageList(PRInt32 aListId)
 {
     ALOG_BRIDGE("AndroidBridge::ClearMessageList");
 
     JNI()->CallStaticVoidMethod(mGeckoAppShellClass, jClearMessageList, aListId);
 }
 
+void
+AndroidBridge::GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
+{
+    ALOG_BRIDGE("AndroidBridge::GetCurrentNetworkInformation");
+
+    AutoLocalJNIFrame jniFrame;
+
+    // To prevent calling too many methods through JNI, the Java method returns
+    // an array of double even if we actually want a double and a boolean.
+    jobject obj = mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentNetworkInformation);
+    jdoubleArray arr = static_cast<jdoubleArray>(obj);
+    if (!arr || mJNIEnv->GetArrayLength(arr) != 2) {
+        return;
+    }
+
+    jdouble* info = mJNIEnv->GetDoubleArrayElements(arr, 0);
+
+    aNetworkInfo->bandwidth() = info[0];
+    aNetworkInfo->canBeMetered() = info[1] == 1.0f;
+
+    mJNIEnv->ReleaseDoubleArrayElements(arr, info, 0);
+}
+
 void *
 AndroidBridge::LockBitmap(jobject bitmap)
 {
     int err;
     void *buf;
 
     if ((err = AndroidBitmap_lockPixels(JNI(), bitmap, &buf)) != 0) {
         ALOG_BRIDGE("AndroidBitmap_lockPixels failed! (error %d)", err);
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -61,16 +61,17 @@
 
 class nsWindow;
 class nsIDOMMozSmsMessage;
 
 namespace mozilla {
 
 namespace hal {
 class BatteryInformation;
+class NetworkInformation;
 } // namespace hal
 
 namespace dom {
 namespace sms {
 struct SmsFilterData;
 } // namespace sms
 } // namespace dom
 
@@ -346,16 +347,18 @@ public:
     void GetMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aProcessId);
     void DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aProcessId);
     void CreateMessageList(const dom::sms::SmsFilterData& aFilter, bool aReverse, PRInt32 aRequestId, PRUint64 aProcessId);
     void GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId, PRUint64 aProcessId);
     void ClearMessageList(PRInt32 aListId);
 
     bool IsTablet();
 
+    void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
+
 protected:
     static AndroidBridge *sBridge;
 
     // the global JavaVM
     JavaVM *mJavaVM;
 
     // the JNIEnv for the main thread
     JNIEnv *mJNIEnv;
@@ -440,16 +443,18 @@ protected:
     jmethodID jSendMessage;
     jmethodID jSaveSentMessage;
     jmethodID jGetMessage;
     jmethodID jDeleteMessage;
     jmethodID jCreateMessageList;
     jmethodID jGetNextMessageinList;
     jmethodID jClearMessageList;
 
+    jmethodID jGetCurrentNetworkInformation;
+
     // stuff we need for CallEglCreateWindowSurface
     jclass jEGLSurfaceImplClass;
     jclass jEGLContextImplClass;
     jclass jEGLConfigImplClass;
     jclass jEGLDisplayImplClass;
     jclass jEGLContextClass;
     jclass jEGL10Class;