mirror of
https://github.com/apache/cordova-android.git
synced 2026-05-11 00:00:05 +08:00
Compare commits
85 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| db099e7722 | |||
| fcc01bc37e | |||
| a18dacf5f2 | |||
| 77f9cae50b | |||
| 3610bbf21b | |||
| d5e3be9a55 | |||
| 80b369d6d5 | |||
| d29eb84010 | |||
| 381ce535bf | |||
| 2e20bb0639 | |||
| 56cd24797e | |||
| 431ca99c23 | |||
| 6ced2ff293 | |||
| 31055bb303 | |||
| 24a53e39dd | |||
| 2ab113b695 | |||
| 9a0481a750 | |||
| 09035eb4c4 | |||
| 1adf268e71 | |||
| 23f57ad5a7 | |||
| d9b15cf69e | |||
| dbfe12a993 | |||
| 2b32dfd99d | |||
| 679de40780 | |||
| 66f15fdd37 | |||
| 038f0e45b1 | |||
| 033bfcc804 | |||
| fa87c08a29 | |||
| dfb799739a | |||
| 1193f7ed22 | |||
| 7530c21a9f | |||
| a120614617 | |||
| 0311f0db38 | |||
| 547b683e61 | |||
| ff1d943a69 | |||
| 15a5c89e86 | |||
| 03b974ee3f | |||
| f145605c63 | |||
| 29230d0316 | |||
| 57fc49ddc2 | |||
| 5ac6853fed | |||
| b870214cca | |||
| 55074b925f | |||
| 958424ce59 | |||
| d04fc289ac | |||
| e14edf134d | |||
| dbb127447f | |||
| dc94fc39ec | |||
| 6db9a7cb12 | |||
| 1f39386616 | |||
| 25aef945d1 | |||
| c9aa43afe0 | |||
| 913e177f6f | |||
| ae431aec12 | |||
| 8ac15048cd | |||
| a1cfe87f1e | |||
| c130396d4e | |||
| bc2e7cf317 | |||
| 7ace1d652d | |||
| 26effd1def | |||
| 5f6824e5dd | |||
| 4589bdd31f | |||
| 72e0b49e0b | |||
| 3caa45d860 | |||
| 7c069f14f8 | |||
| 552885dbd3 | |||
| 6efeb1471c | |||
| 01f062d2ba | |||
| 2a42c463d2 | |||
| 182843edf6 | |||
| 9a9d36e9d9 | |||
| 7d5249eea6 | |||
| f7910c41c3 | |||
| 3973f4f952 | |||
| 8a19769a47 | |||
| c0ee593c10 | |||
| c806451b8a | |||
| 00e5ff1964 | |||
| 432aec62a9 | |||
| c8ec7e5191 | |||
| a0d2b96de6 | |||
| 2c202b82d7 | |||
| a42dc08756 | |||
| 48f58110fe | |||
| 5ca233779d |
@@ -1,16 +1,12 @@
|
||||
Cordova Android
|
||||
===
|
||||
|
||||
Cordova Android is an Android application library that allows for Cordova based projects to be built for the Android Platform. Cordova based applications are, at the core, an application written with web technology: HTML, CSS and JavaScript.
|
||||
Cordova Android is an Android application library that allows for Cordova-based
|
||||
projects to be built for the Android Platform. Cordova based applications are,
|
||||
at the core, applications written with web technology: HTML, CSS and JavaScript.
|
||||
|
||||
Apache Cordova is a project at The Apache Software Foundation (ASF).
|
||||
|
||||
Apache Cordova is an effort undergoing incubation at The Apache
|
||||
Software Foundation (ASF), sponsored by the Apache Incubator project.
|
||||
Incubation is required of all newly accepted projects until a further
|
||||
review indicates that the infrastructure, communications, and decision
|
||||
making process have stabilized in a manner consistent with other
|
||||
successful ASF projects. While incubation status is not necessarily
|
||||
a reflection of the completeness or stability of the code, it does
|
||||
indicate that the project has yet to be fully endorsed by the ASF.
|
||||
|
||||
Requires
|
||||
---
|
||||
@@ -29,11 +25,11 @@ Building
|
||||
|
||||
To create your cordova.jar, copy the commons codec:
|
||||
|
||||
mv commons-codec-1.6.jar framework/libs
|
||||
mv commons-codec-1.7.jar framework/libs
|
||||
|
||||
then run in the framework directory:
|
||||
|
||||
android update project -p . -t android-16
|
||||
android update project -p . -t android-17
|
||||
ant jar
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@
|
||||
#
|
||||
set -e
|
||||
|
||||
if [ -n "$1" ] && [ "$1" == "-h" ]
|
||||
if [ -z "$1" ] || [ "$1" == "-h" ]
|
||||
then
|
||||
echo 'usage: create path package activity'
|
||||
echo "Make sure the Android SDK tools folder is in your PATH!"
|
||||
@@ -69,7 +69,7 @@ function on_error {
|
||||
echo "An unexpected error occurred: $previous_command exited with $?"
|
||||
echo "Deleting project..."
|
||||
[ -d "$PROJECT_PATH" ] && rm -rf "$PROJECT_PATH"
|
||||
exit "$?"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function replace {
|
||||
|
||||
@@ -33,12 +33,22 @@ function read(filename) {
|
||||
f.Close();
|
||||
return s;
|
||||
}
|
||||
|
||||
function checkTargets(targets) {
|
||||
if(!targets) {
|
||||
WScript.Echo("You do not have any android targets setup. Please create at least one target with the `android` command");
|
||||
WScript.Quit(69);
|
||||
}
|
||||
}
|
||||
|
||||
function setTarget() {
|
||||
var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s\d+/g);
|
||||
checkTargets(targets);
|
||||
return targets[targets.length - 1].replace(/id: /, ""); // TODO: give users the option to set their target
|
||||
}
|
||||
function setApiLevel() {
|
||||
var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/API level:\s\d+/g);
|
||||
checkTargets(targets);
|
||||
return targets[targets.length - 1].replace(/API level: /, "");
|
||||
}
|
||||
function write(filename, contents) {
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
package __ID__;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import org.apache.cordova.*;
|
||||
|
||||
@@ -29,7 +28,9 @@ public class __ACTIVITY__ extends DroidGap
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
super.loadUrl("file:///android_asset/www/index.html");
|
||||
// Set by <content src="index.html" /> in config.xml
|
||||
super.loadUrl(Config.getStartUrl());
|
||||
//super.loadUrl("file:///android_asset/www/index.html")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:windowSoftInputMode="adjustPan"
|
||||
package="__PACKAGE__" android:versionName="1.1" android:versionCode="5" android:hardwareAccelerated="true">
|
||||
package="__PACKAGE__" android:versionName="1.0" android:versionCode="1" android:hardwareAccelerated="true">
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<p class="event received">Device is Ready</p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="cordova-2.3.0rc1.js"></script>
|
||||
<script type="text/javascript" src="cordova-2.4.0.js"></script>
|
||||
<script type="text/javascript" src="js/index.js"></script>
|
||||
<script type="text/javascript">
|
||||
app.initialize();
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:windowSoftInputMode="adjustPan"
|
||||
package="org.apache.cordova" android:versionName="1.1" android:versionCode="5">
|
||||
package="org.apache.cordova" android:versionName="1.0" android:versionCode="1">
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script src="cordova-2.3.0rc1.js"></script>
|
||||
<script src="cordova-2.4.0.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
<!-- <access origin="https://example.com" subdomains="true" /> such as above, but including subdomains, such as www -->
|
||||
<access origin=".*"/>
|
||||
|
||||
<!-- <content src="http://mysite.com/myapp.html" /> for external pages -->
|
||||
<content src="index.html" />
|
||||
|
||||
<log level="DEBUG"/>
|
||||
<preference name="useBrowserHistory" value="true" />
|
||||
<preference name="exit-on-suspend" value="false" />
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
|
||||
package org.apache.cordova;
|
||||
|
||||
import org.apache.cordova.api.CallbackContext;
|
||||
import org.apache.cordova.api.CordovaPlugin;
|
||||
import org.apache.cordova.api.LOG;
|
||||
import org.apache.cordova.api.Plugin;
|
||||
import org.apache.cordova.api.PluginResult;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
@@ -36,12 +37,12 @@ public class App extends CordovaPlugin {
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackContext The callback context from which we were invoked.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
@@ -63,7 +64,7 @@ public class App extends CordovaPlugin {
|
||||
this.loadUrl(args.getString(0), args.optJSONObject(1));
|
||||
}
|
||||
else if (action.equals("cancelLoadUrl")) {
|
||||
this.cancelLoadUrl();
|
||||
//this.cancelLoadUrl();
|
||||
}
|
||||
else if (action.equals("clearHistory")) {
|
||||
this.clearHistory();
|
||||
@@ -80,9 +81,11 @@ public class App extends CordovaPlugin {
|
||||
else if (action.equals("exitApp")) {
|
||||
this.exitApp();
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
callbackContext.sendPluginResult(new PluginResult(status, result));
|
||||
return true;
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,14 +160,6 @@ public class App extends CordovaPlugin {
|
||||
this.webView.showWebPage(url, openExternal, clearHistory, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel loadUrl before it has been loaded (Only works on a CordovaInterface class)
|
||||
*/
|
||||
@Deprecated
|
||||
public void cancelLoadUrl() {
|
||||
this.cordova.cancelLoadUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear page history for the app.
|
||||
*/
|
||||
|
||||
@@ -322,7 +322,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
}
|
||||
|
||||
// If all this is true we shouldn't compress the image.
|
||||
if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100 && rotate == 0) {
|
||||
if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100 &&
|
||||
!this.correctOrientation) {
|
||||
writeUncompressedImage(uri);
|
||||
|
||||
this.callbackContext.success(uri.toString());
|
||||
@@ -570,7 +571,13 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(imagePath, options);
|
||||
|
||||
|
||||
//CB-2292: WTF? Why is the width null?
|
||||
if(options.outWidth == 0 || options.outHeight == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// determine the correct aspect ratio
|
||||
int[] widthHeight = calculateAspectRatio(options.outWidth, options.outHeight);
|
||||
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
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 java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.cordova.api.LOG;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.graphics.Color;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class Config {
|
||||
|
||||
public static final String TAG = "Config";
|
||||
|
||||
private ArrayList<Pattern> whiteList = new ArrayList<Pattern>();
|
||||
private HashMap<String, Boolean> whiteListCache = new HashMap<String, Boolean>();
|
||||
private String startUrl;
|
||||
|
||||
private static Config self = null;
|
||||
|
||||
public static void init(Activity action) {
|
||||
if (self == null) {
|
||||
self = new Config(action);
|
||||
}
|
||||
}
|
||||
|
||||
// Intended to be used for testing only; creates an empty configuration.
|
||||
public static void init() {
|
||||
if (self == null) {
|
||||
self = new Config();
|
||||
}
|
||||
}
|
||||
|
||||
// Intended to be used for testing only; creates an empty configuration.
|
||||
private Config() {
|
||||
}
|
||||
|
||||
private Config(Activity action) {
|
||||
if (action == null) {
|
||||
LOG.i("CordovaLog", "There is no activity. Is this on the lock screen?");
|
||||
return;
|
||||
}
|
||||
|
||||
int id = action.getResources().getIdentifier("config", "xml", action.getPackageName());
|
||||
if (id == 0) {
|
||||
id = action.getResources().getIdentifier("cordova", "xml", action.getPackageName());
|
||||
LOG.i("CordovaLog", "config.xml missing, reverting to cordova.xml");
|
||||
}
|
||||
if (id == 0) {
|
||||
LOG.i("CordovaLog", "cordova.xml missing. Ignoring...");
|
||||
return;
|
||||
}
|
||||
|
||||
XmlResourceParser xml = action.getResources().getXml(id);
|
||||
int eventType = -1;
|
||||
while (eventType != XmlResourceParser.END_DOCUMENT) {
|
||||
if (eventType == XmlResourceParser.START_TAG) {
|
||||
String strNode = xml.getName();
|
||||
|
||||
if (strNode.equals("access")) {
|
||||
String origin = xml.getAttributeValue(null, "origin");
|
||||
String subdomains = xml.getAttributeValue(null, "subdomains");
|
||||
if (origin != null) {
|
||||
this._addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0));
|
||||
}
|
||||
}
|
||||
else if (strNode.equals("log")) {
|
||||
String level = xml.getAttributeValue(null, "level");
|
||||
LOG.i("CordovaLog", "Found log level %s", level);
|
||||
if (level != null) {
|
||||
LOG.setLogLevel(level);
|
||||
}
|
||||
}
|
||||
else if (strNode.equals("preference")) {
|
||||
String name = xml.getAttributeValue(null, "name");
|
||||
/* Java 1.6 does not support switch-based strings
|
||||
Java 7 does, but we're using Dalvik, which is apparently not Java.
|
||||
Since we're reading XML, this has to be an ugly if/else.
|
||||
|
||||
Also, due to cast issues, each of them has to call their separate putExtra!
|
||||
Wheee!!! Isn't Java FUN!?!?!?
|
||||
|
||||
Note: We should probably pass in the classname for the variable splash on splashscreen!
|
||||
*/
|
||||
if(name.equals("splashscreen")) {
|
||||
String value = xml.getAttributeValue(null, "value");
|
||||
int resource = 0;
|
||||
if (value != null)
|
||||
{
|
||||
value = "splash";
|
||||
}
|
||||
resource = action.getResources().getIdentifier(value, "drawable", action.getPackageName());
|
||||
|
||||
action.getIntent().putExtra(name, resource);
|
||||
LOG.i("CordovaLog", "Found preference for %s=%s", name, value);
|
||||
Log.d("CordovaLog", "Found preference for " + name + "=" + value);
|
||||
}
|
||||
else if(name.equals("backgroundColor")) {
|
||||
int value = xml.getAttributeIntValue(null, "value", Color.BLACK);
|
||||
action.getIntent().putExtra(name, value);
|
||||
LOG.i("CordovaLog", "Found preference for %s=%d", name, value);
|
||||
Log.d("CordovaLog", "Found preference for " + name + "=" + Integer.toString(value));
|
||||
}
|
||||
else if(name.equals("loadUrlTimeoutValue")) {
|
||||
int value = xml.getAttributeIntValue(null, "value", 20000);
|
||||
action.getIntent().putExtra(name, value);
|
||||
LOG.i("CordovaLog", "Found preference for %s=%d", name, value);
|
||||
Log.d("CordovaLog", "Found preference for " + name + "=" + Integer.toString(value));
|
||||
}
|
||||
else if(name.equals("keepRunning"))
|
||||
{
|
||||
boolean value = xml.getAttributeValue(null, "value").equals("true");
|
||||
action.getIntent().putExtra(name, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
String value = xml.getAttributeValue(null, "value");
|
||||
action.getIntent().putExtra(name, value);
|
||||
LOG.i("CordovaLog", "Found preference for %s=%s", name, value);
|
||||
Log.d("CordovaLog", "Found preference for " + name + "=" + value);
|
||||
}
|
||||
/*
|
||||
LOG.i("CordovaLog", "Found preference for %s=%s", name, value);
|
||||
Log.d("CordovaLog", "Found preference for " + name + "=" + value);
|
||||
*/
|
||||
}
|
||||
else if (strNode.equals("content")) {
|
||||
String src = xml.getAttributeValue(null, "src");
|
||||
|
||||
LOG.i("CordovaLog", "Found start page location: %s", src);
|
||||
|
||||
if (src != null) {
|
||||
Pattern schemeRegex = Pattern.compile("^[a-z]+://");
|
||||
Matcher matcher = schemeRegex.matcher(src);
|
||||
if (matcher.find()) {
|
||||
startUrl = src;
|
||||
} else {
|
||||
if (src.charAt(0) == '/') {
|
||||
src = src.substring(1);
|
||||
}
|
||||
startUrl = "file:///android_asset/www/" + src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
eventType = xml.next();
|
||||
} catch (XmlPullParserException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add entry to approved list of URLs (whitelist)
|
||||
*
|
||||
* @param origin URL regular expression to allow
|
||||
* @param subdomains T=include all subdomains under origin
|
||||
*/
|
||||
public static void addWhiteListEntry(String origin, boolean subdomains) {
|
||||
if (self == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
self._addWhiteListEntry(origin, subdomains);
|
||||
}
|
||||
|
||||
|
||||
private void _addWhiteListEntry(String origin, boolean subdomains) {
|
||||
try {
|
||||
// Unlimited access to network resources
|
||||
if (origin.compareTo("*") == 0) {
|
||||
LOG.d(TAG, "Unlimited access to network resources");
|
||||
this.whiteList.add(Pattern.compile(".*"));
|
||||
} else { // specific access
|
||||
// check if subdomains should be included
|
||||
// TODO: we should not add more domains if * has already been added
|
||||
if (subdomains) {
|
||||
// XXX making it stupid friendly for people who forget to include protocol/SSL
|
||||
if (origin.startsWith("http")) {
|
||||
this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://(.*\\.)?")));
|
||||
} else {
|
||||
this.whiteList.add(Pattern.compile("^https?://(.*\\.)?" + origin));
|
||||
}
|
||||
LOG.d(TAG, "Origin to allow with subdomains: %s", origin);
|
||||
} else {
|
||||
// XXX making it stupid friendly for people who forget to include protocol/SSL
|
||||
if (origin.startsWith("http")) {
|
||||
this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://")));
|
||||
} else {
|
||||
this.whiteList.add(Pattern.compile("^https?://" + origin));
|
||||
}
|
||||
LOG.d(TAG, "Origin to allow: %s", origin);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.d(TAG, "Failed to add origin %s", origin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if URL is in approved list of URLs to load.
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public static boolean isUrlWhiteListed(String url) {
|
||||
if (self == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if we have matched url previously
|
||||
if (self.whiteListCache.get(url) != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Look for match in white list
|
||||
Iterator<Pattern> pit = self.whiteList.iterator();
|
||||
while (pit.hasNext()) {
|
||||
Pattern p = pit.next();
|
||||
Matcher m = p.matcher(url);
|
||||
|
||||
// If match found, then cache it to speed up subsequent comparisons
|
||||
if (m.find()) {
|
||||
self.whiteListCache.put(url, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getStartUrl() {
|
||||
if (self == null || self.startUrl == null) {
|
||||
return "file:///android_asset/www/index.html";
|
||||
}
|
||||
return self.startUrl;
|
||||
}
|
||||
}
|
||||
@@ -219,6 +219,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
|
||||
columnsToFetch.add(ContactsContract.CommonDataKinds.Phone.TYPE);
|
||||
}
|
||||
if (isRequired("emails", populate)) {
|
||||
columnsToFetch.add(ContactsContract.CommonDataKinds.Email._ID);
|
||||
columnsToFetch.add(ContactsContract.CommonDataKinds.Email.DATA);
|
||||
columnsToFetch.add(ContactsContract.CommonDataKinds.Email.TYPE);
|
||||
}
|
||||
@@ -1500,7 +1501,7 @@ public class ContactAccessorSdk5 extends ContactAccessor {
|
||||
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
|
||||
.withValue(ContactsContract.CommonDataKinds.Email.DATA, getJsonString(email, "value"))
|
||||
.withValue(ContactsContract.CommonDataKinds.Email.TYPE, getPhoneType(getJsonString(email, "type")))
|
||||
.withValue(ContactsContract.CommonDataKinds.Email.TYPE, getContactType(getJsonString(email, "type")))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
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 org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
public class CordovaArgs {
|
||||
private JSONArray baseArgs;
|
||||
|
||||
public CordovaArgs(JSONArray args) {
|
||||
this.baseArgs = args;
|
||||
}
|
||||
|
||||
|
||||
// Pass through the basics to the base args.
|
||||
public Object get(int index) throws JSONException {
|
||||
return baseArgs.get(index);
|
||||
}
|
||||
|
||||
public boolean getBoolean(int index) throws JSONException {
|
||||
return baseArgs.getBoolean(index);
|
||||
}
|
||||
|
||||
public double getDouble(int index) throws JSONException {
|
||||
return baseArgs.getDouble(index);
|
||||
}
|
||||
|
||||
public int getInt(int index) throws JSONException {
|
||||
return baseArgs.getInt(index);
|
||||
}
|
||||
|
||||
public JSONArray getJSONArray(int index) throws JSONException {
|
||||
return baseArgs.getJSONArray(index);
|
||||
}
|
||||
|
||||
public Object getJSONObject(int index) throws JSONException {
|
||||
return baseArgs.getJSONObject(index);
|
||||
}
|
||||
|
||||
public long getLong(int index) throws JSONException {
|
||||
return baseArgs.getLong(index);
|
||||
}
|
||||
|
||||
public String getString(int index) throws JSONException {
|
||||
return baseArgs.getString(index);
|
||||
}
|
||||
|
||||
|
||||
public Object opt(int index) {
|
||||
return baseArgs.opt(index);
|
||||
}
|
||||
|
||||
public boolean optBoolean(int index) {
|
||||
return baseArgs.optBoolean(index);
|
||||
}
|
||||
|
||||
public double optDouble(int index) {
|
||||
return baseArgs.optDouble(index);
|
||||
}
|
||||
|
||||
public int optInt(int index) {
|
||||
return baseArgs.optInt(index);
|
||||
}
|
||||
|
||||
public JSONArray optJSONArray(int index) {
|
||||
return baseArgs.optJSONArray(index);
|
||||
}
|
||||
|
||||
public Object optJSONObject(int index) {
|
||||
return baseArgs.optJSONObject(index);
|
||||
}
|
||||
|
||||
public long optLong(int index) {
|
||||
return baseArgs.optLong(index);
|
||||
}
|
||||
|
||||
public String optString(int index) {
|
||||
return baseArgs.optString(index);
|
||||
}
|
||||
|
||||
public boolean isNull(int index) {
|
||||
return baseArgs.isNull(index);
|
||||
}
|
||||
|
||||
|
||||
// The interesting custom helpers.
|
||||
public byte[] getArrayBuffer(int index) throws JSONException {
|
||||
String encoded = baseArgs.getString(index);
|
||||
return Base64.decode(encoded, Base64.DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,12 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
@@ -33,6 +37,7 @@ import android.view.ViewGroup.LayoutParams;
|
||||
import android.webkit.ConsoleMessage;
|
||||
import android.webkit.JsPromptResult;
|
||||
import android.webkit.JsResult;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebStorage;
|
||||
import android.webkit.WebView;
|
||||
@@ -47,6 +52,8 @@ import android.widget.RelativeLayout;
|
||||
*/
|
||||
public class CordovaChromeClient extends WebChromeClient {
|
||||
|
||||
public static final int FILECHOOSER_RESULTCODE = 5173;
|
||||
private static final String LOG_TAG = "CordovaChromeClient";
|
||||
private String TAG = "CordovaLog";
|
||||
private long MAX_QUOTA = 100 * 1024 * 1024;
|
||||
private CordovaInterface cordova;
|
||||
@@ -55,6 +62,9 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
// the video progress view
|
||||
private View mVideoProgressView;
|
||||
|
||||
// File Chooser
|
||||
public ValueCallback<Uri> mUploadMessage;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@@ -197,7 +207,7 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
// Security check to make sure any requests are coming from the page initially
|
||||
// loaded in webview and not another loaded in an iframe.
|
||||
boolean reqOk = false;
|
||||
if (url.startsWith("file://") || url.indexOf(this.appView.baseUrl) == 0 || this.appView.isUrlWhiteListed(url)) {
|
||||
if (url.startsWith("file://") || url.indexOf(this.appView.baseUrl) == 0 || Config.isUrlWhiteListed(url)) {
|
||||
reqOk = true;
|
||||
}
|
||||
|
||||
@@ -296,12 +306,17 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
}
|
||||
|
||||
// console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html
|
||||
// Expect this to not compile in a future Android release!
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onConsoleMessage(String message, int lineNumber, String sourceID)
|
||||
{
|
||||
LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message);
|
||||
super.onConsoleMessage(message, lineNumber, sourceID);
|
||||
//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);
|
||||
super.onConsoleMessage(message, lineNumber, sourceID);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(8)
|
||||
@@ -364,5 +379,26 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
}
|
||||
return mVideoProgressView;
|
||||
}
|
||||
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
|
||||
this.openFileChooser(uploadMsg, "*/*");
|
||||
}
|
||||
|
||||
public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType ) {
|
||||
this.openFileChooser(uploadMsg, acceptType, null);
|
||||
}
|
||||
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
|
||||
{
|
||||
mUploadMessage = uploadMsg;
|
||||
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
i.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
i.setType("*/*");
|
||||
this.cordova.getActivity().startActivityForResult(Intent.createChooser(i, "File Browser"),
|
||||
FILECHOOSER_RESULTCODE);
|
||||
}
|
||||
|
||||
public ValueCallback<Uri> getValueCallback() {
|
||||
return this.mUploadMessage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,30 +19,25 @@
|
||||
|
||||
package org.apache.cordova;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Stack;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.cordova.Config;
|
||||
import org.apache.cordova.api.CordovaInterface;
|
||||
import org.apache.cordova.api.CordovaPlugin;
|
||||
import org.apache.cordova.api.LOG;
|
||||
import org.apache.cordova.api.PluginManager;
|
||||
import org.apache.cordova.api.PluginResult;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@@ -65,15 +60,12 @@ public class CordovaWebView extends WebView {
|
||||
|
||||
public static final String TAG = "CordovaWebView";
|
||||
|
||||
/** The whitelist **/
|
||||
private ArrayList<Pattern> whiteList = new ArrayList<Pattern>();
|
||||
private HashMap<String, Boolean> whiteListCache = new HashMap<String, Boolean>();
|
||||
private ArrayList<Integer> keyDownCodes = new ArrayList<Integer>();
|
||||
private ArrayList<Integer> keyUpCodes = new ArrayList<Integer>();
|
||||
|
||||
public PluginManager pluginManager;
|
||||
private boolean paused;
|
||||
|
||||
|
||||
private BroadcastReceiver receiver;
|
||||
|
||||
|
||||
@@ -105,6 +97,23 @@ public class CordovaWebView extends WebView {
|
||||
/** custom view created by the browser (a video player for example) */
|
||||
private View mCustomView;
|
||||
private WebChromeClient.CustomViewCallback mCustomViewCallback;
|
||||
|
||||
private ActivityResult mResult = null;
|
||||
|
||||
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(
|
||||
@@ -324,71 +333,9 @@ public class CordovaWebView extends WebView {
|
||||
this.chromeClient = client;
|
||||
super.setWebChromeClient(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add entry to approved list of URLs (whitelist)
|
||||
*
|
||||
* @param origin URL regular expression to allow
|
||||
* @param subdomains T=include all subdomains under origin
|
||||
*/
|
||||
public void addWhiteListEntry(String origin, boolean subdomains) {
|
||||
try {
|
||||
// Unlimited access to network resources
|
||||
if (origin.compareTo("*") == 0) {
|
||||
LOG.d(TAG, "Unlimited access to network resources");
|
||||
this.whiteList.add(Pattern.compile(".*"));
|
||||
} else { // specific access
|
||||
// check if subdomains should be included
|
||||
// TODO: we should not add more domains if * has already been added
|
||||
if (subdomains) {
|
||||
// XXX making it stupid friendly for people who forget to include protocol/SSL
|
||||
if (origin.startsWith("http")) {
|
||||
this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://(.*\\.)?")));
|
||||
} else {
|
||||
this.whiteList.add(Pattern.compile("^https?://(.*\\.)?" + origin));
|
||||
}
|
||||
LOG.d(TAG, "Origin to allow with subdomains: %s", origin);
|
||||
} else {
|
||||
// XXX making it stupid friendly for people who forget to include protocol/SSL
|
||||
if (origin.startsWith("http")) {
|
||||
this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://")));
|
||||
} else {
|
||||
this.whiteList.add(Pattern.compile("^https?://" + origin));
|
||||
}
|
||||
LOG.d(TAG, "Origin to allow: %s", origin);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.d(TAG, "Failed to add origin %s", origin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if URL is in approved list of URLs to load.
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public boolean isUrlWhiteListed(String url) {
|
||||
|
||||
// Check to see if we have matched url previously
|
||||
if (this.whiteListCache.get(url) != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Look for match in white list
|
||||
Iterator<Pattern> pit = this.whiteList.iterator();
|
||||
while (pit.hasNext()) {
|
||||
Pattern p = pit.next();
|
||||
Matcher m = p.matcher(url);
|
||||
|
||||
// If match found, then cache it to speed up subsequent comparisons
|
||||
if (m.find()) {
|
||||
this.whiteListCache.put(url, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
public CordovaChromeClient getWebChromeClient() {
|
||||
return this.chromeClient;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -514,8 +461,8 @@ public class CordovaWebView extends WebView {
|
||||
if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) {
|
||||
LOG.d(TAG, ">>> loadUrlNow()");
|
||||
}
|
||||
if (url.startsWith("file://") || url.indexOf(this.baseUrl) == 0 || url.startsWith("javascript:") || this.isUrlWhiteListed(url)) {
|
||||
super.loadUrl(url);
|
||||
if (url.startsWith("file://") || url.indexOf(this.baseUrl) == 0 || url.startsWith("javascript:") || Config.isUrlWhiteListed(url)) {
|
||||
super.loadUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -662,7 +609,7 @@ public class CordovaWebView extends WebView {
|
||||
if (!openExternal) {
|
||||
|
||||
// Make sure url is in whitelist
|
||||
if (url.startsWith("file://") || url.indexOf(this.baseUrl) == 0 || isUrlWhiteListed(url)) {
|
||||
if (url.startsWith("file://") || url.indexOf(this.baseUrl) == 0 || Config.isUrlWhiteListed(url)) {
|
||||
// TODO: What about params?
|
||||
|
||||
// Clear out current url from history, since it will be replacing it
|
||||
@@ -699,68 +646,14 @@ public class CordovaWebView extends WebView {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Cordova configuration from res/xml/cordova.xml.
|
||||
* Check configuration parameters from Config.
|
||||
* Approved list of URLs that can be loaded into DroidGap
|
||||
* <access origin="http://server regexp" subdomains="true" />
|
||||
* Log level: ERROR, WARN, INFO, DEBUG, VERBOSE (default=ERROR)
|
||||
* <log level="DEBUG" />
|
||||
*/
|
||||
private void loadConfiguration() {
|
||||
Activity action = this.cordova.getActivity();
|
||||
if(action == null)
|
||||
{
|
||||
LOG.i("CordovaLog", "There is no activity. Is this on the lock screen?");
|
||||
return;
|
||||
}
|
||||
int id = getResources().getIdentifier("config", "xml", this.cordova.getActivity().getPackageName());
|
||||
if(id == 0)
|
||||
{
|
||||
id = getResources().getIdentifier("cordova", "xml", this.cordova.getActivity().getPackageName());
|
||||
Log.i("CordovaLog", "config.xml missing, reverting to cordova.xml");
|
||||
}
|
||||
if (id == 0) {
|
||||
LOG.i("CordovaLog", "cordova.xml missing. Ignoring...");
|
||||
return;
|
||||
}
|
||||
XmlResourceParser xml = getResources().getXml(id);
|
||||
int eventType = -1;
|
||||
while (eventType != XmlResourceParser.END_DOCUMENT) {
|
||||
if (eventType == XmlResourceParser.START_TAG) {
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("access")) {
|
||||
String origin = xml.getAttributeValue(null, "origin");
|
||||
String subdomains = xml.getAttributeValue(null, "subdomains");
|
||||
if (origin != null) {
|
||||
this.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0));
|
||||
}
|
||||
}
|
||||
else if (strNode.equals("log")) {
|
||||
String level = xml.getAttributeValue(null, "level");
|
||||
LOG.i("CordovaLog", "Found log level %s", level);
|
||||
if (level != null) {
|
||||
LOG.setLogLevel(level);
|
||||
}
|
||||
}
|
||||
else if (strNode.equals("preference")) {
|
||||
String name = xml.getAttributeValue(null, "name");
|
||||
String value = xml.getAttributeValue(null, "value");
|
||||
|
||||
LOG.i("CordovaLog", "Found preference for %s=%s", name, value);
|
||||
Log.d("CordovaLog", "Found preference for " + name + "=" + value);
|
||||
|
||||
// Save preferences in Intent
|
||||
this.cordova.getActivity().getIntent().putExtra(name, value);
|
||||
}
|
||||
}
|
||||
try {
|
||||
eventType = xml.next();
|
||||
} catch (XmlPullParserException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// Config has already been loaded, and it stores these preferences on the Intent.
|
||||
if("false".equals(this.getProperty("useBrowserHistory", "true")))
|
||||
{
|
||||
//Switch back to the old browser history and state the six month policy
|
||||
@@ -939,9 +832,8 @@ public class CordovaWebView extends WebView {
|
||||
public void handleResume(boolean keepRunning, boolean activityResultKeepRunning)
|
||||
{
|
||||
|
||||
// Send resume event to JavaScript
|
||||
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);
|
||||
@@ -1077,4 +969,17 @@ public class CordovaWebView extends WebView {
|
||||
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 void storeResult(int requestCode, int resultCode, Intent intent) {
|
||||
mResult = new ActivityResult(requestCode, resultCode, intent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ package org.apache.cordova;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.apache.cordova.api.CordovaInterface;
|
||||
import org.apache.cordova.api.PluginResult;
|
||||
|
||||
import org.apache.cordova.api.LOG;
|
||||
import org.json.JSONException;
|
||||
@@ -193,7 +192,7 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
|
||||
// If our app or file:, then load into a new Cordova webview container by starting a new instance of our activity.
|
||||
// Our app continues to run. When BACK is pressed, our app is redisplayed.
|
||||
if (url.startsWith("file://") || url.startsWith("data:") || url.indexOf(this.appView.baseUrl) == 0 || this.appView.isUrlWhiteListed(url)) {
|
||||
if (url.startsWith("file://") || url.startsWith("data:") || url.indexOf(this.appView.baseUrl) == 0 || Config.isUrlWhiteListed(url)) {
|
||||
//This will fix iFrames
|
||||
if (appView.useBrowserHistory || url.startsWith("data:"))
|
||||
return false;
|
||||
@@ -231,6 +230,10 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
AuthenticationToken token = this.getAuthenticationToken(host, realm);
|
||||
if (token != null) {
|
||||
handler.proceed(token.getUserName(), token.getPassword());
|
||||
}
|
||||
else {
|
||||
// Handle 401 like we'd normally do!
|
||||
super.onReceivedHttpAuthRequest(view, handler, host, realm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +298,7 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
// not loaded yet then just set a flag so that the onNativeReady can be fired
|
||||
// from the JS side when the JS gets to that code.
|
||||
if (!url.equals("about:blank")) {
|
||||
LOG.d(TAG, "Trying to fire onNativeReady");
|
||||
this.appView.loadUrl("javascript:try{ cordova.require('cordova/channel').onNativeReady.fire();}catch(e){_nativeReady = true;}");
|
||||
this.appView.postMessage("onNativeReady", null);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ import android.telephony.TelephonyManager;
|
||||
public class Device extends CordovaPlugin {
|
||||
public static final String TAG = "Device";
|
||||
|
||||
public static String cordovaVersion = "2.3.0rc1"; // Cordova version
|
||||
public static String cordovaVersion = "2.4.0"; // Cordova version
|
||||
public static String platform = "Android"; // Device OS
|
||||
public static String uuid; // Device UUID
|
||||
|
||||
@@ -80,7 +80,7 @@ public class Device extends CordovaPlugin {
|
||||
r.put("platform", Device.platform);
|
||||
r.put("name", this.getProductName());
|
||||
r.put("cordova", Device.cordovaVersion);
|
||||
r.put("model", this.getProductName());
|
||||
r.put("model", this.getModel());
|
||||
callbackContext.success(r);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -38,8 +38,10 @@ import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Color;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
@@ -48,6 +50,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.LinearLayout;
|
||||
@@ -170,7 +173,7 @@ public class DroidGap 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 = 0;
|
||||
protected int splashscreenTime = 3000;
|
||||
|
||||
// LoadUrl timeout value in msec (default of 20 sec)
|
||||
protected int loadUrlTimeoutValue = 20000;
|
||||
@@ -180,6 +183,18 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
// when another application (activity) is started.
|
||||
protected boolean keepRunning = true;
|
||||
|
||||
private int lastRequestCode;
|
||||
|
||||
private Object responseCode;
|
||||
|
||||
private Intent lastIntent;
|
||||
|
||||
private Object lastResponseCode;
|
||||
|
||||
private String initCallbackClass;
|
||||
|
||||
private Object LOG_TAG;
|
||||
|
||||
/**
|
||||
* Sets the authentication token.
|
||||
*
|
||||
@@ -246,11 +261,15 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
//preferences = new PreferenceSet();
|
||||
|
||||
Config.init(this);
|
||||
LOG.d(TAG, "DroidGap.onCreate()");
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if(savedInstanceState != null)
|
||||
{
|
||||
initCallbackClass = savedInstanceState.getString("callbackClass");
|
||||
}
|
||||
|
||||
if(!this.getBooleanProperty("showTitle", false))
|
||||
{
|
||||
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
|
||||
@@ -338,6 +357,7 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
|
||||
// Clear cancel flag
|
||||
this.cancelLoadUrl = false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -571,6 +591,7 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
* @param value
|
||||
*/
|
||||
public void setBooleanProperty(String name, boolean value) {
|
||||
Log.d(TAG, "Setting boolean properties in DroidGap will be deprecated in 3.0 on July 2013, please use config.xml");
|
||||
this.getIntent().putExtra(name, value);
|
||||
}
|
||||
|
||||
@@ -581,6 +602,7 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
* @param value
|
||||
*/
|
||||
public void setIntegerProperty(String name, int value) {
|
||||
Log.d(TAG, "Setting integer properties in DroidGap will be deprecated in 3.1 on August 2013, please use config.xml");
|
||||
this.getIntent().putExtra(name, value);
|
||||
}
|
||||
|
||||
@@ -591,6 +613,7 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
* @param value
|
||||
*/
|
||||
public void setStringProperty(String name, String value) {
|
||||
Log.d(TAG, "Setting string properties in DroidGap will be deprecated in 3.0 on July 2013, please use config.xml");
|
||||
this.getIntent().putExtra(name, value);
|
||||
}
|
||||
|
||||
@@ -601,6 +624,7 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
* @param value
|
||||
*/
|
||||
public void setDoubleProperty(String name, double value) {
|
||||
Log.d(TAG, "Setting double properties in DroidGap will be deprecated in 3.0 on July 2013, please use config.xml");
|
||||
this.getIntent().putExtra(name, value);
|
||||
}
|
||||
|
||||
@@ -800,9 +824,35 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
* @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
|
||||
*/
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
LOG.d(TAG, "Incoming Result");
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
Log.d(TAG, "Request code = " + requestCode);
|
||||
ValueCallback<Uri> mUploadMessage = this.appView.getWebChromeClient().getValueCallback();
|
||||
if (requestCode == CordovaChromeClient.FILECHOOSER_RESULTCODE) {
|
||||
Log.d(TAG, "did we get here?");
|
||||
if (null == mUploadMessage)
|
||||
return;
|
||||
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
|
||||
Log.d(TAG, "result = " + result);
|
||||
// Uri filepath = Uri.parse("file://" + FileUtils.getRealPathFromURI(result, this));
|
||||
// Log.d(TAG, "result = " + filepath);
|
||||
mUploadMessage.onReceiveValue(result);
|
||||
mUploadMessage = null;
|
||||
}
|
||||
CordovaPlugin callback = this.activityResultCallback;
|
||||
if (callback != null) {
|
||||
if(callback == null)
|
||||
{
|
||||
if(initCallbackClass != null)
|
||||
{
|
||||
this.activityResultCallback = appView.pluginManager.getPlugin(initCallbackClass);
|
||||
callback = activityResultCallback;
|
||||
LOG.d(TAG, "We have a callback to send this result to");
|
||||
callback.onActivityResult(requestCode, resultCode, intent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.d(TAG, "We have a callback to send this result to");
|
||||
callback.onActivityResult(requestCode, resultCode, intent);
|
||||
}
|
||||
}
|
||||
@@ -824,7 +874,7 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
|
||||
// If errorUrl specified, then load it
|
||||
final String errorUrl = me.getStringProperty("errorUrl", null);
|
||||
if ((errorUrl != null) && (errorUrl.startsWith("file://") || this.appView.isUrlWhiteListed(errorUrl)) && (!failingUrl.equals(errorUrl))) {
|
||||
if ((errorUrl != null) && (errorUrl.startsWith("file://") || Config.isUrlWhiteListed(errorUrl)) && (!failingUrl.equals(errorUrl))) {
|
||||
|
||||
// Load URL on UI thread
|
||||
me.runOnUiThread(new Runnable() {
|
||||
@@ -840,8 +890,7 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
final boolean exit = !(errorCode == WebViewClient.ERROR_HOST_LOOKUP);
|
||||
me.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (exit)
|
||||
{
|
||||
if (exit) {
|
||||
me.appView.setVisibility(View.GONE);
|
||||
me.displayError("Application Error", description + " (" + failingUrl + ")", "OK", exit);
|
||||
}
|
||||
@@ -892,11 +941,7 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
* @return
|
||||
*/
|
||||
public boolean isUrlWhiteListed(String url) {
|
||||
// Check to see if we have matched url previously
|
||||
if (this.appView != null) {
|
||||
return this.appView.isUrlWhiteListed(url);
|
||||
}
|
||||
return false;
|
||||
return Config.isUrlWhiteListed(url);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1008,12 +1053,9 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event)
|
||||
{
|
||||
//Determine if the focus is on the current view or not
|
||||
if (appView.getHitTestResult() != null &&
|
||||
appView.getHitTestResult().getType() == WebView.HitTestResult.EDIT_TEXT_TYPE &&
|
||||
(keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
|
||||
return appView.onKeyUp(keyCode, event);
|
||||
} else if (appView.isCustomViewShowing() && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
//Get whatever has focus!
|
||||
View childView = appView.getFocusedChild();
|
||||
if ((appView.isCustomViewShowing() || childView != null ) && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
return appView.onKeyUp(keyCode, event);
|
||||
} else {
|
||||
return super.onKeyUp(keyCode, event);
|
||||
@@ -1030,10 +1072,10 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event)
|
||||
{
|
||||
//Get whatever has focus!
|
||||
View childView = appView.getFocusedChild();
|
||||
//Determine if the focus is on the current view or not
|
||||
if (appView.getHitTestResult() != null &&
|
||||
appView.getHitTestResult().getType() == WebView.HitTestResult.EDIT_TEXT_TYPE &&
|
||||
keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
if (childView != null && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
return appView.onKeyDown(keyCode, event);
|
||||
}
|
||||
else
|
||||
@@ -1056,9 +1098,9 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
}
|
||||
else {
|
||||
// If the splash dialog is showing don't try to show it again
|
||||
if (this.splashDialog != null && !this.splashDialog.isShowing()) {
|
||||
this.splashscreen = this.getIntegerProperty("splashscreen", 0);
|
||||
this.showSplashScreen(this.splashscreenTime);
|
||||
if (this.splashDialog == null || !this.splashDialog.isShowing()) {
|
||||
this.splashscreen = this.getIntegerProperty("splashscreen", 0);
|
||||
this.showSplashScreen(this.splashscreenTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1085,4 +1127,15 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
public ExecutorService getThreadPool() {
|
||||
return threadPool;
|
||||
}
|
||||
|
||||
protected void onSaveInstanceState(Bundle outState)
|
||||
{
|
||||
super.onSaveInstanceState(outState);
|
||||
if(this.activityResultCallback != null)
|
||||
{
|
||||
String cClass = this.activityResultCallback.getClass().getName();
|
||||
outState.putString("callbackClass", cClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,24 +20,28 @@ package org.apache.cordova;
|
||||
|
||||
import org.apache.cordova.api.CallbackContext;
|
||||
import org.apache.cordova.api.CordovaPlugin;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
public class Echo extends CordovaPlugin {
|
||||
|
||||
@Override
|
||||
public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
||||
final String result = args.isNull(0) ? null : args.getString(0);
|
||||
public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
|
||||
if ("echo".equals(action)) {
|
||||
final String result = args.isNull(0) ? null : args.getString(0);
|
||||
callbackContext.success(result);
|
||||
return true;
|
||||
} else if ("echoAsync".equals(action)) {
|
||||
final String result = args.isNull(0) ? null : args.getString(0);
|
||||
cordova.getThreadPool().execute(new Runnable() {
|
||||
public void run() {
|
||||
callbackContext.success(result);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} else if ("echoArrayBuffer".equals(action)) {
|
||||
final byte[] result = args.getArrayBuffer(0);
|
||||
callbackContext.success(result);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -215,6 +215,8 @@ public class FileTransfer extends CordovaPlugin {
|
||||
HttpURLConnection conn = null;
|
||||
HostnameVerifier oldHostnameVerifier = null;
|
||||
SSLSocketFactory oldSocketFactory = null;
|
||||
int totalBytes = 0;
|
||||
int fixedLength = -1;
|
||||
try {
|
||||
// Create return object
|
||||
FileUploadResult result = new FileUploadResult();
|
||||
@@ -320,7 +322,6 @@ public class FileTransfer extends CordovaPlugin {
|
||||
|
||||
int stringLength = extraBytes.length + midParams.length() + tailParams.length() + fileNameBytes.length;
|
||||
Log.d(LOG_TAG, "String Length: " + stringLength);
|
||||
int fixedLength = -1;
|
||||
if (sourceInputStream instanceof FileInputStream) {
|
||||
fixedLength = (int) ((FileInputStream)sourceInputStream).getChannel().size() + stringLength;
|
||||
progress.setLengthComputable(true);
|
||||
@@ -363,13 +364,12 @@ public class FileTransfer extends CordovaPlugin {
|
||||
|
||||
// read file and write it into form...
|
||||
int bytesRead = sourceInputStream.read(buffer, 0, bufferSize);
|
||||
long totalBytes = 0;
|
||||
|
||||
long prevBytesRead = 0;
|
||||
while (bytesRead > 0) {
|
||||
totalBytes += bytesRead;
|
||||
result.setBytesSent(totalBytes);
|
||||
dos.write(buffer, 0, bufferSize);
|
||||
dos.write(buffer, 0, bytesRead);
|
||||
if (totalBytes > prevBytesRead + 102400) {
|
||||
prevBytesRead = totalBytes;
|
||||
Log.d(LOG_TAG, "Uploaded " + totalBytes + " of " + fixedLength + " bytes");
|
||||
@@ -436,6 +436,7 @@ public class FileTransfer extends CordovaPlugin {
|
||||
} catch (IOException e) {
|
||||
JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
|
||||
Log.e(LOG_TAG, error.toString(), e);
|
||||
Log.e(LOG_TAG, "Failed after uploading " + totalBytes + " of " + fixedLength + " bytes.");
|
||||
context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
@@ -602,8 +603,8 @@ public class FileTransfer extends CordovaPlugin {
|
||||
return;
|
||||
}
|
||||
final boolean useHttps = url.getProtocol().toLowerCase().equals("https");
|
||||
|
||||
if (!webView.isUrlWhiteListed(source)) {
|
||||
|
||||
if (!Config.isUrlWhiteListed(source)) {
|
||||
Log.w(LOG_TAG, "Source URL is not in white list: '" + source + "'");
|
||||
JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, 401);
|
||||
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
|
||||
@@ -676,11 +677,12 @@ public class FileTransfer extends CordovaPlugin {
|
||||
progress.setTotal(connection.getContentLength());
|
||||
}
|
||||
|
||||
FileOutputStream outputStream = new FileOutputStream(file);
|
||||
FileOutputStream outputStream = null;
|
||||
InputStream inputStream = null;
|
||||
|
||||
try {
|
||||
inputStream = getInputStream(connection);
|
||||
outputStream = new FileOutputStream(file);
|
||||
synchronized (context) {
|
||||
if (context.aborted) {
|
||||
return;
|
||||
|
||||
@@ -112,11 +112,29 @@ public class FileUtils extends CordovaPlugin {
|
||||
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
|
||||
}
|
||||
else if (action.equals("readAsText")) {
|
||||
String s = this.readAsText(args.getString(0), args.getString(1));
|
||||
int start = 0;
|
||||
int end = Integer.MAX_VALUE;
|
||||
if (args.length() >= 3) {
|
||||
start = args.getInt(2);
|
||||
}
|
||||
if (args.length() >= 4) {
|
||||
end = args.getInt(3);
|
||||
}
|
||||
|
||||
String s = this.readAsText(args.getString(0), args.getString(1), start, end);
|
||||
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, s));
|
||||
}
|
||||
else if (action.equals("readAsDataURL")) {
|
||||
String s = this.readAsDataURL(args.getString(0));
|
||||
int start = 0;
|
||||
int end = Integer.MAX_VALUE;
|
||||
if (args.length() >= 2) {
|
||||
start = args.getInt(1);
|
||||
}
|
||||
if (args.length() >= 3) {
|
||||
end = args.getInt(2);
|
||||
}
|
||||
|
||||
String s = this.readAsDataURL(args.getString(0), start, end);
|
||||
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, s));
|
||||
}
|
||||
else if (action.equals("write")) {
|
||||
@@ -221,9 +239,15 @@ public class FileUtils extends CordovaPlugin {
|
||||
*/
|
||||
private void notifyDelete(String filePath) {
|
||||
String newFilePath = stripFileProtocol(filePath);
|
||||
this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
MediaStore.Images.Media.DATA + " = ?",
|
||||
new String[] { newFilePath });
|
||||
try {
|
||||
this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
MediaStore.Images.Media.DATA + " = ?",
|
||||
new String[] { newFilePath });
|
||||
} catch (UnsupportedOperationException t) {
|
||||
// Was seeing this on the File mobile-spec tests on 4.0.3 x86 emulator.
|
||||
// The ContentResolver applies only when the file was registered in the
|
||||
// first case, which is generally only the case with images.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,17 +956,27 @@ public class FileUtils extends CordovaPlugin {
|
||||
* @param filename The name of the file.
|
||||
* @param encoding The encoding to return contents as. Typical value is UTF-8.
|
||||
* (see http://www.iana.org/assignments/character-sets)
|
||||
* @param start Start position in the file.
|
||||
* @param end End position to stop at (exclusive).
|
||||
* @return Contents of file.
|
||||
* @throws FileNotFoundException, IOException
|
||||
*/
|
||||
public String readAsText(String filename, String encoding) throws FileNotFoundException, IOException {
|
||||
public String readAsText(String filename, String encoding, int start, int end) throws FileNotFoundException, IOException {
|
||||
int diff = end - start;
|
||||
byte[] bytes = new byte[1000];
|
||||
BufferedInputStream bis = new BufferedInputStream(getPathFromUri(filename), 1024);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
int numRead = 0;
|
||||
while ((numRead = bis.read(bytes, 0, 1000)) >= 0) {
|
||||
|
||||
if (start > 0) {
|
||||
bis.skip(start);
|
||||
}
|
||||
|
||||
while ( diff > 0 && (numRead = bis.read(bytes, 0, Math.min(1000, diff))) >= 0) {
|
||||
diff -= numRead;
|
||||
bos.write(bytes, 0, numRead);
|
||||
}
|
||||
|
||||
return new String(bos.toByteArray(), encoding);
|
||||
}
|
||||
|
||||
@@ -953,12 +987,19 @@ public class FileUtils extends CordovaPlugin {
|
||||
* @return Contents of file = data:<media type>;base64,<data>
|
||||
* @throws FileNotFoundException, IOException
|
||||
*/
|
||||
public String readAsDataURL(String filename) throws FileNotFoundException, IOException {
|
||||
public String readAsDataURL(String filename, int start, int end) throws FileNotFoundException, IOException {
|
||||
int diff = end - start;
|
||||
byte[] bytes = new byte[1000];
|
||||
BufferedInputStream bis = new BufferedInputStream(getPathFromUri(filename), 1024);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
int numRead = 0;
|
||||
while ((numRead = bis.read(bytes, 0, 1000)) >= 0) {
|
||||
|
||||
if (start > 0) {
|
||||
bis.skip(start);
|
||||
}
|
||||
|
||||
while (diff > 0 && (numRead = bis.read(bytes, 0, Math.min(1000, diff))) >= 0) {
|
||||
diff -= numRead;
|
||||
bos.write(bytes, 0, numRead);
|
||||
}
|
||||
|
||||
@@ -984,15 +1025,21 @@ public class FileUtils extends CordovaPlugin {
|
||||
* @return a mime type
|
||||
*/
|
||||
public static String getMimeType(String filename) {
|
||||
// Stupid bug in getFileExtensionFromUrl when the file name has a space
|
||||
// So we need to replace the space with a url encoded %20
|
||||
String url = filename.replace(" ", "%20");
|
||||
MimeTypeMap map = MimeTypeMap.getSingleton();
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
|
||||
if (extension.toLowerCase().equals("3ga")) {
|
||||
return "audio/3gpp";
|
||||
if (filename != null) {
|
||||
// Stupid bug in getFileExtensionFromUrl when the file name has a space
|
||||
// So we need to replace the space with a url encoded %20
|
||||
|
||||
// CB-2185: Stupid bug not putting JPG extension in the mime-type map
|
||||
String url = filename.replace(" ", "%20").toLowerCase();
|
||||
MimeTypeMap map = MimeTypeMap.getSingleton();
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
|
||||
if (extension.toLowerCase().equals("3ga")) {
|
||||
return "audio/3gpp";
|
||||
} else {
|
||||
return map.getMimeTypeFromExtension(extension);
|
||||
}
|
||||
} else {
|
||||
return map.getMimeTypeFromExtension(extension);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.apache.cordova;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
@@ -29,12 +28,12 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.text.InputType;
|
||||
import android.util.Log;
|
||||
@@ -56,18 +55,18 @@ import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
public class InAppBrowser extends CordovaPlugin {
|
||||
|
||||
private static final String NULL = "null";
|
||||
protected static final String LOG_TAG = "InAppBrowser";
|
||||
private static final String SELF = "_self";
|
||||
private static final String SYSTEM = "_system";
|
||||
private static final String BLANK = "_blank";
|
||||
// private static final String BLANK = "_blank";
|
||||
private static final String LOCATION = "location";
|
||||
private static int CLOSE_EVENT = 0;
|
||||
private static int LOCATION_CHANGED_EVENT = 1;
|
||||
|
||||
private String browserCallbackId = null;
|
||||
private static final String EXIT_EVENT = "exit";
|
||||
private static final String LOAD_START_EVENT = "loadstart";
|
||||
private static final String LOAD_STOP_EVENT = "loadstop";
|
||||
|
||||
private Dialog dialog;
|
||||
private WebView inAppWebView;
|
||||
@@ -106,7 +105,7 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
Log.d(LOG_TAG, "in self");
|
||||
// load in webview
|
||||
if (url.startsWith("file://") || url.startsWith("javascript:")
|
||||
|| this.webView.isUrlWhiteListed(url)) {
|
||||
|| Config.isUrlWhiteListed(url)) {
|
||||
this.webView.loadUrl(url);
|
||||
}
|
||||
// load in InAppBrowser
|
||||
@@ -128,17 +127,16 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
else if (action.equals("close")) {
|
||||
closeDialog();
|
||||
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("type", CLOSE_EVENT);
|
||||
|
||||
PluginResult pluginResult = new PluginResult(status, obj);
|
||||
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
|
||||
pluginResult.setKeepCallback(false);
|
||||
this.callbackContext.sendPluginResult(pluginResult);
|
||||
}
|
||||
else {
|
||||
status = PluginResult.Status.INVALID_ACTION;
|
||||
}
|
||||
this.callbackContext.sendPluginResult(new PluginResult(status, result));
|
||||
PluginResult pluginResult = new PluginResult(status, result);
|
||||
pluginResult.setKeepCallback(true);
|
||||
this.callbackContext.sendPluginResult(pluginResult);
|
||||
} catch (JSONException e) {
|
||||
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
|
||||
}
|
||||
@@ -208,7 +206,15 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
* Closes the dialog
|
||||
*/
|
||||
private void closeDialog() {
|
||||
// TODO: fire 'exit' event
|
||||
try {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("type", EXIT_EVENT);
|
||||
|
||||
sendUpdate(obj, false);
|
||||
} catch (JSONException ex) {
|
||||
Log.d(LOG_TAG, "Should never happen");
|
||||
}
|
||||
|
||||
if (dialog != null) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
@@ -271,6 +277,8 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
if (features != null) {
|
||||
showLocationBar = features.get(LOCATION).booleanValue();
|
||||
}
|
||||
|
||||
final CordovaWebView thatWebView = this.webView;
|
||||
|
||||
// Create dialog in new thread
|
||||
Runnable runnable = new Runnable() {
|
||||
@@ -298,7 +306,7 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
try {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("type", CLOSE_EVENT);
|
||||
obj.put("type", EXIT_EVENT);
|
||||
|
||||
sendUpdate(obj, false);
|
||||
} catch (JSONException e) {
|
||||
@@ -313,7 +321,7 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
|
||||
// Toolbar layout
|
||||
RelativeLayout toolbar = new RelativeLayout(cordova.getActivity());
|
||||
toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, this.dpToPixels(44)));
|
||||
toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44)));
|
||||
toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2));
|
||||
toolbar.setHorizontalGravity(Gravity.LEFT);
|
||||
toolbar.setVerticalGravity(Gravity.TOP);
|
||||
@@ -327,7 +335,7 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
|
||||
// Back button
|
||||
Button back = new Button(cordova.getActivity());
|
||||
RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT);
|
||||
RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
|
||||
backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT);
|
||||
back.setLayoutParams(backLayoutParams);
|
||||
back.setContentDescription("Back Button");
|
||||
@@ -341,7 +349,7 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
|
||||
// Forward button
|
||||
Button forward = new Button(cordova.getActivity());
|
||||
RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT);
|
||||
RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
|
||||
forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2);
|
||||
forward.setLayoutParams(forwardLayoutParams);
|
||||
forward.setContentDescription("Forward Button");
|
||||
@@ -355,7 +363,7 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
|
||||
// Edit Text Box
|
||||
edittext = new EditText(cordova.getActivity());
|
||||
RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
|
||||
RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||
textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1);
|
||||
textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5);
|
||||
edittext.setLayoutParams(textLayoutParams);
|
||||
@@ -378,7 +386,7 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
|
||||
// Close button
|
||||
Button close = new Button(cordova.getActivity());
|
||||
RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT);
|
||||
RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
|
||||
closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
close.setLayoutParams(closeLayoutParams);
|
||||
forward.setContentDescription("Close Button");
|
||||
@@ -392,15 +400,23 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
|
||||
// WebView
|
||||
inAppWebView = new WebView(cordova.getActivity());
|
||||
inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
|
||||
inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
|
||||
inAppWebView.setWebChromeClient(new WebChromeClient());
|
||||
WebViewClient client = new InAppBrowserClient(edittext);
|
||||
WebViewClient client = new InAppBrowserClient(thatWebView, edittext);
|
||||
inAppWebView.setWebViewClient(client);
|
||||
WebSettings settings = inAppWebView.getSettings();
|
||||
settings.setJavaScriptEnabled(true);
|
||||
settings.setJavaScriptCanOpenWindowsAutomatically(true);
|
||||
settings.setBuiltInZoomControls(true);
|
||||
/**
|
||||
* We need to be careful of this line as a future Android release may deprecate it out of existence.
|
||||
* Can't replace it with the API 8 level call right now as our minimum SDK is 7 until May 2013
|
||||
*/
|
||||
// @TODO: replace with settings.setPluginState(android.webkit.WebSettings.PluginState.ON)
|
||||
settings.setPluginsEnabled(true);
|
||||
settings.setDatabaseEnabled(true);
|
||||
String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
|
||||
settings.setDatabasePath(databasePath);
|
||||
settings.setDomStorageEnabled(true);
|
||||
inAppWebView.loadUrl(url);
|
||||
inAppWebView.setId(6);
|
||||
@@ -429,18 +445,13 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
|
||||
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
|
||||
lp.copyFrom(dialog.getWindow().getAttributes());
|
||||
lp.width = WindowManager.LayoutParams.FILL_PARENT;
|
||||
lp.height = WindowManager.LayoutParams.FILL_PARENT;
|
||||
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
|
||||
lp.height = WindowManager.LayoutParams.MATCH_PARENT;
|
||||
|
||||
dialog.setContentView(main);
|
||||
dialog.show();
|
||||
dialog.getWindow().setAttributes(lp);
|
||||
}
|
||||
|
||||
private Bitmap loadDrawable(String filename) throws java.io.IOException {
|
||||
InputStream input = cordova.getActivity().getAssets().open(filename);
|
||||
return BitmapFactory.decodeStream(input);
|
||||
}
|
||||
};
|
||||
this.cordova.getActivity().runOnUiThread(runnable);
|
||||
return "";
|
||||
@@ -452,11 +463,9 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
* @param obj a JSONObject contain event payload information
|
||||
*/
|
||||
private void sendUpdate(JSONObject obj, boolean keepCallback) {
|
||||
if (this.browserCallbackId != null) {
|
||||
PluginResult result = new PluginResult(PluginResult.Status.OK, obj);
|
||||
result.setKeepCallback(keepCallback);
|
||||
this.callbackContext.sendPluginResult(result);
|
||||
}
|
||||
PluginResult result = new PluginResult(PluginResult.Status.OK, obj);
|
||||
result.setKeepCallback(keepCallback);
|
||||
this.callbackContext.sendPluginResult(result);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -464,6 +473,7 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
*/
|
||||
public class InAppBrowserClient extends WebViewClient {
|
||||
EditText edittext;
|
||||
CordovaWebView webView;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -471,7 +481,8 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
* @param mContext
|
||||
* @param edittext
|
||||
*/
|
||||
public InAppBrowserClient(EditText mEditText) {
|
||||
public InAppBrowserClient(CordovaWebView webView, EditText mEditText) {
|
||||
this.webView = webView;
|
||||
this.edittext = mEditText;
|
||||
}
|
||||
|
||||
@@ -495,21 +506,29 @@ public class InAppBrowser extends CordovaPlugin {
|
||||
edittext.setText(newloc);
|
||||
}
|
||||
|
||||
// TODO: Fire 'loadstart' event
|
||||
try {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("type", LOCATION_CHANGED_EVENT);
|
||||
obj.put("location", url);
|
||||
|
||||
obj.put("type", LOAD_START_EVENT);
|
||||
obj.put("url", newloc);
|
||||
|
||||
sendUpdate(obj, true);
|
||||
} catch (JSONException e) {
|
||||
Log.d("InAppBrowser", "This should never happen");
|
||||
} catch (JSONException ex) {
|
||||
Log.d(LOG_TAG, "Should never happen");
|
||||
}
|
||||
}
|
||||
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
// TODO: Fire 'loadstop' event
|
||||
|
||||
try {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("type", LOAD_STOP_EVENT);
|
||||
obj.put("url", url);
|
||||
|
||||
sendUpdate(obj, true);
|
||||
} catch (JSONException ex) {
|
||||
Log.d(LOG_TAG, "Should never happen");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,8 @@ public class NativeToJsMessageQueue {
|
||||
}
|
||||
|
||||
private void packMessage(JsMessage message, StringBuilder sb) {
|
||||
sb.append(message.calculateEncodedLength())
|
||||
int len = message.calculateEncodedLength();
|
||||
sb.append(len)
|
||||
.append(' ');
|
||||
message.encodeAsMessage(sb);
|
||||
}
|
||||
@@ -166,7 +167,8 @@ public class NativeToJsMessageQueue {
|
||||
// Attach a char to indicate that there are more messages pending.
|
||||
sb.append('*');
|
||||
}
|
||||
return sb.toString();
|
||||
String ret = sb.toString();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +211,8 @@ public class NativeToJsMessageQueue {
|
||||
for (int i = willSendAllMessages ? 1 : 0; i < numMessagesToSend; ++i) {
|
||||
sb.append('}');
|
||||
}
|
||||
return sb.toString();
|
||||
String ret = sb.toString();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,6 +409,9 @@ public class NativeToJsMessageQueue {
|
||||
case PluginResult.MESSAGE_TYPE_STRING: // s
|
||||
ret += 1 + pluginResult.getStrMessage().length();
|
||||
break;
|
||||
case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
|
||||
ret += 1 + pluginResult.getMessage().length();
|
||||
break;
|
||||
case PluginResult.MESSAGE_TYPE_JSON:
|
||||
default:
|
||||
ret += pluginResult.getMessage().length();
|
||||
@@ -445,6 +451,10 @@ public class NativeToJsMessageQueue {
|
||||
sb.append('s');
|
||||
sb.append(pluginResult.getStrMessage());
|
||||
break;
|
||||
case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
|
||||
sb.append('A');
|
||||
sb.append(pluginResult.getMessage());
|
||||
break;
|
||||
case PluginResult.MESSAGE_TYPE_JSON:
|
||||
default:
|
||||
sb.append(pluginResult.getMessage()); // [ or {
|
||||
|
||||
@@ -74,6 +74,7 @@ public class NetworkManager extends CordovaPlugin {
|
||||
|
||||
ConnectivityManager sockMan;
|
||||
BroadcastReceiver receiver;
|
||||
private String lastStatus = "";
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -99,12 +100,11 @@ public class NetworkManager extends CordovaPlugin {
|
||||
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
if (this.receiver == null) {
|
||||
this.receiver = new BroadcastReceiver() {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// (The null check is for the ARM Emulator, please use Intel Emulator for better results)
|
||||
if(NetworkManager.this.webView != null)
|
||||
updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
|
||||
if(NetworkManager.this.webView != null)
|
||||
updateConnectionInfo(sockMan.getActiveNetworkInfo());
|
||||
}
|
||||
};
|
||||
cordova.getActivity().registerReceiver(this.receiver, intentFilter);
|
||||
@@ -159,7 +159,14 @@ public class NetworkManager extends CordovaPlugin {
|
||||
*/
|
||||
private void updateConnectionInfo(NetworkInfo info) {
|
||||
// send update to javascript "navigator.network.connection"
|
||||
sendUpdate(this.getConnectionInfo(info));
|
||||
// Jellybean sends its own info
|
||||
String thisStatus = this.getConnectionInfo(info);
|
||||
if(!thisStatus.equals(lastStatus))
|
||||
{
|
||||
sendUpdate(thisStatus);
|
||||
lastStatus = thisStatus;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,6 +186,7 @@ public class NetworkManager extends CordovaPlugin {
|
||||
type = getType(info);
|
||||
}
|
||||
}
|
||||
Log.d("CordovaNetworkManager", "Connection Type: " + type);
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -193,7 +201,6 @@ public class NetworkManager extends CordovaPlugin {
|
||||
result.setKeepCallback(true);
|
||||
connectionCallbackContext.sendPluginResult(result);
|
||||
}
|
||||
|
||||
webView.postMessage("networkconnection", type);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,15 @@ public class CallbackContext {
|
||||
sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for success callbacks that just returns the Status.OK by default
|
||||
*
|
||||
* @param message The message to add to the success result.
|
||||
*/
|
||||
public void success(byte[] message) {
|
||||
sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for success callbacks that just returns the Status.OK by default
|
||||
*
|
||||
|
||||
@@ -54,11 +54,6 @@ public interface CordovaInterface {
|
||||
*/
|
||||
public abstract Activity getActivity();
|
||||
|
||||
@Deprecated
|
||||
public abstract Context getContext();
|
||||
|
||||
@Deprecated
|
||||
public abstract void cancelLoadUrl();
|
||||
|
||||
/**
|
||||
* Called when a message is sent to plugin.
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
*/
|
||||
package org.apache.cordova.api;
|
||||
|
||||
import org.apache.cordova.CordovaArgs;
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import android.content.Intent;
|
||||
|
||||
|
||||
/**
|
||||
* Plugins must extend this class and override one of the execute methods.
|
||||
*/
|
||||
@@ -76,9 +76,28 @@ public class CordovaPlugin {
|
||||
* @return Whether the action was valid.
|
||||
*/
|
||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||
CordovaArgs cordovaArgs = new CordovaArgs(args);
|
||||
return execute(action, cordovaArgs, callbackContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request.
|
||||
*
|
||||
* This method is called from the WebView thread. To do a non-trivial amount of work, use:
|
||||
* cordova.getThreadPool().execute(runnable);
|
||||
*
|
||||
* To run on the UI thread, use:
|
||||
* cordova.getActivity().runOnUiThread(runnable);
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args The exec() arguments, wrapped with some Cordova helpers.
|
||||
* @param callbackContext The callback context used when calling back into JavaScript.
|
||||
* @return Whether the action was valid.
|
||||
*/
|
||||
public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity.
|
||||
*
|
||||
|
||||
@@ -43,7 +43,6 @@ public class LegacyContext implements CordovaInterface {
|
||||
@Deprecated
|
||||
public void cancelLoadUrl() {
|
||||
Log.i(LOG_TAG, "Replace ctx.cancelLoadUrl() with cordova.cancelLoadUrl()");
|
||||
this.cordova.cancelLoadUrl();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -55,7 +54,7 @@ public class LegacyContext implements CordovaInterface {
|
||||
@Deprecated
|
||||
public Context getContext() {
|
||||
Log.i(LOG_TAG, "Replace ctx.getContext() with cordova.getContext()");
|
||||
return this.cordova.getContext();
|
||||
return this.cordova.getActivity();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
||||
@@ -248,7 +248,7 @@ public class PluginManager {
|
||||
* @param service The name of the service.
|
||||
* @return CordovaPlugin or null
|
||||
*/
|
||||
private CordovaPlugin getPlugin(String service) {
|
||||
public CordovaPlugin getPlugin(String service) {
|
||||
PluginEntry entry = this.entries.get(service);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
|
||||
@@ -21,6 +21,8 @@ package org.apache.cordova.api;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
public class PluginResult {
|
||||
private final int status;
|
||||
private final int messageType;
|
||||
@@ -68,6 +70,12 @@ public class PluginResult {
|
||||
this.encodedMessage = Boolean.toString(b);
|
||||
}
|
||||
|
||||
public PluginResult(Status status, byte[] data) {
|
||||
this.status = status.ordinal();
|
||||
this.messageType = MESSAGE_TYPE_ARRAYBUFFER;
|
||||
this.encodedMessage = Base64.encodeToString(data, Base64.NO_WRAP);
|
||||
}
|
||||
|
||||
public void setKeepCallback(boolean b) {
|
||||
this.keepCallback = b;
|
||||
}
|
||||
@@ -79,7 +87,7 @@ public class PluginResult {
|
||||
public int getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
|
||||
public String getMessage() {
|
||||
if (encodedMessage == null) {
|
||||
encodedMessage = JSONObject.quote(strMessage);
|
||||
@@ -134,7 +142,8 @@ public class PluginResult {
|
||||
public static final int MESSAGE_TYPE_NUMBER = 3;
|
||||
public static final int MESSAGE_TYPE_BOOLEAN = 4;
|
||||
public static final int MESSAGE_TYPE_NULL = 5;
|
||||
|
||||
public static final int MESSAGE_TYPE_ARRAYBUFFER = 6;
|
||||
|
||||
public static String[] StatusMessages = new String[] {
|
||||
"No result",
|
||||
"OK",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:windowSoftInputMode="adjustPan"
|
||||
package="org.apache.cordova.test" android:versionName="1.1" android:versionCode="5">
|
||||
package="org.apache.cordova.test" android:versionName="1.0" android:versionCode="1">
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
|
||||
+761
-744
File diff suppressed because it is too large
Load Diff
@@ -8,5 +8,5 @@
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-16
|
||||
target=android-17
|
||||
android.library.reference.1=../framework
|
||||
|
||||
@@ -21,14 +21,72 @@ package org.apache.cordova.test;
|
||||
*/
|
||||
|
||||
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.apache.cordova.test.util.Purity;
|
||||
import org.apache.cordova.test.actions.iframe;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.test.TouchUtils;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public class IFrameTest extends ActivityInstrumentationTestCase2<iframe> {
|
||||
public class IFrameTest extends ActivityInstrumentationTestCase2 {
|
||||
|
||||
public IFrameTest() {
|
||||
super("org.apache.cordova.test",iframe.class);
|
||||
}
|
||||
|
||||
private Instrumentation mInstr;
|
||||
private Activity testActivity;
|
||||
private FrameLayout containerView;
|
||||
private LinearLayout innerContainer;
|
||||
private CordovaWebView testView;
|
||||
private TouchUtils touch;
|
||||
private Purity touchTool;
|
||||
|
||||
public IFrameTest() {
|
||||
super("org.apache.cordova.test",iframe.class);
|
||||
}
|
||||
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mInstr = this.getInstrumentation();
|
||||
testActivity = this.getActivity();
|
||||
containerView = (FrameLayout) testActivity.findViewById(android.R.id.content);
|
||||
innerContainer = (LinearLayout) containerView.getChildAt(0);
|
||||
testView = (CordovaWebView) innerContainer.getChildAt(0);
|
||||
touch = new TouchUtils();
|
||||
touchTool = new Purity(testActivity, getInstrumentation());
|
||||
}
|
||||
|
||||
|
||||
public void testIframeDest()
|
||||
{
|
||||
testView.sendJavascript("loadUrl('http://maps.google.com/maps?output=embed');");
|
||||
sleep(3000);
|
||||
testView.sendJavascript("loadUrl('index2.html')");
|
||||
sleep(1000);
|
||||
String url = testView.getUrl();
|
||||
assertTrue(url.endsWith("index.html"));
|
||||
}
|
||||
|
||||
public void testIframeHistory()
|
||||
{
|
||||
testView.sendJavascript("loadUrl('http://maps.google.com/maps?output=embed');");
|
||||
sleep(3000);
|
||||
testView.sendJavascript("loadUrl('index2.html')");
|
||||
sleep(1000);
|
||||
String url = testView.getUrl();
|
||||
testView.backHistory();
|
||||
sleep(1000);
|
||||
assertTrue(url.endsWith("index.html"));
|
||||
}
|
||||
|
||||
private void sleep(int timeout) {
|
||||
try {
|
||||
Thread.sleep(timeout);
|
||||
} catch (InterruptedException e) {
|
||||
fail("Unexpected Timeout");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,15 +21,55 @@ package org.apache.cordova.test;
|
||||
*/
|
||||
|
||||
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.apache.cordova.test.util.Purity;
|
||||
import org.apache.cordova.test.actions.jqmtabbackbutton;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public class JQMTabTest extends ActivityInstrumentationTestCase2<jqmtabbackbutton> {
|
||||
|
||||
public JQMTabTest(Class<jqmtabbackbutton> activityClass) {
|
||||
super(activityClass);
|
||||
// TODO Auto-generated constructor stub
|
||||
private Instrumentation mInstr;
|
||||
private jqmtabbackbutton testActivity;
|
||||
private FrameLayout containerView;
|
||||
private LinearLayout innerContainer;
|
||||
private CordovaWebView testView;
|
||||
private Purity touchTool;
|
||||
|
||||
public JQMTabTest()
|
||||
{
|
||||
super("org.apache.cordova.test.activity", jqmtabbackbutton.class);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mInstr = this.getInstrumentation();
|
||||
testActivity = this.getActivity();
|
||||
containerView = (FrameLayout) testActivity.findViewById(android.R.id.content);
|
||||
innerContainer = (LinearLayout) containerView.getChildAt(0);
|
||||
testView = (CordovaWebView) innerContainer.getChildAt(0);
|
||||
touchTool = new Purity(testActivity, getInstrumentation());
|
||||
}
|
||||
|
||||
|
||||
public void testTouch()
|
||||
{
|
||||
sleep(5000);
|
||||
int viewportHeight = touchTool.getViewportHeight() - 40;
|
||||
int viewportWidth = touchTool.getViewportWidth();
|
||||
touchTool.touch(50, viewportHeight);
|
||||
sleep(10000);
|
||||
}
|
||||
|
||||
private void sleep(int timeout) {
|
||||
try {
|
||||
Thread.sleep(timeout);
|
||||
} catch (InterruptedException e) {
|
||||
fail("Unexpected Timeout");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ public class basicauth extends DroidGap {
|
||||
super.setAuthenticationToken(token, "browserspy.dk:80", "BrowserSpy.dk - HTTP Password Test");
|
||||
|
||||
// Add web site to whitelist
|
||||
super.appView.addWhiteListEntry("http://browserspy.dk*", true);
|
||||
Config.init();
|
||||
Config.addWhiteListEntry("http://browserspy.dk*", true);
|
||||
|
||||
// Load test
|
||||
super.loadUrl("file:///android_asset/www/basicauth/index.html");
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Purity is a small set of Android utility methods that allows us to simulate touch events on
|
||||
* Android applications. This is important for simulating some of the most annoying tests.
|
||||
*/
|
||||
|
||||
package org.apache.cordova.test.util;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Picture;
|
||||
import android.os.SystemClock;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.MotionEvent;
|
||||
import android.webkit.WebView;
|
||||
|
||||
|
||||
public class Purity {
|
||||
|
||||
Instrumentation inst;
|
||||
int width, height;
|
||||
float density;
|
||||
Bitmap state;
|
||||
boolean fingerDown = false;
|
||||
|
||||
public Purity(Context ctx, Instrumentation i)
|
||||
{
|
||||
inst = i;
|
||||
DisplayMetrics display = ctx.getResources().getDisplayMetrics();
|
||||
density = display.density;
|
||||
width = display.widthPixels;
|
||||
height = display.heightPixels;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* WebKit doesn't give you real pixels anymore, this is done for subpixel fonts to appear on
|
||||
* iOS and Android. However, Android automation requires real pixels
|
||||
*/
|
||||
private int getRealCoord(int coord)
|
||||
{
|
||||
return (int) (coord * density);
|
||||
}
|
||||
|
||||
public int getViewportWidth()
|
||||
{
|
||||
return (int) (width/density);
|
||||
}
|
||||
|
||||
public int getViewportHeight()
|
||||
{
|
||||
return (int) (height/density);
|
||||
}
|
||||
|
||||
public void touch(int x, int y)
|
||||
{
|
||||
int realX = getRealCoord(x);
|
||||
int realY = getRealCoord(y);
|
||||
long downTime = SystemClock.uptimeMillis();
|
||||
// event time MUST be retrieved only by this way!
|
||||
long eventTime = SystemClock.uptimeMillis();
|
||||
if(!fingerDown)
|
||||
{
|
||||
MotionEvent downEvent = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, realX, realY, 0);
|
||||
inst.sendPointerSync(downEvent);
|
||||
}
|
||||
MotionEvent upEvent = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, realX, realY, 0);
|
||||
inst.sendPointerSync(upEvent);
|
||||
}
|
||||
|
||||
public void touchStart(int x, int y)
|
||||
{
|
||||
int realX = getRealCoord(x);
|
||||
int realY = getRealCoord(y);
|
||||
long downTime = SystemClock.uptimeMillis();
|
||||
// event time MUST be retrieved only by this way!
|
||||
long eventTime = SystemClock.uptimeMillis();
|
||||
MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, realX, realY, 0);
|
||||
inst.sendPointerSync(event);
|
||||
fingerDown = true;
|
||||
}
|
||||
|
||||
//Move from the touch start
|
||||
public void touchMove(int x, int y)
|
||||
{
|
||||
if(!fingerDown)
|
||||
touchStart(x,y);
|
||||
else
|
||||
{
|
||||
int realX = getRealCoord(x);
|
||||
int realY = getRealCoord(y);
|
||||
long downTime = SystemClock.uptimeMillis();
|
||||
// event time MUST be retrieved only by this way!
|
||||
long eventTime = SystemClock.uptimeMillis();
|
||||
MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, realX, realY, 0);
|
||||
inst.sendPointerSync(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void touchEnd(int x, int y)
|
||||
{
|
||||
if(!fingerDown)
|
||||
{
|
||||
touch(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
int realX = getRealCoord(x);
|
||||
int realY = getRealCoord(y);
|
||||
long downTime = SystemClock.uptimeMillis();
|
||||
// event time MUST be retrieved only by this way!
|
||||
long eventTime = SystemClock.uptimeMillis();
|
||||
MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, realX, realY, 0);
|
||||
inst.sendPointerSync(event);
|
||||
fingerDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBitmap(WebView view)
|
||||
{
|
||||
Picture p = view.capturePicture();
|
||||
state = Bitmap.createBitmap(p.getWidth(), p.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
public boolean checkRenderView(WebView view)
|
||||
{
|
||||
if(state == null)
|
||||
{
|
||||
setBitmap(view);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Picture p = view.capturePicture();
|
||||
Bitmap newState = Bitmap.createBitmap(p.getWidth(), p.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
boolean result = newState.equals(state);
|
||||
newState.recycle();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearBitmap()
|
||||
{
|
||||
if(state != null)
|
||||
state.recycle();
|
||||
}
|
||||
|
||||
protected void finalize()
|
||||
{
|
||||
clearBitmap();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user