diff --git a/framework/assets/js/network.js b/framework/assets/js/network.js index ccf5b120..b7e6bfea 100755 --- a/framework/assets/js/network.js +++ b/framework/assets/js/network.js @@ -59,9 +59,66 @@ Network.prototype.isReachable = function(uri, callback, options) { PhoneGap.exec(callback, null, "Network Status", "isReachable", [uri, isIpAddress]); }; +/** + * This class contains information about the current network Connection. + * @constructor + */ +Connection = function() { + this.type = null; + this.homeNW = null; + this.currentNW = null; + + var me = this; + this.getInfo( + function(info) { + me.type = info.type; + me.homeNW = info.homeNW; + me.currentNW = info.currentNW; + PhoneGap.onPhoneGapConnectionReady.fire(); + }, + function(e) { + console.log("Error initializing Network Connection: " + e); + }); +}; + +Connection.UNKNOWN = 0; +Connection.ETHERNET = 1; +Connection.WIFI = 2; +Connection.CELL_2G = 3; +Connection.CELL_3G = 4; +Connection.CELL_4G = 5; +Connection.NONE = 20; + +/** + * Get connection info + * + * @param {Function} successCallback The function to call when the Connection data is available + * @param {Function} errorCallback The function to call when there is an error getting the Connection data. (OPTIONAL) + */ +Connection.prototype.getInfo = function(successCallback, errorCallback) { + // successCallback required + if (typeof successCallback !== "function") { + console.log("Connection Error: successCallback is not a function"); + return; + } + + // errorCallback optional + if (errorCallback && (typeof errorCallback !== "function")) { + console.log("Connection Error: errorCallback is not a function"); + return; + } + + // Get info + PhoneGap.exec(successCallback, errorCallback, "Network Status", "getConnectionInfo", []); +}; + + PhoneGap.addConstructor(function() { if (typeof navigator.network === "undefined") { navigator.network = new Network(); } + if (typeof navigator.connection === "undefined") { + navigator.connection = new Connection(); + } }); }; diff --git a/framework/assets/js/phonegap.js.base b/framework/assets/js/phonegap.js.base index 2bcdbc52..8e2affb0 100755 --- a/framework/assets/js/phonegap.js.base +++ b/framework/assets/js/phonegap.js.base @@ -119,7 +119,7 @@ PhoneGap.Channel.prototype.subscribeOnce = function(f, c) { _this.unsubscribe(g); }; if (this.fired) { - if (typeof c === "object" && f instanceof Function) { f = PhoneGap.close(c, f); } + if (typeof c === "object" && f instanceof Function) { f = PhoneGap.close(c, f); } f.apply(this, this.fireArgs); } else { g = this.subscribe(m); @@ -257,6 +257,12 @@ PhoneGap.onPhoneGapReady = new PhoneGap.Channel('onPhoneGapReady'); */ PhoneGap.onPhoneGapInfoReady = new PhoneGap.Channel('onPhoneGapInfoReady'); +/** + * onPhoneGapConnectionReady channel is fired when the PhoneGap connection properties + * has been set. + */ +PhoneGap.onPhoneGapConnectionReady = new PhoneGap.Channel('onPhoneGapConnectionReady'); + /** * onResume channel is fired when the PhoneGap native code * resumes. @@ -293,7 +299,7 @@ PhoneGap.onDeviceReady = new PhoneGap.Channel('onDeviceReady'); // Array of channels that must fire before "deviceready" is fired -PhoneGap.deviceReadyChannelsArray = [ PhoneGap.onPhoneGapReady, PhoneGap.onPhoneGapInfoReady]; +PhoneGap.deviceReadyChannelsArray = [ PhoneGap.onPhoneGapReady, PhoneGap.onPhoneGapInfoReady, PhoneGap.onPhoneGapConnectionReady]; // Hashtable of user defined channels that must also fire before "deviceready" is fired PhoneGap.deviceReadyChannelsMap = {}; @@ -488,37 +494,37 @@ PhoneGap.stringify = function(args) { */ PhoneGap.clone = function(obj) { var i, retVal; - if(!obj) { - return obj; - } - - if(obj instanceof Array){ - retVal = []; - for(i = 0; i < obj.length; ++i){ - retVal.push(PhoneGap.clone(obj[i])); - } - return retVal; - } - - if (obj instanceof Function) { - return obj; - } - - if(!(obj instanceof Object)){ - return obj; - } - + if(!obj) { + return obj; + } + + if(obj instanceof Array){ + retVal = []; + for(i = 0; i < obj.length; ++i){ + retVal.push(PhoneGap.clone(obj[i])); + } + return retVal; + } + + if (obj instanceof Function) { + return obj; + } + + if(!(obj instanceof Object)){ + return obj; + } + if (obj instanceof Date) { return obj; } - retVal = {}; - for(i in obj){ - if(!(i in retVal) || retVal[i] !== obj[i]) { - retVal[i] = PhoneGap.clone(obj[i]); - } - } - return retVal; + retVal = {}; + for(i in obj){ + if(!(i in retVal) || retVal[i] !== obj[i]) { + retVal[i] = PhoneGap.clone(obj[i]); + } + } + return retVal; }; PhoneGap.callbackId = 0; diff --git a/framework/src/com/phonegap/NetworkManager.java b/framework/src/com/phonegap/NetworkManager.java index d7dfa6dc..779e1c71 100755 --- a/framework/src/com/phonegap/NetworkManager.java +++ b/framework/src/com/phonegap/NetworkManager.java @@ -3,7 +3,7 @@ * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text. * * Copyright (c) 2005-2010, Nitobi Software Inc. - * Copyright (c) 2010, IBM Corporation + * Copyright (c) 2010-2011, IBM Corporation */ package com.phonegap; @@ -11,21 +11,54 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONArray; import org.json.JSONException; +import org.json.JSONObject; import com.phonegap.api.PhonegapActivity; import com.phonegap.api.Plugin; import com.phonegap.api.PluginResult; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.net.*; +import android.telephony.TelephonyManager; +import android.util.Log; public class NetworkManager extends Plugin { public static int NOT_REACHABLE = 0; public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1; public static int REACHABLE_VIA_WIFI_NETWORK = 2; + + public static final String WIFI = "wifi"; + public static final String WIMAX = "wimax"; + // mobile + public static final String MOBILE = "mobile"; + // 2G network types + public static final String GSM = "gsm"; + public static final String GPRS = "gprs"; + public static final String EDGE = "edge"; + // 3G network types + public static final String CDMA = "cdma"; + public static final String UMTS = "umts"; + // 4G network types + public static final String LTE = "lte"; + public static final String UMB = "umb"; + // return types + public static final int TYPE_UNKNOWN = 0; + public static final int TYPE_ETHERNET = 1; + public static final int TYPE_WIFI = 2; + public static final int TYPE_2G = 3; + public static final int TYPE_3G = 4; + public static final int TYPE_4G = 5; + public static final int TYPE_NONE = 20; + private static final String LOG_TAG = "NetworkManager"; + private String connectionCallbackId; + ConnectivityManager sockMan; + TelephonyManager telephonyManager; /** * Constructor. @@ -41,7 +74,18 @@ public class NetworkManager extends Plugin { */ public void setContext(PhonegapActivity ctx) { super.setContext(ctx); - this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); + this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); + this.telephonyManager = ((TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE)); + + // We need to listen to connectivity events to update navigator.connection + IntentFilter intentFilter = new IntentFilter() ; + intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + ctx.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO)); + } + }, intentFilter); } /** @@ -68,6 +112,13 @@ public class NetworkManager extends Plugin { int i = this.isReachable(args.getString(0), args.getBoolean(1)); return new PluginResult(status, i); } + else if (action.equals("getConnectionInfo")) { + this.connectionCallbackId = callbackId; + NetworkInfo info = sockMan.getActiveNetworkInfo(); + PluginResult pluginResult = new PluginResult(status, this.getConnectionInfo(info)); + pluginResult.setKeepCallback(true); + return pluginResult; + } return new PluginResult(status, result); } catch (JSONException e) { return new PluginResult(PluginResult.Status.JSON_EXCEPTION); @@ -89,7 +140,107 @@ public class NetworkManager extends Plugin { // LOCAL METHODS //-------------------------------------------------------------------------- - /** + + /** + * Updates the JavaScript side whenever the connection changes + * + * @param info the current active network info + * @return + */ + private void updateConnectionInfo(NetworkInfo info) { + JSONObject connection = this.getConnectionInfo(info); + + // send update to javascript "navigator.connection" + sendUpdate(connection); + } + + /** + * Get the latest network connection information + * + * @param info the current active network info + * @return a JSONObject that represents the network info + */ + private JSONObject getConnectionInfo(NetworkInfo info) { + JSONObject connection = new JSONObject(); + + try { + if (info != null) { + // If we are not connected to any network set type to none + if (!info.isConnected()) { + connection.put("type", TYPE_NONE); + connection.put("homeNW", null); + connection.put("currentNW", null); + } + else { + // If we are connected check which type + // First off is wifi + if (info.getTypeName().toLowerCase().equals(WIFI)) { + connection.put("type", TYPE_WIFI); + connection.put("homeNW", null); + connection.put("currentNW", null); + } + // Otherwise it must be one of the mobile network protocols + else { + // Determine the correct type, 2G, 3G, 4G + connection.put("type", getType(info)); + connection.put("homeNW", telephonyManager.getSimOperatorName()); + connection.put("currentNW", telephonyManager.getNetworkOperatorName()); + } + } + } + } + catch (JSONException e) { + // this should never happen + Log.e(LOG_TAG, e.getMessage(), e); + } + return connection; + } + + /** + * Create a new plugin result and send it back to JavaScript + * + * @param connection the network info to set as navigator.connection + */ + private void sendUpdate(JSONObject connection) { + PluginResult result = new PluginResult(PluginResult.Status.OK, connection); + result.setKeepCallback(true); + this.success(result, this.connectionCallbackId); + } + + /** + * Determine the type of connection + * + * @param info the network info so we can determine connection type. + * @return the type of mobile network we are on + */ + private int getType(NetworkInfo info) { + if (info != null) { + String type = info.getTypeName(); + + if (type.toLowerCase().equals(MOBILE)) { + type = info.getSubtypeName(); + if (type.toLowerCase().equals(GSM) || + type.toLowerCase().equals(GPRS) || + type.toLowerCase().equals(EDGE)) { + return TYPE_2G; + } + else if (type.toLowerCase().equals(CDMA) || + type.toLowerCase().equals(UMTS)) { + return TYPE_3G; + } + else if (type.toLowerCase().equals(LTE) || + type.toLowerCase().equals(UMB)) { + return TYPE_4G; + } + } + } + else { + return TYPE_NONE; + } + return TYPE_UNKNOWN; + } + + /** * Determine if a network connection exists. * * @return @@ -150,4 +301,4 @@ public class NetworkManager extends Plugin { return reachable; } -} +} \ No newline at end of file