From 0890be581508f773006134519424ae0580611e5b Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Mon, 23 Jan 2012 14:42:55 -0800 Subject: [PATCH] Moved Chrome Client out of DroidGap.java --- .../src/com/phonegap/CordovaChromeClient.java | 293 ++++++++++++++++++ framework/src/com/phonegap/DroidGap.java | 280 +---------------- 2 files changed, 296 insertions(+), 277 deletions(-) create mode 100644 framework/src/com/phonegap/CordovaChromeClient.java diff --git a/framework/src/com/phonegap/CordovaChromeClient.java b/framework/src/com/phonegap/CordovaChromeClient.java new file mode 100644 index 00000000..868b93c2 --- /dev/null +++ b/framework/src/com/phonegap/CordovaChromeClient.java @@ -0,0 +1,293 @@ +package com.phonegap; +import org.json.JSONArray; +import org.json.JSONException; + +import com.phonegap.api.LOG; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.view.KeyEvent; +import android.view.View; +import android.webkit.ConsoleMessage; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.WebChromeClient; +import android.webkit.WebStorage; +import android.webkit.WebView; +import android.webkit.GeolocationPermissions.Callback; +import android.widget.EditText; + + +public class CordovaChromeClient extends WebChromeClient { + + + private String TAG = "PhoneGapLog"; + private long MAX_QUOTA = 100 * 1024 * 1024; + private DroidGap ctx; + + /** + * Constructor. + * + * @param ctx + */ + public CordovaChromeClient(Context ctx) { + this.ctx = (DroidGap) ctx; + } + + /** + * Tell the client to display a javascript alert dialog. + * + * @param view + * @param url + * @param message + * @param result + */ + @Override + public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { + AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx); + dlg.setMessage(message); + dlg.setTitle("Alert"); + //Don't let alerts break the back button + dlg.setCancelable(true); + dlg.setPositiveButton(android.R.string.ok, + new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + result.confirm(); + } + }); + dlg.setOnCancelListener( + new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + result.confirm(); + } + }); + dlg.setOnKeyListener(new DialogInterface.OnKeyListener() { + //DO NOTHING + public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { + if(keyCode == KeyEvent.KEYCODE_BACK) + { + result.confirm(); + return false; + } + else + return true; + } + }); + dlg.create(); + dlg.show(); + return true; + } + + /** + * Tell the client to display a confirm dialog to the user. + * + * @param view + * @param url + * @param message + * @param result + */ + @Override + public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) { + AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx); + dlg.setMessage(message); + dlg.setTitle("Confirm"); + dlg.setCancelable(true); + dlg.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + result.confirm(); + } + }); + dlg.setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + result.cancel(); + } + }); + dlg.setOnCancelListener( + new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + result.cancel(); + } + }); + dlg.setOnKeyListener(new DialogInterface.OnKeyListener() { + //DO NOTHING + public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { + if(keyCode == KeyEvent.KEYCODE_BACK) + { + result.cancel(); + return false; + } + else + return true; + } + }); + dlg.create(); + dlg.show(); + return true; + } + + /** + * Tell the client to display a prompt dialog to the user. + * If the client returns true, WebView will assume that the client will + * handle the prompt dialog and call the appropriate JsPromptResult method. + * + * Since we are hacking prompts for our own purposes, we should not be using them for + * this purpose, perhaps we should hack console.log to do this instead! + * + * @param view + * @param url + * @param message + * @param defaultValue + * @param result + */ + @Override + public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { + + // Security check to make sure any requests are coming from the page initially + // loaded in webview and not another loaded in an iframe. + boolean reqOk = false; + if (url.startsWith("file://") || url.indexOf(this.ctx.baseUrl) == 0 || ctx.isUrlWhiteListed(url)) { + reqOk = true; + } + + // Calling PluginManager.exec() to call a native service using + // prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true])); + if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) { + JSONArray array; + try { + array = new JSONArray(defaultValue.substring(4)); + String service = array.getString(0); + String action = array.getString(1); + String callbackId = array.getString(2); + boolean async = array.getBoolean(3); + String r = ctx.pluginManager.exec(service, action, callbackId, message, async); + result.confirm(r); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + // Polling for JavaScript messages + else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:")) { + String r = ctx.callbackServer.getJavascript(); + result.confirm(r); + } + + // Calling into CallbackServer + else if (reqOk && defaultValue != null && defaultValue.equals("gap_callbackServer:")) { + String r = ""; + if (message.equals("usePolling")) { + r = ""+ ctx.callbackServer.usePolling(); + } + else if (message.equals("restartServer")) { + ctx.callbackServer.restartServer(); + } + else if (message.equals("getPort")) { + r = Integer.toString(ctx.callbackServer.getPort()); + } + else if (message.equals("getToken")) { + r = ctx.callbackServer.getToken(); + } + result.confirm(r); + } + + // PhoneGap JS has initialized, so show webview + // (This solves white flash seen when rendering HTML) + else if (reqOk && defaultValue != null && defaultValue.equals("gap_init:")) { + ctx.appView.setVisibility(View.VISIBLE); + ctx.spinnerStop(); + result.confirm("OK"); + } + + // Show dialog + else { + final JsPromptResult res = result; + AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx); + dlg.setMessage(message); + final EditText input = new EditText(this.ctx); + if (defaultValue != null) { + input.setText(defaultValue); + } + dlg.setView(input); + dlg.setCancelable(false); + dlg.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + String usertext = input.getText().toString(); + res.confirm(usertext); + } + }); + dlg.setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + res.cancel(); + } + }); + dlg.create(); + dlg.show(); + } + return true; + } + + /** + * Handle database quota exceeded notification. + * + * @param url + * @param databaseIdentifier + * @param currentQuota + * @param estimatedSize + * @param totalUsedQuota + * @param quotaUpdater + */ + @Override + public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, + long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) + { + LOG.d(TAG, "DroidGap: onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota); + + if( estimatedSize < MAX_QUOTA) + { + //increase for 1Mb + long newQuota = estimatedSize; + LOG.d(TAG, "calling quotaUpdater.updateQuota newQuota: %d", newQuota); + quotaUpdater.updateQuota(newQuota); + } + else + { + // Set the quota to whatever it is and force an error + // TODO: get docs on how to handle this properly + quotaUpdater.updateQuota(currentQuota); + } + } + + // console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html + @Override + public void onConsoleMessage(String message, int lineNumber, String sourceID) + { + LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message); + super.onConsoleMessage(message, lineNumber, sourceID); + } + + @Override + public boolean onConsoleMessage(ConsoleMessage consoleMessage) + { + LOG.d(TAG, consoleMessage.message()); + return super.onConsoleMessage(consoleMessage); + } + + @Override + /** + * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin. + * + * @param origin + * @param callback + */ + public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) { + super.onGeolocationPermissionsShowPrompt(origin, callback); + callback.invoke(origin, true, false); + } + + +} diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index 1d13e59c..63a6632a 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -191,7 +191,7 @@ public class DroidGap extends PhonegapActivity { // The base of the initial URL for our app. // Does not include file name. Ends with / // ie http://server/path/ - private String baseUrl = null; + String baseUrl = null; // Plugin to call when activity result is received protected IPlugin activityResultCallback = null; @@ -375,7 +375,7 @@ public class DroidGap extends PhonegapActivity { ViewGroup.LayoutParams.FILL_PARENT, 1.0F)); - this.appView.setWebChromeClient(new GapClient(DroidGap.this)); + this.appView.setWebChromeClient(new CordovaChromeClient(DroidGap.this)); this.setWebViewClient(this.appView, new GapViewClient(this)); //14 is Ice Cream Sandwich! @@ -1067,280 +1067,6 @@ public class DroidGap extends PhonegapActivity { } } - /** - * Set the chrome handler. - */ - public class GapClient extends WebChromeClient { - - private String TAG = "PhoneGapLog"; - private long MAX_QUOTA = 100 * 1024 * 1024; - private DroidGap ctx; - - /** - * Constructor. - * - * @param ctx - */ - public GapClient(Context ctx) { - this.ctx = (DroidGap)ctx; - } - - /** - * Tell the client to display a javascript alert dialog. - * - * @param view - * @param url - * @param message - * @param result - */ - @Override - public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { - AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx); - dlg.setMessage(message); - dlg.setTitle("Alert"); - //Don't let alerts break the back button - dlg.setCancelable(true); - dlg.setPositiveButton(android.R.string.ok, - new AlertDialog.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - result.confirm(); - } - }); - dlg.setOnCancelListener( - new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface dialog) { - result.confirm(); - } - }); - dlg.setOnKeyListener(new DialogInterface.OnKeyListener() { - //DO NOTHING - public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { - if(keyCode == KeyEvent.KEYCODE_BACK) - { - result.confirm(); - return false; - } - else - return true; - } - }); - dlg.create(); - dlg.show(); - return true; - } - - /** - * Tell the client to display a confirm dialog to the user. - * - * @param view - * @param url - * @param message - * @param result - */ - @Override - public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) { - AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx); - dlg.setMessage(message); - dlg.setTitle("Confirm"); - dlg.setCancelable(true); - dlg.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - result.confirm(); - } - }); - dlg.setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - result.cancel(); - } - }); - dlg.setOnCancelListener( - new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface dialog) { - result.cancel(); - } - }); - dlg.setOnKeyListener(new DialogInterface.OnKeyListener() { - //DO NOTHING - public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { - if(keyCode == KeyEvent.KEYCODE_BACK) - { - result.cancel(); - return false; - } - else - return true; - } - }); - dlg.create(); - dlg.show(); - return true; - } - - /** - * Tell the client to display a prompt dialog to the user. - * If the client returns true, WebView will assume that the client will - * handle the prompt dialog and call the appropriate JsPromptResult method. - * - * Since we are hacking prompts for our own purposes, we should not be using them for - * this purpose, perhaps we should hack console.log to do this instead! - * - * @param view - * @param url - * @param message - * @param defaultValue - * @param result - */ - @Override - public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { - - // Security check to make sure any requests are coming from the page initially - // loaded in webview and not another loaded in an iframe. - boolean reqOk = false; - if (url.startsWith("file://") || url.indexOf(this.ctx.baseUrl) == 0 || isUrlWhiteListed(url)) { - reqOk = true; - } - - // Calling PluginManager.exec() to call a native service using - // prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true])); - if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) { - JSONArray array; - try { - array = new JSONArray(defaultValue.substring(4)); - String service = array.getString(0); - String action = array.getString(1); - String callbackId = array.getString(2); - boolean async = array.getBoolean(3); - String r = pluginManager.exec(service, action, callbackId, message, async); - result.confirm(r); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - // Polling for JavaScript messages - else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:")) { - String r = callbackServer.getJavascript(); - result.confirm(r); - } - - // Calling into CallbackServer - else if (reqOk && defaultValue != null && defaultValue.equals("gap_callbackServer:")) { - String r = ""; - if (message.equals("usePolling")) { - r = ""+callbackServer.usePolling(); - } - else if (message.equals("restartServer")) { - callbackServer.restartServer(); - } - else if (message.equals("getPort")) { - r = Integer.toString(callbackServer.getPort()); - } - else if (message.equals("getToken")) { - r = callbackServer.getToken(); - } - result.confirm(r); - } - - // PhoneGap JS has initialized, so show webview - // (This solves white flash seen when rendering HTML) - else if (reqOk && defaultValue != null && defaultValue.equals("gap_init:")) { - appView.setVisibility(View.VISIBLE); - ctx.spinnerStop(); - result.confirm("OK"); - } - - // Show dialog - else { - final JsPromptResult res = result; - AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx); - dlg.setMessage(message); - final EditText input = new EditText(this.ctx); - if (defaultValue != null) { - input.setText(defaultValue); - } - dlg.setView(input); - dlg.setCancelable(false); - dlg.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - String usertext = input.getText().toString(); - res.confirm(usertext); - } - }); - dlg.setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - res.cancel(); - } - }); - dlg.create(); - dlg.show(); - } - return true; - } - - /** - * Handle database quota exceeded notification. - * - * @param url - * @param databaseIdentifier - * @param currentQuota - * @param estimatedSize - * @param totalUsedQuota - * @param quotaUpdater - */ - @Override - public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, - long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) - { - LOG.d(TAG, "DroidGap: onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota); - - if( estimatedSize < MAX_QUOTA) - { - //increase for 1Mb - long newQuota = estimatedSize; - LOG.d(TAG, "calling quotaUpdater.updateQuota newQuota: %d", newQuota); - quotaUpdater.updateQuota(newQuota); - } - else - { - // Set the quota to whatever it is and force an error - // TODO: get docs on how to handle this properly - quotaUpdater.updateQuota(currentQuota); - } - } - - // console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html - @Override - public void onConsoleMessage(String message, int lineNumber, String sourceID) - { - LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message); - super.onConsoleMessage(message, lineNumber, sourceID); - } - - @Override - public boolean onConsoleMessage(ConsoleMessage consoleMessage) - { - LOG.d(TAG, consoleMessage.message()); - return super.onConsoleMessage(consoleMessage); - } - - @Override - /** - * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin. - * - * @param origin - * @param callback - */ - public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) { - super.onGeolocationPermissionsShowPrompt(origin, callback); - callback.invoke(origin, true, false); - } - - } - /** * The webview client receives notifications about appView */ @@ -1881,7 +1607,7 @@ public class DroidGap extends PhonegapActivity { * @param url * @return */ - private boolean isUrlWhiteListed(String url) { + boolean isUrlWhiteListed(String url) { // Check to see if we have matched url previously if (whiteListCache.get(url) != null) {