Created
July 10, 2012 17:51
ChildBrowser with Cordova 1.9
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0" /> | |
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.css" /> | |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> | |
<script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script> | |
<script type="text/javascript" charset="utf-8" src="js/cordova-1.9.0.js"></script> | |
<script type="text/javascript" charset="utf-8" src="plugin/childbrowser.js"></script> | |
</head> | |
<body> | |
<div id="page1" data-role="page"> | |
<div data-role="header" data-theme="b" data-position="fixed"> | |
<h2> | |
Childbrowser Test | |
</h2> | |
</div> | |
<div data-role="content"> | |
<a href="#" data-role="button" id="openGoogleWithAddress">Google (with address bar)</a> | |
<a href="#" data-role="button" id="openGoogleWithoutAddress">Google (without address bar)</a> | |
<a href="#" data-role="button" id="openCamera">Open Camera Hack</a> | |
</div> | |
</div> | |
</body> | |
<script type="text/javascript"> | |
$("#openGoogleWithAddress").click(function(){ | |
window.plugins.childBrowser.showWebPage("http://www.google.com", { showLocationBar: true, showAddressBar: true }); | |
}); | |
$("#openGoogleWithoutAddress").click(function(){ | |
window.plugins.childBrowser.showWebPage("http://www.google.com", { showLocationBar: true, showAddressBar: false }); | |
}); | |
</script> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* PhoneGap is available under *either* the terms of the modified BSD license *or* the | |
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text. | |
* | |
* Copyright (c) 2005-2011, Nitobi Software Inc. | |
* Copyright (c) 2010-2011, IBM Corporation | |
*/ | |
package com.jumpbyte.mobile.plugin; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import org.apache.cordova.api.IPlugin; | |
import org.apache.cordova.api.Plugin; | |
import org.apache.cordova.api.PluginResult; | |
import org.json.JSONArray; | |
import org.json.JSONException; | |
import org.json.JSONObject; | |
import android.R; | |
import android.app.Dialog; | |
import android.content.Context; | |
import android.content.DialogInterface; | |
import android.content.Intent; | |
import android.graphics.Bitmap; | |
import android.graphics.BitmapFactory; | |
import android.net.Uri; | |
import android.text.InputType; | |
import android.util.Log; | |
import android.util.TypedValue; | |
import android.view.Gravity; | |
import android.view.KeyEvent; | |
import android.view.View; | |
import android.view.Window; | |
import android.view.WindowManager; | |
import android.view.WindowManager.LayoutParams; | |
import android.view.inputmethod.EditorInfo; | |
import android.view.inputmethod.InputMethodManager; | |
import android.webkit.WebChromeClient; | |
import android.webkit.WebSettings; | |
import android.webkit.WebView; | |
import android.webkit.WebViewClient; | |
import android.widget.EditText; | |
import android.widget.ImageButton; | |
import android.widget.LinearLayout; | |
import android.widget.RelativeLayout; | |
public class ChildBrowser extends Plugin{ | |
protected static final String LOG_TAG = "ChildBrowser"; | |
private static int CLOSE_EVENT = 0; | |
private static int LOCATION_CHANGED_EVENT = 1; | |
private String browserCallbackId = null; | |
private Dialog dialog; | |
private WebView webview; | |
private EditText edittext; | |
private boolean showLocationBar = true; | |
private boolean showAddressBar = true; | |
/** | |
* Executes the request and returns PluginResult. | |
* | |
* @param action The action to execute. | |
* @param args JSONArry of arguments for the plugin. | |
* @param callbackId The callback id used when calling back into JavaScript. | |
* @return A PluginResult object with a status and message. | |
*/ | |
public PluginResult execute(String action, JSONArray args, String callbackId) { | |
PluginResult.Status status = PluginResult.Status.OK; | |
String result = ""; | |
try { | |
if (action.equals("showWebPage")) { | |
Log.i("ChildBrowser", "Showing web page"); | |
this.browserCallbackId = callbackId; | |
// If the ChildBrowser is already open then throw an error | |
if (dialog != null && dialog.isShowing()) { | |
return new PluginResult(PluginResult.Status.ERROR, "ChildBrowser is already open"); | |
} | |
result = this.showWebPage(args.getString(0), args.optJSONObject(1)); | |
if (result.length() > 0) { | |
status = PluginResult.Status.ERROR; | |
return new PluginResult(status, result); | |
} else { | |
PluginResult pluginResult = new PluginResult(status, result); | |
pluginResult.setKeepCallback(true); | |
return pluginResult; | |
} | |
} | |
else if (action.equals("close")) { | |
closeDialog(); | |
JSONObject obj = new JSONObject(); | |
obj.put("type", CLOSE_EVENT); | |
PluginResult pluginResult = new PluginResult(status, obj); | |
pluginResult.setKeepCallback(false); | |
return pluginResult; | |
} | |
else if (action.equals("openExternal")) { | |
result = this.openExternal(args.getString(0), args.optBoolean(1)); | |
if (result.length() > 0) { | |
status = PluginResult.Status.ERROR; | |
} | |
} | |
else { | |
status = PluginResult.Status.INVALID_ACTION; | |
} | |
return new PluginResult(status, result); | |
} catch (JSONException e) { | |
return new PluginResult(PluginResult.Status.JSON_EXCEPTION); | |
} | |
} | |
/** | |
* Display a new browser with the specified URL. | |
* | |
* @param url The url to load. | |
* @param usePhoneGap Load url in PhoneGap webview | |
* @return "" if ok, or error message. | |
*/ | |
public String openExternal(String url, boolean usePhoneGap) { | |
try { | |
Intent intent = null; | |
if (usePhoneGap) { | |
intent = new Intent().setClass(this.ctx.getActivity().getApplicationContext(), org.apache.cordova.DroidGap.class); | |
intent.setData(Uri.parse(url)); // This line will be removed in future. | |
intent.putExtra("url", url); | |
// Timeout parameter: 60 sec max - May be less if http device timeout is less. | |
intent.putExtra("loadUrlTimeoutValue", 60000); | |
// These parameters can be configured if you want to show the loading dialog | |
intent.putExtra("loadingDialog", "Wait,Loading web page..."); // show loading dialog | |
intent.putExtra("hideLoadingDialogOnPageLoad", true); // hide it once page has completely loaded | |
} | |
else { | |
intent = new Intent(Intent.ACTION_VIEW); | |
intent.setData(Uri.parse(url)); | |
} | |
this.ctx.getActivity().startActivity(intent); | |
return ""; | |
} catch (android.content.ActivityNotFoundException e) { | |
//Log.d(LOG_TAG, "ChildBrowser: Error loading url "+url+":"+ e.toString()); | |
return e.toString(); | |
} | |
} | |
/** | |
* Closes the dialog | |
*/ | |
private void closeDialog() { | |
if (dialog != null) { | |
dialog.dismiss(); | |
} | |
} | |
/** | |
* Checks to see if it is possible to go back one page in history, then does so. | |
*/ | |
private void goBack() { | |
if (this.webview.canGoBack()) { | |
this.webview.goBack(); | |
} | |
} | |
/** | |
* Checks to see if it is possible to go forward one page in history, then does so. | |
*/ | |
private void goForward() { | |
if (this.webview.canGoForward()) { | |
this.webview.goForward(); | |
} | |
} | |
/** | |
* Navigate to the new page | |
* | |
* @param url to load | |
*/ | |
private void navigate(String url) { | |
InputMethodManager imm = (InputMethodManager)this.ctx.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); | |
imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0); | |
if (!url.startsWith("http") && !url.startsWith("file:")) { | |
this.webview.loadUrl("http://" + url); | |
} else { | |
this.webview.loadUrl(url); | |
} | |
this.webview.requestFocus(); | |
} | |
/** | |
* Should we show the location bar? | |
* | |
* @return boolean | |
*/ | |
private boolean getShowLocationBar() { | |
return this.showLocationBar; | |
} | |
/** | |
* Display a new browser with the specified URL. | |
* | |
* @param url The url to load. | |
* @param jsonObject | |
*/ | |
public String showWebPage(final String url, JSONObject options) { | |
// Determine if we should hide the location bar. | |
if (options != null) { | |
showLocationBar = options.optBoolean("showLocationBar", true); | |
showAddressBar = options.optBoolean("showAddressBar", true); | |
} | |
// Create dialog in new thread | |
Runnable runnable = new Runnable() { | |
/** | |
* Convert our DIP units to Pixels | |
* | |
* @return int | |
*/ | |
private int dpToPixels(int dipValue) { | |
int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, | |
(float) dipValue, | |
ctx.getActivity().getApplicationContext().getResources().getDisplayMetrics() | |
); | |
return value; | |
} | |
public void run() { | |
// Let's create the main dialog | |
dialog = new Dialog(ctx.getActivity(), android.R.style.Theme_NoTitleBar); | |
dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog; | |
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); | |
dialog.setCancelable(true); | |
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { | |
public void onDismiss(DialogInterface dialog) { | |
try { | |
JSONObject obj = new JSONObject(); | |
obj.put("type", CLOSE_EVENT); | |
sendUpdate(obj, false); | |
} catch (JSONException e) { | |
//Log.d(LOG_TAG, "Should never happen"); | |
} | |
} | |
}); | |
// Main container layout | |
LinearLayout main = new LinearLayout(ctx.getActivity().getApplicationContext()); | |
main.setOrientation(LinearLayout.VERTICAL); | |
// Toolbar layout | |
RelativeLayout toolbar = new RelativeLayout(ctx.getActivity().getApplicationContext()); | |
toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, this.dpToPixels(44))); | |
toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2)); | |
toolbar.setHorizontalGravity(Gravity.LEFT); | |
toolbar.setVerticalGravity(Gravity.TOP); | |
// Action Button Container layout | |
RelativeLayout actionButtonContainer = new RelativeLayout(ctx.getActivity().getApplicationContext()); | |
actionButtonContainer.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); | |
actionButtonContainer.setHorizontalGravity(Gravity.LEFT); | |
actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL); | |
actionButtonContainer.setId(1); | |
// Back button | |
ImageButton back = new ImageButton(ctx.getActivity().getApplicationContext()); | |
RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT); | |
backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT); | |
back.setLayoutParams(backLayoutParams); | |
back.setContentDescription("Back Button"); | |
back.setId(2); | |
try { | |
back.setImageBitmap(loadDrawable("www/childbrowser/icon_arrow_left.png")); | |
} catch (IOException e) { | |
//Log.e(LOG_TAG, e.getMessage(), e); | |
} | |
back.setOnClickListener(new View.OnClickListener() { | |
public void onClick(View v) { | |
goBack(); | |
} | |
}); | |
// Forward button | |
ImageButton forward = new ImageButton(ctx.getActivity().getApplicationContext()); | |
RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT); | |
forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2); | |
forward.setLayoutParams(forwardLayoutParams); | |
forward.setContentDescription("Forward Button"); | |
forward.setId(3); | |
try { | |
forward.setImageBitmap(loadDrawable("www/childbrowser/icon_arrow_right.png")); | |
} catch (IOException e) { | |
//Log.e(LOG_TAG, e.getMessage(), e); | |
} | |
forward.setOnClickListener(new View.OnClickListener() { | |
public void onClick(View v) { | |
goForward(); | |
} | |
}); | |
// Edit Text Box | |
edittext = new EditText(ctx.getActivity().getApplicationContext()); | |
RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); | |
textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1); | |
textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5); | |
edittext.setLayoutParams(textLayoutParams); | |
edittext.setId(4); | |
edittext.setSingleLine(true); | |
edittext.setText(url); | |
edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI); | |
edittext.setImeOptions(EditorInfo.IME_ACTION_GO); | |
edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE | |
edittext.setOnKeyListener(new View.OnKeyListener() { | |
public boolean onKey(View v, int keyCode, KeyEvent event) { | |
// If the event is a key-down event on the "enter" button | |
if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { | |
navigate(edittext.getText().toString()); | |
return true; | |
} | |
return false; | |
} | |
}); | |
if(!showAddressBar){ | |
edittext.setVisibility(EditText.INVISIBLE); | |
} | |
// Close button | |
ImageButton close = new ImageButton(ctx.getActivity().getApplicationContext()); | |
RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT); | |
closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); | |
close.setLayoutParams(closeLayoutParams); | |
forward.setContentDescription("Close Button"); | |
close.setId(5); | |
try { | |
close.setImageBitmap(loadDrawable("www/childbrowser/icon_close.png")); | |
} catch (IOException e) { | |
//Log.e(LOG_TAG, e.getMessage(), e); | |
} | |
close.setOnClickListener(new View.OnClickListener() { | |
public void onClick(View v) { | |
closeDialog(); | |
} | |
}); | |
// WebView | |
webview = new WebView(ctx.getActivity().getApplicationContext()); | |
webview.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); | |
webview.setWebChromeClient(new WebChromeClient()); | |
WebViewClient client = new ChildBrowserClient(edittext); | |
webview.setWebViewClient(client); | |
WebSettings settings = webview.getSettings(); | |
settings.setJavaScriptEnabled(true); | |
settings.setJavaScriptCanOpenWindowsAutomatically(true); | |
settings.setBuiltInZoomControls(true); | |
settings.setPluginsEnabled(true); | |
settings.setDomStorageEnabled(true); | |
webview.loadUrl(url); | |
webview.setId(6); | |
webview.getSettings().setLoadWithOverviewMode(true); | |
webview.getSettings().setUseWideViewPort(true); | |
webview.requestFocus(); | |
webview.requestFocusFromTouch(); | |
// Add the back and forward buttons to our action button container layout | |
actionButtonContainer.addView(back); | |
actionButtonContainer.addView(forward); | |
// Add the views to our toolbar | |
toolbar.addView(actionButtonContainer); | |
toolbar.addView(edittext); | |
toolbar.addView(close); | |
// Don't add the toolbar if its been disabled | |
if (getShowLocationBar()) { | |
// Add our toolbar to our main view/layout | |
main.addView(toolbar); | |
} | |
// Add our webview to our main view/layout | |
main.addView(webview); | |
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); | |
lp.copyFrom(dialog.getWindow().getAttributes()); | |
lp.width = WindowManager.LayoutParams.FILL_PARENT; | |
lp.height = WindowManager.LayoutParams.FILL_PARENT; | |
dialog.setContentView(main); | |
dialog.show(); | |
dialog.getWindow().setAttributes(lp); | |
} | |
private Bitmap loadDrawable(String filename) throws java.io.IOException { | |
InputStream input = ctx.getActivity().getAssets().open(filename); | |
return BitmapFactory.decodeStream(input); | |
} | |
}; | |
this.ctx.getActivity().runOnUiThread(runnable); | |
return ""; | |
} | |
/** | |
* Create a new plugin result and send it back to JavaScript | |
* | |
* @param obj a JSONObject contain event payload information | |
*/ | |
private void sendUpdate(JSONObject obj, boolean keepCallback) { | |
if (this.browserCallbackId != null) { | |
PluginResult result = new PluginResult(PluginResult.Status.OK, obj); | |
result.setKeepCallback(keepCallback); | |
this.success(result, this.browserCallbackId); | |
} | |
} | |
/** | |
* The webview client receives notifications about appView | |
*/ | |
public class ChildBrowserClient extends WebViewClient { | |
EditText edittext; | |
/** | |
* Constructor. | |
* | |
* @param mContext | |
* @param edittext | |
*/ | |
public ChildBrowserClient(EditText mEditText) { | |
this.edittext = mEditText; | |
} | |
/** | |
* Notify the host application that a page has started loading. | |
* | |
* @param view The webview initiating the callback. | |
* @param url The url of the page. | |
*/ | |
@Override | |
public void onPageStarted(WebView view, String url, Bitmap favicon) { | |
super.onPageStarted(view, url, favicon); | |
String newloc; | |
//Log.i("ChildBrowser", "page started " + url); | |
if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) { | |
newloc = url; | |
} else { | |
newloc = "http://" + url; | |
} | |
if(url.startsWith("http://openCamera")){ | |
view.stopLoading(); | |
closeDialog(); | |
return; | |
} | |
if (!newloc.equals(edittext.getText().toString())) { | |
edittext.setText(newloc); | |
} | |
try { | |
JSONObject obj = new JSONObject(); | |
obj.put("type", LOCATION_CHANGED_EVENT); | |
obj.put("location", url); | |
sendUpdate(obj, true); | |
} catch (JSONException e) { | |
//Log.d("ChildBrowser", "This should never happen"); | |
} | |
} | |
@Override | |
public boolean shouldOverrideUrlLoading(WebView view, String url) { | |
//Log.i("ChildBrowser", "load url " + url); | |
if(url.startsWith("http://openCamera")){ | |
return true; | |
}else{ | |
return super.shouldOverrideUrlLoading(view, url); | |
} | |
} | |
@Override | |
public void onLoadResource(WebView view, String url) { | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* cordova is available under *either* the terms of the modified BSD license *or* the | |
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text. | |
* | |
* Copyright (c) 2005-2010, Nitobi Software Inc. | |
* Copyright (c) 2011, IBM Corporation | |
*/ | |
/** | |
* Constructor | |
*/ | |
function ChildBrowser() { | |
}; | |
ChildBrowser.CLOSE_EVENT = 0; | |
ChildBrowser.LOCATION_CHANGED_EVENT = 1; | |
/** | |
* Display a new browser with the specified URL. | |
* This method loads up a new web view in a dialog. | |
* | |
* @param url The url to load | |
* @param options An object that specifies additional options | |
*/ | |
ChildBrowser.prototype.showWebPage = function(url, options) { | |
if (options === null || options === "undefined") { | |
var options = new Object(); | |
options.showLocationBar = true; | |
} | |
cordova.exec(this._onEvent, this._onError, "ChildBrowser", "showWebPage", [url, options]); | |
}; | |
/** | |
* Close the browser opened by showWebPage. | |
*/ | |
ChildBrowser.prototype.close = function() { | |
cordova.exec(null, null, "ChildBrowser", "close", []); | |
}; | |
/** | |
* Display a new browser with the specified URL. | |
* This method starts a new web browser activity. | |
* | |
* @param url The url to load | |
* @param usecordova Load url in cordova webview [optional] | |
*/ | |
ChildBrowser.prototype.openExternal = function(url, usecordova) { | |
if (usecordova === true) { | |
navigator.app.loadUrl(url); | |
} | |
else { | |
cordova.exec(null, null, "ChildBrowser", "openExternal", [url, usecordova]); | |
} | |
}; | |
/** | |
* Method called when the child browser has an event. | |
*/ | |
ChildBrowser.prototype._onEvent = function(data) { | |
if (data.type == ChildBrowser.CLOSE_EVENT && typeof window.plugins.childBrowser.onClose === "function") { | |
window.plugins.childBrowser.onClose(); | |
} | |
if (data.type == ChildBrowser.LOCATION_CHANGED_EVENT && typeof window.plugins.childBrowser.onLocationChange === "function") { | |
window.plugins.childBrowser.onLocationChange(data.location); | |
} | |
}; | |
/** | |
* Method called when the child browser has an error. | |
*/ | |
ChildBrowser.prototype._onError = function(data) { | |
if (typeof window.plugins.childBrowser.onError === "function") { | |
window.plugins.childBrowser.onError(data); | |
} | |
}; | |
/** | |
* Maintain API consistency with iOS | |
*/ | |
ChildBrowser.install = function(){ | |
return window.plugins.childBrowser; | |
}; | |
/** | |
* Load ChildBrowser | |
*/ | |
cordova.addConstructor(function() { | |
cordova.addPlugin("childBrowser", new ChildBrowser()); | |
}); |
Have you put both cordova and childbrowser js files in correct directories?
I have cordova-2.0.0.js and childbrowser.js in /assets/www directory with references to both in index.html. Additionally, ChildBrowser.java is in the package com.phonegap.plugins.childBrowser.
plugins.xml contains
Any thing else you can think of that may be a problem?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi,
When I attempt to run this on Android using 2.0.0 I get 'Can not read property childBrowser.' Any idea what the problem is?
Thanks!