Compare commits

...

40 Commits
2.6.0 ... 2.7.0

Author SHA1 Message Date
Joe Bowser
909e6645e7 Updating JS for Android 2013-04-25 14:55:11 -07:00
Joe Bowser
a308100288 Prep for 2.7.0 final 2013-04-25 13:42:20 -07:00
Joe Bowser
fea8c5d204 Merge branch '2.7.x' of https://git-wip-us.apache.org/repos/asf/cordova-android into 2.7.x 2013-04-25 10:20:07 -07:00
Joe Bowser
a890c8156e This should be 2.7.0rc1 2013-04-25 10:19:48 -07:00
Shravan Narayan
665c1bd8bb [CB-3226] Fix: plugins can intercept urls with "?", "#", "%20"(cherry picked from commit 53982272d6) 2013-04-25 13:11:02 -04:00
Joe Bowser
b22990ca78 cordova-js wasn't properly auto-incremented either 2013-04-19 17:56:26 -07:00
Joe Bowser
832998b67f 2.7.0rc1 prep 2013-04-18 13:05:03 -07:00
Andrew Grieve
c798d131bb Update JS snapshot for 2.7.0 2013-04-18 15:28:00 -04:00
Ian Clelland
bf3e024648 [CB-3066] Fire onNativeReady from JS, as bridge is available immediately 2013-04-18 14:20:32 -04:00
Andrew Grieve
191f31baa7 [CB-2432] Don't try and write exif info for images from picasa 2013-04-17 16:40:00 -04:00
Joe Bowser
d3b7903af8 Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-android 2013-04-17 13:37:48 -07:00
Joe Bowser
99e7d1e161 Merge branches 'sunshine' and 'master' 2013-04-17 13:37:19 -07:00
Andrew Grieve
b13166f5d9 [CB-2432] Fix Camera.getPicture() for picasa images 2013-04-17 16:12:28 -04:00
Andrew Grieve
80fe4458c6 Use FileHelper in IceCreamCordovaWebViewClient.
Removes some duplicate logic and makes it a bit more robust.
2013-04-17 15:51:37 -04:00
Andrew Grieve
791574c26e Make URL parsing more robust in FileHelper.
Fixes some cases when query parameters mess things up.
2013-04-17 15:50:29 -04:00
Joe Bowser
ac61ebf2d5 Merge branch 'master' of github.com:SunshineTech/cordova-android into sunshine 2013-04-17 11:44:49 -07:00
avidmich
cb99ed0a01 Fixing URL transformation algorithm
It didn't work with URL like this:
http://host.com/path/to/file.txt#/foo?bar=baz
When hash sign is in front of question mark - it only strips the question mark, leaving the hash and breaking the whole app.
2013-04-16 15:45:32 -04:00
Andrew Grieve
4864d52966 [CB-2202] Remove Plugin.java (was deprecated). 2013-04-16 15:29:16 -04:00
Andrew Grieve
b2d61679fb [CB-2963] Re-enable sending messages in batches.
Disabled by CB-1745, which is now reverted.
2013-04-16 15:04:56 -04:00
lorinbeer
383b3dadd5 [CB-3024] expanded help string for cl create script 2013-04-12 08:32:22 -07:00
Joe Bowser
c65c259123 CB-2200: Remove deprecated Android device.name 2013-04-11 13:53:12 -07:00
Joe Bowser
e7e2730929 Fixing CB-2955, breaking CB-2085, use localStorage, NOT WebSQL 2013-04-08 15:53:14 -07:00
Joe Bowser
bb9615eed0 Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-android 2013-04-04 16:06:03 -07:00
Joe Bowser
18877bf80e Adding additional condition that the phone must be made by HTC for the setNavDump to be set to true to try and work around CB-2907, if it's still a problem on HTC devices running Android 2.2, that's just the luck of the draw. 2013-04-04 16:05:35 -07:00
HUANG Menghuai
778b784eb6 [CB-2908] Fix the DroidGap activity Lifecycle broken issue
Attempting to invoke the Activity's finish() onDestroy breaks an Activity's lifecycle
flag. OnDestroy can be called by the system, for instance, on restarting an Activity,
it's definitely different from a normal finish().
Finish() incorrectly in onDestroy results in another DroidGap derived activity
is started, while the original one is not yet onDestroy. This issue could be
found when the system is trying to restart the activity upon, for instance,
receiving immediately successive device Config changes.
2013-04-04 16:47:03 -04:00
Andrew Grieve
5ff900f7ec Fixup for CB-2654. 2013-04-04 16:45:39 -04:00
Steren
ba31424604 Keep the splashscreen image ratio instead of streatching it.
An ImageView is used to be able to use ScaleType.CENTER_CROP, which is similar to the background-size:cover CSS property
2013-04-04 16:19:12 -04:00
Ian Clelland
1782111d45 [CB-2654] Delay executeScript/insertCSS callback until resources have loaded; pass JS results to callback 2013-04-04 14:34:58 -04:00
Max Woghiren
1fa63300aa [CB-2666] Added check for null arguments.
If null arguments are received, send an error and an explanation.
2013-04-02 11:51:25 -04:00
Joe Bowser
b42c918973 Prep for 2.6.0 final 2013-04-01 14:54:51 -07:00
Joe Bowser
f12262ea96 Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-android 2013-03-28 10:02:46 -07:00
Joe Bowser
334cf45d6d Fixing CB-1700, we had the file names reversed, so exif was never being written right. Needed to upload a file to debug this thing 2013-03-28 10:02:18 -07:00
Joe Bowser
b7bb72294a CB-1796: Let's make sure we actually write the file instead of just writing EXIF to NOTHING 2013-03-28 10:02:02 -07:00
Joe Bowser
64ff204371 Updating JS 2013-03-28 10:01:15 -07:00
Ian Clelland
282367c6d5 [CB-1517] Properly report download progress for GZIP-encoded resources 2013-03-27 17:00:22 -04:00
James Jong
36c33a5889 CB-1944: Better error messages for Create script
- fixed to detect missing packages individually
- added a specific message for each missing package
- messages include how to correct and package download link
2013-03-27 15:46:45 -04:00
JasonM23
5ee7e81ff9 [CB-51] Added httpMethod for upload (defaults to POST) 2013-03-27 14:22:41 -04:00
Shravan Narayan
f4859444dd Fixed protocol regex bug. Unknown protocol support Added whitelist support for unknown protocols 2013-03-26 00:20:11 -04:00
Joe Bowser
31bc015cdd Pre-2.6 prep 2013-03-21 10:35:09 -07:00
SunshineTech
2bf6509e1d Modify Issue CB-2273. 2013-02-17 21:50:33 +08:00
21 changed files with 1009 additions and 530 deletions

View File

@@ -1 +1 @@
2.5.0
2.7.0

View File

@@ -25,8 +25,11 @@ set -e
if [ -z "$1" ] || [ "$1" == "-h" ]
then
echo 'usage: create path package activity'
echo "Usage: $0 <path_to_new_project> <package_name> <project_name>"
echo "Make sure the Android SDK tools folder is in your PATH!"
echo " <path_to_new_project>: Path to your new Cordova iOS project"
echo " <package_name>: Package name, following reverse-domain style convention"
echo " <project_name>: Project name"
exit 0
fi

View File

@@ -16,17 +16,37 @@
:: under the License.
@ECHO OFF
IF NOT DEFINED JAVA_HOME GOTO MISSING
IF NOT DEFINED JAVA_HOME GOTO MISSING_JAVA_HOME
FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
SET FOUND=%%~$PATH:X
IF NOT DEFINED FOUND GOTO MISSING
IF [%%~$PATH:X]==[] (
ECHO Cannot locate %%X using the PATH environment variable.
ECHO Retry after adding directory containing %%X to the PATH variable.
ECHO Remember to open a new command window after updating the PATH variable.
IF "%%X"=="java.exe" GOTO GET_JAVA
IF "%%X"=="javac.exe" GOTO GET_JAVA
IF "%%X"=="ant.bat" GOTO GET_ANT
IF "%%X"=="android.bat" GOTO GET_ANDROID
GOTO ERROR
)
)
cscript "%~dp0\create.js" %*
GOTO END
:MISSING
ECHO Missing one of the following:
ECHO JDK: http://java.oracle.com
ECHO Android SDK: http://developer.android.com
ECHO Apache ant: http://ant.apache.org
:MISSING_JAVA_HOME
ECHO The JAVA_HOME environment variable is not set.
ECHO Set JAVA_HOME to an existing JRE directory.
ECHO Remember to also add JAVA_HOME to the PATH variable.
ECHO After updating system variables, open a new command window and retry.
GOTO ERROR
:GET_JAVA
ECHO Visit http://java.oracle.com if you need to install Java (JDK).
GOTO ERROR
:GET_ANT
ECHO Visit http://ant.apache.org if you need to install Apache Ant.
GOTO ERROR
:GET_ANDROID
ECHO Visit http://developer.android.com if you need to install the Android SDK.
GOTO ERROR
:ERROR
EXIT /B 1
:END

View File

@@ -19,7 +19,7 @@
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
<link rel="stylesheet" type="text/css" href="css/index.css" />
@@ -33,7 +33,7 @@
<p class="event received">Device is Ready</p>
</div>
</div>
<script type="text/javascript" src="cordova-2.5.0.js"></script>
<script type="text/javascript" src="cordova-2.7.0.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript">
app.initialize();

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,7 @@
<html>
<head>
<title></title>
<script src="cordova-2.5.0.js"></script>
<script src="cordova-2.7.0.js"></script>
</head>
<body>

View File

@@ -42,6 +42,7 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Rect;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.Uri;
@@ -312,10 +313,12 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// If sending filename back
else if (destType == FILE_URI || destType == NATIVE_URI) {
if (!this.saveToPhotoAlbum) {
uri = Uri.fromFile(new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), System.currentTimeMillis() + ".jpg"));
if (this.saveToPhotoAlbum) {
Uri inputUri = getUriFromMediaStore();
//Just because we have a media URI doesn't mean we have a real file, we need to make it
uri = Uri.fromFile(new File(FileHelper.getRealPath(inputUri, this.cordova)));
} else {
uri = getUriFromMediaStore();
uri = Uri.fromFile(new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), System.currentTimeMillis() + ".jpg"));
}
if (uri == null) {
@@ -394,19 +397,21 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
(destType == FILE_URI || destType == NATIVE_URI) && !this.correctOrientation) {
this.callbackContext.success(uri.toString());
} else {
String uriString = uri.toString();
// Get the path to the image. Makes loading so much easier.
String imagePath = FileHelper.getRealPath(uri, this.cordova);
String mimeType = FileHelper.getMimeType(imagePath, this.cordova);
// Log.d(LOG_TAG, "Real path = " + imagePath);
// Log.d(LOG_TAG, "mime type = " + mimeType);
String mimeType = FileHelper.getMimeType(uriString, this.cordova);
// If we don't have a valid image so quit.
if (imagePath == null || mimeType == null ||
!(mimeType.equalsIgnoreCase("image/jpeg") || mimeType.equalsIgnoreCase("image/png"))) {
if (!("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType))) {
Log.d(LOG_TAG, "I either have a null image path or bitmap");
this.failPicture("Unable to retrieve path to picture!");
return;
}
Bitmap bitmap = getScaledBitmap(imagePath);
Bitmap bitmap = null;
try {
bitmap = getScaledBitmap(uriString);
} catch (IOException e) {
e.printStackTrace();
}
if (bitmap == null) {
Log.d(LOG_TAG, "I either have a null image path or bitmap");
this.failPicture("Unable to create bitmap!");
@@ -414,14 +419,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
}
if (this.correctOrientation) {
String[] cols = { MediaStore.Images.Media.ORIENTATION };
Cursor cursor = this.cordova.getActivity().getContentResolver().query(intent.getData(),
cols, null, null, null);
if (cursor != null) {
cursor.moveToPosition(0);
rotate = cursor.getInt(0);
cursor.close();
}
rotate = getImageOrientation(uri);
if (rotate != 0) {
Matrix matrix = new Matrix();
matrix.setRotate(rotate);
@@ -441,15 +439,17 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
try {
// Create an ExifHelper to save the exif data that is lost during compression
String resizePath = DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/resize.jpg";
// Some content: URIs do not map to file paths (e.g. picasa).
String realPath = FileHelper.getRealPath(uri, this.cordova);
ExifHelper exif = new ExifHelper();
try {
if (this.encodingType == JPEG) {
exif.createInFile(resizePath);
if (realPath != null && this.encodingType == JPEG) {
try {
exif.createInFile(realPath);
exif.readExifData();
rotate = exif.getOrientation();
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
OutputStream os = new FileOutputStream(resizePath);
@@ -457,8 +457,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
os.close();
// Restore exif data to file
if (this.encodingType == JPEG) {
exif.createOutFile(FileHelper.getRealPath(uri, this.cordova));
if (realPath != null && this.encodingType == JPEG) {
exif.createOutFile(resizePath);
exif.writeExifData();
}
@@ -491,6 +491,19 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
}
}
private int getImageOrientation(Uri uri) {
String[] cols = { MediaStore.Images.Media.ORIENTATION };
Cursor cursor = cordova.getActivity().getContentResolver().query(uri,
cols, null, null, null);
int rotate = 0;
if (cursor != null) {
cursor.moveToPosition(0);
rotate = cursor.getInt(0);
cursor.close();
}
return rotate;
}
/**
* Figure out if the bitmap should be rotated. For instance if the picture was taken in
* portrait mode
@@ -561,17 +574,18 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
*
* @param imagePath
* @return
* @throws IOException
*/
private Bitmap getScaledBitmap(String imagePath) {
private Bitmap getScaledBitmap(String imageUrl) throws IOException {
// If no new width or height were specified return the original bitmap
if (this.targetWidth <= 0 && this.targetHeight <= 0) {
return BitmapFactory.decodeFile(imagePath);
return BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova));
}
// figure out the original width and height of the image
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, options);
BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
//CB-2292: WTF? Why is the width null?
if(options.outWidth == 0 || options.outHeight == 0)
@@ -585,7 +599,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// Load in the smallest bitmap possible that is closest to the size we want
options.inJustDecodeBounds = false;
options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight);
Bitmap unscaledBitmap = BitmapFactory.decodeFile(imagePath, options);
Bitmap unscaledBitmap = BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
if (unscaledBitmap == null) {
return null;
}

View File

@@ -171,7 +171,7 @@ public class Config {
LOG.i("CordovaLog", "Found start page location: %s", src);
if (src != null) {
Pattern schemeRegex = Pattern.compile("^[a-z]+://");
Pattern schemeRegex = Pattern.compile("^[a-z-]+://");
Matcher matcher = schemeRegex.matcher(src);
if (matcher.find()) {
startUrl = src;
@@ -220,19 +220,33 @@ public class Config {
} else { // specific access
// check if subdomains should be included
// TODO: we should not add more domains if * has already been added
Pattern schemeRegex = Pattern.compile("^[a-z-]+://");
Matcher matcher = schemeRegex.matcher(origin);
if (subdomains) {
// XXX making it stupid friendly for people who forget to include protocol/SSL
// Check for http or https protocols
if (origin.startsWith("http")) {
this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://(.*\\.)?")));
} else {
}
// Check for other protocols
else if(matcher.find()){
this.whiteList.add(Pattern.compile("^" + origin.replaceFirst("//", "//(.*\\.)?")));
}
// XXX making it stupid friendly for people who forget to include protocol/SSL
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
// Check for http or https protocols
if (origin.startsWith("http")) {
this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://")));
} else {
}
// Check for other protocols
else if(matcher.find()){
this.whiteList.add(Pattern.compile("^" + origin));
}
// XXX making it stupid friendly for people who forget to include protocol/SSL
else {
this.whiteList.add(Pattern.compile("^https?://" + origin));
}
LOG.d(TAG, "Origin to allow: %s", origin);

View File

@@ -22,6 +22,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.cordova.api.CallbackContext;
@@ -42,6 +44,8 @@ public class CordovaLocationListener implements LocationListener {
public HashMap<String, CallbackContext> watches = new HashMap<String, CallbackContext>();
private List<CallbackContext> callbacks = new ArrayList<CallbackContext>();
private Timer timer = null;
private String TAG = "[Cordova Location Listener]";
@@ -52,11 +56,12 @@ public class CordovaLocationListener implements LocationListener {
}
protected void fail(int code, String message) {
this.cancelTimer();
for (CallbackContext callbackContext: this.callbacks)
{
this.owner.fail(code, message, callbackContext);
this.owner.fail(code, message, callbackContext, false);
}
if(this.owner.isGlobalListener(this))
if(this.owner.isGlobalListener(this) && this.watches.size() == 0)
{
Log.d(TAG, "Stopping global listener");
this.stop();
@@ -65,16 +70,17 @@ public class CordovaLocationListener implements LocationListener {
Iterator<CallbackContext> it = this.watches.values().iterator();
while (it.hasNext()) {
this.owner.fail(code, message, it.next());
this.owner.fail(code, message, it.next(), true);
}
}
private void win(Location loc) {
this.cancelTimer();
for (CallbackContext callbackContext: this.callbacks)
{
this.owner.win(loc, callbackContext);
this.owner.win(loc, callbackContext, false);
}
if(this.owner.isGlobalListener(this))
if(this.owner.isGlobalListener(this) && this.watches.size() == 0)
{
Log.d(TAG, "Stopping global listener");
this.stop();
@@ -83,7 +89,7 @@ public class CordovaLocationListener implements LocationListener {
Iterator<CallbackContext> it = this.watches.values().iterator();
while (it.hasNext()) {
this.owner.win(loc, it.next());
this.owner.win(loc, it.next(), true);
}
}
@@ -155,8 +161,12 @@ public class CordovaLocationListener implements LocationListener {
this.start();
}
}
public void addCallback(CallbackContext callbackContext) {
this.callbacks.add(callbackContext);
public void addCallback(CallbackContext callbackContext, int timeout) {
if(this.timer == null) {
this.timer = new Timer();
}
this.timer.schedule(new LocationTimeoutTask(callbackContext, this), timeout);
this.callbacks.add(callbackContext);
if (this.size() == 1) {
this.start();
}
@@ -173,7 +183,7 @@ public class CordovaLocationListener implements LocationListener {
/**
* Destroy listener.
*/
public void destroy() {
public void destroy() {
this.stop();
}
@@ -199,9 +209,43 @@ public class CordovaLocationListener implements LocationListener {
* Stop receiving location updates.
*/
private void stop() {
this.cancelTimer();
if (this.running) {
this.locationManager.removeUpdates(this);
this.running = false;
}
}
private void cancelTimer() {
if(this.timer != null) {
this.timer.cancel();
this.timer.purge();
this.timer = null;
}
}
private class LocationTimeoutTask extends TimerTask {
private CallbackContext callbackContext = null;
private CordovaLocationListener listener = null;
public LocationTimeoutTask(CallbackContext callbackContext, CordovaLocationListener listener) {
this.callbackContext = callbackContext;
this.listener = listener;
}
@Override
public void run() {
for (CallbackContext callbackContext: listener.callbacks) {
if(this.callbackContext == callbackContext) {
listener.callbacks.remove(callbackContext);
break;
}
}
if(listener.size() == 0) {
listener.stop();
}
}
}
}

View File

@@ -24,6 +24,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
import java.util.regex.Pattern;
import org.apache.cordova.Config;
import org.apache.cordova.api.CordovaInterface;
@@ -237,7 +238,11 @@ public class CordovaWebView extends WebView {
// Set the nav dump for HTC 2.x devices (disabling for ICS, deprecated entirely for Jellybean 4.2)
try {
Method gingerbread_getMethod = WebSettings.class.getMethod("setNavDump", new Class[] { boolean.class });
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
String manufacturer = android.os.Build.MANUFACTURER;
Log.d(TAG, "CordovaWebView is running on device made by: " + manufacturer);
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB &&
android.os.Build.MANUFACTURER.contains("HTC"))
{
gingerbread_getMethod.invoke(settings, true);
}
@@ -262,11 +267,8 @@ public class CordovaWebView extends WebView {
// Enable database
// We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16
String databasePath = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
{
settings.setDatabaseEnabled(true);
settings.setDatabasePath(databasePath);
}
settings.setDatabaseEnabled(true);
settings.setDatabasePath(databasePath);
settings.setGeolocationDatabasePath(databasePath);

View File

@@ -314,15 +314,6 @@ public class CordovaWebViewClient extends WebViewClient {
// Clear timeout flag
this.appView.loadUrlTimeout++;
// Try firing the onNativeReady event in JS. If it fails because the JS is
// 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);
}
// Broadcast message that page has loaded
this.appView.postMessage("onPageFinished", url);

View File

@@ -38,7 +38,7 @@ import android.telephony.TelephonyManager;
public class Device extends CordovaPlugin {
public static final String TAG = "Device";
public static String cordovaVersion = "2.5.0"; // Cordova version
public static String cordovaVersion = "2.7.0"; // Cordova version
public static String platform = "Android"; // Device OS
public static String uuid; // Device UUID
@@ -77,7 +77,6 @@ public class Device extends CordovaPlugin {
r.put("uuid", Device.uuid);
r.put("version", this.getOSVersion());
r.put("platform", Device.platform);
r.put("name", this.getProductName());
r.put("cordova", Device.cordovaVersion);
r.put("model", this.getModel());
callbackContext.success(r);

View File

@@ -51,6 +51,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.webkit.ValueCallback;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;
@@ -717,7 +718,7 @@ public class DroidGap extends Activity implements CordovaInterface {
appView.handleDestroy();
}
else {
this.endActivity();
this.activityState = ACTIVITY_EXITING;
}
}
@@ -1031,7 +1032,13 @@ public class DroidGap extends Activity implements CordovaInterface {
root.setBackgroundColor(that.getIntegerProperty("backgroundColor", Color.BLACK));
root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT, 0.0F));
root.setBackgroundResource(that.splashscreen);
// We want the splashscreen to keep its ratio,
// for this we need to use an ImageView and not simply the background of the LinearLayout
ImageView splashscreenView = new ImageView(that.getActivity());
splashscreenView.setImageResource(that.splashscreen);
splashscreenView.setScaleType(ImageView.ScaleType.CENTER_CROP); // similar to the background-size:cover CSS property
splashscreenView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
root.addView(splashscreenView);
// Create and show the dialog
splashDialog = new Dialog(that, android.R.style.Theme_Translucent_NoTitleBar);

View File

@@ -20,6 +20,7 @@ package org.apache.cordova;
import android.webkit.JavascriptInterface;
import org.apache.cordova.api.PluginManager;
import org.apache.cordova.api.PluginResult;
import org.json.JSONException;
/**
@@ -39,6 +40,12 @@ import org.json.JSONException;
@JavascriptInterface
public String exec(String service, String action, String callbackId, String arguments) throws JSONException {
// If the arguments weren't received, send a message back to JS. It will switch bridge modes and try again. See CB-2666.
// We send a message meant specifically for this case. It starts with "@" so no other message can be encoded into the same string.
if (arguments == null) {
return "@Null arguments.";
}
jsMessageQueue.setPaused(true);
try {
boolean wasSync = pluginManager.exec(service, action, callbackId, arguments);

View File

@@ -28,6 +28,8 @@ import org.apache.cordova.api.LOG;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
import java.util.Locale;
public class FileHelper {
private static final String LOG_TAG = "FileUtils";
@@ -92,7 +94,8 @@ public class FileHelper {
Uri uri = Uri.parse(uriString);
return cordova.getActivity().getContentResolver().openInputStream(uri);
} else if (uriString.startsWith("file:///android_asset/")) {
String relativePath = uriString.substring(22);
Uri uri = Uri.parse(uriString);
String relativePath = uri.getPath().substring(15);
return cordova.getActivity().getAssets().open(relativePath);
} else {
return new FileInputStream(getRealPath(uriString, cordova));
@@ -122,14 +125,18 @@ public class FileHelper {
public static String getMimeType(String uriString, CordovaInterface cordova) {
String mimeType = null;
Uri uri = Uri.parse(uriString);
if (uriString.startsWith("content://")) {
Uri uri = Uri.parse(uriString);
mimeType = cordova.getActivity().getContentResolver().getType(uri);
} else {
// MimeTypeMap.getFileExtensionFromUrl has a bug that occurs when the filename has a space, so we encode it.
// We also convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
String encodedUriString = uriString.replace(" ", "%20").toLowerCase();
String extension = MimeTypeMap.getFileExtensionFromUrl(encodedUriString);
// MimeTypeMap.getFileExtensionFromUrl() fails when there are query parameters.
String extension = uri.getPath();
int lastDot = extension.lastIndexOf('.');
if (lastDot != -1) {
extension = extension.substring(lastDot + 1);
}
// Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
extension = extension.toLowerCase();
if (extension.equals("3ga")) {
mimeType = "audio/3gpp";
} else {

View File

@@ -41,6 +41,8 @@ import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Iterator;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
@@ -99,11 +101,84 @@ public class FileTransfer extends CordovaPlugin {
}
}
/**
* Adds an interface method to an InputStream to return the number of bytes
* read from the raw stream. This is used to track total progress against
* the HTTP Content-Length header value from the server.
*/
private static abstract class TrackingInputStream extends FilterInputStream {
public TrackingInputStream(final InputStream in) {
super(in);
}
public abstract long getTotalRawBytesRead();
}
private static class ExposedGZIPInputStream extends GZIPInputStream {
public ExposedGZIPInputStream(final InputStream in) throws IOException {
super(in);
}
public Inflater getInflater() {
return inf;
}
}
/**
* Provides raw bytes-read tracking for a GZIP input stream. Reports the
* total number of compressed bytes read from the input, rather than the
* number of uncompressed bytes.
*/
private static class TrackingGZIPInputStream extends TrackingInputStream {
private ExposedGZIPInputStream gzin;
public TrackingGZIPInputStream(final ExposedGZIPInputStream gzin) throws IOException {
super(gzin);
this.gzin = gzin;
}
public long getTotalRawBytesRead() {
return gzin.getInflater().getBytesRead();
}
}
/**
* Provides simple total-bytes-read tracking for an existing InputStream
*/
private static class TrackingHTTPInputStream extends TrackingInputStream {
private long bytesRead = 0;
public TrackingHTTPInputStream(InputStream stream) {
super(stream);
}
private int updateBytesRead(int newBytesRead) {
if (newBytesRead != -1) {
bytesRead += newBytesRead;
}
return newBytesRead;
}
@Override
public int read() throws IOException {
return updateBytesRead(super.read());
}
@Override
public int read(byte[] buffer) throws IOException {
return updateBytesRead(super.read(buffer));
}
@Override
public int read(byte[] bytes, int offset, int count) throws IOException {
return updateBytesRead(super.read(bytes, offset, count));
}
public long getTotalRawBytesRead() {
return bytesRead;
}
}
/**
* Works around a bug on Android 2.3.
* http://code.google.com/p/android/issues/detail?id=14562
*/
private static final class DoneHandlerInputStream extends FilterInputStream {
private static final class DoneHandlerInputStream extends TrackingHTTPInputStream {
private boolean done;
public DoneHandlerInputStream(InputStream stream) {
@@ -204,6 +279,7 @@ public class FileTransfer extends CordovaPlugin {
// Look for headers on the params map for backwards compatibility with older Cordova versions.
final JSONObject headers = args.optJSONObject(8) == null ? params.optJSONObject("headers") : args.optJSONObject(8);
final String objectId = args.getString(9);
final String httpMethod = getArgument(args, 10, "POST");
Log.d(LOG_TAG, "fileKey: " + fileKey);
Log.d(LOG_TAG, "fileName: " + fileName);
@@ -213,6 +289,7 @@ public class FileTransfer extends CordovaPlugin {
Log.d(LOG_TAG, "chunkedMode: " + chunkedMode);
Log.d(LOG_TAG, "headers: " + headers);
Log.d(LOG_TAG, "objectId: " + objectId);
Log.d(LOG_TAG, "httpMethod: " + httpMethod);
final URL url;
try {
@@ -280,7 +357,7 @@ public class FileTransfer extends CordovaPlugin {
conn.setUseCaches(false);
// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestMethod(httpMethod);
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
// Set the cookies on the response
@@ -407,7 +484,7 @@ public class FileTransfer extends CordovaPlugin {
int responseCode = conn.getResponseCode();
Log.d(LOG_TAG, "response code: " + responseCode);
Log.d(LOG_TAG, "response headers: " + conn.getHeaderFields());
InputStream inStream = null;
TrackingInputStream inStream = null;
try {
inStream = getInputStream(conn);
synchronized (context) {
@@ -483,11 +560,15 @@ public class FileTransfer extends CordovaPlugin {
}
}
private static InputStream getInputStream(URLConnection conn) throws IOException {
private static TrackingInputStream getInputStream(URLConnection conn) throws IOException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return new DoneHandlerInputStream(conn.getInputStream());
}
return conn.getInputStream();
String encoding = conn.getContentEncoding();
if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
return new TrackingGZIPInputStream(new ExposedGZIPInputStream(conn.getInputStream()));
}
return new TrackingHTTPInputStream(conn.getInputStream());
}
// always verify the host - don't check for certificate
@@ -698,6 +779,9 @@ public class FileTransfer extends CordovaPlugin {
{
connection.setRequestProperty("cookie", cookie);
}
// This must be explicitly set for gzip progress tracking to work.
connection.setRequestProperty("Accept-Encoding", "gzip");
// Handle the other headers
if (headers != null) {
@@ -709,14 +793,15 @@ public class FileTransfer extends CordovaPlugin {
Log.d(LOG_TAG, "Download file:" + url);
FileProgressResult progress = new FileProgressResult();
if (connection.getContentEncoding() == null) {
// Only trust content-length header if no gzip etc
if (connection.getContentEncoding() == null || connection.getContentEncoding().equalsIgnoreCase("gzip")) {
// Only trust content-length header if we understand
// the encoding -- identity or gzip
progress.setLengthComputable(true);
progress.setTotal(connection.getContentLength());
}
FileOutputStream outputStream = null;
InputStream inputStream = null;
TrackingInputStream inputStream = null;
try {
inputStream = getInputStream(connection);
@@ -731,12 +816,10 @@ public class FileTransfer extends CordovaPlugin {
// write bytes to file
byte[] buffer = new byte[MAX_BUFFER_SIZE];
int bytesRead = 0;
long totalBytes = 0;
while ((bytesRead = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, bytesRead);
totalBytes += bytesRead;
// Send a progress event.
progress.setLoaded(totalBytes);
progress.setLoaded(inputStream.getTotalRawBytesRead());
PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
progressResult.setKeepCallback(true);
context.sendPluginResult(progressResult);

18
framework/src/org/apache/cordova/GeoBroker.java Executable file → Normal file
View File

@@ -38,7 +38,7 @@ import android.location.LocationManager;
public class GeoBroker extends CordovaPlugin {
private GPSListener gpsListener;
private NetworkListener networkListener;
private LocationManager locationManager;
private LocationManager locationManager;
/**
* Constructor.
@@ -73,7 +73,7 @@ public class GeoBroker extends CordovaPlugin {
PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(last));
callbackContext.sendPluginResult(result);
} else {
this.getCurrentLocation(callbackContext, enableHighAccuracy);
this.getCurrentLocation(callbackContext, enableHighAccuracy, args.optInt(2, 60000));
}
}
else if (action.equals("addWatch")) {
@@ -102,11 +102,11 @@ public class GeoBroker extends CordovaPlugin {
this.networkListener.clearWatch(id);
}
private void getCurrentLocation(CallbackContext callbackContext, boolean enableHighAccuracy) {
private void getCurrentLocation(CallbackContext callbackContext, boolean enableHighAccuracy, int timeout) {
if (enableHighAccuracy) {
this.gpsListener.addCallback(callbackContext);
this.gpsListener.addCallback(callbackContext, timeout);
} else {
this.networkListener.addCallback(callbackContext);
this.networkListener.addCallback(callbackContext, timeout);
}
}
@@ -160,8 +160,9 @@ public class GeoBroker extends CordovaPlugin {
return o;
}
public void win(Location loc, CallbackContext callbackContext) {
PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc));
public void win(Location loc, CallbackContext callbackContext, boolean keepCallback) {
PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc));
result.setKeepCallback(keepCallback);
callbackContext.sendPluginResult(result);
}
@@ -172,7 +173,7 @@ public class GeoBroker extends CordovaPlugin {
* @param msg The error message
* @throws JSONException
*/
public void fail(int code, String msg, CallbackContext callbackContext) {
public void fail(int code, String msg, CallbackContext callbackContext, boolean keepCallback) {
JSONObject obj = new JSONObject();
String backup = null;
try {
@@ -189,6 +190,7 @@ public class GeoBroker extends CordovaPlugin {
result = new PluginResult(PluginResult.Status.ERROR, backup);
}
result.setKeepCallback(keepCallback);
callbackContext.sendPluginResult(result);
}

View File

@@ -24,11 +24,12 @@ import java.io.InputStream;
import org.apache.cordova.api.CordovaInterface;
import org.apache.cordova.api.LOG;
import android.content.res.AssetManager;
import android.net.Uri;
import android.annotation.TargetApi;
import android.os.Build;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
@@ -42,35 +43,20 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
if(url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url)){
return generateWebResourceResponse(url);
} else {
return super.shouldInterceptRequest(view, url);
//Check if plugins intercept the request
WebResourceResponse ret = super.shouldInterceptRequest(view, url);
if(ret == null && (url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url))){
ret = generateWebResourceResponse(url);
}
return ret;
}
private WebResourceResponse generateWebResourceResponse(String url) {
final String ANDROID_ASSET = "file:///android_asset/";
if (url.startsWith(ANDROID_ASSET)) {
String niceUrl = url;
niceUrl = url.replaceFirst(ANDROID_ASSET, "");
if(niceUrl.contains("?")){
niceUrl = niceUrl.split("\\?")[0];
}
else if(niceUrl.contains("#"))
{
niceUrl = niceUrl.split("#")[0];
}
String mimetype = null;
if(niceUrl.endsWith(".html")){
mimetype = "text/html";
}
if (url.startsWith("file:///android_asset/")) {
String mimetype = FileHelper.getMimeType(url, cordova);
try {
AssetManager assets = cordova.getActivity().getAssets();
Uri uri = Uri.parse(niceUrl);
InputStream stream = assets.open(uri.getPath(), AssetManager.ACCESS_STREAMING);
InputStream stream = FileHelper.getInputStreamFromUriString(url, cordova);
WebResourceResponse response = new WebResourceResponse(mimetype, "UTF-8", stream);
return response;
} catch (IOException e) {

View File

@@ -51,6 +51,7 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebChromeClient;
import android.webkit.GeolocationPermissions.Callback;
import android.webkit.JsPromptResult;
import android.webkit.WebSettings;
import android.webkit.WebStorage;
import android.webkit.WebView;
@@ -92,12 +93,9 @@ public class InAppBrowser extends CordovaPlugin {
* @return A PluginResult object with a status and message.
*/
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
PluginResult.Status status = PluginResult.Status.OK;
String result = "";
this.callbackContext = callbackContext;
try {
if (action.equals("open")) {
this.callbackContext = callbackContext;
String url = args.getString(0);
String target = args.optString(1);
if (target == null || target.equals("") || target.equals(NULL)) {
@@ -108,6 +106,7 @@ public class InAppBrowser extends CordovaPlugin {
Log.d(LOG_TAG, "target = " + target);
url = updateUrl(url);
String result = "";
// SELF
if (SELF.equals(target)) {
@@ -143,41 +142,89 @@ public class InAppBrowser extends CordovaPlugin {
Log.d(LOG_TAG, "in blank");
result = this.showWebPage(url, features);
}
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
pluginResult.setKeepCallback(true);
this.callbackContext.sendPluginResult(pluginResult);
}
else if (action.equals("close")) {
closeDialog();
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
pluginResult.setKeepCallback(false);
this.callbackContext.sendPluginResult(pluginResult);
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
}
else if (action.equals("injectScriptCode")) {
String source = args.getString(0);
org.json.JSONArray jsonEsc = new org.json.JSONArray();
jsonEsc.put(source);
String jsonRepr = jsonEsc.toString();
String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
String scriptEnclosure = "(function(d){var c=d.createElement('script');c.type='text/javascript';c.innerText="
+ jsonSourceString
+ ";d.getElementsByTagName('head')[0].appendChild(c);})(document)";
this.inAppWebView.loadUrl("javascript:" + scriptEnclosure);
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
this.callbackContext.sendPluginResult(pluginResult);
String jsWrapper = null;
if (args.getBoolean(1)) {
jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId());
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectScriptFile")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectStyleCode")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectStyleFile")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else {
status = PluginResult.Status.INVALID_ACTION;
return false;
}
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));
}
return true;
}
/**
* Inject an object (script or style) into the InAppBrowser WebView.
*
* This is a helper method for the inject{Script|Style}{Code|File} API calls, which
* provides a consistent method for injecting JavaScript code into the document.
*
* If a wrapper string is supplied, then the source string will be JSON-encoded (adding
* quotes) and wrapped using string formatting. (The wrapper string should have a single
* '%s' marker)
*
* @param source The source object (filename or script/style text) to inject into
* the document.
* @param jsWrapper A JavaScript string to wrap the source string in, so that the object
* is properly injected, or null if the source string is JavaScript text
* which should be executed directly.
*/
private void injectDeferredObject(String source, String jsWrapper) {
String scriptToInject;
if (jsWrapper != null) {
org.json.JSONArray jsonEsc = new org.json.JSONArray();
jsonEsc.put(source);
String jsonRepr = jsonEsc.toString();
String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
scriptToInject = String.format(jsWrapper, jsonSourceString);
} else {
scriptToInject = source;
}
// This action will have the side-effect of blurring the currently focused element
this.inAppWebView.loadUrl("javascript:" + scriptToInject);
}
/**
* Put the list of features into a hash map
*
@@ -444,7 +491,7 @@ public class InAppBrowser extends CordovaPlugin {
// WebView
inAppWebView = new WebView(cordova.getActivity());
inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
inAppWebView.setWebChromeClient(new InAppChromeClient());
inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView));
WebViewClient client = new InAppBrowserClient(thatWebView, edittext);
inAppWebView.setWebViewClient(client);
WebSettings settings = inAppWebView.getSettings();
@@ -527,8 +574,15 @@ public class InAppBrowser extends CordovaPlugin {
result.setKeepCallback(keepCallback);
this.callbackContext.sendPluginResult(result);
}
public class InAppChromeClient extends WebChromeClient {
private CordovaWebView webView;
public InAppChromeClient(CordovaWebView webView) {
super();
this.webView = webView;
}
/**
* Handle database quota exceeded notification.
*
@@ -571,6 +625,57 @@ public class InAppBrowser extends CordovaPlugin {
super.onGeolocationPermissionsShowPrompt(origin, callback);
callback.invoke(origin, true, false);
}
/**
* Tell the client to display a prompt dialog to the user.
* If the client returns true, WebView will assume that the client will
* handle the prompt dialog and call the appropriate JsPromptResult method.
*
* The prompt bridge provided for the InAppBrowser is capable of executing any
* oustanding callback belonging to the InAppBrowser plugin. Care has been
* taken that other callbacks cannot be triggered, and that no other code
* execution is possible.
*
* To trigger the bridge, the prompt default value should be of the form:
*
* gap-iab://<callbackId>
*
* where <callbackId> is the string id of the callback to trigger (something
* like "InAppBrowser0123456789")
*
* If present, the prompt message is expected to be a JSON-encoded value to
* pass to the callback. A JSON_EXCEPTION is returned if the JSON is invalid.
*
* @param view
* @param url
* @param message
* @param defaultValue
* @param result
*/
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
// See if the prompt string uses the 'gap-iab' protocol. If so, the remainder should be the id of a callback to execute.
if (defaultValue != null && defaultValue.startsWith("gap-iab://")) {
PluginResult scriptResult;
String scriptCallbackId = defaultValue.substring(10);
if (scriptCallbackId.startsWith("InAppBrowser")) {
if(message == null || message.length() == 0) {
scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray());
} else {
try {
scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray(message));
} catch(JSONException e) {
scriptResult = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
}
}
this.webView.sendPluginResult(scriptResult, scriptCallbackId);
result.confirm("");
return true;
}
}
return false;
}
}
/**

View File

@@ -50,13 +50,10 @@ public class NativeToJsMessageQueue {
// exec() is asynchronous. Set this to true when running bridge benchmarks.
static final boolean DISABLE_EXEC_CHAINING = false;
// Upper limit for how much data to send to JS in one shot.
// TODO(agrieve): This is currently disable. It should be re-enabled once we
// remove support for returning values from exec() calls. This was
// deprecated in 2.2.0.
// Also, this currently only chops up on message boundaries. It may be useful
// Arbitrarily chosen upper limit for how much data to send to JS in one shot.
// This currently only chops up on message boundaries. It may be useful
// to allow it to break up messages.
private static int MAX_PAYLOAD_SIZE = -1; //50 * 1024 * 10240;
private static int MAX_PAYLOAD_SIZE = 50 * 1024 * 10240;
/**
* The index into registeredListeners to treat as active.

View File

@@ -1,177 +0,0 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova.api;
import org.apache.cordova.CordovaWebView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Legacy Plugin class. This acts as a shim to support the old execute() signature.
* New plugins should extend CordovaPlugin directly.
*/
@Deprecated
public abstract class Plugin extends CordovaPlugin {
public LegacyContext ctx; // LegacyContext object
public abstract PluginResult execute(String action, JSONArray args, String callbackId);
public boolean isSynch(String action) {
return false;
}
@Override
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
this.setContext(cordova);
this.setView(webView);
}
/**
* Sets the context of the Plugin. This can then be used to do things like
* get file paths associated with the Activity.
*
* @param ctx The context of the main Activity.
*/
public void setContext(CordovaInterface ctx) {
this.cordova = ctx;
this.ctx = new LegacyContext(cordova);
}
/**
* Sets the main View of the application, this is the WebView within which
* a Cordova app runs.
*
* @param webView The Cordova WebView
*/
public void setView(CordovaWebView webView) {
this.webView = webView;
}
@Override
public boolean execute(final String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
final String callbackId = callbackContext.getCallbackId();
boolean runAsync = !isSynch(action);
if (runAsync) {
// Run this on a different thread so that this one can return back to JS
cordova.getThreadPool().execute(new Runnable() {
public void run() {
PluginResult cr;
try {
cr = execute(action, args, callbackId);
} catch (Throwable e) {
cr = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
}
sendPluginResult(cr, callbackId);
}
});
} else {
PluginResult cr = execute(action, args, callbackId);
// Interpret a null response as NO_RESULT, which *does* clear the callbacks on the JS side.
if (cr == null) {
cr = new PluginResult(PluginResult.Status.NO_RESULT);
}
callbackContext.sendPluginResult(cr);
}
return true;
}
/**
* Send generic JavaScript statement back to JavaScript.
* sendPluginResult() should be used instead where possible.
*/
public void sendJavascript(String statement) {
this.webView.sendJavascript(statement);
}
/**
* Send generic JavaScript statement back to JavaScript.
*/
public void sendPluginResult(PluginResult pluginResult, String callbackId) {
this.webView.sendPluginResult(pluginResult, callbackId);
}
/**
* Call the JavaScript success callback for this plugin.
*
* This can be used if the execute code for the plugin is asynchronous meaning
* that execute should return null and the callback from the async operation can
* call success(...) or error(...)
*
* @param pluginResult The result to return.
* @param callbackId The callback id used when calling back into JavaScript.
*/
public void success(PluginResult pluginResult, String callbackId) {
this.webView.sendPluginResult(pluginResult, callbackId);
}
/**
* Helper for success callbacks that just returns the Status.OK by default
*
* @param message The message to add to the success result.
* @param callbackId The callback id used when calling back into JavaScript.
*/
public void success(JSONObject message, String callbackId) {
this.webView.sendPluginResult(new PluginResult(PluginResult.Status.OK, message), callbackId);
}
/**
* Helper for success callbacks that just returns the Status.OK by default
*
* @param message The message to add to the success result.
* @param callbackId The callback id used when calling back into JavaScript.
*/
public void success(String message, String callbackId) {
this.webView.sendPluginResult(new PluginResult(PluginResult.Status.OK, message), callbackId);
}
/**
* Call the JavaScript error callback for this plugin.
*
* @param pluginResult The result to return.
* @param callbackId The callback id used when calling back into JavaScript.
*/
public void error(PluginResult pluginResult, String callbackId) {
this.webView.sendPluginResult(pluginResult, callbackId);
}
/**
* Helper for error callbacks that just returns the Status.ERROR by default
*
* @param message The message to add to the error result.
* @param callbackId The callback id used when calling back into JavaScript.
*/
public void error(JSONObject message, String callbackId) {
this.webView.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message), callbackId);
}
/**
* Helper for error callbacks that just returns the Status.ERROR by default
*
* @param message The message to add to the error result.
* @param callbackId The callback id used when calling back into JavaScript.
*/
public void error(String message, String callbackId) {
this.webView.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message), callbackId);
}
}