From 9036eb8fcce4c10fb3ddbf182d993ea7fcdab3c6 Mon Sep 17 00:00:00 2001 From: macdonst Date: Mon, 30 May 2011 15:12:31 -0400 Subject: [PATCH 01/24] Issue #94: feature request: Event for Keyboard show/hide --- framework/src/com/phonegap/DroidGap.java | 67 +++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index 91eeb173..e0d42d66 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -9,6 +9,8 @@ package com.phonegap; import org.json.JSONArray; import org.json.JSONException; + +import android.app.Activity; import android.app.AlertDialog; import android.widget.EditText; import android.content.Context; @@ -17,6 +19,7 @@ import android.content.Intent; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Color; +import android.graphics.Rect; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; @@ -168,7 +171,7 @@ public class DroidGap extends PhonegapActivity { WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); // This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket! - root = new LinearLayout(this); + root = new LinearLayoutSoftKeyboardDetect(this); root.setOrientation(LinearLayout.VERTICAL); root.setBackgroundColor(Color.BLACK); root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, @@ -1276,4 +1279,66 @@ public class DroidGap extends PhonegapActivity { } }); } + + /** + * We are providing this class to detect when the soft keyboard is shown + * and hidden in the web view. + */ + class LinearLayoutSoftKeyboardDetect extends LinearLayout { + + private static final String LOG_TAG = "SoftKeyboardDetect"; + + private int oldHeight = 0; // Need to save the old height as not to send redundant events + + public LinearLayoutSoftKeyboardDetect(Context context) { + super(context); + } + + @Override + /** + * Start listening to new measurement events. Fire events when the height + * gets smaller fire a show keyboard event and when height gets bigger fire + * a hide keyboard event. + * + * Note: We are using callbackServer.sendJavascript() instead of + * this.appView.loadUrl() as changing the URL of the app would cause the + * soft keyboard to go away. + * + * @param widthMeasureSpec + * @param heightMeasureSpec + */ + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + Log.d(LOG_TAG, "We are in our onMeasure method"); + + // Get the current height of the visible part of the screen. + // This height will not included the status bar. + int height = MeasureSpec.getSize(heightMeasureSpec); + + Log.d(LOG_TAG, "Old Height = " + oldHeight); + Log.d(LOG_TAG, "Height = " + height); + + // If the oldHeight = 0 then this is the first measure event as the app starts up. + // If oldHeight == height then we got a measurement change that doesn't affect us. + if (oldHeight == 0 || oldHeight == height) { + Log.d(LOG_TAG, "Ignore this event"); + } + // If the height as gotten bigger then we will assume the soft keyboard has + // gone away. + else if (height > oldHeight) { + Log.d(LOG_TAG, "Throw hide keyboard event"); + callbackServer.sendJavascript("PhoneGap.fireEvent('hidekeyboard');"); + } + // If the height as gotten smaller then we will assume the soft keyboard has + // been displayed. + else if (height < oldHeight) { + Log.d(LOG_TAG, "Throw show keyboard event"); + callbackServer.sendJavascript("PhoneGap.fireEvent('showkeyboard');"); + } + + // Update the old height for the next event + oldHeight = height; + } + } } From 431c80782ee002dafb7af09e1b37e59116410e4d Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 31 May 2011 15:38:03 -0700 Subject: [PATCH 02/24] Changing the layout class so it has the screen dimensions to take into account Device Orientation --- framework/src/com/phonegap/DroidGap.java | 33 ++++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index e0d42d66..a9a06b4c 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -24,6 +24,7 @@ import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; import android.util.Log; +import android.view.Display; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; @@ -171,7 +172,11 @@ public class DroidGap extends PhonegapActivity { WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); // This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket! - root = new LinearLayoutSoftKeyboardDetect(this); + Display display = getWindowManager().getDefaultDisplay(); + int width = display.getWidth(); + int height = display.getHeight(); + + root = new LinearLayoutSoftKeyboardDetect(this, width, height); root.setOrientation(LinearLayout.VERTICAL); root.setBackgroundColor(Color.BLACK); root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, @@ -1289,9 +1294,14 @@ public class DroidGap extends PhonegapActivity { private static final String LOG_TAG = "SoftKeyboardDetect"; private int oldHeight = 0; // Need to save the old height as not to send redundant events - - public LinearLayoutSoftKeyboardDetect(Context context) { - super(context); + private int oldWidth = 0; // Need to save old width for orientation change + private int screenWidth = 0; + private int screenHeight = 0; + + public LinearLayoutSoftKeyboardDetect(Context context, int width, int height) { + super(context); + screenWidth = width; + screenHeight = height; } @Override @@ -1315,15 +1325,27 @@ public class DroidGap extends PhonegapActivity { // Get the current height of the visible part of the screen. // This height will not included the status bar. int height = MeasureSpec.getSize(heightMeasureSpec); + int width = MeasureSpec.getSize(widthMeasureSpec); Log.d(LOG_TAG, "Old Height = " + oldHeight); - Log.d(LOG_TAG, "Height = " + height); + Log.d(LOG_TAG, "Height = " + height); + Log.d(LOG_TAG, "Old Width = " + oldWidth); + Log.d(LOG_TAG, "Width = " + width); + // If the oldHeight = 0 then this is the first measure event as the app starts up. // If oldHeight == height then we got a measurement change that doesn't affect us. if (oldHeight == 0 || oldHeight == height) { Log.d(LOG_TAG, "Ignore this event"); } + // Account for orientation change and ignore this event/Fire orientation change + else if(screenHeight == width) + { + int tmp_var = screenHeight; + screenHeight = screenWidth; + screenWidth = tmp_var; + Log.d(LOG_TAG, "Orientation Change"); + } // If the height as gotten bigger then we will assume the soft keyboard has // gone away. else if (height > oldHeight) { @@ -1339,6 +1361,7 @@ public class DroidGap extends PhonegapActivity { // Update the old height for the next event oldHeight = height; + oldWidth = width; } } } From afa85a74b3a1c3047972968f45456d8b8950e8b9 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 21 Jun 2011 10:08:42 -0700 Subject: [PATCH 03/24] 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 af18a8e1aa142421af32576be22ba9c7b26a2721 Mon Sep 17 00:00:00 2001 From: macdonst Date: Wed, 1 Jun 2011 02:54:18 +0800 Subject: [PATCH 04/24] 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 088c3421989cd441167e6d23d9bfdb7d3fdd1cb2 Mon Sep 17 00:00:00 2001 From: macdonst Date: Thu, 2 Jun 2011 01:46:27 +0800 Subject: [PATCH 05/24] 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 3c90a9a23cfea9938bd150a674bbd5d28e7adeef Mon Sep 17 00:00:00 2001 From: Nitobi Date: Fri, 3 Jun 2011 10:59:48 -0700 Subject: [PATCH 06/24] 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 0280d5dd8207c0e22ede3cc7539cfdc14d456411 Mon Sep 17 00:00:00 2001 From: macdonst Date: Fri, 3 Jun 2011 01:11:51 +0800 Subject: [PATCH 07/24] 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 85eb6e49972e658ff86d31eb1fdcf8ed664f8c74 Mon Sep 17 00:00:00 2001 From: macdonst Date: Tue, 7 Jun 2011 02:37:29 +0800 Subject: [PATCH 08/24] 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 ff7de25b625f4b42967b25d1923c299f29afac30 Mon Sep 17 00:00:00 2001 From: macdonst Date: Tue, 7 Jun 2011 22:03:16 +0800 Subject: [PATCH 09/24] 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 66f3018767ec8eebf4540b33c8c115e57575b24f Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Tue, 7 Jun 2011 14:18:18 -0500 Subject: [PATCH 10/24] 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 8a1ab69235195188ff7d997aba446d7318ece0a0 Mon Sep 17 00:00:00 2001 From: macdonst Date: Thu, 9 Jun 2011 03:03:03 +0800 Subject: [PATCH 11/24] 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 eb3b1f91d4949a66ff91fdfe48475ab9f8b60d18 Mon Sep 17 00:00:00 2001 From: Benjamin Weingarten Date: Sun, 12 Jun 2011 12:24:25 +0300 Subject: [PATCH 12/24] 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 d35e8cd44b51a00e781432b2020fa40febacb9e4 Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Mon, 13 Jun 2011 15:16:08 -0500 Subject: [PATCH 13/24] 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 d09165e7..93dbe552 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -787,10 +787,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)); @@ -806,13 +810,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 80e66d87a9508adc1b4ea7aa1ce42da5a6ec610b Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Wed, 15 Jun 2011 13:01:03 -0500 Subject: [PATCH 14/24] 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 a5039f021d344b7d38d642d4973a838508550420 Mon Sep 17 00:00:00 2001 From: Kevin Griffin Date: Tue, 21 Jun 2011 11:32:18 -0400 Subject: [PATCH 15/24] 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 7bc0d624acd8c09f18b8fe72b5cd29ed1285e2e7 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Fri, 24 Jun 2011 14:08:26 -0700 Subject: [PATCH 16/24] Fixing conflict --- framework/src/com/phonegap/DroidGap.java | 37 ++++++++++++------- framework/src/com/phonegap/api/Plugin.java | 6 +++ .../src/com/phonegap/api/PluginManager.java | 11 ++++++ 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index 93dbe552..d3984fa3 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -12,12 +12,10 @@ import org.json.JSONException; import android.app.Activity; 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.graphics.Rect; import android.media.AudioManager; @@ -30,19 +28,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 @@ -616,17 +616,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. @@ -640,6 +651,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) { @@ -649,9 +663,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 7d53eb8e3e2ce8c52010a54831ace4ce07b63445 Mon Sep 17 00:00:00 2001 From: Kevin Griffin Date: Tue, 21 Jun 2011 11:46:54 -0400 Subject: [PATCH 17/24] 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 d3984fa3..211dbde5 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -627,16 +627,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 44aa0aeb0ffd4360e304afc9a8fdedfb10ebb42a Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 21 Jun 2011 10:08:42 -0700 Subject: [PATCH 18/24] 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 211dbde5..c106468c 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -15,11 +15,15 @@ import android.app.AlertDialog; 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.Color; import android.graphics.Rect; import android.media.AudioManager; import android.net.Uri; +import android.net.http.SslError; import android.os.Bundle; import android.util.Log; import android.view.Display; @@ -31,6 +35,7 @@ import android.view.WindowManager; import android.webkit.GeolocationPermissions.Callback; import android.webkit.JsPromptResult; import android.webkit.JsResult; +import android.webkit.SslErrorHandler; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebSettings.LayoutAlgorithm; @@ -1134,6 +1139,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 54fdcbfd46165ce4932a8495f366cc94b3443d82 Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Tue, 21 Jun 2011 22:50:53 -0500 Subject: [PATCH 19/24] 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 c106468c..b89de591 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -128,8 +128,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; @@ -343,6 +348,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) { @@ -717,13 +723,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. @@ -731,7 +753,7 @@ public class DroidGap extends PhonegapActivity { * @param ctx */ public GapClient(Context ctx) { - this.ctx = ctx; + this.ctx = (DroidGap)ctx; } /** @@ -804,7 +826,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 53de070a4122d3adec739650654a6f0a3020ff5e Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Tue, 21 Jun 2011 22:53:45 -0500 Subject: [PATCH 20/24] 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 b89de591..d1b9b808 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -1202,6 +1202,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 @@ -1210,6 +1211,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 @@ -1222,11 +1224,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 435c903baf281ce835bdf19c51ea7c5dfa9823af Mon Sep 17 00:00:00 2001 From: Kevin Griffin Date: Wed, 22 Jun 2011 11:05:33 -0400 Subject: [PATCH 21/24] 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 d1b9b808..2da3fd37 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -637,18 +637,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 05eacf4792278ccad1117fc66427a3a3298bc6e2 Mon Sep 17 00:00:00 2001 From: Bryce Curtis Date: Thu, 23 Jun 2011 23:22:48 -0500 Subject: [PATCH 22/24] 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 2da3fd37..b1323817 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -628,7 +628,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) { @@ -663,7 +663,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 ac2e92321fbfda36224d3d66f399011643438c92 Mon Sep 17 00:00:00 2001 From: macdonst Date: Sat, 25 Jun 2011 04:29:25 +0800 Subject: [PATCH 23/24] 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(); From 8ef93ff0e514ead90d9b40fa739630c6e3886398 Mon Sep 17 00:00:00 2001 From: macdonst Date: Tue, 28 Jun 2011 00:30:53 +0800 Subject: [PATCH 24/24] Issue 123: Fixing problem where name object is not specified --- framework/src/com/phonegap/ContactAccessor.java | 10 ++++++---- framework/src/com/phonegap/ContactAccessorSdk5.java | 2 -- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/framework/src/com/phonegap/ContactAccessor.java b/framework/src/com/phonegap/ContactAccessor.java index 1cc49644..fdbb996f 100644 --- a/framework/src/com/phonegap/ContactAccessor.java +++ b/framework/src/com/phonegap/ContactAccessor.java @@ -178,11 +178,13 @@ public abstract class ContactAccessor { protected String getJsonString(JSONObject obj, String property) { String value = null; try { + if (obj != null) { value = obj.getString(property); - if (value.equals("null")) { - Log.d(LOG_TAG, property + " is string called 'null'"); - value = null; - } + if (value.equals("null")) { + Log.d(LOG_TAG, property + " is string called 'null'"); + value = null; + } + } } catch (JSONException e) { Log.d(LOG_TAG, "Could not get = " + e.getMessage()); diff --git a/framework/src/com/phonegap/ContactAccessorSdk5.java b/framework/src/com/phonegap/ContactAccessorSdk5.java index a1e7d428..e8b34ae8 100644 --- a/framework/src/com/phonegap/ContactAccessorSdk5.java +++ b/framework/src/com/phonegap/ContactAccessorSdk5.java @@ -1420,7 +1420,6 @@ public class ContactAccessorSdk5 extends ContactAccessor { .build()); } - // Add urls JSONArray websites = null; try { @@ -1473,7 +1472,6 @@ public class ContactAccessorSdk5 extends ContactAccessor { Log.e(LOG_TAG, e.getMessage(), e); retVal = false; } - return retVal; }