/* -*- 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 (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.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; 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 extends BroadcastReceiver { static private final GeckoNetworkManager sInstance = new 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 kNetworkSpeedEthernet = 20.0; // 20 Mb/s static private final double kNetworkSpeedWifi = 20.0; // 20 Mb/s static private final double kNetworkSpeedWiMax = 40.0; // 40 Mb/s 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 NetworkType { NETWORK_NONE, NETWORK_ETHERNET, NETWORK_WIFI, NETWORK_WIMAX, 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 NetworkType mNetworkType = NetworkType.NETWORK_NONE; private IntentFilter mNetworkFilter = new IntentFilter(); // Whether the manager should be listening to Network Information changes. private boolean mShouldBeListening = false; // Whether the manager should notify Gecko that a change in Network // Information happened. private boolean mShouldNotify = false; public static GeckoNetworkManager getInstance() { return sInstance; } @Override public void onReceive(Context aContext, Intent aIntent) { updateNetworkType(); } public void init() { mNetworkFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mNetworkType = getNetworkType(); } public void start() { mShouldBeListening = true; updateNetworkType(); if (mShouldNotify) { startListening(); } } private void startListening() { GeckoApp.mAppContext.registerReceiver(sInstance, mNetworkFilter); } public void stop() { mShouldBeListening = false; if (mShouldNotify) { stopListening(); } } private void stopListening() { GeckoApp.mAppContext.unregisterReceiver(sInstance); } private void updateNetworkType() { NetworkType previousNetworkType = mNetworkType; mNetworkType = getNetworkType(); if (mNetworkType == previousNetworkType || !mShouldNotify) { return; } GeckoAppShell.sendEventToGecko(new GeckoEvent(getNetworkSpeed(mNetworkType), isNetworkUsuallyMetered(mNetworkType))); } public double[] getCurrentInformation() { return new double[] { getNetworkSpeed(mNetworkType), isNetworkUsuallyMetered(mNetworkType) ? 1.0 : 0.0 }; } public void enableNotifications() { // We set mShouldNotify *after* calling updateNetworkType() to make sure we // don't notify an eventual change in mNetworkType. updateNetworkType(); mShouldNotify = true; if (mShouldBeListening) { startListening(); } } public void disableNotifications() { mShouldNotify = false; if (mShouldBeListening) { stopListening(); } } private static NetworkType getNetworkType() { ConnectivityManager cm = (ConnectivityManager)GeckoApp.mAppContext.getSystemService(Context.CONNECTIVITY_SERVICE); if (cm.getActiveNetworkInfo() == null) { return NetworkType.NETWORK_NONE; } switch (cm.getActiveNetworkInfo().getType()) { case ConnectivityManager.TYPE_ETHERNET: return NetworkType.NETWORK_ETHERNET; case ConnectivityManager.TYPE_WIFI: return NetworkType.NETWORK_WIFI; case ConnectivityManager.TYPE_WIMAX: return NetworkType.NETWORK_WIMAX; case ConnectivityManager.TYPE_MOBILE: break; // We will handle sub-types after the switch. default: Log.w("GeckoNetworkManager", "Ignoring the current network type."); return NetworkType.NETWORK_UNKNOWN; } TelephonyManager tm = (TelephonyManager)GeckoApp.mAppContext.getSystemService(Context.TELEPHONY_SERVICE); switch (tm.getNetworkType()) { case TelephonyManager.NETWORK_TYPE_IDEN: case TelephonyManager.NETWORK_TYPE_CDMA: return NetworkType.NETWORK_2_G; case TelephonyManager.NETWORK_TYPE_GPRS: case TelephonyManager.NETWORK_TYPE_1xRTT: return NetworkType.NETWORK_2_5_G; case TelephonyManager.NETWORK_TYPE_EDGE: return NetworkType.NETWORK_2_75_G; case TelephonyManager.NETWORK_TYPE_UMTS: case TelephonyManager.NETWORK_TYPE_EVDO_0: return NetworkType.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 NetworkType.NETWORK_3_5_G; case TelephonyManager.NETWORK_TYPE_HSPAP: return NetworkType.NETWORK_3_75_G; case TelephonyManager.NETWORK_TYPE_LTE: return NetworkType.NETWORK_3_9_G; case TelephonyManager.NETWORK_TYPE_UNKNOWN: default: Log.w("GeckoNetworkManager", "Connected to an unknown mobile network!"); return NetworkType.NETWORK_UNKNOWN; } } private static double getNetworkSpeed(NetworkType aType) { switch (aType) { case NETWORK_NONE: return 0.0; case NETWORK_ETHERNET: return kNetworkSpeedEthernet; case NETWORK_WIFI: return kNetworkSpeedWifi; case NETWORK_WIMAX: return kNetworkSpeedWiMax; 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; } } private static boolean isNetworkUsuallyMetered(NetworkType aType) { switch (aType) { case NETWORK_NONE: case NETWORK_UNKNOWN: case NETWORK_ETHERNET: case NETWORK_WIFI: case NETWORK_WIMAX: return false; case NETWORK_2_G: case NETWORK_2_5_G: case NETWORK_2_75_G: case NETWORK_3_G: case NETWORK_3_5_G: case NETWORK_3_75_G: case NETWORK_3_9_G: return true; default: Log.e("GeckoNetworkManager", "Got an unexpected network type!"); return false; } } }