Compare commits

..

1 Commits

Author SHA1 Message Date
Ian Clelland
22b1959333 Manually fix Android sdk location to support library projects without local.properties 2014-05-22 14:04:00 -04:00
11 changed files with 887 additions and 943 deletions

23
bin/node_modules/which/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,23 @@
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
All rights reserved.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

5
bin/node_modules/which/README.md generated vendored Normal file
View File

@@ -0,0 +1,5 @@
The "which" util from npm's guts.
Finds the first instance of a specified executable in the PATH
environment variable. Does not cache the results, so `hash -r` is not
needed when the PATH changes.

14
bin/node_modules/which/bin/which generated vendored Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env node
var which = require("../")
if (process.argv.length < 3) {
console.error("Usage: which <thing>")
process.exit(1)
}
which(process.argv[2], function (er, thing) {
if (er) {
console.error(er.message)
process.exit(er.errno || 127)
}
console.log(thing)
})

31
bin/node_modules/which/package.json generated vendored Normal file
View File

@@ -0,0 +1,31 @@
{
"author": {
"name": "Isaac Z. Schlueter",
"email": "i@izs.me",
"url": "http://blog.izs.me"
},
"name": "which",
"description": "Like which(1) unix command. Find the first instance of an executable in the PATH.",
"version": "1.0.5",
"repository": {
"type": "git",
"url": "git://github.com/isaacs/node-which.git"
},
"main": "which.js",
"bin": {
"which": "./bin/which"
},
"engines": {
"node": "*"
},
"dependencies": {},
"devDependencies": {},
"readme": "The \"which\" util from npm's guts.\n\nFinds the first instance of a specified executable in the PATH\nenvironment variable. Does not cache the results, so `hash -r` is not\nneeded when the PATH changes.\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/isaacs/node-which/issues"
},
"homepage": "https://github.com/isaacs/node-which",
"_id": "which@1.0.5",
"_from": "which@^1.0.5"
}

104
bin/node_modules/which/which.js generated vendored Normal file
View File

@@ -0,0 +1,104 @@
module.exports = which
which.sync = whichSync
var path = require("path")
, fs
, COLON = process.platform === "win32" ? ";" : ":"
, isExe
try {
fs = require("graceful-fs")
} catch (ex) {
fs = require("fs")
}
if (process.platform == "win32") {
// On windows, there is no good way to check that a file is executable
isExe = function isExe () { return true }
} else {
isExe = function isExe (mod, uid, gid) {
//console.error(mod, uid, gid);
//console.error("isExe?", (mod & 0111).toString(8))
var ret = (mod & 0001)
|| (mod & 0010) && process.getgid && gid === process.getgid()
|| (mod & 0100) && process.getuid && uid === process.getuid()
//console.error("isExe?", ret)
return ret
}
}
function which (cmd, cb) {
if (isAbsolute(cmd)) return cb(null, cmd)
var pathEnv = (process.env.PATH || "").split(COLON)
, pathExt = [""]
if (process.platform === "win32") {
pathEnv.push(process.cwd())
pathExt = (process.env.PATHEXT || ".EXE").split(COLON)
if (cmd.indexOf(".") !== -1) pathExt.unshift("")
}
//console.error("pathEnv", pathEnv)
;(function F (i, l) {
if (i === l) return cb(new Error("not found: "+cmd))
var p = path.resolve(pathEnv[i], cmd)
;(function E (ii, ll) {
if (ii === ll) return F(i + 1, l)
var ext = pathExt[ii]
//console.error(p + ext)
fs.stat(p + ext, function (er, stat) {
if (!er &&
stat &&
stat.isFile() &&
isExe(stat.mode, stat.uid, stat.gid)) {
//console.error("yes, exe!", p + ext)
return cb(null, p + ext)
}
return E(ii + 1, ll)
})
})(0, pathExt.length)
})(0, pathEnv.length)
}
function whichSync (cmd) {
if (isAbsolute(cmd)) return cmd
var pathEnv = (process.env.PATH || "").split(COLON)
, pathExt = [""]
if (process.platform === "win32") {
pathEnv.push(process.cwd())
pathExt = (process.env.PATHEXT || ".EXE").split(COLON)
if (cmd.indexOf(".") !== -1) pathExt.unshift("")
}
for (var i = 0, l = pathEnv.length; i < l; i ++) {
var p = path.join(pathEnv[i], cmd)
for (var j = 0, ll = pathExt.length; j < ll; j ++) {
var cur = p + pathExt[j]
var stat
try { stat = fs.statSync(cur) } catch (ex) {}
if (stat &&
stat.isFile() &&
isExe(stat.mode, stat.uid, stat.gid)) return cur
}
}
throw new Error("not found: "+cmd)
}
var isAbsolute = process.platform === "win32" ? absWin : absUnix
function absWin (p) {
if (absUnix(p)) return true
// pull off the device/UNC bit from a windows path.
// from node's lib/path.js
var splitDeviceRe =
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?/
, result = splitDeviceRe.exec(p)
, device = result[1] || ''
, isUnc = device && device.charAt(1) !== ':'
, isAbsolute = !!result[2] || isUnc // UNC paths are always absolute
return isAbsolute
}
function absUnix (p) {
return p.charAt(0) === "/" || p === ""
}

View File

@@ -24,6 +24,7 @@ var shell = require('shelljs'),
Q = require('q'),
path = require('path'),
fs = require('fs'),
which = require('which'),
ROOT = path.join(__dirname, '..', '..');
@@ -32,6 +33,12 @@ function hasCustomRules() {
}
module.exports.getAntArgs = function(cmd) {
var args = [cmd, '-f', path.join(ROOT, 'build.xml')];
try {
// Specify sdk dir in case local properties are missing
args.push('-Dsdk.dir='+path.join(which.sync('android'), '../..'));
} catch(e) {
// Can't find android; don't push arg: assume all is okay
}
// custom_rules.xml is required for incremental builds.
if (hasCustomRules()) {
args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');

View File

@@ -1,837 +0,0 @@
/*
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.
*/
package org.apache.cordova;
import java.util.HashMap;
import java.util.Locale;
import org.apache.cordova.Config;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginManager;
import org.apache.cordova.PluginResult;
import org.json.JSONException;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.webkit.WebChromeClient;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
/*
* This class is our web view.
*
* @see <a href="http://developer.android.com/guide/webapps/webview.html">WebView guide</a>
* @see <a href="http://developer.android.com/reference/android/webkit/WebView.html">WebView</a>
*/
public class AndroidCordovaWebView extends CordovaWebView {
public static final String TAG = "CordovaWebView";
public static final String CORDOVA_VERSION = "3.6.0-dev";
private boolean paused;
private BroadcastReceiver receiver;
private AndroidWebView webview;
/** Activities and other important classes **/
private CordovaInterface cordova;
private CordovaWebViewClient viewClient;
private CordovaChromeClient chromeClient;
private String url;
// Flag to track that a loadUrl timeout occurred
int loadUrlTimeout = 0;
private boolean bound;
private boolean handleButton = false;
ExposedJsApi exposedJsApi;
/** custom view created by the browser (a video player for example) */
private View mCustomView;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
private ActivityResult mResult = null;
private CordovaResourceApi resourceApi;
class ActivityResult {
int request;
int result;
Intent incoming;
public ActivityResult(int req, int res, Intent intent) {
request = req;
result = res;
incoming = intent;
}
}
static final FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER =
new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
Gravity.CENTER);
/**
* Constructor.
*
* @param context
*/
public AndroidCordovaWebView(Context context) {
if (CordovaInterface.class.isInstance(context))
{
this.cordova = (CordovaInterface) context;
}
else
{
Log.d(TAG, "Your activity must implement CordovaInterface to work");
}
webview = new AndroidWebView(context);
webview.setCordovaWebView(this);
this.loadConfiguration();
this.setup();
}
/**
* Constructor.
*
* @param context
* @param attrs
*/
public AndroidCordovaWebView(Context context, AttributeSet attrs) {
if (CordovaInterface.class.isInstance(context))
{
this.cordova = (CordovaInterface) context;
}
else
{
Log.d(TAG, "Your activity must implement CordovaInterface to work");
}
webview = new AndroidWebView(context, attrs);
webview.setCordovaWebView(this);
this.loadConfiguration();
this.setup();
}
/**
* Constructor.
*
* @param context
* @param attrs
* @param defStyle
*
*/
public AndroidCordovaWebView(Context context, AttributeSet attrs, int defStyle) {
if (CordovaInterface.class.isInstance(context))
{
this.cordova = (CordovaInterface) context;
}
else
{
Log.d(TAG, "Your activity must implement CordovaInterface to work");
}
webview = new AndroidWebView(context, attrs, defStyle);
webview.setCordovaWebView(this);
this.loadConfiguration();
this.setup();
}
/**
* Constructor.
*
* @param context
* @param attrs
* @param defStyle
* @param privateBrowsing
*/
@TargetApi(11)
public AndroidCordovaWebView(Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) {
if (CordovaInterface.class.isInstance(context))
{
this.cordova = (CordovaInterface) context;
}
else
{
Log.d(TAG, "Your activity must implement CordovaInterface to work");
}
webview = new AndroidWebView(context, attrs, defStyle, privateBrowsing);
webview.setCordovaWebView(this);
this.loadConfiguration();
this.setup();
}
/**
* Create a default WebViewClient object for this webview. This can be overridden by the
* main application's CordovaActivity subclass.
*
* There are two possible client objects that can be returned:
* AndroidWebViewClient for android < 3.0
* IceCreamCordovaWebViewClient for Android >= 3.0 (Supports shouldInterceptRequest)
*/
@Override
public CordovaWebViewClient makeWebViewClient() {
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
{
return (CordovaWebViewClient) new AndroidWebViewClient(this.cordova, this);
}
else
{
return (CordovaWebViewClient) new IceCreamCordovaWebViewClient(this.cordova, this);
}
}
/**
* Create a default WebViewClient object for this webview. This can be overridden by the
* main application's CordovaActivity subclass.
*/
@Override
public CordovaChromeClient makeWebChromeClient() {
return (CordovaChromeClient) new AndroidChromeClient(this.cordova);
}
/**
* Initialize webview.
*/
private void setup() {
pluginManager = new PluginManager(this, this.cordova);
jsMessageQueue = new NativeToJsMessageQueue(this, cordova);
exposedJsApi = new AndroidExposedJsApi(pluginManager, jsMessageQueue);
resourceApi = new CordovaResourceApi(this.getContext(), pluginManager);
exposeJsInterface();
}
private void exposeJsInterface() {
int SDK_INT = Build.VERSION.SDK_INT;
if ((SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) {
Log.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old.");
// Bug being that Java Strings do not get converted to JS strings automatically.
// This isn't hard to work-around on the JS side, but it's easier to just
// use the prompt bridge instead.
return;
}
webview.addJavascriptInterface(exposedJsApi, "_cordovaNative");
}
/**
* Set the WebViewClient.
*
* @param client
*/
@Override
public void setWebViewClient(CordovaWebViewClient client) {
this.viewClient = client;
webview.setWebViewClient((WebViewClient) client);
}
// @Override
public CordovaWebViewClient getWebViewClient() {
return this.viewClient;
}
/**
* Set the WebChromeClient.
*
* @param client
*/
@Override
public void setWebChromeClient(CordovaChromeClient client) {
this.chromeClient = client;
webview.setWebChromeClient((WebChromeClient) client);
}
@Override
public CordovaChromeClient getWebChromeClient() {
return this.chromeClient;
}
/**
* Load the url into the webview.
*
* @param url
*/
@Override
public void loadUrl(String url) {
if (url.equals("about:blank") || url.startsWith("javascript:")) {
this.loadUrlNow(url);
}
else {
String initUrl = getProperty("url", null);
// If first page of app, then set URL to load to be the one passed in
if (initUrl == null) {
this.loadUrlIntoView(url);
}
// Otherwise use the URL specified in the activity's extras bundle
else {
this.loadUrlIntoView(initUrl);
}
}
}
/**
* Load the url into the webview after waiting for period of time.
* This is used to display the splashscreen for certain amount of time.
*
* @param url
* @param time The number of ms to wait before loading webview
*/
@Override
public void loadUrl(final String url, int time) {
String initUrl = getProperty("url", null);
// If first page of app, then set URL to load to be the one passed in
if (initUrl == null) {
this.loadUrlIntoView(url, time);
}
// Otherwise use the URL specified in the activity's extras bundle
else {
this.loadUrlIntoView(initUrl);
}
}
@Override
public void loadUrlIntoView(final String url) {
loadUrlIntoView(url, true);
}
/**
* Load the url into the webview.
*
* @param url
*/
@Override
public void loadUrlIntoView(final String url, boolean recreatePlugins) {
if (recreatePlugins) {
this.url = url;
this.pluginManager.init();
}
webview.loadUrlIntoView(url);
}
/**
* Load URL in webview.
*
* @param url
*/
@Override
public void loadUrlNow(String url) {
webview.loadUrlNow(url);
}
/**
* Load the url into the webview after waiting for period of time.
* This is used to display the splashscreen for certain amount of time.
*
* @param url
* @param time The number of ms to wait before loading webview
*/
@Override
public void loadUrlIntoView(final String url, final int time) {
// If not first page of app, then load immediately
// Add support for browser history if we use it.
if ((url.startsWith("javascript:")) || this.canGoBack()) {
}
// If first page, then show splashscreen
else {
LOG.d(TAG, "loadUrlIntoView(%s, %d)", url, time);
// Send message to show splashscreen now if desired
postMessage("splashscreen", "show");
}
// Load url
this.loadUrlIntoView(url);
}
@Override
public void stopLoading() {
//viewClient.isCurrentlyLoading = false;
webview.stopLoading();
}
/**
* Send JavaScript statement back to JavaScript.
* (This is a convenience method)
*
* @param statement
*/
@Override
public void sendJavascript(String statement) {
this.jsMessageQueue.addJavaScript(statement);
}
/**
* Send a plugin result back to JavaScript.
* (This is a convenience method)
*
* @param result
* @param callbackId
*/
@Override
public void sendPluginResult(PluginResult result, String callbackId) {
this.jsMessageQueue.addPluginResult(result, callbackId);
}
/**
* Send a message to all plugins.
*
* @param id The message id
* @param data The message data
*/
@Override
public void postMessage(String id, Object data) {
if (this.pluginManager != null) {
this.pluginManager.postMessage(id, data);
}
}
/**
* Go to previous page in history. (We manage our own history)
*
* @return true if we went back, false if we are already at top
*/
@Override
public boolean backHistory() {
return webview.backHistory();
}
/**
* Load the specified URL in the Cordova webview or a new browser instance.
*
* NOTE: If openExternal is false, only URLs listed in whitelist can be loaded.
*
* @param url The url to load.
* @param openExternal Load url in browser instead of Cordova webview.
* @param clearHistory Clear the history stack, so new page becomes top of history
* @param params Parameters for new app
*/
@Override
public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap<String, Object> params) {
LOG.d(TAG, "showWebPage(%s, %b, %b, HashMap", url, openExternal, clearHistory);
// If clearing history
if (clearHistory) {
this.clearHistory();
}
// If loading into our webview
if (!openExternal) {
// Make sure url is in whitelist
if (url.startsWith("file://") || Config.isUrlWhiteListed(url)) {
// TODO: What about params?
// Load new URL
this.loadUrl(url);
return;
}
// Load in default viewer if not
LOG.w(TAG, "showWebPage: Cannot load URL into webview since it is not in white list. Loading into browser instead. (URL=" + url + ")");
}
try {
// Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
// Adding the MIME type to http: URLs causes them to not be handled by the downloader.
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse(url);
if ("file".equals(uri.getScheme())) {
intent.setDataAndType(uri, resourceApi.getMimeType(uri));
} else {
intent.setData(uri);
}
cordova.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
LOG.e(TAG, "Error loading url " + url, e);
}
}
/**
* Check configuration parameters from Config.
* Approved list of URLs that can be loaded into Cordova
* <access origin="http://server regexp" subdomains="true" />
* Log level: ERROR, WARN, INFO, DEBUG, VERBOSE (default=ERROR)
* <log level="DEBUG" />
*/
private void loadConfiguration() {
if ("true".equals(this.getProperty("Fullscreen", "false"))) {
this.cordova.getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
this.cordova.getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
/**
* Get string property for activity.
*
* @param name
* @param defaultValue
* @return the String value for the named property
*/
public String getProperty(String name, String defaultValue) {
Bundle bundle = this.cordova.getActivity().getIntent().getExtras();
if (bundle == null) {
return defaultValue;
}
name = name.toLowerCase(Locale.getDefault());
Object p = bundle.get(name);
if (p == null) {
return defaultValue;
}
return p.toString();
}
/*
* onKeyDown
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return webview.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
return webview.onKeyUp(keyCode, event);
}
@Override
public void bindButton(boolean override)
{
this.bound = override;
}
@Override
public void bindButton(String button, boolean override) {
if (button.compareTo("volumeup")==0) {
webview.bindButton(KeyEvent.KEYCODE_VOLUME_UP, true);
}
else if (button.compareTo("volumedown")==0) {
webview.bindButton(KeyEvent.KEYCODE_VOLUME_DOWN, true);
}
}
@Override
public boolean isBackButtonBound()
{
return this.bound;
}
@Override
public void handlePause(boolean keepRunning)
{
LOG.d(TAG, "Handle the pause");
// Send pause event to JavaScript
this.loadUrl("javascript:try{cordova.fireDocumentEvent('pause');}catch(e){console.log('exception firing pause event from native');};");
// Forward to plugins
if (this.pluginManager != null) {
this.pluginManager.onPause(keepRunning);
}
// If app doesn't want to run in background
if (!keepRunning) {
// Pause JavaScript timers (including setInterval)
webview.pauseTimers();
}
paused = true;
}
@Override
public void handleResume(boolean keepRunning, boolean activityResultKeepRunning)
{
this.loadUrl("javascript:try{cordova.fireDocumentEvent('resume');}catch(e){console.log('exception firing resume event from native');};");
// Forward to plugins
if (this.pluginManager != null) {
this.pluginManager.onResume(keepRunning);
}
// Resume JavaScript timers (including setInterval)
webview.resumeTimers();
paused = false;
}
@Override
public void handleDestroy()
{
// Send destroy event to JavaScript
this.loadUrl("javascript:try{cordova.require('cordova/channel').onDestroy.fire();}catch(e){console.log('exception firing destroy event from native');};");
// Load blank page so that JavaScript onunload is called
this.loadUrl("about:blank");
// Forward to plugins
if (this.pluginManager != null) {
this.pluginManager.onDestroy();
}
// unregister the receiver
if (this.receiver != null) {
try {
this.cordova.getActivity().unregisterReceiver(this.receiver);
} catch (Exception e) {
Log.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e);
}
}
}
@Override
public void onNewIntent(Intent intent)
{
//Forward to plugins
if (this.pluginManager != null) {
this.pluginManager.onNewIntent(intent);
}
}
@Override
public boolean isPaused()
{
return paused;
}
/* CB-1146 */
public boolean hadKeyEvent() {
return handleButton;
}
@Override
public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {
// This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
Log.d(TAG, "showing Custom View");
// if a view already exists then immediately terminate the new one
if (mCustomView != null) {
callback.onCustomViewHidden();
return;
}
// Store the view and its callback for later (to kill it properly)
mCustomView = view;
mCustomViewCallback = callback;
// Add the custom view to its container.
ViewGroup parent = (ViewGroup) this.getParent();
parent.addView(view, COVER_SCREEN_GRAVITY_CENTER);
// Hide the content view.
this.setVisibility(View.GONE);
// Finally show the custom view container.
parent.setVisibility(View.VISIBLE);
parent.bringToFront();
}
@Override
public void hideCustomView() {
// This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
Log.d(TAG, "Hiding Custom View");
if (mCustomView == null) return;
// Hide the custom view.
mCustomView.setVisibility(View.GONE);
// Remove the custom view from its container.
ViewGroup parent = (ViewGroup) this.getParent();
parent.removeView(mCustomView);
mCustomView = null;
mCustomViewCallback.onCustomViewHidden();
// Show the content view.
this.setVisibility(View.VISIBLE);
}
/**
* if the video overlay is showing then we need to know
* as it effects back button handling
*
* @return true if custom view is showing
*/
@Override
public boolean isCustomViewShowing() {
return mCustomView != null;
}
public void storeResult(int requestCode, int resultCode, Intent intent) {
mResult = new ActivityResult(requestCode, resultCode, intent);
}
/* git:5ca233779d11177ec2bef97afa2910d383d6d4a2 */
public CordovaResourceApi getResourceApi() {
return resourceApi;
}
@Override
public void setLayoutParams(
android.widget.LinearLayout.LayoutParams layoutParams) {
webview.setLayoutParams(layoutParams);
}
@SuppressLint("NewApi")
@Override
public void setOverScrollMode(int mode) {
webview.setOverScrollMode(mode);
}
@Override
public void addJavascript(String statement) {
this.jsMessageQueue.addJavaScript(statement);
}
@Override
public CordovaPlugin getPlugin(String initCallbackClass) {
return this.pluginManager.getPlugin(initCallbackClass);
}
@Override
public String exec(String service, String action, String callbackId,
String message) throws JSONException {
return this.exposedJsApi.exec(service, action, callbackId, message);
}
@Override
public void setNativeToJsBridgeMode(int parseInt) {
this.exposedJsApi.setNativeToJsBridgeMode(parseInt);
}
@Override
public String retrieveJsMessages(boolean equals) {
return this.exposedJsApi.retrieveJsMessages(equals);
}
@Override
public boolean onOverrideUrlLoading(String url) {
return this.pluginManager.onOverrideUrlLoading(url);
}
@Override
public void resetJsMessageQueue() {
this.jsMessageQueue.reset();
}
@Override
public void onReset() {
this.pluginManager.onReset();
}
@Override
public void incUrlTimeout() {
this.loadUrlTimeout++;
}
@Override
public PluginManager getPluginManager() {
return this.pluginManager;
}
@Override
public void setLayoutParams(
android.widget.FrameLayout.LayoutParams layoutParams) {
webview.setLayoutParams(layoutParams);
}
@Override
public View getView() {
return webview;
}
@Override
public void setId(int i) {
webview.setId(i);
}
@Override
public int getVisibility() {
return webview.getVisibility();
}
@Override
public void setVisibility(int invisible) {
webview.setVisibility(invisible);
}
@Override
public Object getParent() {
return webview.getParent();
}
@Override
public boolean canGoBack() {
return webview.canGoBack();
}
@Override
public void clearCache(boolean b) {
webview.clearCache(b);
}
@Override
public void clearHistory() {
webview.clearHistory();
}
@Override
public Object getFocusedChild() {
return webview.getFocusedChild();
}
@Override
public Context getContext() {
return webview.getContext();
}
@Override
public void setNetworkAvailable(boolean online) {
webview.setNetworkAvailable(online);
}
@Override
public String getUrl() {
return webview.getUrl();
}
}

684
framework/src/org/apache/cordova/AndroidWebView.java Normal file → Executable file
View File

@@ -1,8 +1,36 @@
/*
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.
*/
package org.apache.cordova;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import org.apache.cordova.Config;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginManager;
import org.apache.cordova.PluginResult;
import org.json.JSONException;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
@@ -13,19 +41,33 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebBackForwardList;
import android.webkit.WebHistoryItem;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebSettings.LayoutAlgorithm;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
public class AndroidWebView extends WebView {
/*
* This class is our web view.
*
* @see <a href="http://developer.android.com/guide/webapps/webview.html">WebView guide</a>
* @see <a href="http://developer.android.com/reference/android/webkit/WebView.html">WebView</a>
*/
public class AndroidWebView extends WebView implements CordovaWebView {
public static final String TAG = "CordovaWebView";
public static final String CORDOVA_VERSION = "3.6.0-dev";
@@ -33,20 +75,62 @@ public class AndroidWebView extends WebView {
private ArrayList<Integer> keyDownCodes = new ArrayList<Integer>();
private ArrayList<Integer> keyUpCodes = new ArrayList<Integer>();
PluginManager pluginManager;
private boolean paused;
private BroadcastReceiver receiver;
private AndroidCordovaWebView cordovaWebView;
/** Activities and other important classes **/
private CordovaInterface cordova;
CordovaWebViewClient viewClient;
@SuppressWarnings("unused")
private CordovaChromeClient chromeClient;
private String url;
// Flag to track that a loadUrl timeout occurred
int loadUrlTimeout = 0;
private boolean bound;
private boolean handleButton = false;
private long lastMenuEventTime = 0;
NativeToJsMessageQueue jsMessageQueue;
ExposedJsApi exposedJsApi;
/** custom view created by the browser (a video player for example) */
private View mCustomView;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
private ActivityResult mResult = null;
private CordovaResourceApi resourceApi;
class ActivityResult {
int request;
int result;
Intent incoming;
public ActivityResult(int req, int res, Intent intent) {
request = req;
result = res;
incoming = intent;
}
}
static final FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER =
new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
Gravity.CENTER);
/**
* Constructor.
*
@@ -54,7 +138,16 @@ public class AndroidWebView extends WebView {
*/
public AndroidWebView(Context context) {
super(context);
this.setup((CordovaInterface)context);
if (CordovaInterface.class.isInstance(context))
{
this.cordova = (CordovaInterface) context;
}
else
{
Log.d(TAG, "Your activity must implement CordovaInterface to work");
}
this.loadConfiguration();
this.setup();
}
/**
@@ -65,7 +158,16 @@ public class AndroidWebView extends WebView {
*/
public AndroidWebView(Context context, AttributeSet attrs) {
super(context, attrs);
this.setup((CordovaInterface)context);
if (CordovaInterface.class.isInstance(context))
{
this.cordova = (CordovaInterface) context;
}
else
{
Log.d(TAG, "Your activity must implement CordovaInterface to work");
}
this.loadConfiguration();
this.setup();
}
/**
@@ -78,7 +180,16 @@ public class AndroidWebView extends WebView {
*/
public AndroidWebView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setup((CordovaInterface)context);
if (CordovaInterface.class.isInstance(context))
{
this.cordova = (CordovaInterface) context;
}
else
{
Log.d(TAG, "Your activity must implement CordovaInterface to work");
}
this.loadConfiguration();
this.setup();
}
/**
@@ -89,20 +200,56 @@ public class AndroidWebView extends WebView {
* @param defStyle
* @param privateBrowsing
*/
@SuppressWarnings("deprecation")
@TargetApi(11)
@TargetApi(11)
public AndroidWebView(Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) {
super(context, attrs, defStyle, privateBrowsing);
this.setup((CordovaInterface)context);
if (CordovaInterface.class.isInstance(context))
{
this.cordova = (CordovaInterface) context;
}
else
{
Log.d(TAG, "Your activity must implement CordovaInterface to work");
}
this.loadConfiguration();
this.setup();
}
/**
* Create a default WebViewClient object for this webview. This can be overridden by the
* main application's CordovaActivity subclass.
*
* There are two possible client objects that can be returned:
* AndroidWebViewClient for android < 3.0
* IceCreamCordovaWebViewClient for Android >= 3.0 (Supports shouldInterceptRequest)
*/
@Override
public CordovaWebViewClient makeWebViewClient() {
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
{
return (CordovaWebViewClient) new AndroidWebViewClient(this.cordova, this);
}
else
{
return (CordovaWebViewClient) new IceCreamCordovaWebViewClient(this.cordova, this);
}
}
/**
* Create a default WebViewClient object for this webview. This can be overridden by the
* main application's CordovaActivity subclass.
*/
@Override
public CordovaChromeClient makeWebChromeClient() {
return (CordovaChromeClient) new AndroidChromeClient(this.cordova);
}
/**
* Initialize webview.
*/
@SuppressWarnings("deprecation")
@SuppressLint({ "NewApi", "SetJavaScriptEnabled" })
private void setup(CordovaInterface cordova) {
this.cordova = cordova;
@SuppressLint("NewApi")
private void setup() {
this.setInitialScale(0);
this.setVerticalScrollBarEnabled(false);
if (shouldRequestFocusOnInit()) {
@@ -145,15 +292,15 @@ public class AndroidWebView extends WebView {
Level16Apis.enableUniversalAccess(settings);
// Enable database
// We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16
String databasePath = cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
String databasePath = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
settings.setDatabaseEnabled(true);
settings.setDatabasePath(databasePath);
//Determine whether we're in debug or release mode, and turn on Debugging!
try {
final String packageName = cordova.getActivity().getPackageName();
final PackageManager pm = cordova.getActivity().getPackageManager();
final String packageName = this.cordova.getActivity().getPackageName();
final PackageManager pm = this.cordova.getActivity().getPackageManager();
ApplicationInfo appInfo;
appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
@@ -182,13 +329,13 @@ public class AndroidWebView extends WebView {
// Enable AppCache
// Fix for CB-2282
settings.setAppCacheMaxSize(5 * 1048576);
String pathToCache = cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
String pathToCache = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
settings.setAppCachePath(pathToCache);
settings.setAppCacheEnabled(true);
// Fix for CB-1405
// Google issue 4641
updateUserAgentString();
this.updateUserAgentString();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
@@ -199,10 +346,15 @@ public class AndroidWebView extends WebView {
updateUserAgentString();
}
};
cordova.getActivity().registerReceiver(this.receiver, intentFilter);
this.cordova.getActivity().registerReceiver(this.receiver, intentFilter);
}
// end CB-1405
pluginManager = new PluginManager(this, this.cordova);
jsMessageQueue = new NativeToJsMessageQueue(this, cordova);
exposedJsApi = new AndroidExposedJsApi(pluginManager, jsMessageQueue);
resourceApi = new CordovaResourceApi(this.getContext(), pluginManager);
exposeJsInterface();
}
/**
@@ -219,13 +371,41 @@ public class AndroidWebView extends WebView {
this.getSettings().getUserAgentString();
}
public AndroidCordovaWebView getCordovaWebView() {
return cordovaWebView;
}
private void exposeJsInterface() {
int SDK_INT = Build.VERSION.SDK_INT;
if ((SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) {
Log.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old.");
// Bug being that Java Strings do not get converted to JS strings automatically.
// This isn't hard to work-around on the JS side, but it's easier to just
// use the prompt bridge instead.
return;
}
this.addJavascriptInterface(exposedJsApi, "_cordovaNative");
}
public void setCordovaWebView(AndroidCordovaWebView cordovaWebView) {
this.cordovaWebView = cordovaWebView;
}
/**
* Set the WebViewClient.
*
* @param client
*/
public void setWebViewClient(CordovaWebViewClient client) {
this.viewClient = client;
super.setWebViewClient((WebViewClient) client);
}
/**
* Set the WebChromeClient.
*
* @param client
*/
public void setWebChromeClient(CordovaChromeClient client) {
this.chromeClient = client;
super.setWebChromeClient((WebChromeClient) client);
}
public CordovaChromeClient getWebChromeClient() {
return this.chromeClient;
}
/**
* Load the url into the webview.
@@ -234,7 +414,46 @@ public class AndroidWebView extends WebView {
*/
@Override
public void loadUrl(String url) {
this.getCordovaWebView().loadUrl(url);
if (url.equals("about:blank") || url.startsWith("javascript:")) {
this.loadUrlNow(url);
}
else {
String initUrl = this.getProperty("url", null);
// If first page of app, then set URL to load to be the one passed in
if (initUrl == null) {
this.loadUrlIntoView(url);
}
// Otherwise use the URL specified in the activity's extras bundle
else {
this.loadUrlIntoView(initUrl);
}
}
}
/**
* Load the url into the webview after waiting for period of time.
* This is used to display the splashscreen for certain amount of time.
*
* @param url
* @param time The number of ms to wait before loading webview
*/
public void loadUrl(final String url, int time) {
String initUrl = this.getProperty("url", null);
// If first page of app, then set URL to load to be the one passed in
if (initUrl == null) {
this.loadUrlIntoView(url, time);
}
// Otherwise use the URL specified in the activity's extras bundle
else {
this.loadUrlIntoView(initUrl);
}
}
public void loadUrlIntoView(final String url) {
loadUrlIntoView(url, true);
}
/**
@@ -242,22 +461,26 @@ public class AndroidWebView extends WebView {
*
* @param url
*/
public void loadUrlIntoView(final String url) {
public void loadUrlIntoView(final String url, boolean recreatePlugins) {
LOG.d(TAG, ">>> loadUrl(" + url + ")");
if (recreatePlugins) {
this.url = url;
this.pluginManager.init();
}
// Create a timeout timer for loadUrl
final AndroidWebView me = this;
final int currentLoadUrlTimeout = me.loadUrlTimeout;
final int loadUrlTimeoutValue = Integer.parseInt(getCordovaWebView().getProperty("LoadUrlTimeoutValue", "20000"));
final int loadUrlTimeoutValue = Integer.parseInt(this.getProperty("LoadUrlTimeoutValue", "20000"));
// Timeout error method
final Runnable loadError = new Runnable() {
public void run() {
me.stopLoading();
LOG.e(TAG, "CordovaWebView: TIMEOUT ERROR!");
CordovaWebViewClient viewClient = me.getCordovaWebView().getWebViewClient();
if (viewClient != null) {
viewClient.onReceivedError(me.getCordovaWebView(), -6, "The connection to the server was unsuccessful.", url);
viewClient.onReceivedError(me, -6, "The connection to the server was unsuccessful.", url);
}
}
};
@@ -303,21 +526,80 @@ public class AndroidWebView extends WebView {
}
}
/**
* Load the url into the webview after waiting for period of time.
* This is used to display the splashscreen for certain amount of time.
*
* @param url
* @param time The number of ms to wait before loading webview
*/
public void loadUrlIntoView(final String url, final int time) {
// If not first page of app, then load immediately
// Add support for browser history if we use it.
if ((url.startsWith("javascript:")) || this.canGoBack()) {
}
// If first page, then show splashscreen
else {
LOG.d(TAG, "loadUrlIntoView(%s, %d)", url, time);
// Send message to show splashscreen now if desired
this.postMessage("splashscreen", "show");
}
// Load url
this.loadUrlIntoView(url);
}
@Override
public void stopLoading() {
//viewClient.isCurrentlyLoading = false;
super.stopLoading();
}
@Override
public void onScrollChanged(int l, int t, int oldl, int oldt)
{
super.onScrollChanged(l, t, oldl, oldt);
//We should post a message that the scroll changed
ScrollEvent myEvent = new ScrollEvent(l, t, oldl, oldt, this);
getCordovaWebView().postMessage("onScrollChanged", myEvent);
this.postMessage("onScrollChanged", myEvent);
}
/**
* Send JavaScript statement back to JavaScript.
* (This is a convenience method)
*
* @param statement
*/
public void sendJavascript(String statement) {
this.jsMessageQueue.addJavaScript(statement);
}
/**
* Send a plugin result back to JavaScript.
* (This is a convenience method)
*
* @param result
* @param callbackId
*/
public void sendPluginResult(PluginResult result, String callbackId) {
this.jsMessageQueue.addPluginResult(result, callbackId);
}
/**
* Send a message to all plugins.
*
* @param id The message id
* @param data The message data
*/
public void postMessage(String id, Object data) {
if (this.pluginManager != null) {
this.pluginManager.postMessage(id, data);
}
}
/**
* Go to previous page in history. (We manage our own history)
@@ -337,19 +619,88 @@ public class AndroidWebView extends WebView {
return false;
}
/*
* Add a key code to either the keyUp or keyDown handler lists.
/**
* Load the specified URL in the Cordova webview or a new browser instance.
*
* NOTE: If openExternal is false, only URLs listed in whitelist can be loaded.
*
* @param url The url to load.
* @param openExternal Load url in browser instead of Cordova webview.
* @param clearHistory Clear the history stack, so new page becomes top of history
* @param params Parameters for new app
*/
void bindButton(int keyCode, boolean keyDown) {
if(keyDown)
{
keyDownCodes.add(keyCode);
public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap<String, Object> params) {
LOG.d(TAG, "showWebPage(%s, %b, %b, HashMap", url, openExternal, clearHistory);
// If clearing history
if (clearHistory) {
this.clearHistory();
}
else
{
keyUpCodes.add(keyCode);
// If loading into our webview
if (!openExternal) {
// Make sure url is in whitelist
if (url.startsWith("file://") || Config.isUrlWhiteListed(url)) {
// TODO: What about params?
// Load new URL
this.loadUrl(url);
return;
}
// Load in default viewer if not
LOG.w(TAG, "showWebPage: Cannot load URL into webview since it is not in white list. Loading into browser instead. (URL=" + url + ")");
}
}
try {
// Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
// Adding the MIME type to http: URLs causes them to not be handled by the downloader.
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse(url);
if ("file".equals(uri.getScheme())) {
intent.setDataAndType(uri, resourceApi.getMimeType(uri));
} else {
intent.setData(uri);
}
cordova.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
LOG.e(TAG, "Error loading url " + url, e);
}
}
/**
* Check configuration parameters from Config.
* Approved list of URLs that can be loaded into Cordova
* <access origin="http://server regexp" subdomains="true" />
* Log level: ERROR, WARN, INFO, DEBUG, VERBOSE (default=ERROR)
* <log level="DEBUG" />
*/
private void loadConfiguration() {
if ("true".equals(this.getProperty("Fullscreen", "false"))) {
this.cordova.getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
this.cordova.getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
/**
* Get string property for activity.
*
* @param name
* @param defaultValue
* @return the String value for the named property
*/
public String getProperty(String name, String defaultValue) {
Bundle bundle = this.cordova.getActivity().getIntent().getExtras();
if (bundle == null) {
return defaultValue;
}
name = name.toLowerCase(Locale.getDefault());
Object p = bundle.get(name);
if (p == null) {
return defaultValue;
}
return p.toString();
}
/*
* onKeyDown
@@ -398,6 +749,7 @@ public class AndroidWebView extends WebView {
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event)
@@ -405,8 +757,8 @@ public class AndroidWebView extends WebView {
// If back key
if (keyCode == KeyEvent.KEYCODE_BACK) {
// A custom view is currently displayed (e.g. playing a video)
if(getCordovaWebView().isCustomViewShowing()) {
getCordovaWebView().hideCustomView();
if(mCustomView != null) {
this.hideCustomView();
} else {
// The webview is currently displayed
// If back key is bound, then send event to JavaScript
@@ -452,6 +804,113 @@ public class AndroidWebView extends WebView {
return super.onKeyUp(keyCode, event);
}
public void bindButton(boolean override)
{
this.bound = override;
}
public void bindButton(String button, boolean override) {
// TODO Auto-generated method stub
if (button.compareTo("volumeup")==0) {
keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_UP);
}
else if (button.compareTo("volumedown")==0) {
keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_DOWN);
}
}
public void bindButton(int keyCode, boolean keyDown, boolean override) {
if(keyDown)
{
keyDownCodes.add(keyCode);
}
else
{
keyUpCodes.add(keyCode);
}
}
public boolean isBackButtonBound()
{
return this.bound;
}
public void handlePause(boolean keepRunning)
{
LOG.d(TAG, "Handle the pause");
// Send pause event to JavaScript
this.loadUrl("javascript:try{cordova.fireDocumentEvent('pause');}catch(e){console.log('exception firing pause event from native');};");
// Forward to plugins
if (this.pluginManager != null) {
this.pluginManager.onPause(keepRunning);
}
// If app doesn't want to run in background
if (!keepRunning) {
// Pause JavaScript timers (including setInterval)
this.pauseTimers();
}
paused = true;
}
public void handleResume(boolean keepRunning, boolean activityResultKeepRunning)
{
this.loadUrl("javascript:try{cordova.fireDocumentEvent('resume');}catch(e){console.log('exception firing resume event from native');};");
// Forward to plugins
if (this.pluginManager != null) {
this.pluginManager.onResume(keepRunning);
}
// Resume JavaScript timers (including setInterval)
this.resumeTimers();
paused = false;
}
public void handleDestroy()
{
// Send destroy event to JavaScript
this.loadUrl("javascript:try{cordova.require('cordova/channel').onDestroy.fire();}catch(e){console.log('exception firing destroy event from native');};");
// Load blank page so that JavaScript onunload is called
this.loadUrl("about:blank");
// Forward to plugins
if (this.pluginManager != null) {
this.pluginManager.onDestroy();
}
// unregister the receiver
if (this.receiver != null) {
try {
this.cordova.getActivity().unregisterReceiver(this.receiver);
} catch (Exception e) {
Log.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e);
}
}
}
public void onNewIntent(Intent intent)
{
//Forward to plugins
if (this.pluginManager != null) {
this.pluginManager.onNewIntent(intent);
}
}
public boolean isPaused()
{
return paused;
}
public boolean hadKeyEvent() {
return handleButton;
}
// Wrapping these functions in their own class prevents warnings in adb like:
// VFY: unable to resolve virtual method 285: Landroid/webkit/WebSettings;.setAllowUniversalAccessFromFileURLs
@TargetApi(16)
@@ -472,6 +931,7 @@ public class AndroidWebView extends WebView {
}
}
//Can Go Back is BROKEN!
public boolean startOfHistory()
{
@@ -487,14 +947,150 @@ public class AndroidWebView extends WebView {
return false;
}
@Override
public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {
// This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
Log.d(TAG, "showing Custom View");
// if a view already exists then immediately terminate the new one
if (mCustomView != null) {
callback.onCustomViewHidden();
return;
}
// Store the view and its callback for later (to kill it properly)
mCustomView = view;
mCustomViewCallback = callback;
// Add the custom view to its container.
ViewGroup parent = (ViewGroup) this.getParent();
parent.addView(view, COVER_SCREEN_GRAVITY_CENTER);
// Hide the content view.
this.setVisibility(View.GONE);
// Finally show the custom view container.
parent.setVisibility(View.VISIBLE);
parent.bringToFront();
}
public void hideCustomView() {
// This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
Log.d(TAG, "Hiding Custom View");
if (mCustomView == null) return;
// Hide the custom view.
mCustomView.setVisibility(View.GONE);
// Remove the custom view from its container.
ViewGroup parent = (ViewGroup) this.getParent();
parent.removeView(mCustomView);
mCustomView = null;
mCustomViewCallback.onCustomViewHidden();
// Show the content view.
this.setVisibility(View.VISIBLE);
}
/**
* if the video overlay is showing then we need to know
* as it effects back button handling
*
* @return true if custom view is showing
*/
public boolean isCustomViewShowing() {
return mCustomView != null;
}
public WebBackForwardList restoreState(Bundle savedInstanceState)
{
WebBackForwardList myList = super.restoreState(savedInstanceState);
Log.d(TAG, "WebView restoration crew now restoring!");
//Initialize the plugin manager once more
getCordovaWebView().pluginManager.init();
this.pluginManager.init();
return myList;
}
public void storeResult(int requestCode, int resultCode, Intent intent) {
mResult = new ActivityResult(requestCode, resultCode, intent);
}
public CordovaResourceApi getResourceApi() {
return resourceApi;
}
@Override
public void setLayoutParams(
android.widget.LinearLayout.LayoutParams layoutParams) {
super.setLayoutParams(layoutParams);
}
@Override
public void setOverScrollMode(int mode) {
super.setOverScrollMode(mode);
}
@Override
public void addJavascript(String statement) {
this.jsMessageQueue.addJavaScript(statement);
}
@Override
public CordovaPlugin getPlugin(String initCallbackClass) {
// TODO Auto-generated method stub
return this.pluginManager.getPlugin(initCallbackClass);
}
@Override
public String exec(String service, String action, String callbackId,
String message) throws JSONException {
return this.exposedJsApi.exec(service, action, callbackId, message);
}
@Override
public void setNativeToJsBridgeMode(int parseInt) {
this.exposedJsApi.setNativeToJsBridgeMode(parseInt);
}
@Override
public String retrieveJsMessages(boolean equals) {
return this.exposedJsApi.retrieveJsMessages(equals);
}
@Override
public boolean onOverrideUrlLoading(String url) {
return this.pluginManager.onOverrideUrlLoading(url);
}
@Override
public void resetJsMessageQueue() {
this.jsMessageQueue.reset();
}
@Override
public void onReset() {
this.pluginManager.onReset();
}
@Override
public void incUrlTimeout() {
this.loadUrlTimeout++;
}
@Override
public PluginManager getPluginManager() {
// TODO Auto-generated method stub
return this.pluginManager;
}
@Override
public void setLayoutParams(
android.widget.FrameLayout.LayoutParams layoutParams) {
super.setLayoutParams(layoutParams);
}
@Override
public View getView() {
return this;
}
}

View File

@@ -214,7 +214,7 @@ public class CordovaActivity extends Activity implements CordovaInterface {
* require a more specialized web view.
*/
protected CordovaWebView makeWebView() {
String r = this.getStringProperty("webView", "org.apache.cordova.AndroidCordovaWebView");
String r = this.getStringProperty("webView", "org.apache.cordova.AndroidWebView");
try {
Class webViewClass = Class.forName(r);
@@ -244,7 +244,7 @@ public class CordovaActivity extends Activity implements CordovaInterface {
}
// If all else fails, return a default WebView
return (CordovaWebView) new AndroidCordovaWebView(CordovaActivity.this);
return (CordovaWebView) new AndroidWebView(CordovaActivity.this);
}
/**

View File

@@ -11,121 +11,121 @@ import android.view.View;
import android.webkit.WebChromeClient.CustomViewCallback;
import android.widget.LinearLayout.LayoutParams;
public abstract class CordovaWebView {
public interface CordovaWebView {
String OVER_SCROLL_NEVER = null;
public PluginManager pluginManager = null;
protected NativeToJsMessageQueue jsMessageQueue = null;
Object pluginManager = null;
Object jsMessageQueue = null;
public abstract View getView();
View getView();
public abstract CordovaWebViewClient makeWebViewClient();
CordovaWebViewClient makeWebViewClient();
public abstract CordovaChromeClient makeWebChromeClient();
CordovaChromeClient makeWebChromeClient();
public abstract void setWebViewClient(CordovaWebViewClient webViewClient);
void setWebViewClient(CordovaWebViewClient webViewClient);
public abstract void setWebChromeClient(CordovaChromeClient webChromeClient);
void setWebChromeClient(CordovaChromeClient webChromeClient);
public abstract void setId(int i);
void setId(int i);
public abstract void setLayoutParams(LayoutParams layoutParams);
void setLayoutParams(LayoutParams layoutParams);
public abstract void setVisibility(int invisible);
void setVisibility(int invisible);
public abstract Object getParent();
Object getParent();
public abstract void loadUrl(String url);
void loadUrl(String url);
public abstract void loadUrl(String url, int splashscreenTime);
void loadUrl(String url, int splashscreenTime);
public abstract void loadUrlNow(String url);
void loadUrlNow(String url);
public abstract void loadUrlIntoView(final String url);
void loadUrlIntoView(final String url);
public abstract void loadUrlIntoView(final String url, boolean recreatePlugins);
void loadUrlIntoView(final String url, boolean recreatePlugins);
public abstract void loadUrlIntoView(final String url, final int splashscreenTime);
void loadUrlIntoView(final String url, final int splashscreenTime);
public abstract void stopLoading();
void stopLoading();
public abstract boolean canGoBack();
boolean canGoBack();
public abstract void clearCache(boolean b);
void clearCache(boolean b);
public abstract void clearHistory();
void clearHistory();
public abstract boolean backHistory();
boolean backHistory();
public abstract void handlePause(boolean keepRunning);
void handlePause(boolean keepRunning);
public abstract void onNewIntent(Intent intent);
void onNewIntent(Intent intent);
public abstract void handleResume(boolean keepRunning, boolean activityResultKeepRunning);
void handleResume(boolean keepRunning, boolean activityResultKeepRunning);
public abstract void handleDestroy();
void handleDestroy();
public abstract void postMessage(String id, Object data);
void postMessage(String id, Object data);
public abstract void addJavascript(String statement);
void addJavascript(String statement);
public abstract void sendJavascript(String statememt);
void sendJavascript(String statememt);
public abstract CordovaChromeClient getWebChromeClient();
CordovaChromeClient getWebChromeClient();
public abstract CordovaPlugin getPlugin(String initCallbackClass);
CordovaPlugin getPlugin(String initCallbackClass);
public abstract void showWebPage(String errorUrl, boolean b, boolean c, HashMap<String, Object> params);
void showWebPage(String errorUrl, boolean b, boolean c, HashMap<String, Object> params);
public abstract Object getFocusedChild();
Object getFocusedChild();
public abstract boolean isCustomViewShowing();
boolean isCustomViewShowing();
public abstract boolean onKeyUp(int keyCode, KeyEvent event);
boolean onKeyUp(int keyCode, KeyEvent event);
public abstract boolean onKeyDown(int keyCode, KeyEvent event);
boolean onKeyDown(int keyCode, KeyEvent event);
public abstract String exec(String service, String action, String callbackId, String message) throws JSONException;
String exec(String service, String action, String callbackId, String message) throws JSONException;
public abstract void setNativeToJsBridgeMode(int parseInt);
void setNativeToJsBridgeMode(int parseInt);
public abstract String retrieveJsMessages(boolean equals);
String retrieveJsMessages(boolean equals);
public abstract void showCustomView(View view, CustomViewCallback callback);
void showCustomView(View view, CustomViewCallback callback);
public abstract void hideCustomView();
void hideCustomView();
public abstract Context getContext();
Context getContext();
public abstract boolean onOverrideUrlLoading(String url);
boolean onOverrideUrlLoading(String url);
public abstract void resetJsMessageQueue();
void resetJsMessageQueue();
public abstract void onReset();
void onReset();
public abstract int getVisibility();
int getVisibility();
public abstract void incUrlTimeout();
void incUrlTimeout();
public abstract void setOverScrollMode(int overScrollNever);
void setOverScrollMode(int overScrollNever);
public abstract void setNetworkAvailable(boolean online);
void setNetworkAvailable(boolean online);
public abstract CordovaResourceApi getResourceApi();
CordovaResourceApi getResourceApi();
public abstract void bindButton(boolean override);
public abstract void bindButton(String button, boolean override);
void bindButton(boolean override);
void bindButton(String button, boolean override);
public abstract boolean isBackButtonBound();
boolean isBackButtonBound();
public abstract void sendPluginResult(PluginResult cr, String callbackId);
void sendPluginResult(PluginResult cr, String callbackId);
public abstract PluginManager getPluginManager();
PluginManager getPluginManager();
public abstract void setLayoutParams(android.widget.FrameLayout.LayoutParams layoutParams);
void setLayoutParams(android.widget.FrameLayout.LayoutParams layoutParams);
// Required for test
public abstract String getUrl();
public abstract boolean isPaused();
String getUrl();
boolean isPaused();
}

View File

@@ -16,6 +16,7 @@
"license": "Apache version 2.0",
"dependencies": {
"q": "^0.9.0",
"shelljs": "^0.2.6"
"shelljs": "^0.2.6",
"which": "^1.0.5"
}
}