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 85968 e652d673382fae155a88ef779b2fa3b4e16421f6
parent 85967 778597344568aa509f3731056fad9501307977a3
child 85969 b92399819ec4dc53371f336283ed58c21884b9bd
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdougt
bugs713687
milestone12.0a1
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;