mirror of
https://github.com/apache/cordova-android.git
synced 2026-01-30 00:05:28 +08:00
Compare commits
122 Commits
3.7.1
...
update-gra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ed2272e51 | ||
|
|
d022be547b | ||
|
|
215adab1f9 | ||
|
|
c32bcca67b | ||
|
|
6bdc01290d | ||
|
|
6fb164d200 | ||
|
|
6eb4409a72 | ||
|
|
8f27b2ab56 | ||
|
|
a10106c61a | ||
|
|
4c1efe7ad4 | ||
|
|
be01ce03d0 | ||
|
|
18fda7ec68 | ||
|
|
30e8b818f5 | ||
|
|
3cd567dc95 | ||
|
|
d99386ef1e | ||
|
|
dd5a337a49 | ||
|
|
51e634ccb4 | ||
|
|
31b1a821ca | ||
|
|
0b6b068097 | ||
|
|
623b2306ca | ||
|
|
233e513860 | ||
|
|
7caa96abcd | ||
|
|
b2776269cf | ||
|
|
4c1942e3fe | ||
|
|
a7ccb9243d | ||
|
|
f9b8f9a45f | ||
|
|
5054b714e2 | ||
|
|
05868b541b | ||
|
|
a40424e75c | ||
|
|
a99c8219bd | ||
|
|
a03fdaba39 | ||
|
|
6f301576eb | ||
|
|
e2b3f76a10 | ||
|
|
b277202838 | ||
|
|
a4f6d9f6e7 | ||
|
|
1d4aa44d3d | ||
|
|
b52fcb8aa9 | ||
|
|
f0da63a8ff | ||
|
|
f38c460588 | ||
|
|
9b9c59766f | ||
|
|
fc2a202afa | ||
|
|
4b4b71ff32 | ||
|
|
9358838dab | ||
|
|
a4d9f702e4 | ||
|
|
efcedabee0 | ||
|
|
25a7b66296 | ||
|
|
ac194cd34f | ||
|
|
eca05e6bad | ||
|
|
84bf20152b | ||
|
|
200e9f1a8e | ||
|
|
7dc09b4019 | ||
|
|
dbb196a17e | ||
|
|
05a95c699f | ||
|
|
9c5e340fb8 | ||
|
|
67006add53 | ||
|
|
1571b26a65 | ||
|
|
bdf2f22f81 | ||
|
|
a8330773ca | ||
|
|
4ca2305693 | ||
|
|
428e1bc14d | ||
|
|
d66bb84924 | ||
|
|
4ce5123a12 | ||
|
|
96a1192474 | ||
|
|
c052f40ef8 | ||
|
|
98246c0e35 | ||
|
|
8ac067da89 | ||
|
|
0ffb5d253a | ||
|
|
3a9898a6a6 | ||
|
|
693ec14df5 | ||
|
|
fa189b3234 | ||
|
|
3b27cd093b | ||
|
|
6abb9da88a | ||
|
|
d5e8807756 | ||
|
|
7e9fdb3555 | ||
|
|
b42faea2eb | ||
|
|
635a6279a9 | ||
|
|
404d3e0959 | ||
|
|
f77b20bbca | ||
|
|
1d0a1664e6 | ||
|
|
410afbf9a1 | ||
|
|
aaddfa6f3a | ||
|
|
2d9a16e857 | ||
|
|
1dcba51092 | ||
|
|
7c63b30de1 | ||
|
|
c0eae1ad52 | ||
|
|
c012b98223 | ||
|
|
559493babd | ||
|
|
990ab2c7ef | ||
|
|
437003de29 | ||
|
|
22b1959333 | ||
|
|
97008305ff | ||
|
|
1a17083e8c | ||
|
|
b6664cc859 | ||
|
|
e595c313a1 | ||
|
|
955da2e360 | ||
|
|
04b3fc0268 | ||
|
|
105ccc81a5 | ||
|
|
3571307df5 | ||
|
|
df05f3a3c0 | ||
|
|
8e31ef7be6 | ||
|
|
f4555f7c96 | ||
|
|
8408da55ea | ||
|
|
4a67dd2e28 | ||
|
|
bd806a34d8 | ||
|
|
2f7e833a79 | ||
|
|
c17503ab78 | ||
|
|
19f76d34db | ||
|
|
25c8b2fabb | ||
|
|
bfd8bf9ca4 | ||
|
|
7a5405d2ab | ||
|
|
b9a24f00ad | ||
|
|
dbfc292353 | ||
|
|
a09255b2ff | ||
|
|
9d1c72cc07 | ||
|
|
09ac30ef2e | ||
|
|
79e313a0c0 | ||
|
|
9f4c75d1c2 | ||
|
|
b37492644c | ||
|
|
04a792a8c2 | ||
|
|
35ec24c3f0 | ||
|
|
61b23677d1 | ||
|
|
90037dc6cd |
@@ -119,7 +119,6 @@ function writeProjectProperties(projectPath, target_api, shared) {
|
||||
|
||||
function copyBuildRules(projectPath) {
|
||||
var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
|
||||
shell.cp('-f', path.join(srcDir, 'custom_rules.xml'), projectPath);
|
||||
|
||||
shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
|
||||
shell.cp('-f', path.join(srcDir, 'settings.gradle'), projectPath);
|
||||
|
||||
8
bin/templates/cordova/lib/build.js
vendored
8
bin/templates/cordova/lib/build.js
vendored
@@ -214,6 +214,14 @@ var builders = {
|
||||
shell.rm('-rf', path.join(projectPath, 'gradle', 'wrapper'));
|
||||
shell.mkdir('-p', path.join(projectPath, 'gradle'));
|
||||
shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(projectPath, 'gradle'));
|
||||
|
||||
// If the gradle distribution URL is set, make sure it points to version 1.12.
|
||||
// If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
|
||||
// For some reason, using ^ and $ don't work. This does the job, though.
|
||||
var distributionUrlRegex = /distributionUrl.*zip/;
|
||||
var distributionUrl = 'distributionUrl=http\\://services.gradle.org/distributions/gradle-1.12-all.zip';
|
||||
var gradleWrapperPropertiesPath = path.join(projectPath, 'gradle', 'wrapper', 'gradle-wrapper.properties');
|
||||
shell.sed('-i', distributionUrlRegex, distributionUrl, gradleWrapperPropertiesPath);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
*/
|
||||
|
||||
// Coho updates this line:
|
||||
var VERSION = "3.7.0-dev";
|
||||
var VERSION = "4.0.0-dev";
|
||||
|
||||
console.log(VERSION);
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
/>
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
||||
android:hardwareAccelerated="true" android:supportsRtl="true">
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project>
|
||||
<target name="-pre-compile">
|
||||
<!-- Fix library references due to bug in build.xml: See: https://groups.google.com/forum/#!topic/android-developers/0ivH-YqCjzg -->
|
||||
<pathconvert property="fixedJarsPath" refid="project.all.jars.path">
|
||||
<filtermapper>
|
||||
<replacestring from="/bin/" to="/ant-build/"/>
|
||||
<replacestring from="\bin\" to="\ant-build\"/>
|
||||
</filtermapper>
|
||||
</pathconvert>
|
||||
<path id="project.all.jars.path">
|
||||
<pathelement path="${fixedJarsPath}"/>
|
||||
</path>
|
||||
<echo message="Set jars path to: ${toString:project.all.jars.path}"/>
|
||||
</target>
|
||||
<!-- Rename AndroidManifest.xml so that Eclipse's import wizard doesn't detect ant-build as a project -->
|
||||
<target name="-post-build">
|
||||
<move file="ant-build/AndroidManifest.xml" tofile="ant-build/AndroidManifest.cordova.xml" failonerror="false" overwrite="true" />
|
||||
<move file="CordovaLib/ant-build/AndroidManifest.xml" tofile="CordovaLib/ant-build/AndroidManifest.cordova.xml" failonerror="false" overwrite="true" />
|
||||
</target>
|
||||
</project>
|
||||
|
||||
@@ -29,7 +29,9 @@ buildscript {
|
||||
// It can affect things like where the .apk is generated.
|
||||
// It also dictates what the minimum android build-tools version
|
||||
// that you need (Set in bin/templates/project/cordova.gradle).
|
||||
// Be sure to also update the value in bin/templates/project.
|
||||
// Be sure to also update the value in:
|
||||
// (1) bin/templates/project/build.gradle, and
|
||||
// (2) the distribution URL in bin/templates/cordova/lib/build.js.
|
||||
classpath 'com.android.tools.build:gradle:0.12.+'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
<content src="index.html" />
|
||||
|
||||
<preference name="loglevel" value="DEBUG" />
|
||||
|
||||
<!--
|
||||
<preference name="splashscreen" value="resourceName" />
|
||||
<preference name="backgroundColor" value="0xFFF" />
|
||||
|
||||
@@ -54,35 +54,25 @@ import android.widget.RelativeLayout;
|
||||
* @see CordovaWebViewClient
|
||||
* @see CordovaWebView
|
||||
*/
|
||||
public class CordovaChromeClient extends WebChromeClient {
|
||||
public class AndroidChromeClient extends WebChromeClient {
|
||||
|
||||
public static final int FILECHOOSER_RESULTCODE = 5173;
|
||||
private String TAG = "CordovaLog";
|
||||
private static final String LOG_TAG = "AndroidChromeClient";
|
||||
private long MAX_QUOTA = 100 * 1024 * 1024;
|
||||
protected CordovaInterface cordova;
|
||||
protected CordovaWebView appView;
|
||||
protected final CordovaInterface cordova;
|
||||
protected final AndroidWebView appView;
|
||||
|
||||
// the video progress view
|
||||
private View mVideoProgressView;
|
||||
|
||||
// File Chooser
|
||||
public ValueCallback<Uri> mUploadMessage;
|
||||
protected ValueCallback<Uri> mUploadMessage;
|
||||
|
||||
@Deprecated
|
||||
public CordovaChromeClient(CordovaInterface cordova) {
|
||||
this.cordova = cordova;
|
||||
}
|
||||
|
||||
public CordovaChromeClient(CordovaInterface ctx, CordovaWebView app) {
|
||||
public AndroidChromeClient(CordovaInterface ctx, AndroidWebView app) {
|
||||
this.cordova = ctx;
|
||||
this.appView = app;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setWebView(CordovaWebView view) {
|
||||
this.appView = view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the client to display a javascript alert dialog.
|
||||
*
|
||||
@@ -228,7 +218,7 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
|
||||
long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
|
||||
{
|
||||
LOG.d(TAG, "onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
|
||||
LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
|
||||
quotaUpdater.updateQuota(MAX_QUOTA);
|
||||
}
|
||||
|
||||
@@ -241,7 +231,7 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
//This is only for Android 2.1
|
||||
if(android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.ECLAIR_MR1)
|
||||
{
|
||||
LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message);
|
||||
LOG.d(LOG_TAG, "%s: Line %d : %s", sourceID, lineNumber, message);
|
||||
super.onConsoleMessage(message, lineNumber, sourceID);
|
||||
}
|
||||
}
|
||||
@@ -251,7 +241,7 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
public boolean onConsoleMessage(ConsoleMessage consoleMessage)
|
||||
{
|
||||
if (consoleMessage.message() != null)
|
||||
LOG.d(TAG, "%s: Line %d : %s" , consoleMessage.sourceId() , consoleMessage.lineNumber(), consoleMessage.message());
|
||||
LOG.d(LOG_TAG, "%s: Line %d : %s" , consoleMessage.sourceId() , consoleMessage.lineNumber(), consoleMessage.message());
|
||||
return super.onConsoleMessage(consoleMessage);
|
||||
}
|
||||
|
||||
@@ -310,7 +300,7 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
|
||||
this.openFileChooser(uploadMsg, "*/*");
|
||||
}
|
||||
|
||||
|
||||
public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType ) {
|
||||
this.openFileChooser(uploadMsg, acceptType, null);
|
||||
}
|
||||
@@ -324,8 +314,4 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
this.cordova.getActivity().startActivityForResult(Intent.createChooser(i, "File Browser"),
|
||||
FILECHOOSER_RESULTCODE);
|
||||
}
|
||||
|
||||
public ValueCallback<Uri> getValueCallback() {
|
||||
return this.mUploadMessage;
|
||||
}
|
||||
}
|
||||
50
framework/src/org/apache/cordova/AndroidExposedJsApi.java
Executable file
50
framework/src/org/apache/cordova/AndroidExposedJsApi.java
Executable file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
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 android.webkit.JavascriptInterface;
|
||||
import org.json.JSONException;
|
||||
|
||||
/**
|
||||
* Contains APIs that the JS can call. All functions in here should also have
|
||||
* an equivalent entry in CordovaChromeClient.java, and be added to
|
||||
* cordova-js/lib/android/plugin/android/promptbasednativeapi.js
|
||||
*/
|
||||
class AndroidExposedJsApi implements ExposedJsApi {
|
||||
private final CordovaBridge bridge;
|
||||
|
||||
AndroidExposedJsApi(CordovaBridge bridge) {
|
||||
this.bridge = bridge;
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
|
||||
return bridge.jsExec(bridgeSecret, service, action, callbackId, arguments);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
|
||||
bridge.jsSetNativeToJsBridgeMode(bridgeSecret, value);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
|
||||
return bridge.jsRetrieveJsMessages(bridgeSecret, fromOnlineEvent);
|
||||
}
|
||||
}
|
||||
775
framework/src/org/apache/cordova/AndroidWebView.java
Executable file
775
framework/src/org/apache/cordova/AndroidWebView.java
Executable file
@@ -0,0 +1,775 @@
|
||||
/*
|
||||
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.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
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.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;
|
||||
|
||||
|
||||
/*
|
||||
* 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 = "AndroidWebView";
|
||||
|
||||
private HashSet<Integer> boundKeyCodes = new HashSet<Integer>();
|
||||
|
||||
PluginManager pluginManager;
|
||||
|
||||
private BroadcastReceiver receiver;
|
||||
|
||||
|
||||
/** Activities and other important classes **/
|
||||
private CordovaInterface cordova;
|
||||
AndroidWebViewClient viewClient;
|
||||
private AndroidChromeClient chromeClient;
|
||||
|
||||
// Flag to track that a loadUrl timeout occurred
|
||||
int loadUrlTimeout = 0;
|
||||
|
||||
private long lastMenuEventTime = 0;
|
||||
|
||||
CordovaBridge bridge;
|
||||
|
||||
/** custom view created by the browser (a video player for example) */
|
||||
private View mCustomView;
|
||||
private WebChromeClient.CustomViewCallback mCustomViewCallback;
|
||||
|
||||
private CordovaResourceApi resourceApi;
|
||||
private Whitelist internalWhitelist;
|
||||
private Whitelist externalWhitelist;
|
||||
private CordovaPreferences preferences;
|
||||
// The URL passed to loadUrl(), not necessarily the URL of the current page.
|
||||
String loadedUrl;
|
||||
|
||||
static final FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER =
|
||||
new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
Gravity.CENTER);
|
||||
|
||||
/** Used when created via reflection. */
|
||||
public AndroidWebView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
/** Required to allow view to be used within XML layouts. */
|
||||
public AndroidWebView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
// Use two-phase init so that the control will work with XML layouts.
|
||||
@Override
|
||||
public void init(CordovaInterface cordova, List<PluginEntry> pluginEntries,
|
||||
Whitelist internalWhitelist, Whitelist externalWhitelist,
|
||||
CordovaPreferences preferences) {
|
||||
if (this.cordova != null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
this.cordova = cordova;
|
||||
this.internalWhitelist = internalWhitelist;
|
||||
this.externalWhitelist = externalWhitelist;
|
||||
this.preferences = preferences;
|
||||
|
||||
pluginManager = new PluginManager(this, this.cordova, pluginEntries);
|
||||
resourceApi = new CordovaResourceApi(this.getContext(), pluginManager);
|
||||
bridge = new CordovaBridge(pluginManager, new NativeToJsMessageQueue(this, cordova));
|
||||
pluginManager.addService("App", "org.apache.cordova.CoreAndroid");
|
||||
initWebViewSettings();
|
||||
|
||||
if (this.viewClient == null) {
|
||||
setWebViewClient(Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH ?
|
||||
new AndroidWebViewClient(cordova, this) :
|
||||
new IceCreamCordovaWebViewClient(cordova, this));
|
||||
}
|
||||
if (this.chromeClient == null) {
|
||||
setWebChromeClient(new AndroidChromeClient(cordova, this));
|
||||
}
|
||||
|
||||
exposeJsInterface();
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@SuppressWarnings("deprecation")
|
||||
private void initWebViewSettings() {
|
||||
this.setInitialScale(0);
|
||||
this.setVerticalScrollBarEnabled(false);
|
||||
// TODO: The Activity is the one that should call requestFocus().
|
||||
if (shouldRequestFocusOnInit()) {
|
||||
this.requestFocusFromTouch();
|
||||
}
|
||||
this.setInitialScale(0);
|
||||
this.setVerticalScrollBarEnabled(false);
|
||||
if (shouldRequestFocusOnInit()) {
|
||||
this.requestFocusFromTouch();
|
||||
}
|
||||
// Enable JavaScript
|
||||
final WebSettings settings = this.getSettings();
|
||||
settings.setJavaScriptEnabled(true);
|
||||
settings.setJavaScriptCanOpenWindowsAutomatically(true);
|
||||
settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
|
||||
|
||||
// Set the nav dump for HTC 2.x devices (disabling for ICS, deprecated entirely for Jellybean 4.2)
|
||||
try {
|
||||
Method gingerbread_getMethod = WebSettings.class.getMethod("setNavDump", new Class[] { boolean.class });
|
||||
|
||||
String manufacturer = android.os.Build.MANUFACTURER;
|
||||
Log.d(TAG, "CordovaWebView is running on device made by: " + manufacturer);
|
||||
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB &&
|
||||
android.os.Build.MANUFACTURER.contains("HTC"))
|
||||
{
|
||||
gingerbread_getMethod.invoke(settings, true);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.d(TAG, "We are on a modern version of Android, we will deprecate HTC 2.3 devices in 2.8");
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.d(TAG, "Doing the NavDump failed with bad arguments");
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.d(TAG, "This should never happen: IllegalAccessException means this isn't Android anymore");
|
||||
} catch (InvocationTargetException e) {
|
||||
Log.d(TAG, "This should never happen: InvocationTargetException means this isn't Android anymore.");
|
||||
}
|
||||
|
||||
//We don't save any form data in the application
|
||||
settings.setSaveFormData(false);
|
||||
settings.setSavePassword(false);
|
||||
|
||||
// Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist
|
||||
// while we do this
|
||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
|
||||
Level16Apis.enableUniversalAccess(settings);
|
||||
// Enable database
|
||||
// We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16
|
||||
String databasePath = getContext().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!
|
||||
ApplicationInfo appInfo = getContext().getApplicationContext().getApplicationInfo();
|
||||
if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 &&
|
||||
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
|
||||
enableRemoteDebugging();
|
||||
}
|
||||
|
||||
settings.setGeolocationDatabasePath(databasePath);
|
||||
|
||||
// Enable DOM storage
|
||||
settings.setDomStorageEnabled(true);
|
||||
|
||||
// Enable built-in geolocation
|
||||
settings.setGeolocationEnabled(true);
|
||||
|
||||
// Enable AppCache
|
||||
// Fix for CB-2282
|
||||
settings.setAppCacheMaxSize(5 * 1048576);
|
||||
settings.setAppCachePath(databasePath);
|
||||
settings.setAppCacheEnabled(true);
|
||||
|
||||
// Fix for CB-1405
|
||||
// Google issue 4641
|
||||
settings.getUserAgentString();
|
||||
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
|
||||
if (this.receiver == null) {
|
||||
this.receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
settings.getUserAgentString();
|
||||
}
|
||||
};
|
||||
getContext().registerReceiver(this.receiver, intentFilter);
|
||||
}
|
||||
// end CB-1405
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
private void enableRemoteDebugging() {
|
||||
try {
|
||||
WebView.setWebContentsDebuggingEnabled(true);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.d(TAG, "You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to decide whether or not you need to request the
|
||||
* focus when your application start
|
||||
*
|
||||
* @return true unless this method is overriden to return a different value
|
||||
*/
|
||||
protected boolean shouldRequestFocusOnInit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void exposeJsInterface() {
|
||||
if ((Build.VERSION.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;
|
||||
}
|
||||
AndroidExposedJsApi exposedJsApi = new AndroidExposedJsApi(bridge);
|
||||
this.addJavascriptInterface(exposedJsApi, "_cordovaNative");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWebViewClient(WebViewClient client) {
|
||||
this.viewClient = (AndroidWebViewClient)client;
|
||||
super.setWebViewClient(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWebChromeClient(WebChromeClient client) {
|
||||
this.chromeClient = (AndroidChromeClient)client;
|
||||
super.setWebChromeClient(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the url into the webview.
|
||||
*/
|
||||
@Override
|
||||
public void loadUrl(String url) {
|
||||
this.loadUrlIntoView(url, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the url into the webview.
|
||||
*/
|
||||
@Override
|
||||
public void loadUrlIntoView(final String url, boolean recreatePlugins) {
|
||||
if (url.equals("about:blank") || url.startsWith("javascript:")) {
|
||||
this.loadUrlNow(url);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.d(TAG, ">>> loadUrl(" + url + ")");
|
||||
recreatePlugins = recreatePlugins || (loadedUrl == null);
|
||||
|
||||
if (recreatePlugins) {
|
||||
this.loadedUrl = url;
|
||||
this.pluginManager.init();
|
||||
}
|
||||
|
||||
// Create a timeout timer for loadUrl
|
||||
final AndroidWebView me = this;
|
||||
final int currentLoadUrlTimeout = me.loadUrlTimeout;
|
||||
final int loadUrlTimeoutValue = preferences.getInteger("LoadUrlTimeoutValue", 20000);
|
||||
|
||||
// Timeout error method
|
||||
final Runnable loadError = new Runnable() {
|
||||
public void run() {
|
||||
me.stopLoading();
|
||||
LOG.e(TAG, "CordovaWebView: TIMEOUT ERROR!");
|
||||
if (viewClient != null) {
|
||||
viewClient.onReceivedError(AndroidWebView.this, -6, "The connection to the server was unsuccessful.", url);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Timeout timer method
|
||||
final Runnable timeoutCheck = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
synchronized (this) {
|
||||
wait(loadUrlTimeoutValue);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// If timeout, then stop loading and handle error
|
||||
if (me.loadUrlTimeout == currentLoadUrlTimeout) {
|
||||
me.cordova.getActivity().runOnUiThread(loadError);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Load url
|
||||
this.cordova.getActivity().runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
cordova.getThreadPool().execute(timeoutCheck);
|
||||
me.loadUrlNow(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load URL in webview.
|
||||
*/
|
||||
private void loadUrlNow(String url) {
|
||||
if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) {
|
||||
LOG.d(TAG, ">>> loadUrlNow()");
|
||||
}
|
||||
if (url.startsWith("file://") || url.startsWith("javascript:") || internalWhitelist.isUrlWhiteListed(url)) {
|
||||
super.loadUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopLoading() {
|
||||
//viewClient.isCurrentlyLoading = false;
|
||||
super.stopLoading();
|
||||
}
|
||||
|
||||
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);
|
||||
pluginManager.postMessage("onScrollChanged", myEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send JavaScript statement back to JavaScript.
|
||||
* (This is a convenience method)
|
||||
*/
|
||||
public void sendJavascript(String statement) {
|
||||
bridge.getMessageQueue().addJavaScript(statement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a plugin result back to JavaScript.
|
||||
*/
|
||||
public void sendPluginResult(PluginResult result, String callbackId) {
|
||||
bridge.getMessageQueue().addPluginResult(result, callbackId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to previous page in history. (We manage our own history)
|
||||
*
|
||||
* @return true if we went back, false if we are already at top
|
||||
*/
|
||||
public boolean backHistory() {
|
||||
|
||||
// Check webview first to see if there is a history
|
||||
// This is needed to support curPage#diffLink, since they are added to appView's history, but not our history url array (JQMobile behavior)
|
||||
if (super.canGoBack()) {
|
||||
printBackForwardList();
|
||||
super.goBack();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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://") || internalWhitelist.isUrlWhiteListed(url)) {
|
||||
// TODO: What about params?
|
||||
// Load new URL
|
||||
loadUrlIntoView(url, true);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* onKeyDown
|
||||
*/
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event)
|
||||
{
|
||||
if(boundKeyCodes.contains(keyCode))
|
||||
{
|
||||
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');");
|
||||
return true;
|
||||
}
|
||||
else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
}
|
||||
else if(keyCode == KeyEvent.KEYCODE_BACK)
|
||||
{
|
||||
return !(this.startOfHistory()) || isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
|
||||
|
||||
}
|
||||
else if(keyCode == KeyEvent.KEYCODE_MENU)
|
||||
{
|
||||
//How did we get here? Is there a childView?
|
||||
View childView = this.getFocusedChild();
|
||||
if(childView != null)
|
||||
{
|
||||
//Make sure we close the keyboard if it's present
|
||||
InputMethodManager imm = (InputMethodManager) cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(childView.getWindowToken(), 0);
|
||||
cordova.getActivity().openOptionsMenu();
|
||||
return true;
|
||||
} else {
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event)
|
||||
{
|
||||
// If back key
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
// A custom view is currently displayed (e.g. playing a video)
|
||||
if(mCustomView != null) {
|
||||
this.hideCustomView();
|
||||
return true;
|
||||
} else {
|
||||
// The webview is currently displayed
|
||||
// If back key is bound, then send event to JavaScript
|
||||
if (isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK)) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('backbutton');");
|
||||
return true;
|
||||
} else {
|
||||
// If not bound
|
||||
// Go to previous page in webview if it is possible to go back
|
||||
if (this.backHistory()) {
|
||||
return true;
|
||||
}
|
||||
// If not, then invoke default behavior
|
||||
}
|
||||
}
|
||||
}
|
||||
// Legacy
|
||||
else if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
if (this.lastMenuEventTime < event.getEventTime()) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('menubutton');");
|
||||
}
|
||||
this.lastMenuEventTime = event.getEventTime();
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
// If search key
|
||||
else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('searchbutton');");
|
||||
return true;
|
||||
}
|
||||
|
||||
//Does webkit change this behavior?
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setButtonPlumbedToJs(int keyCode, boolean override) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
// TODO: Why are search and menu buttons handled separately?
|
||||
if (override) {
|
||||
boundKeyCodes.add(keyCode);
|
||||
} else {
|
||||
boundKeyCodes.remove(keyCode);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isButtonPlumbedToJs(int keyCode)
|
||||
{
|
||||
return boundKeyCodes.contains(keyCode);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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 {
|
||||
getContext().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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
private static class Level16Apis {
|
||||
static void enableUniversalAccess(WebSettings settings) {
|
||||
settings.setAllowUniversalAccessFromFileURLs(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void printBackForwardList() {
|
||||
WebBackForwardList currentList = this.copyBackForwardList();
|
||||
int currentSize = currentList.getSize();
|
||||
for(int i = 0; i < currentSize; ++i)
|
||||
{
|
||||
WebHistoryItem item = currentList.getItemAtIndex(i);
|
||||
String url = item.getUrl();
|
||||
LOG.d(TAG, "The URL at index: " + Integer.toString(i) + " is " + url );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Can Go Back is BROKEN!
|
||||
public boolean startOfHistory()
|
||||
{
|
||||
WebBackForwardList currentList = this.copyBackForwardList();
|
||||
WebHistoryItem item = currentList.getItemAtIndex(0);
|
||||
if( item!=null){ // Null-fence in case they haven't called loadUrl yet (CB-2458)
|
||||
String url = item.getUrl();
|
||||
String currentUrl = this.getUrl();
|
||||
LOG.d(TAG, "The current URL is: " + currentUrl);
|
||||
LOG.d(TAG, "The URL at item 0 is: " + url);
|
||||
return currentUrl.equals(url);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
this.pluginManager.init();
|
||||
return myList;
|
||||
}
|
||||
|
||||
public CordovaResourceApi getResourceApi() {
|
||||
return resourceApi;
|
||||
}
|
||||
|
||||
void onPageReset() {
|
||||
boundKeyCodes.clear();
|
||||
pluginManager.onReset();
|
||||
bridge.reset(loadedUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginManager getPluginManager() {
|
||||
return this.pluginManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Whitelist getWhitelist() {
|
||||
return this.internalWhitelist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Whitelist getExternalWhitelist() {
|
||||
return this.externalWhitelist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CordovaPreferences getPreferences() {
|
||||
return preferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilePickerResult(Uri uri) {
|
||||
if (null == chromeClient.mUploadMessage)
|
||||
return;
|
||||
chromeClient.mUploadMessage.onReceiveValue(uri);
|
||||
chromeClient.mUploadMessage = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postMessage(String id, Object data) {
|
||||
return pluginManager.postMessage(id, data);
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,6 @@ package org.apache.cordova;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.apache.cordova.CordovaInterface;
|
||||
|
||||
import org.apache.cordova.LOG;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@@ -38,6 +35,7 @@ import android.webkit.SslErrorHandler;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
|
||||
/**
|
||||
* This class is the WebViewClient that implements callbacks for our web view.
|
||||
* The kind of callbacks that happen here are regarding the rendering of the
|
||||
@@ -50,42 +48,20 @@ import android.webkit.WebViewClient;
|
||||
* @see CordovaChromeClient
|
||||
* @see CordovaWebView
|
||||
*/
|
||||
public class CordovaWebViewClient extends WebViewClient {
|
||||
public class AndroidWebViewClient extends WebViewClient {
|
||||
|
||||
private static final String TAG = "CordovaWebViewClient";
|
||||
CordovaInterface cordova;
|
||||
CordovaWebView appView;
|
||||
CordovaUriHelper helper;
|
||||
private static final String TAG = "AndroidWebViewClient";
|
||||
protected final CordovaInterface cordova;
|
||||
protected final AndroidWebView appView;
|
||||
protected final CordovaUriHelper helper;
|
||||
private boolean doClearHistory = false;
|
||||
boolean isCurrentlyLoading;
|
||||
|
||||
/** The authorization tokens. */
|
||||
private Hashtable<String, AuthenticationToken> authenticationTokens = new Hashtable<String, AuthenticationToken>();
|
||||
|
||||
@Deprecated
|
||||
public CordovaWebViewClient(CordovaInterface cordova) {
|
||||
public AndroidWebViewClient(CordovaInterface cordova, AndroidWebView view) {
|
||||
this.cordova = cordova;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param cordova
|
||||
* @param view
|
||||
*/
|
||||
public CordovaWebViewClient(CordovaInterface cordova, CordovaWebView view) {
|
||||
this.cordova = cordova;
|
||||
this.appView = view;
|
||||
helper = new CordovaUriHelper(cordova, view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param view
|
||||
*/
|
||||
@Deprecated
|
||||
public void setWebView(CordovaWebView view) {
|
||||
this.appView = view;
|
||||
helper = new CordovaUriHelper(cordova, view);
|
||||
}
|
||||
@@ -100,17 +76,12 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
*/
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
return helper.shouldOverrideUrlLoading(view, url);
|
||||
return helper.shouldOverrideUrlLoading(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* On received http auth request.
|
||||
* The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination
|
||||
*
|
||||
* @param view
|
||||
* @param handler
|
||||
* @param host
|
||||
* @param realm
|
||||
*/
|
||||
@Override
|
||||
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
|
||||
@@ -140,16 +111,11 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
super.onPageStarted(view, url, favicon);
|
||||
isCurrentlyLoading = true;
|
||||
LOG.d(TAG, "onPageStarted(" + url + ")");
|
||||
// Flush stale messages.
|
||||
this.appView.bridge.reset(url);
|
||||
// Flush stale messages & reset plugins.
|
||||
this.appView.onPageReset();
|
||||
|
||||
// Broadcast message that page has loaded
|
||||
this.appView.postMessage("onPageStarted", url);
|
||||
|
||||
// Notify all plugins of the navigation, so they can clean up if necessary.
|
||||
if (this.appView.pluginManager != null) {
|
||||
this.appView.pluginManager.onReset();
|
||||
}
|
||||
this.appView.getPluginManager().postMessage("onPageStarted", url);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,10 +148,10 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
}
|
||||
|
||||
// Clear timeout flag
|
||||
this.appView.loadUrlTimeout++;
|
||||
appView.loadUrlTimeout++;
|
||||
|
||||
// Broadcast message that page has loaded
|
||||
this.appView.postMessage("onPageFinished", url);
|
||||
this.appView.getPluginManager().postMessage("onPageFinished", url);
|
||||
|
||||
// Make app visible after 2 sec in case there was a JS error and Cordova JS never initialized correctly
|
||||
if (this.appView.getVisibility() == View.INVISIBLE) {
|
||||
@@ -195,7 +161,7 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
Thread.sleep(2000);
|
||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
appView.postMessage("spinner", "stop");
|
||||
appView.getPluginManager().postMessage("spinner", "stop");
|
||||
}
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
@@ -207,7 +173,7 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
|
||||
// Shutdown if blank loaded
|
||||
if (url.equals("about:blank")) {
|
||||
appView.postMessage("exit", null);
|
||||
appView.getPluginManager().postMessage("exit", null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +195,7 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
LOG.d(TAG, "CordovaWebViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl);
|
||||
|
||||
// Clear timeout flag
|
||||
this.appView.loadUrlTimeout++;
|
||||
appView.loadUrlTimeout++;
|
||||
|
||||
// If this is a "Protocol Not Supported" error, then revert to the previous
|
||||
// page. If there was no previous page, then punt. The application's config
|
||||
@@ -252,7 +218,7 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.appView.postMessage("onReceivedError", data);
|
||||
this.appView.getPluginManager().postMessage("onReceivedError", data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -361,5 +327,4 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
public void clearAuthenticationTokens() {
|
||||
this.authenticationTokens.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.util.Log;
|
||||
|
||||
public class ConfigXmlParser {
|
||||
private static String TAG = "ConfigXmlParser";
|
||||
@@ -80,7 +79,6 @@ public class ConfigXmlParser {
|
||||
String service = "", pluginClass = "", paramType = "";
|
||||
boolean onload = false;
|
||||
boolean insideFeature = false;
|
||||
ArrayList<String> urlMap = null;
|
||||
|
||||
// Add implicitly allowed URLs
|
||||
internalWhitelist.addWhiteListEntry("file:///*", false);
|
||||
@@ -90,13 +88,7 @@ public class ConfigXmlParser {
|
||||
while (eventType != XmlResourceParser.END_DOCUMENT) {
|
||||
if (eventType == XmlResourceParser.START_TAG) {
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("url-filter")) {
|
||||
Log.w(TAG, "Plugin " + service + " is using deprecated tag <url-filter>");
|
||||
if (urlMap == null) {
|
||||
urlMap = new ArrayList<String>(2);
|
||||
}
|
||||
urlMap.add(xml.getAttributeValue(null, "value"));
|
||||
} else if (strNode.equals("feature")) {
|
||||
if (strNode.equals("feature")) {
|
||||
//Check for supported feature sets aka. plugins (Accelerometer, Geolocation, etc)
|
||||
//Set the bit for reading params
|
||||
insideFeature = true;
|
||||
@@ -147,13 +139,12 @@ public class ConfigXmlParser {
|
||||
{
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("feature")) {
|
||||
pluginEntries.add(new PluginEntry(service, pluginClass, onload, urlMap));
|
||||
pluginEntries.add(new PluginEntry(service, pluginClass, onload));
|
||||
|
||||
service = "";
|
||||
pluginClass = "";
|
||||
insideFeature = false;
|
||||
onload = false;
|
||||
urlMap = null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
*/
|
||||
package org.apache.cordova;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@@ -29,7 +30,6 @@ import org.apache.cordova.LOG;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
@@ -44,14 +44,12 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
@@ -91,12 +89,6 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
// The webview for our app
|
||||
protected CordovaWebView appView;
|
||||
|
||||
@Deprecated // unused.
|
||||
protected CordovaWebViewClient webViewClient;
|
||||
|
||||
@Deprecated // Will be removed. Use findViewById() to retrieve views.
|
||||
protected LinearLayout root;
|
||||
|
||||
protected ProgressDialog spinnerDialog = null;
|
||||
private final ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
|
||||
@@ -116,7 +108,6 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
// Draw a splash screen using an image located in the drawable resource directory.
|
||||
// This is not the same as calling super.loadSplashscreen(url)
|
||||
protected int splashscreen = 0;
|
||||
protected int splashscreenTime = 3000;
|
||||
|
||||
// LoadUrl timeout value in msec (default of 20 sec)
|
||||
protected int loadUrlTimeoutValue = 20000;
|
||||
@@ -135,64 +126,6 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
protected String launchUrl;
|
||||
protected ArrayList<PluginEntry> pluginEntries;
|
||||
|
||||
/**
|
||||
* Sets the authentication token.
|
||||
*
|
||||
* @param authenticationToken
|
||||
* @param host
|
||||
* @param realm
|
||||
*/
|
||||
public void setAuthenticationToken(AuthenticationToken authenticationToken, String host, String realm) {
|
||||
if (this.appView != null && this.appView.viewClient != null) {
|
||||
this.appView.viewClient.setAuthenticationToken(authenticationToken, host, realm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the authentication token.
|
||||
*
|
||||
* @param host
|
||||
* @param realm
|
||||
*
|
||||
* @return the authentication token or null if did not exist
|
||||
*/
|
||||
public AuthenticationToken removeAuthenticationToken(String host, String realm) {
|
||||
if (this.appView != null && this.appView.viewClient != null) {
|
||||
return this.appView.viewClient.removeAuthenticationToken(host, realm);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the authentication token.
|
||||
*
|
||||
* In order it tries:
|
||||
* 1- host + realm
|
||||
* 2- host
|
||||
* 3- realm
|
||||
* 4- no host, no realm
|
||||
*
|
||||
* @param host
|
||||
* @param realm
|
||||
*
|
||||
* @return the authentication token
|
||||
*/
|
||||
public AuthenticationToken getAuthenticationToken(String host, String realm) {
|
||||
if (this.appView != null && this.appView.viewClient != null) {
|
||||
return this.appView.viewClient.getAuthenticationToken(host, realm);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all authentication tokens.
|
||||
*/
|
||||
public void clearAuthenticationTokens() {
|
||||
if (this.appView != null && this.appView.viewClient != null) {
|
||||
this.appView.viewClient.clearAuthenticationTokens();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@@ -209,6 +142,38 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
if(!preferences.getBoolean("ShowTitle", false))
|
||||
{
|
||||
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
|
||||
}
|
||||
|
||||
if(preferences.getBoolean("SetFullscreen", false))
|
||||
{
|
||||
Log.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version.");
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
} else if (preferences.getBoolean("Fullscreen", false)) {
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
} else {
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
|
||||
}
|
||||
|
||||
appView = makeWebView();
|
||||
|
||||
// TODO: Have the views set this themselves.
|
||||
if (preferences.getBoolean("DisallowOverscroll", false)) {
|
||||
appView.getView().setOverScrollMode(View.OVER_SCROLL_NEVER);
|
||||
}
|
||||
createViews();
|
||||
|
||||
// TODO: Make this a preference (CB-6153)
|
||||
// Setup the hardware volume controls to handle volume control
|
||||
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void loadConfig() {
|
||||
@@ -226,26 +191,25 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void createViews() {
|
||||
// This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket!
|
||||
// This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket!
|
||||
Display display = getWindowManager().getDefaultDisplay();
|
||||
int width = display.getWidth();
|
||||
int height = display.getHeight();
|
||||
|
||||
root = new LinearLayoutSoftKeyboardDetect(this, width, height);
|
||||
LinearLayoutSoftKeyboardDetect root = new LinearLayoutSoftKeyboardDetect(this, width, height);
|
||||
root.setOrientation(LinearLayout.VERTICAL);
|
||||
root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, 0.0F));
|
||||
|
||||
appView.setId(100);
|
||||
appView.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
appView.getView().setId(100);
|
||||
appView.getView().setLayoutParams(new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
1.0F));
|
||||
|
||||
// Add web view but make it invisible while loading URL
|
||||
appView.setVisibility(View.INVISIBLE);
|
||||
root.addView((View) appView);
|
||||
appView.getView().setVisibility(View.INVISIBLE);
|
||||
root.addView(appView.getView());
|
||||
setContentView(root);
|
||||
|
||||
int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK);
|
||||
@@ -266,93 +230,50 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
* require a more specialized web view.
|
||||
*/
|
||||
protected CordovaWebView makeWebView() {
|
||||
return new CordovaWebView(CordovaActivity.this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the client for the default web view object.
|
||||
*
|
||||
* This is intended to be overridable by subclasses of CordovaIntent which
|
||||
* require a more specialized web view.
|
||||
*
|
||||
* @param webView the default constructed web view object
|
||||
*/
|
||||
protected CordovaWebViewClient makeWebViewClient(CordovaWebView webView) {
|
||||
return webView.makeWebViewClient(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the chrome client for the default web view object.
|
||||
*
|
||||
* This is intended to be overridable by subclasses of CordovaIntent which
|
||||
* require a more specialized web view.
|
||||
*
|
||||
* @param webView the default constructed web view object
|
||||
*/
|
||||
protected CordovaChromeClient makeChromeClient(CordovaWebView webView) {
|
||||
return webView.makeWebChromeClient(this);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
this.init(appView, null, null);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Deprecated // Call init() instead and override makeWebView() to customize.
|
||||
public void init(CordovaWebView webView, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient) {
|
||||
LOG.d(TAG, "CordovaActivity.init()");
|
||||
|
||||
if(!preferences.getBoolean("ShowTitle", false))
|
||||
{
|
||||
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
|
||||
String r = preferences.getString("webView", null);
|
||||
CordovaWebView ret = null;
|
||||
if (r != null) {
|
||||
try {
|
||||
Class<?> webViewClass = Class.forName(r);
|
||||
Constructor<?> constructor = webViewClass.getConstructor(Context.class);
|
||||
ret = (CordovaWebView) constructor.newInstance((Context)this);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if(preferences.getBoolean("SetFullscreen", false))
|
||||
{
|
||||
Log.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version.");
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
} else if (preferences.getBoolean("Fullscreen", false)) {
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
} else {
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
|
||||
|
||||
if (ret == null) {
|
||||
// If all else fails, return a default WebView
|
||||
ret = new AndroidWebView(this);
|
||||
}
|
||||
|
||||
appView = webView != null ? webView : makeWebView();
|
||||
if (appView.pluginManager == null) {
|
||||
appView.init(this, webViewClient != null ? webViewClient : makeWebViewClient(appView),
|
||||
webChromeClient != null ? webChromeClient : makeChromeClient(appView),
|
||||
pluginEntries, internalWhitelist, externalWhitelist, preferences);
|
||||
}
|
||||
|
||||
// TODO: Have the views set this themselves.
|
||||
if (preferences.getBoolean("DisallowOverscroll", false)) {
|
||||
appView.setOverScrollMode(View.OVER_SCROLL_NEVER);
|
||||
}
|
||||
createViews();
|
||||
|
||||
// TODO: Make this a preference (CB-6153)
|
||||
// Setup the hardware volume controls to handle volume control
|
||||
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
ret.init(this, pluginEntries, internalWhitelist, externalWhitelist, preferences);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the url into the webview.
|
||||
*/
|
||||
public void loadUrl(String url) {
|
||||
public void loadUrl(String url, int splashscreenTime) {
|
||||
if (appView == null) {
|
||||
init();
|
||||
}
|
||||
this.splashscreenTime = preferences.getInteger("SplashScreenDelay", this.splashscreenTime);
|
||||
String splash = preferences.getString("SplashScreen", null);
|
||||
if(this.splashscreenTime > 0 && splash != null)
|
||||
if(splashscreenTime > 0 && splash != null)
|
||||
{
|
||||
this.splashscreen = getResources().getIdentifier(splash, "drawable", getClass().getPackage().getName());;
|
||||
if(this.splashscreen != 0)
|
||||
{
|
||||
this.showSplashScreen(this.splashscreenTime);
|
||||
this.showSplashScreen(splashscreenTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,21 +281,17 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
this.keepRunning = preferences.getBoolean("KeepRunning", true);
|
||||
|
||||
//Check if the view is attached to anything
|
||||
if(appView.getParent() != null)
|
||||
if(appView.getView().getParent() != null)
|
||||
{
|
||||
// Then load the spinner
|
||||
this.loadSpinner();
|
||||
}
|
||||
//Load the correct splashscreen
|
||||
|
||||
if(this.splashscreen != 0)
|
||||
{
|
||||
this.appView.loadUrl(url, this.splashscreenTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.appView.loadUrl(url);
|
||||
appView.getPluginManager().postMessage("splashscreen", "show");
|
||||
}
|
||||
this.appView.loadUrlIntoView(url, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -384,10 +301,11 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
* @param url
|
||||
* @param time The number of ms to wait before loading webview
|
||||
*/
|
||||
public void loadUrl(final String url, int time) {
|
||||
|
||||
this.splashscreenTime = time;
|
||||
this.loadUrl(url);
|
||||
public void loadUrl(final String url) {
|
||||
if (appView == null) {
|
||||
init();
|
||||
}
|
||||
this.loadUrl(url, preferences.getInteger("SplashScreenDelay", 3000));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -423,134 +341,6 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void cancelLoadUrl() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the resource cache.
|
||||
*/
|
||||
@Deprecated // Call method on appView directly.
|
||||
public void clearCache() {
|
||||
if (appView == null) {
|
||||
init();
|
||||
}
|
||||
this.appView.clearCache(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear web history in this web view.
|
||||
*/
|
||||
@Deprecated // Call method on appView directly.
|
||||
public void clearHistory() {
|
||||
this.appView.clearHistory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to previous page in history. (We manage our own history)
|
||||
*
|
||||
* @return true if we went back, false if we are already at top
|
||||
*/
|
||||
@Deprecated // Call method on appView directly.
|
||||
public boolean backHistory() {
|
||||
if (this.appView != null) {
|
||||
return appView.backHistory();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get boolean property for activity.
|
||||
*/
|
||||
@Deprecated // Call method on preferences directly.
|
||||
public boolean getBooleanProperty(String name, boolean defaultValue) {
|
||||
return preferences.getBoolean(name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get int property for activity.
|
||||
*/
|
||||
@Deprecated // Call method on preferences directly.
|
||||
public int getIntegerProperty(String name, int defaultValue) {
|
||||
return preferences.getInteger(name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string property for activity.
|
||||
*/
|
||||
@Deprecated // Call method on preferences directly.
|
||||
public String getStringProperty(String name, String defaultValue) {
|
||||
return preferences.getString(name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get double property for activity.
|
||||
*/
|
||||
@Deprecated // Call method on preferences directly.
|
||||
public double getDoubleProperty(String name, double defaultValue) {
|
||||
return preferences.getDouble(name, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set boolean property on activity.
|
||||
* This method has been deprecated in 3.0 and will be removed at a future
|
||||
* time. Please use config.xml instead.
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setBooleanProperty(String name, boolean value) {
|
||||
Log.d(TAG, "Setting boolean properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml");
|
||||
this.getIntent().putExtra(name.toLowerCase(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set int property on activity.
|
||||
* This method has been deprecated in 3.0 and will be removed at a future
|
||||
* time. Please use config.xml instead.
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setIntegerProperty(String name, int value) {
|
||||
Log.d(TAG, "Setting integer properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml");
|
||||
this.getIntent().putExtra(name.toLowerCase(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set string property on activity.
|
||||
* This method has been deprecated in 3.0 and will be removed at a future
|
||||
* time. Please use config.xml instead.
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setStringProperty(String name, String value) {
|
||||
Log.d(TAG, "Setting string properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml");
|
||||
this.getIntent().putExtra(name.toLowerCase(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set double property on activity.
|
||||
* This method has been deprecated in 3.0 and will be removed at a future
|
||||
* time. Please use config.xml instead.
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDoubleProperty(String name, double value) {
|
||||
Log.d(TAG, "Setting double properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml");
|
||||
this.getIntent().putExtra(name.toLowerCase(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity.
|
||||
*/
|
||||
@@ -640,41 +430,6 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to all plugins.
|
||||
*/
|
||||
public void postMessage(String id, Object data) {
|
||||
if (this.appView != null) {
|
||||
this.appView.postMessage(id, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Add services to res/xml/plugins.xml instead.
|
||||
*
|
||||
* Add a class that implements a service.
|
||||
*/
|
||||
@Deprecated
|
||||
public void addService(String serviceType, String className) {
|
||||
if (this.appView != null && this.appView.pluginManager != null) {
|
||||
this.appView.pluginManager.addService(serviceType, className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send JavaScript statement back to JavaScript.
|
||||
* (This is a convenience method)
|
||||
*
|
||||
* @param statement
|
||||
*/
|
||||
@Deprecated // Call method on appView directly.
|
||||
public void sendJavascript(String statement) {
|
||||
if (this.appView != null) {
|
||||
this.appView.bridge.getMessageQueue().addJavaScript(statement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the spinner. Must be called from the UI thread.
|
||||
*
|
||||
@@ -709,6 +464,11 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
* End this activity by calling finish for activity
|
||||
*/
|
||||
public void endActivity() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
this.activityState = ACTIVITY_EXITING;
|
||||
super.finish();
|
||||
}
|
||||
@@ -749,21 +509,16 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
LOG.d(TAG, "Incoming Result");
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
Log.d(TAG, "Request code = " + requestCode);
|
||||
if (appView != null && requestCode == CordovaChromeClient.FILECHOOSER_RESULTCODE) {
|
||||
ValueCallback<Uri> mUploadMessage = this.appView.getWebChromeClient().getValueCallback();
|
||||
Log.d(TAG, "did we get here?");
|
||||
if (null == mUploadMessage)
|
||||
return;
|
||||
if (appView != null && requestCode == AndroidChromeClient.FILECHOOSER_RESULTCODE) {
|
||||
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
|
||||
Log.d(TAG, "result = " + result);
|
||||
mUploadMessage.onReceiveValue(result);
|
||||
mUploadMessage = null;
|
||||
appView.onFilePickerResult(result);
|
||||
}
|
||||
CordovaPlugin callback = this.activityResultCallback;
|
||||
if(callback == null && initCallbackClass != null) {
|
||||
// The application was restarted, but had defined an initial callback
|
||||
// before being shut down.
|
||||
this.activityResultCallback = appView.pluginManager.getPlugin(initCallbackClass);
|
||||
//this.activityResultCallback = appView.pluginManager.getPlugin(initCallbackClass);
|
||||
this.activityResultCallback = appView.getPluginManager().getPlugin(initCallbackClass);
|
||||
callback = this.activityResultCallback;
|
||||
}
|
||||
if(callback != null) {
|
||||
@@ -790,7 +545,6 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
// If errorUrl specified, then load it
|
||||
final String errorUrl = preferences.getString("errorUrl", null);
|
||||
if ((errorUrl != null) && (errorUrl.startsWith("file://") || internalWhitelist.isUrlWhiteListed(errorUrl)) && (!failingUrl.equals(errorUrl))) {
|
||||
|
||||
// Load URL on UI thread
|
||||
me.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
@@ -806,7 +560,7 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
me.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (exit) {
|
||||
me.appView.setVisibility(View.GONE);
|
||||
me.appView.getView().setVisibility(View.GONE);
|
||||
me.displayError("Application Error", description + " (" + failingUrl + ")", "OK", exit);
|
||||
}
|
||||
}
|
||||
@@ -844,59 +598,31 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if URL is in approved list of URLs to load.
|
||||
*/
|
||||
@Deprecated // Use whitelist object directly.
|
||||
public boolean isUrlWhiteListed(String url) {
|
||||
return internalWhitelist.isUrlWhiteListed(url);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hook in Cordova for menu plugins
|
||||
*/
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
this.postMessage("onCreateOptionsMenu", menu);
|
||||
if (appView != null) {
|
||||
appView.getPluginManager().postMessage("onCreateOptionsMenu", menu);
|
||||
}
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
this.postMessage("onPrepareOptionsMenu", menu);
|
||||
if (appView != null) {
|
||||
appView.getPluginManager().postMessage("onPrepareOptionsMenu", menu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
this.postMessage("onOptionsItemSelected", item);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Activity context.
|
||||
*/
|
||||
@Deprecated
|
||||
public Context getContext() {
|
||||
LOG.d(TAG, "This will be deprecated December 2012");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Deprecated // Call method on appView directly.
|
||||
public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap<String, Object> params) {
|
||||
if (this.appView != null) {
|
||||
appView.showWebPage(url, openExternal, clearHistory, params);
|
||||
if (appView != null) {
|
||||
appView.getPluginManager().postMessage("onOptionsItemSelected", item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Dialog splashDialog;
|
||||
@@ -957,36 +683,6 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
this.runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event)
|
||||
{
|
||||
if (appView != null && (appView.isCustomViewShowing() || appView.getFocusedChild() != null ) &&
|
||||
(keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
|
||||
return appView.onKeyUp(keyCode, event);
|
||||
} else {
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Android 2.x needs to be able to check where the cursor is. Android 4.x does not
|
||||
*
|
||||
* (non-Javadoc)
|
||||
* @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event)
|
||||
{
|
||||
//Determine if the focus is on the current view or not
|
||||
if (appView != null && appView.getFocusedChild() != null && (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
|
||||
return appView.onKeyDown(keyCode, event);
|
||||
}
|
||||
else
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when a message is sent to plugin.
|
||||
*
|
||||
@@ -1010,14 +706,14 @@ public class CordovaActivity extends Activity implements CordovaInterface {
|
||||
if (splashResource != null) {
|
||||
splashscreen = getResources().getIdentifier(splashResource, "drawable", getClass().getPackage().getName());
|
||||
}
|
||||
this.showSplashScreen(this.splashscreenTime);
|
||||
this.showSplashScreen(preferences.getInteger("SplashScreenDelay", 3000));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ("spinner".equals(id)) {
|
||||
if ("stop".equals(data.toString())) {
|
||||
this.spinnerStop();
|
||||
this.appView.setVisibility(View.VISIBLE);
|
||||
this.appView.getView().setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
else if ("onReceivedError".equals(id)) {
|
||||
|
||||
@@ -32,8 +32,6 @@ import android.net.Uri;
|
||||
* Plugins must extend this class and override one of the execute methods.
|
||||
*/
|
||||
public class CordovaPlugin {
|
||||
@Deprecated // This is never set.
|
||||
public String id;
|
||||
public CordovaWebView webView;
|
||||
public CordovaInterface cordova;
|
||||
protected CordovaPreferences preferences;
|
||||
|
||||
@@ -84,7 +84,7 @@ public class CordovaResourceApi {
|
||||
// Creating this is light-weight.
|
||||
private static OkHttpClient httpClient = new OkHttpClient();
|
||||
|
||||
static Thread jsThread;
|
||||
public static Thread jsThread;
|
||||
|
||||
private final AssetManager assetManager;
|
||||
private final ContentResolver contentResolver;
|
||||
|
||||
@@ -25,14 +25,14 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.webkit.WebView;
|
||||
|
||||
class CordovaUriHelper {
|
||||
public class CordovaUriHelper {
|
||||
|
||||
private static final String TAG = "CordovaUriHelper";
|
||||
|
||||
private CordovaWebView appView;
|
||||
private CordovaInterface cordova;
|
||||
|
||||
CordovaUriHelper(CordovaInterface cdv, CordovaWebView webView)
|
||||
public CordovaUriHelper(CordovaInterface cdv, CordovaWebView webView)
|
||||
{
|
||||
appView = webView;
|
||||
cordova = cdv;
|
||||
@@ -47,9 +47,9 @@ class CordovaUriHelper {
|
||||
* @return true to override, false for default behavior
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
|
||||
boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
public boolean shouldOverrideUrlLoading(String url) {
|
||||
// Give plugins the chance to handle the url
|
||||
if (this.appView.pluginManager.onOverrideUrlLoading(url)) {
|
||||
if (this.appView.getPluginManager().onOverrideUrlLoading(url)) {
|
||||
// Do nothing other than what the plugins wanted.
|
||||
// If any returned true, then the request was handled.
|
||||
return true;
|
||||
|
||||
916
framework/src/org/apache/cordova/CordovaWebView.java
Executable file → Normal file
916
framework/src/org/apache/cordova/CordovaWebView.java
Executable file → Normal file
@@ -1,488 +1,48 @@
|
||||
/*
|
||||
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.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
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.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;
|
||||
import android.webkit.WebChromeClient.CustomViewCallback;
|
||||
|
||||
/*
|
||||
* 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 CordovaWebView extends WebView {
|
||||
public interface CordovaWebView {
|
||||
public static final String CORDOVA_VERSION = "4.0.0-dev";
|
||||
|
||||
public static final String TAG = "CordovaWebView";
|
||||
public static final String CORDOVA_VERSION = "3.7.0-dev";
|
||||
void init(CordovaInterface cordova, List<PluginEntry> pluginEntries,
|
||||
Whitelist internalWhitelist, Whitelist externalWhitelist,
|
||||
CordovaPreferences preferences);
|
||||
|
||||
private HashSet<Integer> boundKeyCodes = new HashSet<Integer>();
|
||||
View getView();
|
||||
|
||||
public PluginManager pluginManager;
|
||||
private boolean paused;
|
||||
void loadUrlIntoView(String url, boolean recreatePlugins);
|
||||
|
||||
private BroadcastReceiver receiver;
|
||||
void stopLoading();
|
||||
|
||||
boolean canGoBack();
|
||||
|
||||
/** Activities and other important classes **/
|
||||
private CordovaInterface cordova;
|
||||
CordovaWebViewClient viewClient;
|
||||
private CordovaChromeClient chromeClient;
|
||||
void clearCache(boolean b);
|
||||
|
||||
// Flag to track that a loadUrl timeout occurred
|
||||
int loadUrlTimeout = 0;
|
||||
void clearHistory();
|
||||
|
||||
private long lastMenuEventTime = 0;
|
||||
boolean backHistory();
|
||||
|
||||
CordovaBridge bridge;
|
||||
void handlePause(boolean keepRunning);
|
||||
|
||||
/** custom view created by the browser (a video player for example) */
|
||||
private View mCustomView;
|
||||
private WebChromeClient.CustomViewCallback mCustomViewCallback;
|
||||
void onNewIntent(Intent intent);
|
||||
|
||||
private CordovaResourceApi resourceApi;
|
||||
private Whitelist internalWhitelist;
|
||||
private Whitelist externalWhitelist;
|
||||
void handleResume(boolean keepRunning, boolean activityResultKeepRunning);
|
||||
|
||||
// The URL passed to loadUrl(), not necessarily the URL of the current page.
|
||||
String loadedUrl;
|
||||
private CordovaPreferences preferences;
|
||||
void handleDestroy();
|
||||
|
||||
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);
|
||||
|
||||
public CordovaWebView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public CordovaWebView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public CordovaWebView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@TargetApi(11)
|
||||
@Deprecated
|
||||
public CordovaWebView(Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) {
|
||||
super(context, attrs, defStyle, privateBrowsing);
|
||||
}
|
||||
|
||||
// Use two-phase init so that the control will work with XML layouts.
|
||||
public void init(CordovaInterface cordova, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient,
|
||||
List<PluginEntry> pluginEntries, Whitelist internalWhitelist, Whitelist externalWhitelist,
|
||||
CordovaPreferences preferences) {
|
||||
if (this.cordova != null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
this.cordova = cordova;
|
||||
this.viewClient = webViewClient;
|
||||
this.chromeClient = webChromeClient;
|
||||
this.internalWhitelist = internalWhitelist;
|
||||
this.externalWhitelist = externalWhitelist;
|
||||
this.preferences = preferences;
|
||||
super.setWebChromeClient(webChromeClient);
|
||||
super.setWebViewClient(webViewClient);
|
||||
|
||||
pluginManager = new PluginManager(this, this.cordova, pluginEntries);
|
||||
bridge = new CordovaBridge(pluginManager, new NativeToJsMessageQueue(this, cordova));
|
||||
resourceApi = new CordovaResourceApi(this.getContext(), pluginManager);
|
||||
|
||||
pluginManager.addService("App", "org.apache.cordova.App");
|
||||
initWebViewSettings();
|
||||
exposeJsInterface();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void initIfNecessary() {
|
||||
if (pluginManager == null) {
|
||||
Log.w(TAG, "CordovaWebView.init() was not called. This will soon be required.");
|
||||
// Before the refactor to a two-phase init, the Context needed to implement CordovaInterface.
|
||||
CordovaInterface cdv = (CordovaInterface)getContext();
|
||||
if (!Config.isInitialized()) {
|
||||
Config.init(cdv.getActivity());
|
||||
}
|
||||
init(cdv, makeWebViewClient(cdv), makeWebChromeClient(cdv), Config.getPluginEntries(), Config.getWhitelist(), Config.getExternalWhitelist(), Config.getPreferences());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@SuppressWarnings("deprecation")
|
||||
private void initWebViewSettings() {
|
||||
this.setInitialScale(0);
|
||||
this.setVerticalScrollBarEnabled(false);
|
||||
// TODO: The Activity is the one that should call requestFocus().
|
||||
if (shouldRequestFocusOnInit()) {
|
||||
this.requestFocusFromTouch();
|
||||
}
|
||||
// Enable JavaScript
|
||||
WebSettings settings = this.getSettings();
|
||||
settings.setJavaScriptEnabled(true);
|
||||
settings.setJavaScriptCanOpenWindowsAutomatically(true);
|
||||
settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
|
||||
|
||||
// Set the nav dump for HTC 2.x devices (disabling for ICS, deprecated entirely for Jellybean 4.2)
|
||||
try {
|
||||
Method gingerbread_getMethod = WebSettings.class.getMethod("setNavDump", new Class[] { boolean.class });
|
||||
|
||||
String manufacturer = android.os.Build.MANUFACTURER;
|
||||
Log.d(TAG, "CordovaWebView is running on device made by: " + manufacturer);
|
||||
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB &&
|
||||
android.os.Build.MANUFACTURER.contains("HTC"))
|
||||
{
|
||||
gingerbread_getMethod.invoke(settings, true);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.d(TAG, "We are on a modern version of Android, we will deprecate HTC 2.3 devices in 2.8");
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.d(TAG, "Doing the NavDump failed with bad arguments");
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.d(TAG, "This should never happen: IllegalAccessException means this isn't Android anymore");
|
||||
} catch (InvocationTargetException e) {
|
||||
Log.d(TAG, "This should never happen: InvocationTargetException means this isn't Android anymore.");
|
||||
}
|
||||
|
||||
//We don't save any form data in the application
|
||||
settings.setSaveFormData(false);
|
||||
settings.setSavePassword(false);
|
||||
|
||||
// Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist
|
||||
// while we do this
|
||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
|
||||
Level16Apis.enableUniversalAccess(settings);
|
||||
// Enable database
|
||||
// We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16
|
||||
String databasePath = getContext().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!
|
||||
ApplicationInfo appInfo = getContext().getApplicationContext().getApplicationInfo();
|
||||
if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 &&
|
||||
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
|
||||
enableRemoteDebugging();
|
||||
}
|
||||
|
||||
settings.setGeolocationDatabasePath(databasePath);
|
||||
|
||||
// Enable DOM storage
|
||||
settings.setDomStorageEnabled(true);
|
||||
|
||||
// Enable built-in geolocation
|
||||
settings.setGeolocationEnabled(true);
|
||||
|
||||
// Enable AppCache
|
||||
// Fix for CB-2282
|
||||
settings.setAppCacheMaxSize(5 * 1048576);
|
||||
settings.setAppCachePath(databasePath);
|
||||
settings.setAppCacheEnabled(true);
|
||||
|
||||
// Fix for CB-1405
|
||||
// Google issue 4641
|
||||
settings.getUserAgentString();
|
||||
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
|
||||
if (this.receiver == null) {
|
||||
this.receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
getSettings().getUserAgentString();
|
||||
}
|
||||
};
|
||||
getContext().registerReceiver(this.receiver, intentFilter);
|
||||
}
|
||||
// end CB-1405
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
private void enableRemoteDebugging() {
|
||||
try {
|
||||
WebView.setWebContentsDebuggingEnabled(true);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.d(TAG, "You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public CordovaChromeClient makeWebChromeClient(CordovaInterface cordova) {
|
||||
return new CordovaChromeClient(cordova, this);
|
||||
}
|
||||
|
||||
public CordovaWebViewClient makeWebViewClient(CordovaInterface cordova) {
|
||||
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
return new CordovaWebViewClient(cordova, this);
|
||||
}
|
||||
return new IceCreamCordovaWebViewClient(cordova, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to decide whether or not you need to request the
|
||||
* focus when your application start
|
||||
*
|
||||
* @return true unless this method is overriden to return a different value
|
||||
*/
|
||||
protected boolean shouldRequestFocusOnInit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void exposeJsInterface() {
|
||||
if ((Build.VERSION.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(new ExposedJsApi(bridge), "_cordovaNative");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWebViewClient(WebViewClient client) {
|
||||
this.viewClient = (CordovaWebViewClient)client;
|
||||
super.setWebViewClient(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWebChromeClient(WebChromeClient client) {
|
||||
this.chromeClient = (CordovaChromeClient)client;
|
||||
super.setWebChromeClient(client);
|
||||
}
|
||||
|
||||
public CordovaChromeClient getWebChromeClient() {
|
||||
return this.chromeClient;
|
||||
}
|
||||
|
||||
|
||||
public Whitelist getWhitelist() {
|
||||
return this.internalWhitelist;
|
||||
}
|
||||
|
||||
public Whitelist getExternalWhitelist() {
|
||||
return this.externalWhitelist;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
this.loadUrlIntoView(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
|
||||
*/
|
||||
@Deprecated
|
||||
public void loadUrl(final String url, int time) {
|
||||
if(url == null)
|
||||
{
|
||||
this.loadUrlIntoView(Config.getStartUrl());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.loadUrlIntoView(url);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadUrlIntoView(final String url) {
|
||||
loadUrlIntoView(url, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the url into the webview.
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
public void loadUrlIntoView(final String url, boolean recreatePlugins) {
|
||||
LOG.d(TAG, ">>> loadUrl(" + url + ")");
|
||||
|
||||
initIfNecessary();
|
||||
|
||||
if (recreatePlugins) {
|
||||
this.loadedUrl = url;
|
||||
this.pluginManager.init();
|
||||
}
|
||||
|
||||
// Create a timeout timer for loadUrl
|
||||
final CordovaWebView me = this;
|
||||
final int currentLoadUrlTimeout = me.loadUrlTimeout;
|
||||
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!");
|
||||
if (viewClient != null) {
|
||||
viewClient.onReceivedError(me, -6, "The connection to the server was unsuccessful.", url);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Timeout timer method
|
||||
final Runnable timeoutCheck = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
synchronized (this) {
|
||||
wait(loadUrlTimeoutValue);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// If timeout, then stop loading and handle error
|
||||
if (me.loadUrlTimeout == currentLoadUrlTimeout) {
|
||||
me.cordova.getActivity().runOnUiThread(loadError);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Load url
|
||||
this.cordova.getActivity().runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
cordova.getThreadPool().execute(timeoutCheck);
|
||||
me.loadUrlNow(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load URL in webview.
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
void loadUrlNow(String url) {
|
||||
if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) {
|
||||
LOG.d(TAG, ">>> loadUrlNow()");
|
||||
}
|
||||
if (url.startsWith("file://") || url.startsWith("javascript:") || internalWhitelist.isUrlWhiteListed(url)) {
|
||||
super.loadUrl(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
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
this.postMessage("onScrollChanged", myEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send JavaScript statement back to JavaScript.
|
||||
* (This is a convenience method)
|
||||
*
|
||||
* @param statement
|
||||
* Deprecated (https://issues.apache.org/jira/browse/CB-6851)
|
||||
* Instead of executing snippets of JS, you should use the exec bridge
|
||||
* to create a Java->JS communication channel.
|
||||
@@ -502,433 +62,37 @@ public class CordovaWebView extends WebView {
|
||||
* savedCallbackContext.sendPluginResult(dataResult);
|
||||
*/
|
||||
@Deprecated
|
||||
public void sendJavascript(String statement) {
|
||||
this.bridge.getMessageQueue().addJavaScript(statement);
|
||||
}
|
||||
void sendJavascript(String statememt);
|
||||
|
||||
/**
|
||||
* Send a plugin result back to JavaScript.
|
||||
* (This is a convenience method)
|
||||
*
|
||||
* @param result
|
||||
* @param callbackId
|
||||
*/
|
||||
public void sendPluginResult(PluginResult result, String callbackId) {
|
||||
this.bridge.getMessageQueue().addPluginResult(result, callbackId);
|
||||
}
|
||||
void showWebPage(String errorUrl, boolean b, boolean c, HashMap<String, Object> params);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
boolean isCustomViewShowing();
|
||||
|
||||
void showCustomView(View view, CustomViewCallback callback);
|
||||
|
||||
/**
|
||||
* Go to previous page in history. (We manage our own history)
|
||||
*
|
||||
* @return true if we went back, false if we are already at top
|
||||
*/
|
||||
public boolean backHistory() {
|
||||
// Check webview first to see if there is a history
|
||||
// This is needed to support curPage#diffLink, since they are added to appView's history, but not our history url array (JQMobile behavior)
|
||||
if (super.canGoBack()) {
|
||||
super.goBack();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void hideCustomView();
|
||||
|
||||
CordovaResourceApi getResourceApi();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap<String, Object> params) {
|
||||
LOG.d(TAG, "showWebPage(%s, %b, %b, HashMap", url, openExternal, clearHistory);
|
||||
void setButtonPlumbedToJs(int keyCode, boolean override);
|
||||
boolean isButtonPlumbedToJs(int keyCode);
|
||||
|
||||
// If clearing history
|
||||
if (clearHistory) {
|
||||
this.clearHistory();
|
||||
}
|
||||
void sendPluginResult(PluginResult cr, String callbackId);
|
||||
|
||||
// If loading into our webview
|
||||
if (!openExternal) {
|
||||
PluginManager getPluginManager();
|
||||
|
||||
// Make sure url is in whitelist
|
||||
if (url.startsWith("file://") || internalWhitelist.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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event)
|
||||
{
|
||||
if(boundKeyCodes.contains(keyCode))
|
||||
{
|
||||
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');");
|
||||
return true;
|
||||
}
|
||||
// If volumeup key
|
||||
else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
}
|
||||
else if(keyCode == KeyEvent.KEYCODE_BACK)
|
||||
{
|
||||
return !(this.startOfHistory()) || isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
|
||||
}
|
||||
else if(keyCode == KeyEvent.KEYCODE_MENU)
|
||||
{
|
||||
//How did we get here? Is there a childView?
|
||||
View childView = this.getFocusedChild();
|
||||
if(childView != null)
|
||||
{
|
||||
//Make sure we close the keyboard if it's present
|
||||
InputMethodManager imm = (InputMethodManager) cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(childView.getWindowToken(), 0);
|
||||
cordova.getActivity().openOptionsMenu();
|
||||
return true;
|
||||
} else {
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event)
|
||||
{
|
||||
// If back key
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
// A custom view is currently displayed (e.g. playing a video)
|
||||
if(mCustomView != null) {
|
||||
this.hideCustomView();
|
||||
return true;
|
||||
} else {
|
||||
// The webview is currently displayed
|
||||
// If back key is bound, then send event to JavaScript
|
||||
if (isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK)) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('backbutton');");
|
||||
return true;
|
||||
} else {
|
||||
// If not bound
|
||||
// Go to previous page in webview if it is possible to go back
|
||||
if (this.backHistory()) {
|
||||
return true;
|
||||
}
|
||||
// If not, then invoke default behavior
|
||||
}
|
||||
}
|
||||
}
|
||||
// Legacy
|
||||
else if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
if (this.lastMenuEventTime < event.getEventTime()) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('menubutton');");
|
||||
}
|
||||
this.lastMenuEventTime = event.getEventTime();
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
// If search key
|
||||
else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('searchbutton');");
|
||||
return true;
|
||||
}
|
||||
|
||||
//Does webkit change this behavior?
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
public void setButtonPlumbedToJs(int keyCode, boolean override) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
// TODO: Why are search and menu buttons handled separately?
|
||||
if (override) {
|
||||
boundKeyCodes.add(keyCode);
|
||||
} else {
|
||||
boundKeyCodes.remove(keyCode);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated // Use setButtonPlumbedToJs() instead.
|
||||
public void bindButton(boolean override)
|
||||
{
|
||||
setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override);
|
||||
}
|
||||
|
||||
@Deprecated // Use setButtonPlumbedToJs() instead.
|
||||
public void bindButton(String button, boolean override) {
|
||||
if (button.compareTo("volumeup")==0) {
|
||||
setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
|
||||
}
|
||||
else if (button.compareTo("volumedown")==0) {
|
||||
setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated // Use setButtonPlumbedToJs() instead.
|
||||
public void bindButton(int keyCode, boolean keyDown, boolean override) {
|
||||
setButtonPlumbedToJs(keyCode, override);
|
||||
}
|
||||
|
||||
@Deprecated // Use isButtonPlumbedToJs
|
||||
public boolean isBackButtonBound()
|
||||
{
|
||||
return isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
|
||||
}
|
||||
|
||||
public boolean isButtonPlumbedToJs(int keyCode)
|
||||
{
|
||||
return boundKeyCodes.contains(keyCode);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
Whitelist getWhitelist();
|
||||
Whitelist getExternalWhitelist();
|
||||
CordovaPreferences getPreferences();
|
||||
|
||||
public void handleResume(boolean keepRunning, boolean activityResultKeepRunning)
|
||||
{
|
||||
void onFilePickerResult(Uri uri);
|
||||
|
||||
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;
|
||||
}
|
||||
void setNetworkAvailable(boolean online);
|
||||
|
||||
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');};");
|
||||
String getUrl();
|
||||
|
||||
// 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 {
|
||||
getContext().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;
|
||||
}
|
||||
|
||||
@Deprecated // This never did anything.
|
||||
public boolean hadKeyEvent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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)
|
||||
private static class Level16Apis {
|
||||
static void enableUniversalAccess(WebSettings settings) {
|
||||
settings.setAllowUniversalAccessFromFileURLs(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void printBackForwardList() {
|
||||
WebBackForwardList currentList = this.copyBackForwardList();
|
||||
int currentSize = currentList.getSize();
|
||||
for(int i = 0; i < currentSize; ++i)
|
||||
{
|
||||
WebHistoryItem item = currentList.getItemAtIndex(i);
|
||||
String url = item.getUrl();
|
||||
LOG.d(TAG, "The URL at index: " + Integer.toString(i) + " is " + url );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Can Go Back is BROKEN!
|
||||
public boolean startOfHistory()
|
||||
{
|
||||
WebBackForwardList currentList = this.copyBackForwardList();
|
||||
WebHistoryItem item = currentList.getItemAtIndex(0);
|
||||
if( item!=null){ // Null-fence in case they haven't called loadUrl yet (CB-2458)
|
||||
String url = item.getUrl();
|
||||
String currentUrl = this.getUrl();
|
||||
LOG.d(TAG, "The current URL is: " + currentUrl);
|
||||
LOG.d(TAG, "The URL at item 0 is: " + url);
|
||||
return currentUrl.equals(url);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
this.pluginManager.init();
|
||||
return myList;
|
||||
}
|
||||
|
||||
@Deprecated // This never did anything
|
||||
public void storeResult(int requestCode, int resultCode, Intent intent) {
|
||||
}
|
||||
|
||||
public CordovaResourceApi getResourceApi() {
|
||||
return resourceApi;
|
||||
}
|
||||
|
||||
public CordovaPreferences getPreferences() {
|
||||
return preferences;
|
||||
}
|
||||
// TODO: Work on deleting these by removing refs from plugins.
|
||||
Context getContext();
|
||||
void loadUrl(String url);
|
||||
Object postMessage(String id, Object data);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ import java.util.HashMap;
|
||||
/**
|
||||
* This class exposes methods in Cordova that can be called from JavaScript.
|
||||
*/
|
||||
public class App extends CordovaPlugin {
|
||||
public class CoreAndroid extends CordovaPlugin {
|
||||
|
||||
protected static final String TAG = "CordovaApp";
|
||||
private BroadcastReceiver telephonyReceiver;
|
||||
@@ -75,7 +75,7 @@ public class App extends CordovaPlugin {
|
||||
// indicative of what this actually does (shows the webview).
|
||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
webView.postMessage("spinner", "stop");
|
||||
webView.getPluginManager().postMessage("spinner", "stop");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -247,7 +247,7 @@ public class App extends CordovaPlugin {
|
||||
* Exit the Android application.
|
||||
*/
|
||||
public void exitApp() {
|
||||
this.webView.postMessage("exit", null);
|
||||
this.webView.getPluginManager().postMessage("exit", null);
|
||||
}
|
||||
|
||||
|
||||
@@ -271,15 +271,15 @@ public class App extends CordovaPlugin {
|
||||
String extraData = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
|
||||
if (extraData.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
|
||||
LOG.i(TAG, "Telephone RINGING");
|
||||
webView.postMessage("telephone", "ringing");
|
||||
webView.getPluginManager().postMessage("telephone", "ringing");
|
||||
}
|
||||
else if (extraData.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
|
||||
LOG.i(TAG, "Telephone OFFHOOK");
|
||||
webView.postMessage("telephone", "offhook");
|
||||
webView.getPluginManager().postMessage("telephone", "offhook");
|
||||
}
|
||||
else if (extraData.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
|
||||
LOG.i(TAG, "Telephone IDLE");
|
||||
webView.postMessage("telephone", "idle");
|
||||
webView.getPluginManager().postMessage("telephone", "idle");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,162 +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.io.File;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import android.os.StatFs;
|
||||
|
||||
/**
|
||||
* This class provides file directory utilities.
|
||||
* All file operations are performed on the SD card.
|
||||
*
|
||||
* It is used by the FileUtils class.
|
||||
*/
|
||||
@Deprecated // Deprecated in 3.1. To be removed in 4.0.
|
||||
public class DirectoryManager {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String LOG_TAG = "DirectoryManager";
|
||||
|
||||
/**
|
||||
* Determine if a file or directory exists.
|
||||
* @param name The name of the file to check.
|
||||
* @return T=exists, F=not found
|
||||
*/
|
||||
public static boolean testFileExists(String name) {
|
||||
boolean status;
|
||||
|
||||
// If SD card exists
|
||||
if ((testSaveLocationExists()) && (!name.equals(""))) {
|
||||
File path = Environment.getExternalStorageDirectory();
|
||||
File newPath = constructFilePaths(path.toString(), name);
|
||||
status = newPath.exists();
|
||||
}
|
||||
// If no SD card
|
||||
else {
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the free disk space
|
||||
*
|
||||
* @return Size in KB or -1 if not available
|
||||
*/
|
||||
public static long getFreeDiskSpace(boolean checkInternal) {
|
||||
String status = Environment.getExternalStorageState();
|
||||
long freeSpace = 0;
|
||||
|
||||
// If SD card exists
|
||||
if (status.equals(Environment.MEDIA_MOUNTED)) {
|
||||
freeSpace = freeSpaceCalculation(Environment.getExternalStorageDirectory().getPath());
|
||||
}
|
||||
else if (checkInternal) {
|
||||
freeSpace = freeSpaceCalculation("/");
|
||||
}
|
||||
// If no SD card and we haven't been asked to check the internal directory then return -1
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return freeSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a path return the number of free KB
|
||||
*
|
||||
* @param path to the file system
|
||||
* @return free space in KB
|
||||
*/
|
||||
private static long freeSpaceCalculation(String path) {
|
||||
StatFs stat = new StatFs(path);
|
||||
long blockSize = stat.getBlockSize();
|
||||
long availableBlocks = stat.getAvailableBlocks();
|
||||
return availableBlocks * blockSize / 1024;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if SD card exists.
|
||||
*
|
||||
* @return T=exists, F=not found
|
||||
*/
|
||||
public static boolean testSaveLocationExists() {
|
||||
String sDCardStatus = Environment.getExternalStorageState();
|
||||
boolean status;
|
||||
|
||||
// If SD card is mounted
|
||||
if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) {
|
||||
status = true;
|
||||
}
|
||||
|
||||
// If no SD card
|
||||
else {
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new file object from two file paths.
|
||||
*
|
||||
* @param file1 Base file path
|
||||
* @param file2 Remaining file path
|
||||
* @return File object
|
||||
*/
|
||||
private static File constructFilePaths (String file1, String file2) {
|
||||
File newPath;
|
||||
if (file2.startsWith(file1)) {
|
||||
newPath = new File(file2);
|
||||
}
|
||||
else {
|
||||
newPath = new File(file1 + "/" + file2);
|
||||
}
|
||||
return newPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we can use the SD Card to store the temporary file. If not then use
|
||||
* the internal cache directory.
|
||||
*
|
||||
* @return the absolute path of where to store the file
|
||||
*/
|
||||
public static String getTempDirectoryPath(Context ctx) {
|
||||
File cache = null;
|
||||
|
||||
// SD Card Mounted
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
cache = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
|
||||
"/Android/data/" + ctx.getPackageName() + "/cache/");
|
||||
}
|
||||
// Use internal storage
|
||||
else {
|
||||
cache = ctx.getCacheDir();
|
||||
}
|
||||
|
||||
// Create the cache directory if it doesn't exist
|
||||
if (!cache.exists()) {
|
||||
cache.mkdirs();
|
||||
}
|
||||
|
||||
return cache.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
@@ -1,34 +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;
|
||||
|
||||
/**
|
||||
* This used to be the class that should be extended by application
|
||||
* developers, but everything has been moved to CordovaActivity. So
|
||||
* you should extend CordovaActivity instead of DroidGap. This class
|
||||
* will be removed at a future time.
|
||||
*
|
||||
* @see CordovaActivity
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public class DroidGap extends CordovaActivity {
|
||||
|
||||
}
|
||||
@@ -1,186 +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.io.IOException;
|
||||
|
||||
import android.media.ExifInterface;
|
||||
|
||||
@Deprecated // Deprecated in 3.1. To be removed in 4.0.
|
||||
public class ExifHelper {
|
||||
private String aperture = null;
|
||||
private String datetime = null;
|
||||
private String exposureTime = null;
|
||||
private String flash = null;
|
||||
private String focalLength = null;
|
||||
private String gpsAltitude = null;
|
||||
private String gpsAltitudeRef = null;
|
||||
private String gpsDateStamp = null;
|
||||
private String gpsLatitude = null;
|
||||
private String gpsLatitudeRef = null;
|
||||
private String gpsLongitude = null;
|
||||
private String gpsLongitudeRef = null;
|
||||
private String gpsProcessingMethod = null;
|
||||
private String gpsTimestamp = null;
|
||||
private String iso = null;
|
||||
private String make = null;
|
||||
private String model = null;
|
||||
private String orientation = null;
|
||||
private String whiteBalance = null;
|
||||
|
||||
private ExifInterface inFile = null;
|
||||
private ExifInterface outFile = null;
|
||||
|
||||
/**
|
||||
* The file before it is compressed
|
||||
*
|
||||
* @param filePath
|
||||
* @throws IOException
|
||||
*/
|
||||
public void createInFile(String filePath) throws IOException {
|
||||
this.inFile = new ExifInterface(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* The file after it has been compressed
|
||||
*
|
||||
* @param filePath
|
||||
* @throws IOException
|
||||
*/
|
||||
public void createOutFile(String filePath) throws IOException {
|
||||
this.outFile = new ExifInterface(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all the EXIF data from the input file.
|
||||
*/
|
||||
public void readExifData() {
|
||||
this.aperture = inFile.getAttribute(ExifInterface.TAG_APERTURE);
|
||||
this.datetime = inFile.getAttribute(ExifInterface.TAG_DATETIME);
|
||||
this.exposureTime = inFile.getAttribute(ExifInterface.TAG_EXPOSURE_TIME);
|
||||
this.flash = inFile.getAttribute(ExifInterface.TAG_FLASH);
|
||||
this.focalLength = inFile.getAttribute(ExifInterface.TAG_FOCAL_LENGTH);
|
||||
this.gpsAltitude = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE);
|
||||
this.gpsAltitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF);
|
||||
this.gpsDateStamp = inFile.getAttribute(ExifInterface.TAG_GPS_DATESTAMP);
|
||||
this.gpsLatitude = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
|
||||
this.gpsLatitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
|
||||
this.gpsLongitude = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
|
||||
this.gpsLongitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
|
||||
this.gpsProcessingMethod = inFile.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD);
|
||||
this.gpsTimestamp = inFile.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP);
|
||||
this.iso = inFile.getAttribute(ExifInterface.TAG_ISO);
|
||||
this.make = inFile.getAttribute(ExifInterface.TAG_MAKE);
|
||||
this.model = inFile.getAttribute(ExifInterface.TAG_MODEL);
|
||||
this.orientation = inFile.getAttribute(ExifInterface.TAG_ORIENTATION);
|
||||
this.whiteBalance = inFile.getAttribute(ExifInterface.TAG_WHITE_BALANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the previously stored EXIF data to the output file.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeExifData() throws IOException {
|
||||
// Don't try to write to a null file
|
||||
if (this.outFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.aperture != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_APERTURE, this.aperture);
|
||||
}
|
||||
if (this.datetime != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_DATETIME, this.datetime);
|
||||
}
|
||||
if (this.exposureTime != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_EXPOSURE_TIME, this.exposureTime);
|
||||
}
|
||||
if (this.flash != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_FLASH, this.flash);
|
||||
}
|
||||
if (this.focalLength != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_FOCAL_LENGTH, this.focalLength);
|
||||
}
|
||||
if (this.gpsAltitude != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, this.gpsAltitude);
|
||||
}
|
||||
if (this.gpsAltitudeRef != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, this.gpsAltitudeRef);
|
||||
}
|
||||
if (this.gpsDateStamp != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, this.gpsDateStamp);
|
||||
}
|
||||
if (this.gpsLatitude != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE, this.gpsLatitude);
|
||||
}
|
||||
if (this.gpsLatitudeRef != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, this.gpsLatitudeRef);
|
||||
}
|
||||
if (this.gpsLongitude != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, this.gpsLongitude);
|
||||
}
|
||||
if (this.gpsLongitudeRef != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, this.gpsLongitudeRef);
|
||||
}
|
||||
if (this.gpsProcessingMethod != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, this.gpsProcessingMethod);
|
||||
}
|
||||
if (this.gpsTimestamp != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, this.gpsTimestamp);
|
||||
}
|
||||
if (this.iso != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_ISO, this.iso);
|
||||
}
|
||||
if (this.make != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_MAKE, this.make);
|
||||
}
|
||||
if (this.model != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_MODEL, this.model);
|
||||
}
|
||||
if (this.orientation != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_ORIENTATION, this.orientation);
|
||||
}
|
||||
if (this.whiteBalance != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_WHITE_BALANCE, this.whiteBalance);
|
||||
}
|
||||
|
||||
this.outFile.saveAttributes();
|
||||
}
|
||||
|
||||
public int getOrientation() {
|
||||
int o = Integer.parseInt(this.orientation);
|
||||
|
||||
if (o == ExifInterface.ORIENTATION_NORMAL) {
|
||||
return 0;
|
||||
} else if (o == ExifInterface.ORIENTATION_ROTATE_90) {
|
||||
return 90;
|
||||
} else if (o == ExifInterface.ORIENTATION_ROTATE_180) {
|
||||
return 180;
|
||||
} else if (o == ExifInterface.ORIENTATION_ROTATE_270) {
|
||||
return 270;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void resetOrientation() {
|
||||
this.orientation = "" + ExifInterface.ORIENTATION_NORMAL;
|
||||
}
|
||||
}
|
||||
52
framework/src/org/apache/cordova/ExposedJsApi.java
Executable file → Normal file
52
framework/src/org/apache/cordova/ExposedJsApi.java
Executable file → Normal file
@@ -1,52 +1,12 @@
|
||||
/*
|
||||
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 android.webkit.JavascriptInterface;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
/**
|
||||
* Contains APIs that the JS can call. All functions in here should also have
|
||||
* an equivalent entry in CordovaChromeClient.java, and be added to
|
||||
* cordova-js/lib/android/plugin/android/promptbasednativeapi.js
|
||||
/*
|
||||
* Any exposed Javascript API MUST implement these three things!
|
||||
*/
|
||||
/* package */ class ExposedJsApi {
|
||||
|
||||
private CordovaBridge bridge;
|
||||
|
||||
public ExposedJsApi(CordovaBridge bridge) {
|
||||
this.bridge = bridge;
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
|
||||
return bridge.jsExec(bridgeSecret, service, action, callbackId, arguments);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
|
||||
bridge.jsSetNativeToJsBridgeMode(bridgeSecret, value);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
|
||||
return bridge.jsRetrieveJsMessages(bridgeSecret, fromOnlineEvent);
|
||||
}
|
||||
public interface ExposedJsApi {
|
||||
public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException;
|
||||
public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException;
|
||||
public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException;
|
||||
}
|
||||
|
||||
@@ -1,163 +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 android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import org.apache.cordova.CordovaInterface;
|
||||
import org.apache.cordova.LOG;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Locale;
|
||||
|
||||
@Deprecated // Deprecated in 3.1. To be removed in 4.0.
|
||||
public class FileHelper {
|
||||
private static final String LOG_TAG = "FileUtils";
|
||||
private static final String _DATA = "_data";
|
||||
|
||||
/**
|
||||
* Returns the real path of the given URI string.
|
||||
* If the given URI string represents a content:// URI, the real path is retrieved from the media store.
|
||||
*
|
||||
* @param uriString the URI string of the audio/image/video
|
||||
* @param cordova the current application context
|
||||
* @return the full path to the file
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static String getRealPath(String uriString, CordovaInterface cordova) {
|
||||
String realPath = null;
|
||||
|
||||
if (uriString.startsWith("content://")) {
|
||||
String[] proj = { _DATA };
|
||||
Cursor cursor = cordova.getActivity().managedQuery(Uri.parse(uriString), proj, null, null, null);
|
||||
int column_index = cursor.getColumnIndexOrThrow(_DATA);
|
||||
cursor.moveToFirst();
|
||||
realPath = cursor.getString(column_index);
|
||||
if (realPath == null) {
|
||||
LOG.e(LOG_TAG, "Could get real path for URI string %s", uriString);
|
||||
}
|
||||
} else if (uriString.startsWith("file://")) {
|
||||
realPath = uriString.substring(7);
|
||||
if (realPath.startsWith("/android_asset/")) {
|
||||
LOG.e(LOG_TAG, "Cannot get real path for URI string %s because it is a file:///android_asset/ URI.", uriString);
|
||||
realPath = null;
|
||||
}
|
||||
} else {
|
||||
realPath = uriString;
|
||||
}
|
||||
|
||||
return realPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the real path of the given URI.
|
||||
* If the given URI is a content:// URI, the real path is retrieved from the media store.
|
||||
*
|
||||
* @param uri the URI of the audio/image/video
|
||||
* @param cordova the current application context
|
||||
* @return the full path to the file
|
||||
*/
|
||||
public static String getRealPath(Uri uri, CordovaInterface cordova) {
|
||||
return FileHelper.getRealPath(uri.toString(), cordova);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an input stream based on given URI string.
|
||||
*
|
||||
* @param uriString the URI string from which to obtain the input stream
|
||||
* @param cordova the current application context
|
||||
* @return an input stream into the data at the given URI or null if given an invalid URI string
|
||||
* @throws IOException
|
||||
*/
|
||||
public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) throws IOException {
|
||||
if (uriString.startsWith("content")) {
|
||||
Uri uri = Uri.parse(uriString);
|
||||
return cordova.getActivity().getContentResolver().openInputStream(uri);
|
||||
} else if (uriString.startsWith("file://")) {
|
||||
int question = uriString.indexOf("?");
|
||||
if (question > -1) {
|
||||
uriString = uriString.substring(0,question);
|
||||
}
|
||||
if (uriString.startsWith("file:///android_asset/")) {
|
||||
Uri uri = Uri.parse(uriString);
|
||||
String relativePath = uri.getPath().substring(15);
|
||||
return cordova.getActivity().getAssets().open(relativePath);
|
||||
} else {
|
||||
return new FileInputStream(getRealPath(uriString, cordova));
|
||||
}
|
||||
} else {
|
||||
return new FileInputStream(getRealPath(uriString, cordova));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the "file://" prefix from the given URI string, if applicable.
|
||||
* If the given URI string doesn't have a "file://" prefix, it is returned unchanged.
|
||||
*
|
||||
* @param uriString the URI string to operate on
|
||||
* @return a path without the "file://" prefix
|
||||
*/
|
||||
public static String stripFileProtocol(String uriString) {
|
||||
if (uriString.startsWith("file://")) {
|
||||
uriString = uriString.substring(7);
|
||||
}
|
||||
return uriString;
|
||||
}
|
||||
|
||||
public static String getMimeTypeForExtension(String path) {
|
||||
String extension = path;
|
||||
int lastDot = extension.lastIndexOf('.');
|
||||
if (lastDot != -1) {
|
||||
extension = extension.substring(lastDot + 1);
|
||||
}
|
||||
// Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
|
||||
extension = extension.toLowerCase(Locale.getDefault());
|
||||
if (extension.equals("3ga")) {
|
||||
return "audio/3gpp";
|
||||
}
|
||||
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime type of the data specified by the given URI string.
|
||||
*
|
||||
* @param uriString the URI string of the data
|
||||
* @return the mime type of the specified data
|
||||
*/
|
||||
public static String getMimeType(String uriString, CordovaInterface cordova) {
|
||||
String mimeType = null;
|
||||
|
||||
Uri uri = Uri.parse(uriString);
|
||||
if (uriString.startsWith("content://")) {
|
||||
mimeType = cordova.getActivity().getContentResolver().getType(uri);
|
||||
} else {
|
||||
mimeType = getMimeTypeForExtension(uri.getPath());
|
||||
}
|
||||
|
||||
return mimeType;
|
||||
}
|
||||
}
|
||||
@@ -32,16 +32,11 @@ import android.webkit.WebResourceResponse;
|
||||
import android.webkit.WebView;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
|
||||
public class IceCreamCordovaWebViewClient extends AndroidWebViewClient {
|
||||
|
||||
private static final String TAG = "IceCreamCordovaWebViewClient";
|
||||
private CordovaUriHelper helper;
|
||||
|
||||
public IceCreamCordovaWebViewClient(CordovaInterface cordova) {
|
||||
super(cordova);
|
||||
}
|
||||
|
||||
public IceCreamCordovaWebViewClient(CordovaInterface cordova, CordovaWebView view) {
|
||||
public IceCreamCordovaWebViewClient(CordovaInterface cordova, AndroidWebView view) {
|
||||
super(cordova, view);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,43 +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.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
@Deprecated // Deprecated in 3.1. To be removed in 4.0.
|
||||
public class JSONUtils {
|
||||
public static List<String> toStringList(JSONArray array) throws JSONException {
|
||||
if(array == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
List<String> list = new ArrayList<String>();
|
||||
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
list.add(array.get(i).toString());
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ public class NativeToJsMessageQueue {
|
||||
registeredListeners[3] = new PrivateApiBridgeMode();
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
public boolean isBridgeEnabled() {
|
||||
return activeBridgeMode != null;
|
||||
}
|
||||
@@ -298,7 +298,7 @@ public class NativeToJsMessageQueue {
|
||||
public void run() {
|
||||
String js = popAndEncodeAsJs();
|
||||
if (js != null) {
|
||||
webView.loadUrlNow("javascript:" + js);
|
||||
webView.loadUrlIntoView("javascript:" + js, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -18,43 +18,38 @@
|
||||
*/
|
||||
package org.apache.cordova;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
|
||||
/**
|
||||
* This class represents a service entry object.
|
||||
*/
|
||||
public class PluginEntry {
|
||||
public final class PluginEntry {
|
||||
|
||||
/**
|
||||
* The name of the service that this plugin implements
|
||||
*/
|
||||
public String service;
|
||||
public final String service;
|
||||
|
||||
/**
|
||||
* The plugin class name that implements the service.
|
||||
*/
|
||||
public String pluginClass;
|
||||
public final String pluginClass;
|
||||
|
||||
/**
|
||||
* The pre-instantiated plugin to use for this entry.
|
||||
*/
|
||||
public CordovaPlugin plugin;
|
||||
public final CordovaPlugin plugin;
|
||||
|
||||
/**
|
||||
* Flag that indicates the plugin object should be created when PluginManager is initialized.
|
||||
*/
|
||||
public boolean onload;
|
||||
|
||||
private List<String> urlFilters;
|
||||
|
||||
public final boolean onload;
|
||||
|
||||
/**
|
||||
* Constructs with a CordovaPlugin already instantiated.
|
||||
*/
|
||||
public PluginEntry(String service, CordovaPlugin plugin) {
|
||||
this(service, plugin.getClass().getName(), true, plugin, null);
|
||||
this(service, plugin.getClass().getName(), true, plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,27 +58,13 @@ public class PluginEntry {
|
||||
* @param onload Create plugin object when HTML page is loaded
|
||||
*/
|
||||
public PluginEntry(String service, String pluginClass, boolean onload) {
|
||||
this(service, pluginClass, onload, null, null);
|
||||
}
|
||||
|
||||
@Deprecated // urlFilters are going away
|
||||
public PluginEntry(String service, String pluginClass, boolean onload, List<String> urlFilters) {
|
||||
this.service = service;
|
||||
this.pluginClass = pluginClass;
|
||||
this.onload = onload;
|
||||
this.urlFilters = urlFilters;
|
||||
plugin = null;
|
||||
this(service, pluginClass, onload, null);
|
||||
}
|
||||
|
||||
private PluginEntry(String service, String pluginClass, boolean onload, CordovaPlugin plugin, List<String> urlFilters) {
|
||||
private PluginEntry(String service, String pluginClass, boolean onload, CordovaPlugin plugin) {
|
||||
this.service = service;
|
||||
this.pluginClass = pluginClass;
|
||||
this.onload = onload;
|
||||
this.urlFilters = urlFilters;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public List<String> getUrlFilters() {
|
||||
return urlFilters;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
*/
|
||||
package org.apache.cordova;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.apache.cordova.CallbackContext;
|
||||
@@ -51,31 +51,21 @@ public class PluginManager {
|
||||
private final CordovaInterface ctx;
|
||||
private final CordovaWebView app;
|
||||
|
||||
// Stores mapping of Plugin Name -> <url-filter> values.
|
||||
// Using <url-filter> is deprecated.
|
||||
protected HashMap<String, List<String>> urlMap = new HashMap<String, List<String>>();
|
||||
|
||||
@Deprecated
|
||||
PluginManager(CordovaWebView cordovaWebView, CordovaInterface cordova) {
|
||||
this(cordovaWebView, cordova, null);
|
||||
}
|
||||
|
||||
PluginManager(CordovaWebView cordovaWebView, CordovaInterface cordova, List<PluginEntry> pluginEntries) {
|
||||
public PluginManager(CordovaWebView cordovaWebView, CordovaInterface cordova, Collection<PluginEntry> pluginEntries) {
|
||||
this.ctx = cordova;
|
||||
this.app = cordovaWebView;
|
||||
if (pluginEntries == null) {
|
||||
ConfigXmlParser parser = new ConfigXmlParser();
|
||||
parser.parse(ctx.getActivity());
|
||||
pluginEntries = parser.getPluginEntries();
|
||||
}
|
||||
setPluginEntries(pluginEntries);
|
||||
}
|
||||
|
||||
public void setPluginEntries(List<PluginEntry> pluginEntries) {
|
||||
public Collection<PluginEntry> getPluginEntries() {
|
||||
return entryMap.values();
|
||||
}
|
||||
|
||||
public void setPluginEntries(Collection<PluginEntry> pluginEntries) {
|
||||
this.onPause(false);
|
||||
this.onDestroy();
|
||||
pluginMap.clear();
|
||||
urlMap.clear();
|
||||
entryMap.clear();
|
||||
for (PluginEntry entry : pluginEntries) {
|
||||
addService(entry);
|
||||
}
|
||||
@@ -92,23 +82,10 @@ public class PluginManager {
|
||||
this.startupPlugins();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void loadPlugins() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all plugin objects.
|
||||
*/
|
||||
@Deprecated // Should not be exposed as public.
|
||||
public void clearPluginObjects() {
|
||||
pluginMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create plugins objects that have onload set.
|
||||
*/
|
||||
@Deprecated // Should not be exposed as public.
|
||||
public void startupPlugins() {
|
||||
private void startupPlugins() {
|
||||
for (PluginEntry entry : entryMap.values()) {
|
||||
if (entry.onload) {
|
||||
getPlugin(entry.service);
|
||||
@@ -163,11 +140,6 @@ public class PluginManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void exec(String service, String action, String callbackId, String jsonArgs, boolean async) {
|
||||
exec(service, action, callbackId, jsonArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin object that implements the service.
|
||||
* If the plugin object does not already exist, then create it.
|
||||
@@ -214,15 +186,10 @@ public class PluginManager {
|
||||
*/
|
||||
public void addService(PluginEntry entry) {
|
||||
this.entryMap.put(entry.service, entry);
|
||||
List<String> urlFilters = entry.getUrlFilters();
|
||||
if (urlFilters != null) {
|
||||
urlMap.put(entry.service, urlFilters);
|
||||
}
|
||||
if (entry.plugin != null) {
|
||||
entry.plugin.privateInitialize(ctx, app, app.getPreferences());
|
||||
pluginMap.put(entry.service, entry.plugin);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,18 +265,9 @@ public class PluginManager {
|
||||
// that they are loaded before this function is called (either by setting
|
||||
// the onload <param> or by making an exec() call to them)
|
||||
for (PluginEntry entry : this.entryMap.values()) {
|
||||
List<String> urlFilters = urlMap.get(entry.service);
|
||||
if (urlFilters != null) {
|
||||
for (String s : urlFilters) {
|
||||
if (url.startsWith(s)) {
|
||||
return getPlugin(entry.service).onOverrideUrlLoading(url);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CordovaPlugin plugin = pluginMap.get(entry.service);
|
||||
if (plugin != null && plugin.onOverrideUrlLoading(url)) {
|
||||
return true;
|
||||
}
|
||||
CordovaPlugin plugin = pluginMap.get(entry.service);
|
||||
if (plugin != null && plugin.onOverrideUrlLoading(url)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -43,7 +43,7 @@ public class ScrollEvent {
|
||||
* @param view
|
||||
*/
|
||||
|
||||
ScrollEvent(int nx, int ny, int x, int y, View view)
|
||||
public ScrollEvent(int nx, int ny, int x, int y, View view)
|
||||
{
|
||||
l = x; y = t; nl = nx; nt = ny;
|
||||
targetView = view;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cordova-android",
|
||||
"version": "3.7.0-dev",
|
||||
"version": "4.0.0-dev",
|
||||
"description": "cordova-android release",
|
||||
"main": "bin/create",
|
||||
"repository": {
|
||||
@@ -20,10 +20,11 @@
|
||||
"license": "Apache version 2.0",
|
||||
"dependencies": {
|
||||
"q": "^0.9.0",
|
||||
"shelljs": "^0.2.6"
|
||||
"shelljs": "^0.2.6",
|
||||
"which": "^1.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jasmine-node": "~1",
|
||||
"promise-matchers": "~0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
test/assets/www/error.html
Normal file
8
test/assets/www/error.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>OH NOES!</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Things went terribly wrong!</h1>
|
||||
</body>
|
||||
</html>
|
||||
@@ -22,7 +22,7 @@
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<org.apache.cordova.CordovaWebView
|
||||
<org.apache.cordova.AndroidWebView
|
||||
android:id="@+id/cordovaWebView"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
||||
@@ -22,12 +22,12 @@ package org.apache.cordova.test;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.apache.cordova.AndroidChromeClient;
|
||||
import org.apache.cordova.AndroidWebViewClient;
|
||||
import org.apache.cordova.Config;
|
||||
import org.apache.cordova.CordovaChromeClient;
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.apache.cordova.CordovaInterface;
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.apache.cordova.CordovaWebViewClient;
|
||||
import org.apache.cordova.test.R;
|
||||
|
||||
import android.app.Activity;
|
||||
@@ -51,8 +51,8 @@ public class CordovaWebViewTestActivity extends Activity implements CordovaInter
|
||||
Config.init(this);
|
||||
|
||||
cordovaWebView = (CordovaWebView) findViewById(R.id.cordovaWebView);
|
||||
cordovaWebView.init(this, new CordovaWebViewClient(this, cordovaWebView), new CordovaChromeClient(this, cordovaWebView),
|
||||
Config.getPluginEntries(), Config.getWhitelist(), Config.getExternalWhitelist(), Config.getPreferences());
|
||||
cordovaWebView.init(this, Config.getPluginEntries(), Config.getWhitelist(),
|
||||
Config.getExternalWhitelist(), Config.getPreferences());
|
||||
|
||||
cordovaWebView.loadUrl("file:///android_asset/www/index.html");
|
||||
|
||||
|
||||
@@ -1,46 +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.test;
|
||||
|
||||
import android.os.Bundle;
|
||||
import org.apache.cordova.*;
|
||||
|
||||
public class basicauth extends CordovaActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
super.init();
|
||||
|
||||
// LogCat: onReceivedHttpAuthRequest(browserspy.dk:80,BrowserSpy.dk - HTTP Password Test)
|
||||
AuthenticationToken token = new AuthenticationToken();
|
||||
token.setUserName("test");
|
||||
token.setPassword("test");
|
||||
// classic webview includes port in hostname, Chromium webview does not. Handle both here.
|
||||
// BTW, the realm is optional.
|
||||
setAuthenticationToken(token, "browserspy.dk:80", "BrowserSpy.dk - HTTP Password Test");
|
||||
setAuthenticationToken(token, "browserspy.dk", "BrowserSpy.dk - HTTP Password Test");
|
||||
|
||||
// Add web site to whitelist
|
||||
Config.getWhitelist().addWhiteListEntry("http://browserspy.dk/*", true);
|
||||
|
||||
// Load test
|
||||
super.loadUrl("file:///android_asset/www/basicauth/index.html");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import org.apache.cordova.test.backbuttonmultipage;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.test.UiThreadTest;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.BaseInputConnection;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
@@ -174,7 +175,7 @@ public class BackButtonMultiPageTest extends ActivityInstrumentationTestCase2<ba
|
||||
{
|
||||
String url = testView.getUrl();
|
||||
assertTrue(url.endsWith("sample3.html"));
|
||||
BaseInputConnection viewConnection = new BaseInputConnection(testView, true);
|
||||
BaseInputConnection viewConnection = new BaseInputConnection((View) testView, true);
|
||||
KeyEvent backDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
|
||||
KeyEvent backUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
|
||||
viewConnection.sendKeyEvent(backDown);
|
||||
@@ -187,7 +188,7 @@ public class BackButtonMultiPageTest extends ActivityInstrumentationTestCase2<ba
|
||||
{
|
||||
String url = testView.getUrl();
|
||||
assertTrue(url.endsWith("sample2.html"));
|
||||
BaseInputConnection viewConnection = new BaseInputConnection(testView, true);
|
||||
BaseInputConnection viewConnection = new BaseInputConnection((View) testView, true);
|
||||
KeyEvent backDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
|
||||
KeyEvent backUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
|
||||
viewConnection.sendKeyEvent(backDown);
|
||||
|
||||
@@ -59,9 +59,9 @@ public class CordovaActivityTest extends ActivityInstrumentationTestCase2<MainTe
|
||||
}
|
||||
|
||||
|
||||
public void testForCordovaView() {
|
||||
public void testForAndroidWebView() {
|
||||
String className = testView.getClass().getSimpleName();
|
||||
assertTrue(className.equals("CordovaWebView"));
|
||||
assertTrue(className.equals("AndroidWebView"));
|
||||
}
|
||||
|
||||
public void testForLinearLayout() {
|
||||
|
||||
@@ -65,7 +65,7 @@ public class CordovaResourceApiTest extends ActivityInstrumentationTestCase2<Cor
|
||||
cordovaWebView = activity.cordovaWebView;
|
||||
resourceApi = cordovaWebView.getResourceApi();
|
||||
resourceApi.setThreadCheckingEnabled(false);
|
||||
cordovaWebView.pluginManager.addService(new PluginEntry("CordovaResourceApiTestPlugin1", new CordovaPlugin() {
|
||||
cordovaWebView.getPluginManager().addService(new PluginEntry("CordovaResourceApiTestPlugin1", new CordovaPlugin() {
|
||||
@Override
|
||||
public Uri remapUri(Uri uri) {
|
||||
if (uri.getQuery() != null && uri.getQuery().contains("pluginRewrite")) {
|
||||
|
||||
@@ -49,11 +49,11 @@ public class CordovaTest extends
|
||||
assertNotNull(testView);
|
||||
}
|
||||
|
||||
public void testForCordovaView() {
|
||||
public void testForAndroidWebView() {
|
||||
//Sleep for no reason!!!!
|
||||
sleep();
|
||||
sleep();
|
||||
String className = testView.getClass().getSimpleName();
|
||||
assertTrue(className.equals("CordovaWebView"));
|
||||
assertTrue(className.equals("AndroidWebView"));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
66
test/src/org/apache/cordova/test/junit/GapClientTest.java
Normal file
66
test/src/org/apache/cordova/test/junit/GapClientTest.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
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.test.junit;
|
||||
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.apache.cordova.PluginManager;
|
||||
import org.apache.cordova.test.CordovaWebViewTestActivity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Resources;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public class GapClientTest extends ActivityInstrumentationTestCase2<CordovaWebViewTestActivity> {
|
||||
|
||||
private CordovaWebViewTestActivity testActivity;
|
||||
private FrameLayout containerView;
|
||||
private LinearLayout innerContainer;
|
||||
private View testView;
|
||||
private String rString;
|
||||
|
||||
public GapClientTest() {
|
||||
super("org.apache.cordova.test.activities",CordovaWebViewTestActivity.class);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception{
|
||||
super.setUp();
|
||||
testActivity = this.getActivity();
|
||||
containerView = (FrameLayout) testActivity.findViewById(android.R.id.content);
|
||||
innerContainer = (LinearLayout) containerView.getChildAt(0);
|
||||
testView = innerContainer.getChildAt(0);
|
||||
|
||||
}
|
||||
|
||||
public void testPreconditions(){
|
||||
assertNotNull(innerContainer);
|
||||
assertNotNull(testView);
|
||||
}
|
||||
|
||||
public void testForAndroidWebView() {
|
||||
String className = testView.getClass().getSimpleName();
|
||||
assertTrue(className.equals("AndroidWebView"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,32 +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.test.junit;
|
||||
|
||||
import org.apache.cordova.test.menus;
|
||||
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
|
||||
public class MenuTest extends ActivityInstrumentationTestCase2<menus> {
|
||||
|
||||
public MenuTest() {
|
||||
super("org.apache.cordova.test", menus.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +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.test;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
|
||||
import org.apache.cordova.*;
|
||||
import org.apache.cordova.LOG;
|
||||
|
||||
public class menus extends CordovaActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// need the title to be shown for the options menu to be visible
|
||||
preferences.set("showTitle", true);
|
||||
super.init();
|
||||
super.registerForContextMenu(super.appView);
|
||||
super.loadUrl("file:///android_asset/www/menus/index.html");
|
||||
}
|
||||
|
||||
// Demonstrate how to add your own menus to app
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
int base = Menu.FIRST;
|
||||
// Group, item id, order, title
|
||||
menu.add(base, base, base, "Item1");
|
||||
menu.add(base, base + 1, base + 1, "Item2");
|
||||
menu.add(base, base + 2, base + 2, "Item3");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
LOG.d("menus", "Item " + item.getItemId() + " pressed.");
|
||||
this.appView.loadUrl("javascript:alert('Menu " + item.getItemId() + " pressed.')");
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
LOG.d("menus", "onPrepareOptionsMenu()");
|
||||
// this.appView.loadUrl("javascript:alert('onPrepareOptionsMenu()')");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) {
|
||||
LOG.d("menus", "onCreateContextMenu()");
|
||||
menu.setHeaderTitle("Test Context Menu");
|
||||
menu.add(200, 200, 200, "Context Item1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
this.appView.loadUrl("javascript:alert('Context Menu " + item.getItemId() + " pressed.')");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,16 +32,16 @@ public class userwebview extends MainTestActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
testViewClient = new TestViewClient(this, appView);
|
||||
testChromeClient = new TestChromeClient(this, appView);
|
||||
testViewClient = new TestViewClient(this, ((AndroidWebView)appView));
|
||||
testChromeClient = new TestChromeClient(this, ((AndroidWebView)appView));
|
||||
super.init();
|
||||
appView.setWebViewClient(testViewClient);
|
||||
appView.setWebChromeClient(testChromeClient);
|
||||
((AndroidWebView)appView).setWebViewClient(testViewClient);
|
||||
((AndroidWebView)appView).setWebChromeClient(testChromeClient);
|
||||
super.loadUrl("file:///android_asset/www/userwebview/index.html");
|
||||
}
|
||||
|
||||
public class TestChromeClient extends CordovaChromeClient {
|
||||
public TestChromeClient(CordovaInterface ctx, CordovaWebView app) {
|
||||
public class TestChromeClient extends AndroidChromeClient {
|
||||
public TestChromeClient(CordovaInterface ctx, AndroidWebView app) {
|
||||
super(ctx, app);
|
||||
LOG.d("userwebview", "TestChromeClient()");
|
||||
}
|
||||
@@ -57,8 +57,8 @@ public class userwebview extends MainTestActivity {
|
||||
/**
|
||||
* This class can be used to override the GapViewClient and receive notification of webview events.
|
||||
*/
|
||||
public class TestViewClient extends CordovaWebViewClient {
|
||||
public TestViewClient(CordovaInterface ctx, CordovaWebView app) {
|
||||
public class TestViewClient extends AndroidWebViewClient {
|
||||
public TestViewClient(CordovaInterface ctx, AndroidWebView app) {
|
||||
super(ctx, app);
|
||||
LOG.d("userwebview", "TestViewClient()");
|
||||
}
|
||||
|
||||
@@ -22,23 +22,22 @@ import android.os.Bundle;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import org.apache.cordova.*;
|
||||
import org.apache.cordova.LOG;
|
||||
|
||||
public class whitelist extends MainTestActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
super.init();
|
||||
appView.setWebViewClient(new TestViewClient(this, appView));
|
||||
((AndroidWebView)appView).setWebViewClient(new TestViewClient(this, ((AndroidWebView)appView)));
|
||||
super.loadUrl("file:///android_asset/www/whitelist/index.html");
|
||||
}
|
||||
|
||||
/**
|
||||
* This class can be used to override the GapViewClient and receive notification of webview events.
|
||||
*/
|
||||
public class TestViewClient extends CordovaWebViewClient {
|
||||
public class TestViewClient extends AndroidWebViewClient {
|
||||
|
||||
public TestViewClient(CordovaInterface ctx, CordovaWebView app) {
|
||||
public TestViewClient(CordovaInterface ctx, AndroidWebView app) {
|
||||
super(ctx, app);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user