From 992ee0bca4e8a6485e5a4c5e2a0c106f6196072b Mon Sep 17 00:00:00 2001 From: macdonst Date: Wed, 1 Jun 2011 02:54:18 +0800 Subject: [PATCH 01/20] Issue #80: Unable to open large json files on android 2.2 + phonegap 0.9.5 I could not get rid of the url encoding and decoding without hampering some users ability to pass non-ascii characters back to JavaScript. However, I was able to reduce the amount of data being passed from Java to JavaScript by 40% by decoding common characters that occur in JSON and XML. These characters will survive the round trip just fine and don't need to be encoded. This is the best solution I could come up with. You won't be able to read files as large as you could in 0.9.4 but it will get close and it will support non-ascii characters. --- framework/assets/js/phonegap.js.base | 4 +- .../src/com/phonegap/CallbackServer.java | 46 ++++++++++++++++++- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/framework/assets/js/phonegap.js.base b/framework/assets/js/phonegap.js.base index 068b46e5..5d06bf99 100755 --- a/framework/assets/js/phonegap.js.base +++ b/framework/assets/js/phonegap.js.base @@ -767,8 +767,8 @@ PhoneGap.JSCallback = function() { // If callback has JavaScript statement to execute if (xmlhttp.status === 200) { - // Need to url decode the response and replace %20 with a space - var msg = decodeURIComponent(xmlhttp.responseText.replace(/\+/g, '%20')); + // Need to url decode the response + var msg = decodeURIComponent(xmlhttp.responseText); setTimeout(function() { try { var t = eval(msg); diff --git a/framework/src/com/phonegap/CallbackServer.java b/framework/src/com/phonegap/CallbackServer.java index 859ac40a..66c282ec 100755 --- a/framework/src/com/phonegap/CallbackServer.java +++ b/framework/src/com/phonegap/CallbackServer.java @@ -11,11 +11,14 @@ import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; import java.net.ServerSocket; import java.net.Socket; import java.net.URLEncoder; import java.util.LinkedList; +import android.util.Log; + /** * This class provides a way for Java to run JavaScript in the web page that has loaded PhoneGap. * The CallbackServer class implements an XHR server and a polling server with a list of JavaScript @@ -42,6 +45,8 @@ import java.util.LinkedList; */ public class CallbackServer implements Runnable { + private static final String LOG_TAG = "CallbackServer"; + /** * The list of JavaScript statements to be sent to JavaScript. */ @@ -224,8 +229,9 @@ public class CallbackServer implements Runnable { //System.out.println("CallbackServer -- sending item"); response = "HTTP/1.1 200 OK\r\n\r\n"; String js = this.getJavascript(); - if (js != null) - response += URLEncoder.encode(js, "UTF-8"); + if (js != null) { + response += encode(js); + } } } else { @@ -321,4 +327,40 @@ public class CallbackServer implements Runnable { } } + /** + * This will encode the return value to JavaScript. We revert the encoding for + * common characters that don't require encoding to reduce the size of the string + * being passed to JavaScript. + * + * @param value to be encoded + * @return encoded string + */ + public static String encode(String value) { + String encoded = null; + try { + encoded = URLEncoder.encode(value, "UTF-8") + .replaceAll("\\+", " ") + .replaceAll("\\%21", "!") + .replaceAll("\\%22", "\"") + .replaceAll("\\%27", "'") + .replaceAll("\\%28", "(") + .replaceAll("\\%29", ")") + .replaceAll("\\%2C", ",") + .replaceAll("\\%3C", "<") + .replaceAll("\\%3D", "=") + .replaceAll("\\%3E", ">") + .replaceAll("\\%3F", "?") + .replaceAll("\\%40", "@") + .replaceAll("\\%5B", "[") + .replaceAll("\\%5D", "]") + .replaceAll("\\%7B", "{") + .replaceAll("\\%7D", "}") + .replaceAll("\\%3A", ":") + .replaceAll("\\%7E", "~"); + } catch (UnsupportedEncodingException e) { + Log.e(LOG_TAG, e.getMessage(), e); + } + return encoded; + } + } From 7d41646a35b6c50ac2584a9ea2ea8c7e67a4e008 Mon Sep 17 00:00:00 2001 From: macdonst Date: Thu, 2 Jun 2011 01:46:27 +0800 Subject: [PATCH 02/20] Improve performance of our encoding Move from using String.replaceAll() to a modified version or URLEncoder.encode(). --- .../src/com/phonegap/CallbackServer.java | 113 ++++++++++++------ 1 file changed, 77 insertions(+), 36 deletions(-) diff --git a/framework/src/com/phonegap/CallbackServer.java b/framework/src/com/phonegap/CallbackServer.java index 66c282ec..2c2a9c84 100755 --- a/framework/src/com/phonegap/CallbackServer.java +++ b/framework/src/com/phonegap/CallbackServer.java @@ -230,7 +230,7 @@ public class CallbackServer implements Runnable { response = "HTTP/1.1 200 OK\r\n\r\n"; String js = this.getJavascript(); if (js != null) { - response += encode(js); + response += encode(js, "UTF-8"); } } } @@ -327,40 +327,81 @@ public class CallbackServer implements Runnable { } } - /** - * This will encode the return value to JavaScript. We revert the encoding for - * common characters that don't require encoding to reduce the size of the string - * being passed to JavaScript. - * - * @param value to be encoded - * @return encoded string - */ - public static String encode(String value) { - String encoded = null; - try { - encoded = URLEncoder.encode(value, "UTF-8") - .replaceAll("\\+", " ") - .replaceAll("\\%21", "!") - .replaceAll("\\%22", "\"") - .replaceAll("\\%27", "'") - .replaceAll("\\%28", "(") - .replaceAll("\\%29", ")") - .replaceAll("\\%2C", ",") - .replaceAll("\\%3C", "<") - .replaceAll("\\%3D", "=") - .replaceAll("\\%3E", ">") - .replaceAll("\\%3F", "?") - .replaceAll("\\%40", "@") - .replaceAll("\\%5B", "[") - .replaceAll("\\%5D", "]") - .replaceAll("\\%7B", "{") - .replaceAll("\\%7D", "}") - .replaceAll("\\%3A", ":") - .replaceAll("\\%7E", "~"); - } catch (UnsupportedEncodingException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - return encoded; - } + /* The Following code has been modified from original implementation of URLEncoder */ + /* start */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + static final String digits = "0123456789ABCDEF"; + + /** + * This will encode the return value to JavaScript. We revert the encoding for + * common characters that don't require encoding to reduce the size of the string + * being passed to JavaScript. + * + * @param s to be encoded + * @param enc encoding type + * @return encoded string + */ + public static String encode(String s, String enc) throws UnsupportedEncodingException { + if (s == null || enc == null) { + throw new NullPointerException(); + } + // check for UnsupportedEncodingException + "".getBytes(enc); + + // Guess a bit bigger for encoded form + StringBuilder buf = new StringBuilder(s.length() + 16); + int start = -1; + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') + || (ch >= '0' && ch <= '9') + || " .-*_'(),<>=?@[]{}:~\"\\/;!".indexOf(ch) > -1) { + if (start >= 0) { + convert(s.substring(start, i), buf, enc); + start = -1; + } + if (ch != ' ') { + buf.append(ch); + } else { + buf.append(' '); + } + } else { + if (start < 0) { + start = i; + } + } + } + if (start >= 0) { + convert(s.substring(start, s.length()), buf, enc); + } + return buf.toString(); + } + + private static void convert(String s, StringBuilder buf, String enc) throws UnsupportedEncodingException { + byte[] bytes = s.getBytes(enc); + for (int j = 0; j < bytes.length; j++) { + buf.append('%'); + buf.append(digits.charAt((bytes[j] & 0xf0) >> 4)); + buf.append(digits.charAt(bytes[j] & 0xf)); + } + } + + /* end */ } From 8d1722ad67cccc9957bb63bf12b2ac04a70c97b3 Mon Sep 17 00:00:00 2001 From: Nitobi Date: Fri, 3 Jun 2011 10:59:48 -0700 Subject: [PATCH 03/20] Fixed droidgap update command --- lib/update.rb | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/update.rb b/lib/update.rb index aa1459a1..23e57a70 100755 --- a/lib/update.rb +++ b/lib/update.rb @@ -33,12 +33,19 @@ class Update # TODO need to allow for www import inc icon def copy_libs puts "Copying over libraries and assets..." - - FileUtils.mkdir_p File.join(@path, "libs") - FileUtils.cp File.join(@framework_dir, "phonegap.jar"), File.join(@path, "libs") + version = IO.read(File.join(@framework_dir, '../VERSION')) - FileUtils.mkdir_p File.join(@path, "assets", "www") - FileUtils.cp File.join(@framework_dir, "assets", "www", "phonegap.js"), File.join(@path, "assets", "www") + FileUtils.cp File.join(@framework_dir, "phonegap.#{ version }.jar"), File.join(@path, "libs") + + # concat JS and put into www folder. this can be overridden in the config.xml via @app_js_dir + js_dir = File.join(@framework_dir, "assets", "js") + phonegapjs = IO.read(File.join(js_dir, 'phonegap.js.base')) + Dir.new(js_dir).entries.each do |script| + next if script[0].chr == "." or script == "phonegap.js.base" + phonegapjs << IO.read(File.join(js_dir, script)) + phonegapjs << "\n\n" + end + File.open(File.join(@path, "assets", "www", "phonegap.#{ version }.js"), 'w') {|f| f.write(phonegapjs) } end # end \ No newline at end of file From 3ce0fc4897901c172ffc7a9055708d29d96905e8 Mon Sep 17 00:00:00 2001 From: macdonst Date: Fri, 3 Jun 2011 01:11:51 +0800 Subject: [PATCH 04/20] Updating Connection object to conform with recently released spec - Replacing currentNW and homeNW with networkName. - Changing Connection constants to strings instead of ints. - Firing online/offline events on network change. --- framework/AndroidManifest.xml | 3 + framework/assets/js/network.js | 49 +++++++++++---- .../src/com/phonegap/NetworkManager.java | 59 +++++++++++-------- 3 files changed, 73 insertions(+), 38 deletions(-) diff --git a/framework/AndroidManifest.xml b/framework/AndroidManifest.xml index ea2a6636..2807d65b 100644 --- a/framework/AndroidManifest.xml +++ b/framework/AndroidManifest.xml @@ -14,15 +14,18 @@ + + + diff --git a/framework/assets/js/network.js b/framework/assets/js/network.js index 2e092f23..d93c95ba 100755 --- a/framework/assets/js/network.js +++ b/framework/assets/js/network.js @@ -65,29 +65,52 @@ Network.prototype.isReachable = function(uri, callback, options) { */ var Connection = function() { this.type = null; - this.homeNW = null; - this.currentNW = null; + this.networkName = null; + this._firstRun = true; + this._timer = null; + this.timeout = 500; var me = this; this.getInfo( function(info) { - me.type = info.type; - me.homeNW = info.homeNW; - me.currentNW = info.currentNW; - PhoneGap.onPhoneGapConnectionReady.fire(); + // Need to send events if we are on or offline + if (info.type == "none") { + // set a timer if still offline at the end of timer send the offline event + me._timer = setTimeout(function(){ + me.type = info.type; + me.networkName = info.networkName; + PhoneGap.fireEvent('offline'); + me._timer = null; + }, me.timeout); + } else { + // If there is a current offline event pending clear it + if (me._timer != null) { + clearTimeout(me._timer); + me._timer = null; + } + me.type = info.type; + me.networkName = info.networkName; + PhoneGap.fireEvent('online'); + } + + // should only fire this once + if (me._firstRun) { + me._firstRun = false; + 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; +Connection.UNKNOWN = "unknown"; +Connection.ETHERNET = "ethernet"; +Connection.WIFI = "wifi"; +Connection.CELL_2G = "2g"; +Connection.CELL_3G = "3g"; +Connection.CELL_4G = "4g"; +Connection.NONE = "none"; /** * Get connection info diff --git a/framework/src/com/phonegap/NetworkManager.java b/framework/src/com/phonegap/NetworkManager.java index 0a2fdb1b..f05d089c 100755 --- a/framework/src/com/phonegap/NetworkManager.java +++ b/framework/src/com/phonegap/NetworkManager.java @@ -22,12 +22,14 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.*; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; import android.telephony.TelephonyManager; import android.util.Log; public class NetworkManager extends Plugin { - public static int NOT_REACHABLE = 0; + public static int NOT_REACHABLE = 0; public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1; public static int REACHABLE_VIA_WIFI_NETWORK = 2; @@ -46,19 +48,23 @@ public class NetworkManager extends Plugin { 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; + public static final String TYPE_UNKNOWN = "unknown"; + public static final String TYPE_ETHERNET = "ethernet"; + public static final String TYPE_WIFI = "wifi"; + public static final String TYPE_2G = "2g"; + public static final String TYPE_3G = "3g"; + public static final String TYPE_4G = "4g"; + public static final String TYPE_NONE = "none"; private static final String LOG_TAG = "NetworkManager"; + private static final String NETWORK_NAME = "networkName"; + private static final String TYPE = "type"; + private String connectionCallbackId; ConnectivityManager sockMan; TelephonyManager telephonyManager; + WifiManager wifiManager; BroadcastReceiver receiver; /** @@ -78,8 +84,9 @@ public class NetworkManager extends Plugin { super.setContext(ctx); this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); this.telephonyManager = ((TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE)); + this.wifiManager = ((WifiManager) ctx.getSystemService(Context.WIFI_SERVICE)); this.connectionCallbackId = null; - + // We need to listen to connectivity events to update navigator.connection IntentFilter intentFilter = new IntentFilter() ; intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); @@ -151,7 +158,7 @@ public class NetworkManager extends Plugin { try { this.ctx.unregisterReceiver(this.receiver); } catch (Exception e) { - System.out.println("Error unregistering network receiver: " + e.getMessage()); + Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e); } } } @@ -167,11 +174,11 @@ public class NetworkManager extends Plugin { * @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); + private void updateConnectionInfo(NetworkInfo info) { + JSONObject connection = this.getConnectionInfo(info); + + // send update to javascript "navigator.network.connection" + sendUpdate(connection); } /** @@ -187,24 +194,26 @@ public class NetworkManager extends Plugin { 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); + connection.put(TYPE, TYPE_NONE); + connection.put(NETWORK_NAME, 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); + connection.put(TYPE, TYPE_WIFI); + WifiInfo wifiInfo = this.wifiManager.getConnectionInfo(); + if (wifiInfo != null) { + connection.put(NETWORK_NAME, wifiInfo.getSSID()); + } else { + connection.put(NETWORK_NAME, 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()); + connection.put(TYPE, getType(info)); + connection.put(NETWORK_NAME, telephonyManager.getNetworkOperatorName()); } } } @@ -233,7 +242,7 @@ public class NetworkManager extends Plugin { * @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) { + private String getType(NetworkInfo info) { if (info != null) { String type = info.getTypeName(); From 740e50ce61ef2445841f5e45f4d14e753a78e144 Mon Sep 17 00:00:00 2001 From: macdonst Date: Tue, 7 Jun 2011 02:37:29 +0800 Subject: [PATCH 05/20] Issue #104: Bug in FileUtils.copyDirectory & moveDirectory Adding better test to see if a directory is being moved/copied into itself. Copy /sdcard/myDir to /sdcard/myDir-backup is okay but Copy /sdcard/myDir to /sdcard/myDir/backup should thow an INVALID_MODIFICATION_ERR --- framework/src/com/phonegap/FileUtils.java | 26 ++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/framework/src/com/phonegap/FileUtils.java b/framework/src/com/phonegap/FileUtils.java index a2ed7a11..a53884ef 100755 --- a/framework/src/com/phonegap/FileUtils.java +++ b/framework/src/com/phonegap/FileUtils.java @@ -411,7 +411,7 @@ public class FileUtils extends Plugin { } // Check to make sure we are not copying the directory into itself - if (destinationDir.getAbsolutePath().startsWith(srcDir.getAbsolutePath())) { + if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) { throw new InvalidModificationException("Can't copy itself into itself"); } @@ -435,6 +435,26 @@ public class FileUtils extends Plugin { return getEntry(destinationDir); } + /** + * Check to see if the user attempted to copy an entry into its parent without changing its name, + * or attempted to copy a directory into a directory that it contains directly or indirectly. + * + * @param srcDir + * @param destinationDir + * @return + */ + private boolean isCopyOnItself(String src, String dest) { + + // This weird test is to determine if we are copying or moving a directory into itself. + // Copy /sdcard/myDir to /sdcard/myDir-backup is okay but + // Copy /sdcard/myDir to /sdcard/myDir/backup should thow an INVALID_MODIFICATION_ERR + if (dest.startsWith(src) && dest.indexOf(File.separator, src.length()-1) != -1) { + return true; + } + + return false; + } + /** * Move a file * @@ -480,8 +500,8 @@ public class FileUtils extends Plugin { } // Check to make sure we are not copying the directory into itself - if (destinationDir.getAbsolutePath().startsWith(srcDir.getAbsolutePath())) { - throw new InvalidModificationException("Can't copy itself into itself"); + if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) { + throw new InvalidModificationException("Can't move itself into itself"); } // If the destination directory already exists and is empty then delete it. This is according to spec. From 8da5ad8eca7876bdc2019be8d53626a9a9281fa2 Mon Sep 17 00:00:00 2001 From: macdonst Date: Tue, 7 Jun 2011 22:03:16 +0800 Subject: [PATCH 06/20] Issue #106: Typo in LocalFileSystem.prototype._castDate --- framework/assets/js/file.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/assets/js/file.js b/framework/assets/js/file.js index d2f21cd3..11229b35 100755 --- a/framework/assets/js/file.js +++ b/framework/assets/js/file.js @@ -1044,7 +1044,7 @@ LocalFileSystem.prototype._castDate = function(pluginResult) { file.type = pluginResult.message.type; file.name = pluginResult.message.name; file.fullPath = pluginResult.message.fullPath; - file.lastModifedDate = new Date(pluginResult.message.lastModifiedDate); + file.lastModifiedDate = new Date(pluginResult.message.lastModifiedDate); pluginResult.message = file; } return pluginResult; From 315b5a59b3d1dc74de29bbd3b4122e0a7c577548 Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Tue, 7 Jun 2011 14:18:18 -0500 Subject: [PATCH 07/20] Set PhoneGap.UsePolling flag based upon result from CallbackServer. --- framework/assets/js/phonegap.js.base | 3 +++ 1 file changed, 3 insertions(+) diff --git a/framework/assets/js/phonegap.js.base b/framework/assets/js/phonegap.js.base index 5d06bf99..e48fbf55 100755 --- a/framework/assets/js/phonegap.js.base +++ b/framework/assets/js/phonegap.js.base @@ -344,10 +344,13 @@ PhoneGap.Channel.join(function() { } else { var polling = prompt("usePolling", "gap_callbackServer:"); + PhoneGap.UsePolling = polling; if (polling == "true") { + PhoneGap.UsePolling = true; PhoneGap.JSCallbackPolling(); } else { + PhoneGap.UsePolling = false; PhoneGap.JSCallback(); } } From a67aeed5711fbd5ec6571d1d515a2221060f7ff8 Mon Sep 17 00:00:00 2001 From: macdonst Date: Thu, 9 Jun 2011 03:03:03 +0800 Subject: [PATCH 08/20] Updating Network Connection API to match spec released on June 7th --- framework/AndroidManifest.xml | 2 - framework/assets/js/network.js | 11 ++- framework/src/com/phonegap/Device.java | 32 ++------- .../src/com/phonegap/NetworkManager.java | 70 +++++-------------- 4 files changed, 27 insertions(+), 88 deletions(-) diff --git a/framework/AndroidManifest.xml b/framework/AndroidManifest.xml index 2807d65b..53d7afb5 100644 --- a/framework/AndroidManifest.xml +++ b/framework/AndroidManifest.xml @@ -14,8 +14,6 @@ - - diff --git a/framework/assets/js/network.js b/framework/assets/js/network.js index d93c95ba..be94402b 100755 --- a/framework/assets/js/network.js +++ b/framework/assets/js/network.js @@ -65,20 +65,18 @@ Network.prototype.isReachable = function(uri, callback, options) { */ var Connection = function() { this.type = null; - this.networkName = null; this._firstRun = true; this._timer = null; this.timeout = 500; var me = this; this.getInfo( - function(info) { + function(type) { // Need to send events if we are on or offline - if (info.type == "none") { + if (type == "none") { // set a timer if still offline at the end of timer send the offline event me._timer = setTimeout(function(){ - me.type = info.type; - me.networkName = info.networkName; + me.type = type; PhoneGap.fireEvent('offline'); me._timer = null; }, me.timeout); @@ -88,8 +86,7 @@ var Connection = function() { clearTimeout(me._timer); me._timer = null; } - me.type = info.type; - me.networkName = info.networkName; + me.type = type; PhoneGap.fireEvent('online'); } diff --git a/framework/src/com/phonegap/Device.java b/framework/src/com/phonegap/Device.java index ac0a8ecc..035058fe 100755 --- a/framework/src/com/phonegap/Device.java +++ b/framework/src/com/phonegap/Device.java @@ -14,9 +14,7 @@ import org.json.JSONObject; import com.phonegap.api.PhonegapActivity; import com.phonegap.api.Plugin; import com.phonegap.api.PluginResult; -import android.content.Context; import android.provider.Settings; -import android.telephony.TelephonyManager; public class Device extends Plugin { @@ -116,34 +114,13 @@ public class Device extends Plugin { public String getPhonegapVersion() { return Device.phonegapVersion; } - - public String getLine1Number(){ - TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE); - return operator.getLine1Number(); - } - public String getDeviceId(){ - TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE); - return operator.getDeviceId(); - } - - public String getSimSerialNumber(){ - TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE); - return operator.getSimSerialNumber(); - } - - public String getSubscriberId(){ - TelephonyManager operator = (TelephonyManager)this.ctx.getSystemService(Context.TELEPHONY_SERVICE); - return operator.getSubscriberId(); - } - - public String getModel() - { + public String getModel() { String model = android.os.Build.MODEL; return model; } - public String getProductName() - { + + public String getProductName() { String productname = android.os.Build.PRODUCT; return productname; } @@ -158,8 +135,7 @@ public class Device extends Plugin { return osversion; } - public String getSDKVersion() - { + public String getSDKVersion() { String sdkversion = android.os.Build.VERSION.SDK; return sdkversion; } diff --git a/framework/src/com/phonegap/NetworkManager.java b/framework/src/com/phonegap/NetworkManager.java index f05d089c..c2b756bc 100755 --- a/framework/src/com/phonegap/NetworkManager.java +++ b/framework/src/com/phonegap/NetworkManager.java @@ -11,7 +11,6 @@ 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; @@ -21,10 +20,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.net.*; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.telephony.TelephonyManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.util.Log; public class NetworkManager extends Plugin { @@ -57,14 +54,10 @@ public class NetworkManager extends Plugin { public static final String TYPE_NONE = "none"; private static final String LOG_TAG = "NetworkManager"; - private static final String NETWORK_NAME = "networkName"; - private static final String TYPE = "type"; private String connectionCallbackId; ConnectivityManager sockMan; - TelephonyManager telephonyManager; - WifiManager wifiManager; BroadcastReceiver receiver; /** @@ -83,8 +76,6 @@ public class NetworkManager extends Plugin { public void setContext(PhonegapActivity ctx) { super.setContext(ctx); this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); - this.telephonyManager = ((TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE)); - this.wifiManager = ((WifiManager) ctx.getSystemService(Context.WIFI_SERVICE)); this.connectionCallbackId = null; // We need to listen to connectivity events to update navigator.connection @@ -175,10 +166,8 @@ public class NetworkManager extends Plugin { * @return */ private void updateConnectionInfo(NetworkInfo info) { - JSONObject connection = this.getConnectionInfo(info); - // send update to javascript "navigator.network.connection" - sendUpdate(connection); + sendUpdate(this.getConnectionInfo(info)); } /** @@ -187,42 +176,18 @@ public class NetworkManager extends Plugin { * @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(NETWORK_NAME, null); - } - else { - // If we are connected check which type - // First off is wifi - if (info.getTypeName().toLowerCase().equals(WIFI)) { - connection.put(TYPE, TYPE_WIFI); - WifiInfo wifiInfo = this.wifiManager.getConnectionInfo(); - if (wifiInfo != null) { - connection.put(NETWORK_NAME, wifiInfo.getSSID()); - } else { - connection.put(NETWORK_NAME, 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(NETWORK_NAME, telephonyManager.getNetworkOperatorName()); - } - } + private String getConnectionInfo(NetworkInfo info) { + String type = TYPE_NONE; + if (info != null) { + // If we are not connected to any network set type to none + if (!info.isConnected()) { + type = TYPE_NONE; + } + else { + type = getType(info); } } - catch (JSONException e) { - // this should never happen - Log.e(LOG_TAG, e.getMessage(), e); - } - return connection; + return type; } /** @@ -230,8 +195,8 @@ public class NetworkManager extends Plugin { * * @param connection the network info to set as navigator.connection */ - private void sendUpdate(JSONObject connection) { - PluginResult result = new PluginResult(PluginResult.Status.OK, connection); + private void sendUpdate(String type) { + PluginResult result = new PluginResult(PluginResult.Status.OK, type); result.setKeepCallback(true); this.success(result, this.connectionCallbackId); } @@ -246,7 +211,10 @@ public class NetworkManager extends Plugin { if (info != null) { String type = info.getTypeName(); - if (type.toLowerCase().equals(MOBILE)) { + if (type.toLowerCase().equals(WIFI)) { + return TYPE_WIFI; + } + else if (type.toLowerCase().equals(MOBILE)) { type = info.getSubtypeName(); if (type.toLowerCase().equals(GSM) || type.toLowerCase().equals(GPRS) || From a89c8bf482cf5f5e5d75358f317203f5bd266d36 Mon Sep 17 00:00:00 2001 From: Benjamin Weingarten Date: Sun, 12 Jun 2011 12:24:25 +0300 Subject: [PATCH 09/20] Fix bug where isreachable doesn't return correct results for https (http secure) url protocol. --- framework/src/com/phonegap/NetworkManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/com/phonegap/NetworkManager.java b/framework/src/com/phonegap/NetworkManager.java index c2b756bc..62140f31 100755 --- a/framework/src/com/phonegap/NetworkManager.java +++ b/framework/src/com/phonegap/NetworkManager.java @@ -275,7 +275,7 @@ public class NetworkManager extends Plugin { public int isReachable(String uri, boolean isIpAddress) { int reachable = NOT_REACHABLE; - if (uri.indexOf("http://") == -1) { + if (uri.indexOf("http://") == -1 && uri.indexOf("https://") == -1) { uri = "http://" + uri; } @@ -298,4 +298,4 @@ public class NetworkManager extends Plugin { return reachable; } -} \ No newline at end of file +} From 33bfb44f670bad34e0b552dc119809733f9eb807 Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Mon, 13 Jun 2011 15:16:08 -0500 Subject: [PATCH 10/20] Fix security vulnerability - make sure any requests to run native code only come from url currently loaded into webview. --- framework/src/com/phonegap/DroidGap.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index fae84535..7dc2aed0 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -779,10 +779,14 @@ public class DroidGap extends PhonegapActivity { */ @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { + boolean reqOk = false; + if (((DroidGap)(this.ctx)).url.equals(url)) { + reqOk = true; + } // Calling PluginManager.exec() to call a native service using // prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true])); - if (defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) { + if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) { JSONArray array; try { array = new JSONArray(defaultValue.substring(4)); @@ -798,13 +802,13 @@ public class DroidGap extends PhonegapActivity { } // Polling for JavaScript messages - else if (defaultValue.equals("gap_poll:")) { + else if (reqOk && defaultValue.equals("gap_poll:")) { String r = callbackServer.getJavascript(); result.confirm(r); } // Calling into CallbackServer - else if (defaultValue.equals("gap_callbackServer:")) { + else if (reqOk && defaultValue.equals("gap_callbackServer:")) { String r = ""; if (message.equals("usePolling")) { r = ""+callbackServer.usePolling(); From d1448e90732fa95ba4840d2d4e917f917e69853f Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Wed, 15 Jun 2011 13:01:03 -0500 Subject: [PATCH 11/20] Issue 112: PhoneGap.Channel: replace instanceof Function with typeof === 'Function' --- framework/assets/js/phonegap.js.base | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/framework/assets/js/phonegap.js.base b/framework/assets/js/phonegap.js.base index e48fbf55..4f26fd8d 100755 --- a/framework/assets/js/phonegap.js.base +++ b/framework/assets/js/phonegap.js.base @@ -99,7 +99,7 @@ PhoneGap.Channel.prototype.subscribe = function(f, c, g) { if (f === null) { return; } var func = f; - if (typeof c === "object" && f instanceof Function) { func = PhoneGap.close(c, f); } + if (typeof c === "object" && typeof f === "function") { func = PhoneGap.close(c, f); } g = g || func.observer_guid || f.observer_guid || this.guid++; func.observer_guid = g; @@ -120,7 +120,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" && typeof f === "function") { f = PhoneGap.close(c, f); } f.apply(this, this.fireArgs); } else { g = this.subscribe(m); @@ -132,7 +132,7 @@ PhoneGap.Channel.prototype.subscribeOnce = function(f, c) { * Unsubscribes the function with the given guid from the channel. */ PhoneGap.Channel.prototype.unsubscribe = function(g) { - if (g instanceof Function) { g = g.observer_guid; } + if (typeof g === "function") { g = g.observer_guid; } this.handlers[g] = null; delete this.handlers[g]; }; @@ -147,7 +147,7 @@ PhoneGap.Channel.prototype.fire = function(e) { for (item in this.handlers) { if (this.handlers.hasOwnProperty(item)) { handler = this.handlers[item]; - if (handler instanceof Function) { + if (typeof handler === "function") { rv = (handler.apply(this, arguments) === false); fail = fail || rv; } @@ -510,7 +510,7 @@ PhoneGap.clone = function(obj) { return retVal; } - if (obj instanceof Function) { + if (typeof obj === "function") { return obj; } From c978341d837764073c33ad5e7f8114362cfb2615 Mon Sep 17 00:00:00 2001 From: Kevin Griffin Date: Tue, 21 Jun 2011 11:32:18 -0400 Subject: [PATCH 12/20] made the mistake of opening anything in finder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5c53ca30..afa78b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ local.properties framework/phonegap.jar framework/bin framework/assets/www/.DS_Store +.DS_Store \ No newline at end of file From 327bda49a0d228da83e3ab94c183e8f1be4386f6 Mon Sep 17 00:00:00 2001 From: Kevin Griffin Date: Tue, 21 Jun 2011 11:32:22 -0400 Subject: [PATCH 13/20] Sending pause/resume notifcations to plugins regardless of 'keepRunning' state. Not sure why you wouldn't want to send them Added a OnNewIntent override for Plugins to use. --- framework/src/com/phonegap/DroidGap.java | 38 ++++++++++++------- framework/src/com/phonegap/api/Plugin.java | 6 +++ .../src/com/phonegap/api/PluginManager.java | 11 ++++++ 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index 7dc2aed0..fefbc144 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -9,13 +9,12 @@ package com.phonegap; import org.json.JSONArray; import org.json.JSONException; + import android.app.AlertDialog; -import android.widget.EditText; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; -import android.graphics.Bitmap; import android.graphics.Color; import android.media.AudioManager; import android.net.Uri; @@ -26,19 +25,21 @@ import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; +import android.webkit.GeolocationPermissions.Callback; +import android.webkit.JsPromptResult; import android.webkit.JsResult; import android.webkit.WebChromeClient; -import android.webkit.JsPromptResult; import android.webkit.WebSettings; +import android.webkit.WebSettings.LayoutAlgorithm; import android.webkit.WebStorage; import android.webkit.WebView; import android.webkit.WebViewClient; -import android.webkit.GeolocationPermissions.Callback; -import android.webkit.WebSettings.LayoutAlgorithm; +import android.widget.EditText; import android.widget.LinearLayout; + +import com.phonegap.api.PhonegapActivity; import com.phonegap.api.Plugin; import com.phonegap.api.PluginManager; -import com.phonegap.api.PhonegapActivity; /** * This class is the main Android activity that represents the PhoneGap @@ -608,17 +609,28 @@ public class DroidGap extends PhonegapActivity { // Send pause event to JavaScript this.appView.loadUrl("javascript:try{PhoneGap.onPause.fire();}catch(e){};"); + // Forward to plugins + this.pluginManager.onPause(); + // If app doesn't want to run in background if (!this.keepRunning) { - - // Forward to plugins - this.pluginManager.onPause(); // Pause JavaScript timers (including setInterval) this.appView.pauseTimers(); } } - + + @Override + /** + * Called when the activity receives a new intent + **/ + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + //Forward to plugins + this.pluginManager.onNewIntent(intent); + } + @Override /** * Called when the activity will start interacting with the user. @@ -632,6 +644,9 @@ public class DroidGap extends PhonegapActivity { // Send resume event to JavaScript this.appView.loadUrl("javascript:try{PhoneGap.onResume.fire();}catch(e){};"); + // Forward to plugins + this.pluginManager.onResume(); + // If app doesn't want to run in background if (!this.keepRunning || this.activityResultKeepRunning) { @@ -641,9 +656,6 @@ public class DroidGap extends PhonegapActivity { this.activityResultKeepRunning = false; } - // Forward to plugins - this.pluginManager.onResume(); - // Resume JavaScript timers (including setInterval) this.appView.resumeTimers(); } diff --git a/framework/src/com/phonegap/api/Plugin.java b/framework/src/com/phonegap/api/Plugin.java index a527159a..39da4b89 100755 --- a/framework/src/com/phonegap/api/Plugin.java +++ b/framework/src/com/phonegap/api/Plugin.java @@ -74,6 +74,12 @@ public abstract class Plugin implements IPlugin { public void onResume() { } + /** + * Called when the activity receives a new intent. + */ + public void onNewIntent(Intent intent) { + } + /** * The final call you receive before your activity is destroyed. */ diff --git a/framework/src/com/phonegap/api/PluginManager.java b/framework/src/com/phonegap/api/PluginManager.java index ad1cf20b..616ee856 100755 --- a/framework/src/com/phonegap/api/PluginManager.java +++ b/framework/src/com/phonegap/api/PluginManager.java @@ -13,6 +13,7 @@ import java.util.Map.Entry; import org.json.JSONArray; import org.json.JSONException; +import android.content.Intent; import android.webkit.WebView; /** @@ -265,4 +266,14 @@ public final class PluginManager { plugin.onDestroy(); } } + + public void onNewIntent(Intent intent) { + java.util.Set> s = this.plugins.entrySet(); + java.util.Iterator> it = s.iterator(); + while(it.hasNext()) { + Entry entry = it.next(); + Plugin plugin = entry.getValue(); + plugin.onNewIntent(intent); + } + } } \ No newline at end of file From 517b5e0db9ea547bf79d1f4a136b1a8c4832c3f6 Mon Sep 17 00:00:00 2001 From: Kevin Griffin Date: Tue, 21 Jun 2011 11:46:54 -0400 Subject: [PATCH 14/20] formattage --- framework/src/com/phonegap/DroidGap.java | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index fefbc144..cafc0ef0 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -620,16 +620,16 @@ public class DroidGap extends PhonegapActivity { } } - @Override - /** - * Called when the activity receives a new intent - **/ - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - //Forward to plugins - this.pluginManager.onNewIntent(intent); - } + @Override + /** + * Called when the activity receives a new intent + **/ + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + //Forward to plugins + this.pluginManager.onNewIntent(intent); + } @Override /** From afa85a74b3a1c3047972968f45456d8b8950e8b9 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 21 Jun 2011 10:08:42 -0700 Subject: [PATCH 15/20] Adding SSL dev code --- framework/src/com/phonegap/DroidGap.java | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index 7dc2aed0..01e226b0 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -14,11 +14,15 @@ import android.widget.EditText; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Color; import android.media.AudioManager; import android.net.Uri; +import android.net.http.SslError; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; @@ -27,6 +31,7 @@ import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.webkit.JsResult; +import android.webkit.SslErrorHandler; import android.webkit.WebChromeClient; import android.webkit.JsPromptResult; import android.webkit.WebSettings; @@ -1115,6 +1120,27 @@ public class DroidGap extends PhonegapActivity { // Handle error this.ctx.onReceivedError(errorCode, description, failingUrl); } + + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { + + final String packageName = this.ctx.getPackageName(); + final PackageManager pm = this.ctx.getPackageManager(); + ApplicationInfo appInfo; + try { + appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA); + if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { + // debug = true + handler.proceed(); + return; + } else { + // debug = false + super.onReceivedSslError(view, handler, error); + } + } catch (NameNotFoundException e) { + // When it doubt, lock it out! + super.onReceivedSslError(view, handler, error); + } + } } /** From 9b52827744f8df0c76e157c7744e83dd59f65d57 Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Tue, 21 Jun 2011 22:50:53 -0500 Subject: [PATCH 16/20] Urls with same path and file but different # or ? should compare to same url. --- framework/src/com/phonegap/DroidGap.java | 28 +++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index 7dc2aed0..914d74bb 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -119,8 +119,13 @@ public class DroidGap extends PhonegapActivity { protected boolean clearHistory = false; // The initial URL for our app + // ie http://server/path/index.html#abc?query private String url; + // The initial URL for our app up to and including the file name + // ie http://server/path/index.html + private String urlFile; + // The base of the initial URL for our app private String baseUrl; @@ -330,6 +335,7 @@ public class DroidGap extends PhonegapActivity { */ public void loadUrl(final String url) { System.out.println("loadUrl("+url+")"); + this.urlFile = this.getUrlFile(url); this.url = url; int i = url.lastIndexOf('/'); if (i > 0) { @@ -693,13 +699,29 @@ public class DroidGap extends PhonegapActivity { this.callbackServer.sendJavascript(statement); } + /** + * Return up to file part of url. + * If url = http://server/page.html#abc, then return http://server/page.html + * + * @param url + * @return + */ + private String getUrlFile(String url) { + int p1 = url.indexOf("#"); + int p2 = url.indexOf("?"); + if (p1 < 0) p1 = url.length(); + if (p2 < 0) p2 = url.length(); + int p3 = (p1 < p2) ? p1 : p2; + return url.substring(0, p3); + } + /** * Provides a hook for calling "alert" from javascript. Useful for * debugging your javascript. */ public class GapClient extends WebChromeClient { - private Context ctx; + private DroidGap ctx; /** * Constructor. @@ -707,7 +729,7 @@ public class DroidGap extends PhonegapActivity { * @param ctx */ public GapClient(Context ctx) { - this.ctx = ctx; + this.ctx = (DroidGap)ctx; } /** @@ -780,7 +802,7 @@ public class DroidGap extends PhonegapActivity { @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { boolean reqOk = false; - if (((DroidGap)(this.ctx)).url.equals(url)) { + if (this.ctx.urlFile.equals(this.ctx.getUrlFile(url))) { reqOk = true; } From a67dfdb75ee0dfdd4b3b64a1f648a9d384058a21 Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Tue, 21 Jun 2011 22:53:45 -0500 Subject: [PATCH 17/20] Return true when handling key events, indicating that no further processing is necessary. --- framework/src/com/phonegap/DroidGap.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index 914d74bb..c3a9d357 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -1157,6 +1157,7 @@ public class DroidGap extends PhonegapActivity { // If back key is bound, then send event to JavaScript if (this.bound) { this.appView.loadUrl("javascript:PhoneGap.fireEvent('backbutton');"); + return true; } // If not bound @@ -1165,6 +1166,7 @@ public class DroidGap extends PhonegapActivity { // Go to previous page in webview if it is possible to go back if (this.appView.canGoBack()) { this.appView.goBack(); + return true; } // If not, then invoke behavior of super class @@ -1177,11 +1179,13 @@ public class DroidGap extends PhonegapActivity { // If menu key else if (keyCode == KeyEvent.KEYCODE_MENU) { this.appView.loadUrl("javascript:PhoneGap.fireEvent('menubutton');"); + return true; } // If search key else if (keyCode == KeyEvent.KEYCODE_SEARCH) { this.appView.loadUrl("javascript:PhoneGap.fireEvent('searchbutton');"); + return true; } return false; From c15971253fa891d5d360bd97307059a8adc6946f Mon Sep 17 00:00:00 2001 From: Kevin Griffin Date: Wed, 22 Jun 2011 11:05:33 -0400 Subject: [PATCH 18/20] formatting - sigh --- framework/src/com/phonegap/DroidGap.java | 24 +++++++++---------- framework/src/com/phonegap/api/Plugin.java | 4 ++-- .../src/com/phonegap/api/PluginManager.java | 3 +++ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index cafc0ef0..042f83d8 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -619,18 +619,18 @@ public class DroidGap extends PhonegapActivity { this.appView.pauseTimers(); } } - - @Override - /** - * Called when the activity receives a new intent - **/ - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - //Forward to plugins - this.pluginManager.onNewIntent(intent); - } - + + @Override + /** + * Called when the activity receives a new intent + **/ + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + //Forward to plugins + this.pluginManager.onNewIntent(intent); + } + @Override /** * Called when the activity will start interacting with the user. diff --git a/framework/src/com/phonegap/api/Plugin.java b/framework/src/com/phonegap/api/Plugin.java index 39da4b89..502552c6 100755 --- a/framework/src/com/phonegap/api/Plugin.java +++ b/framework/src/com/phonegap/api/Plugin.java @@ -77,8 +77,8 @@ public abstract class Plugin implements IPlugin { /** * Called when the activity receives a new intent. */ - public void onNewIntent(Intent intent) { - } + public void onNewIntent(Intent intent) { + } /** * The final call you receive before your activity is destroyed. diff --git a/framework/src/com/phonegap/api/PluginManager.java b/framework/src/com/phonegap/api/PluginManager.java index 616ee856..7dafa564 100755 --- a/framework/src/com/phonegap/api/PluginManager.java +++ b/framework/src/com/phonegap/api/PluginManager.java @@ -267,6 +267,9 @@ public final class PluginManager { } } + /** + * Called when the activity receives a new intent. + */ public void onNewIntent(Intent intent) { java.util.Set> s = this.plugins.entrySet(); java.util.Iterator> it = s.iterator(); From 1c3ea54dcbe695a5caa3920b00e85ca956030a43 Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Thu, 23 Jun 2011 23:22:48 -0500 Subject: [PATCH 19/20] Always call plugin's onPause/onResume with multitasking flag when these lifecycle events occur in activity. It is up to the plugin to handle as necessary. --- framework/src/com/phonegap/DroidGap.java | 4 ++-- framework/src/com/phonegap/api/IPlugin.java | 8 ++++++-- framework/src/com/phonegap/api/Plugin.java | 8 ++++++-- framework/src/com/phonegap/api/PluginManager.java | 12 ++++++++---- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index 78160743..99bf63f5 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -616,7 +616,7 @@ public class DroidGap extends PhonegapActivity { this.appView.loadUrl("javascript:try{PhoneGap.onPause.fire();}catch(e){};"); // Forward to plugins - this.pluginManager.onPause(); + this.pluginManager.onPause(this.keepRunning); // If app doesn't want to run in background if (!this.keepRunning) { @@ -651,7 +651,7 @@ public class DroidGap extends PhonegapActivity { this.appView.loadUrl("javascript:try{PhoneGap.onResume.fire();}catch(e){};"); // Forward to plugins - this.pluginManager.onResume(); + this.pluginManager.onResume(this.keepRunning || this.activityResultKeepRunning); // If app doesn't want to run in background if (!this.keepRunning || this.activityResultKeepRunning) { diff --git a/framework/src/com/phonegap/api/IPlugin.java b/framework/src/com/phonegap/api/IPlugin.java index b3b3a1da..b9c316e0 100755 --- a/framework/src/com/phonegap/api/IPlugin.java +++ b/framework/src/com/phonegap/api/IPlugin.java @@ -54,13 +54,17 @@ public interface IPlugin { /** * Called when the system is about to start resuming a previous activity. + * + * @param multitasking Flag indicating if multitasking is turned on for app */ - void onPause(); + void onPause(boolean multitasking); /** * Called when the activity will start interacting with the user. + * + * @param multitasking Flag indicating if multitasking is turned on for app */ - void onResume(); + void onResume(boolean multitasking); /** * The final call you receive before your activity is destroyed. diff --git a/framework/src/com/phonegap/api/Plugin.java b/framework/src/com/phonegap/api/Plugin.java index 502552c6..746bd408 100755 --- a/framework/src/com/phonegap/api/Plugin.java +++ b/framework/src/com/phonegap/api/Plugin.java @@ -64,14 +64,18 @@ public abstract class Plugin implements IPlugin { /** * Called when the system is about to start resuming a previous activity. + * + * @param multitasking Flag indicating if multitasking is turned on for app */ - public void onPause() { + public void onPause(boolean multitasking) { } /** * Called when the activity will start interacting with the user. + * + * @param multitasking Flag indicating if multitasking is turned on for app */ - public void onResume() { + public void onResume(boolean multitasking) { } /** diff --git a/framework/src/com/phonegap/api/PluginManager.java b/framework/src/com/phonegap/api/PluginManager.java index 7dafa564..393c6a29 100755 --- a/framework/src/com/phonegap/api/PluginManager.java +++ b/framework/src/com/phonegap/api/PluginManager.java @@ -230,27 +230,31 @@ public final class PluginManager { /** * Called when the system is about to start resuming a previous activity. + * + * @param multitasking Flag indicating if multitasking is turned on for app */ - public void onPause() { + public void onPause(boolean multitasking) { java.util.Set> s = this.plugins.entrySet(); java.util.Iterator> it = s.iterator(); while(it.hasNext()) { Entry entry = it.next(); Plugin plugin = entry.getValue(); - plugin.onPause(); + plugin.onPause(multitasking); } } /** * Called when the activity will start interacting with the user. + * + * @param multitasking Flag indicating if multitasking is turned on for app */ - public void onResume() { + public void onResume(boolean multitasking) { java.util.Set> s = this.plugins.entrySet(); java.util.Iterator> it = s.iterator(); while(it.hasNext()) { Entry entry = it.next(); Plugin plugin = entry.getValue(); - plugin.onResume(); + plugin.onResume(multitasking); } } From 08c44f5c5dc82f9ef3e896aba507c0c060276416 Mon Sep 17 00:00:00 2001 From: macdonst Date: Sat, 25 Jun 2011 04:29:25 +0800 Subject: [PATCH 20/20] Issue #121: Problem with resolveLocalFileSystemURI if file name has spaces --- framework/src/com/phonegap/FileUtils.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/framework/src/com/phonegap/FileUtils.java b/framework/src/com/phonegap/FileUtils.java index a53884ef..08ff7cce 100755 --- a/framework/src/com/phonegap/FileUtils.java +++ b/framework/src/com/phonegap/FileUtils.java @@ -10,6 +10,7 @@ package com.phonegap; import java.io.*; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLDecoder; import java.nio.channels.FileChannel; import org.apache.commons.codec.binary.Base64; @@ -229,15 +230,16 @@ public class FileUtils extends Plugin { * @throws JSONException */ private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException { + String decoded = URLDecoder.decode(url, "UTF-8"); // Test to see if this is a valid URL first - @SuppressWarnings("unused") - URL testUrl = new URL(url); - + @SuppressWarnings("unused") + URL testUrl = new URL(decoded); + File fp = null; - if (url.startsWith("file://")) { - fp = new File(url.substring(7, url.length())); + if (decoded.startsWith("file://")) { + fp = new File(decoded.substring(7, decoded.length())); } else { - fp = new File(url); + fp = new File(decoded); } if (!fp.exists()) { throw new FileNotFoundException();