Compare commits

..

8 Commits
2.7.0 ... 2.6.0

Author SHA1 Message Date
Joe Bowser
34b606b9fc Prep for 2.6.0 final 2013-04-01 14:55:10 -07:00
Joe Bowser
d1932ad473 CB-1796: Let's make sure we actually write the file instead of just writing EXIF to NOTHING 2013-03-27 15:11:11 -07:00
Joe Bowser
ff6ef1eea5 JS Changed once again, this will require a retag of 2.6.0rc1 2013-03-27 13:25:53 -07:00
Joe Bowser
b7e67ffb3c Merge branch '2.6.x' of https://git-wip-us.apache.org/repos/asf/cordova-android into 2.6.x 2013-03-25 16:04:44 -07:00
Joe Bowser
4ab4606ad2 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-25 16:04:22 -07:00
Joe Bowser
957f2fd10b Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-android into 2.6.x 2013-03-25 10:50:28 -07:00
Andrew Grieve
cdbe9c7204 Fix NPE in InAppBrowser.
When cordova.getActivity().getIntent().getExtras() == null.
2013-03-23 14:09:32 -04:00
Joe Bowser
85c25630a8 Grabbed the wrong JS 2013-03-21 10:49:51 -07:00
21 changed files with 493 additions and 645 deletions

View File

@@ -1 +1 @@
2.7.0
2.6.0

View File

@@ -25,11 +25,8 @@ set -e
if [ -z "$1" ] || [ "$1" == "-h" ]
then
echo "Usage: $0 <path_to_new_project> <package_name> <project_name>"
echo 'usage: create path package activity'
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,37 +16,17 @@
:: under the License.
@ECHO OFF
IF NOT DEFINED JAVA_HOME GOTO MISSING_JAVA_HOME
IF NOT DEFINED JAVA_HOME GOTO MISSING
FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
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
)
SET FOUND=%%~$PATH:X
IF NOT DEFINED FOUND GOTO MISSING
)
cscript "%~dp0\create.js" %*
GOTO END
: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
: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
EXIT /B 1
:END

View File

@@ -33,7 +33,7 @@
<p class="event received">Device is Ready</p>
</div>
</div>
<script type="text/javascript" src="cordova-2.7.0.js"></script>
<script type="text/javascript" src="cordova-2.6.0.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript">
app.initialize();

View File

@@ -1,8 +1,8 @@
// Platform: android
// commit cd29cf0f224ccf25e9d422a33fd02ef67d3a78f4
// commit 125dca530923a44a8f44f68f5e1970cbdd4e7faf
// File generated at :: Thu Apr 25 2013 14:53:10 GMT-0700 (PDT)
// File generated at :: Mon Apr 01 2013 13:28:03 GMT-0700 (PDT)
/*
Licensed to the Apache Software Foundation (ASF) under one
@@ -219,10 +219,6 @@ var cordova = {
}
else {
setTimeout(function() {
// Fire deviceready on listeners that were registered before cordova.js was loaded.
if (type == 'deviceready') {
document.dispatchEvent(evt);
}
documentEventHandlers[type].fire(evt);
}, 0);
}
@@ -746,7 +742,6 @@ channel.createSticky('onDestroy');
// Channels that must fire before "deviceready" is fired.
channel.waitForInitialization('onCordovaReady');
channel.waitForInitialization('onCordovaConnectionReady');
channel.waitForInitialization('onDOMContentLoaded');
module.exports = channel;
@@ -845,27 +840,32 @@ function androidExec(success, fail, service, action, args) {
}
var callbackId = service + cordova.callbackId++,
argsJson = JSON.stringify(args);
argsJson = JSON.stringify(args),
returnValue;
if (success || fail) {
cordova.callbacks[callbackId] = {success:success, fail:fail};
// TODO: Returning the payload of a synchronous call was deprecated in 2.2.0.
// Remove it after 6 months.
function captureReturnValue(value) {
returnValue = value;
success && success(value);
}
cordova.callbacks[callbackId] = {success:captureReturnValue, fail:fail};
if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) {
window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson;
} else {
var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson);
// If argsJson was received by Java as null, try again with the PROMPT bridge mode.
// This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2. See CB-2666.
if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && messages === "@Null arguments.") {
androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
androidExec(success, fail, service, action, args);
androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
return;
androidExec.processMessages(messages);
}
if (cordova.callbacks[callbackId]) {
if (success || fail) {
cordova.callbacks[callbackId].success = success;
} else {
androidExec.processMessages(messages);
delete cordova.callbacks[callbackId];
}
}
return returnValue;
}
function pollOnce() {
@@ -981,30 +981,30 @@ function processMessage(message) {
androidExec.processMessages = function(messages) {
if (messages) {
messagesFromNative.push(messages);
// Check for the reentrant case, and enqueue the message if that's the case.
if (messagesFromNative.length > 1) {
return;
}
while (messagesFromNative.length) {
// Don't unshift until the end so that reentrancy can be detected.
messages = messagesFromNative[0];
messages = messagesFromNative.shift();
// The Java side can send a * message to indicate that it
// still has messages waiting to be retrieved.
// TODO(agrieve): This is currently disabled on the Java side
// since it breaks returning the result in exec of synchronous
// plugins. Once we remove this ability, we can remove this comment.
if (messages == '*') {
messagesFromNative.shift();
window.setTimeout(pollOnce, 0);
return;
continue;
}
var spaceIdx = messages.indexOf(' ');
var msgLen = +messages.slice(0, spaceIdx);
var message = messages.substr(spaceIdx + 1, msgLen);
messages = messages.slice(spaceIdx + msgLen + 1);
processMessage(message);
// Put the remaining messages back into queue in case an exec()
// is made by the callback.
if (messages) {
messagesFromNative[0] = messages;
} else {
messagesFromNative.shift();
messagesFromNative.unshift(messages);
}
if (message) {
processMessage(message);
}
}
}
@@ -2398,7 +2398,7 @@ function initRead(reader, file) {
if (typeof file == 'string') {
// Deprecated in Cordova 2.4.
console.warn('Using a string argument with FileReader.readAs functions is deprecated.');
console.warning('Using a string argument with FileReader.readAs functions is deprecated.');
reader._fileName = file;
} else if (typeof file.fullPath == 'string') {
reader._fileName = file.fullPath;
@@ -2756,7 +2756,7 @@ function getBasicAuthHeader(urlString) {
var origin = protocol + url.host;
// check whether there are the username:password credentials in the url
if (url.href.indexOf(origin) !== 0) { // credentials found
if (url.href.indexOf(origin) != 0) { // credentials found
var atIndex = url.href.indexOf("@");
credentials = url.href.substring(protocol.length, atIndex);
}
@@ -2805,11 +2805,15 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
var params = null;
var chunkedMode = true;
var headers = null;
var httpMethod = null;
var basicAuthHeader = getBasicAuthHeader(server);
if (basicAuthHeader) {
options = options || {};
options.headers = options.headers || {};
if (!options) {
options = new FileUploadOptions();
}
if (!options.headers) {
options.headers = {};
}
options.headers[basicAuthHeader.name] = basicAuthHeader.value;
}
@@ -2818,12 +2822,6 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
fileName = options.fileName;
mimeType = options.mimeType;
headers = options.headers;
httpMethod = options.httpMethod || "POST";
if (httpMethod.toUpperCase() == "PUT"){
httpMethod = "PUT";
} else {
httpMethod = "POST";
}
if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
chunkedMode = options.chunkedMode;
}
@@ -2850,7 +2848,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
successCallback && successCallback(result);
}
};
exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id]);
};
/**
@@ -2868,8 +2866,12 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
var basicAuthHeader = getBasicAuthHeader(source);
if (basicAuthHeader) {
options = options || {};
options.headers = options.headers || {};
if (!options) {
options = {};
}
if (!options.headers) {
options.headers = {};
}
options.headers[basicAuthHeader.name] = basicAuthHeader.value;
}
@@ -2908,11 +2910,12 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
};
/**
* Aborts the ongoing file transfer on this object. The original error
* callback for the file transfer will be called if necessary.
* Aborts the ongoing file transfer on this object
* @param successCallback {Function} Callback to be invoked upon success
* @param errorCallback {Function} Callback to be invoked upon error
*/
FileTransfer.prototype.abort = function() {
exec(null, null, 'FileTransfer', 'abort', [this._id]);
FileTransfer.prototype.abort = function(successCallback, errorCallback) {
exec(successCallback, errorCallback, 'FileTransfer', 'abort', [this._id]);
};
module.exports = FileTransfer;
@@ -2956,13 +2959,12 @@ define("cordova/plugin/FileUploadOptions", function(require, exports, module) {
* @param headers {Object} Keys are header names, values are header values. Multiple
* headers of the same name are not supported.
*/
var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers, httpMethod) {
var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers) {
this.fileKey = fileKey || null;
this.fileName = fileName || null;
this.mimeType = mimeType || null;
this.params = params || null;
this.headers = headers || null;
this.httpMethod = httpMethod || null;
};
module.exports = FileUploadOptions;
@@ -3297,7 +3299,6 @@ define("cordova/plugin/InAppBrowser", function(require, exports, module) {
var exec = require('cordova/exec');
var channel = require('cordova/channel');
var modulemapper = require('cordova/modulemapper');
function InAppBrowser() {
this.channels = {
@@ -3326,26 +3327,6 @@ InAppBrowser.prototype = {
if (eventname in this.channels) {
this.channels[eventname].unsubscribe(f);
}
},
executeScript: function(injectDetails, cb) {
if (injectDetails.code) {
exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]);
} else if (injectDetails.file) {
exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]);
} else {
throw new Error('executeScript requires exactly one of code or file to be specified');
}
},
insertCSS: function(injectDetails, cb) {
if (injectDetails.code) {
exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]);
} else if (injectDetails.file) {
exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]);
} else {
throw new Error('insertCSS requires exactly one of code or file to be specified');
}
}
};
@@ -3354,13 +3335,6 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) {
var cb = function(eventname) {
iab._eventHandler(eventname);
};
// Don't catch calls that write to existing frames (e.g. named iframes).
if (window.frames && window.frames[strWindowName]) {
var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
return origOpenFunc.apply(window, arguments);
}
exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
return iab;
};
@@ -4884,7 +4858,7 @@ console.debug = function() {
console.assert = function(expression) {
if (expression) return;
var message = logger.format.apply(logger.format, [].slice.call(arguments, 1));
var message = utils.vformat(arguments[1], [].slice.call(arguments, 2));
console.log("ASSERT: " + message);
};
@@ -5984,10 +5958,10 @@ function logWithArgs(level, args) {
* Parameters passed after message are used applied to
* the message with utils.format()
*/
logger.logLevel = function(level /* , ... */) {
logger.logLevel = function(level, message /* , ... */) {
// format the message with the parameters
var formatArgs = [].slice.call(arguments, 1);
var message = logger.format.apply(logger.format, formatArgs);
var formatArgs = [].slice.call(arguments, 2);
message = utils.vformat(message, formatArgs);
if (LevelsMap[level] === null) {
throw new Error("invalid logging level: " + level);
@@ -6022,92 +5996,6 @@ logger.logLevel = function(level /* , ... */) {
}
};
/**
* Formats a string and arguments following it ala console.log()
*
* Any remaining arguments will be appended to the formatted string.
*
* for rationale, see FireBug's Console API:
* http://getfirebug.com/wiki/index.php/Console_API
*/
logger.format = function(formatString, args) {
return __format(arguments[0], [].slice.call(arguments,1)).join(' ');
};
//------------------------------------------------------------------------------
/**
* Formats a string and arguments following it ala vsprintf()
*
* format chars:
* %j - format arg as JSON
* %o - format arg as JSON
* %c - format arg as ''
* %% - replace with '%'
* any other char following % will format it's
* arg via toString().
*
* Returns an array containing the formatted string and any remaining
* arguments.
*/
function __format(formatString, args) {
if (formatString === null || formatString === undefined) return [""];
if (arguments.length == 1) return [formatString.toString()];
if (typeof formatString != "string")
formatString = formatString.toString();
var pattern = /(.*?)%(.)(.*)/;
var rest = formatString;
var result = [];
while (args.length) {
var match = pattern.exec(rest);
if (!match) break;
var arg = args.shift();
rest = match[3];
result.push(match[1]);
if (match[2] == '%') {
result.push('%');
args.unshift(arg);
continue;
}
result.push(__formatted(arg, match[2]));
}
result.push(rest);
var remainingArgs = [].slice.call(args);
remainingArgs.unshift(result.join(''));
return remainingArgs;
}
function __formatted(object, formatChar) {
try {
switch(formatChar) {
case 'j':
case 'o': return JSON.stringify(object);
case 'c': return '';
}
}
catch (e) {
return "error JSON.stringify()ing argument: " + e;
}
if ((object === null) || (object === undefined)) {
return Object.prototype.toString.call(object);
}
return object.toString();
}
//------------------------------------------------------------------------------
// when deviceready fires, log queued messages
logger.__onDeviceReady = function() {
if (DeviceReady) return;
@@ -6276,13 +6164,13 @@ module.exports = {
console.log("Notification.confirm(string, function, string, string) is deprecated. Use Notification.confirm(string, function, string, array).");
}
// Some platforms take an array of button label names.
// Android and iOS take an array of button label names.
// Other platforms take a comma separated list.
// For compatibility, we convert to the desired type based on the platform.
if (platform.id == "android" || platform.id == "ios" || platform.id == "windowsphone") {
if (platform.id == "android" || platform.id == "ios") {
if (typeof _buttonLabels === 'string') {
var buttonLabelString = _buttonLabels;
_buttonLabels = _buttonLabels.split(","); // not crazy about changing the var type here
_buttonLabels = buttonLabelString.split(",");
}
} else {
if (Array.isArray(_buttonLabels)) {
@@ -6633,6 +6521,62 @@ utils.alert = function(msg) {
}
};
/**
* Formats a string and arguments following it ala sprintf()
*
* see utils.vformat() for more information
*/
utils.format = function(formatString /* ,... */) {
var args = [].slice.call(arguments, 1);
return utils.vformat(formatString, args);
};
/**
* Formats a string and arguments following it ala vsprintf()
*
* format chars:
* %j - format arg as JSON
* %o - format arg as JSON
* %c - format arg as ''
* %% - replace with '%'
* any other char following % will format it's
* arg via toString().
*
* for rationale, see FireBug's Console API:
* http://getfirebug.com/wiki/index.php/Console_API
*/
utils.vformat = function(formatString, args) {
if (formatString === null || formatString === undefined) return "";
if (arguments.length == 1) return formatString.toString();
if (typeof formatString != "string") return formatString.toString();
var pattern = /(.*?)%(.)(.*)/;
var rest = formatString;
var result = [];
while (args.length) {
var arg = args.shift();
var match = pattern.exec(rest);
if (!match) break;
rest = match[3];
result.push(match[1]);
if (match[2] == '%') {
result.push('%');
args.unshift(arg);
continue;
}
result.push(formatted(arg, match[2]));
}
result.push(rest);
return result.join('');
};
//------------------------------------------------------------------------------
function UUIDcreatePart(length) {
@@ -6647,6 +6591,26 @@ function UUIDcreatePart(length) {
return uuidpart;
}
//------------------------------------------------------------------------------
function formatted(object, formatChar) {
try {
switch(formatChar) {
case 'j':
case 'o': return JSON.stringify(object);
case 'c': return '';
}
}
catch (e) {
return "error JSON.stringify()ing argument: " + e;
}
if ((object === null) || (object === undefined)) {
return Object.prototype.toString.call(object);
}
return object.toString();
}
});
@@ -6656,25 +6620,6 @@ window.cordova = require('cordova');
// file: lib/scripts/bootstrap.js
(function (context) {
var channel = require('cordova/channel');
var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];
function logUnfiredChannels(arr) {
for (var i = 0; i < arr.length; ++i) {
if (arr[i].state != 2) {
console.log('Channel not fired: ' + arr[i].type);
}
}
}
window.setTimeout(function() {
if (channel.onDeviceReady.state != 2) {
console.log('deviceready has not fired after 5 seconds.');
logUnfiredChannels(platformInitChannelsArray);
logUnfiredChannels(channel.deviceReadyChannelsArray);
}
}, 5000);
// Replace navigator before any modules are required(), to ensure it happens as soon as possible.
// We replace it so that properties that can't be clobbered can instead be overridden.
function replaceNavigator(origNavigator) {
@@ -6696,6 +6641,8 @@ window.cordova = require('cordova');
context.navigator = replaceNavigator(context.navigator);
}
var channel = require("cordova/channel");
// _nativeReady is global variable that the native side can set
// to signify that the native code is ready. It is a global since
// it may be called before any cordova JS is ready.
@@ -6704,33 +6651,32 @@ window.cordova = require('cordova');
}
/**
* Create all cordova objects once native side is ready.
* Create all cordova objects once page has fully loaded and native side is ready.
*/
channel.join(function() {
var builder = require('cordova/builder'),
platform = require('cordova/platform');
builder.buildIntoButDoNotClobber(platform.defaults, context);
builder.buildIntoAndClobber(platform.clobbers, context);
builder.buildIntoAndMerge(platform.merges, context);
// Call the platform-specific initialization
require('cordova/platform').initialize();
platform.initialize();
// Fire event to notify that all objects are created
channel.onCordovaReady.fire();
// Fire onDeviceReady event once page has fully loaded, all
// constructors have run and cordova info has been received from native
// side.
// This join call is deliberately made after platform.initialize() in
// order that plugins may manipulate channel.deviceReadyChannelsArray
// if necessary.
// Fire onDeviceReady event once all constructors have run and
// cordova info has been received from native side.
channel.join(function() {
require('cordova').fireDocumentEvent('deviceready');
}, channel.deviceReadyChannelsArray);
}, platformInitChannelsArray);
}, [ channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady ]);
}(window));
// file: lib/scripts/bootstrap-android.js
require('cordova/channel').onNativeReady.fire();
// file: lib/scripts/plugin_loader.js
// Tries to load all plugins' js-modules.
@@ -6806,31 +6752,35 @@ require('cordova/channel').onNativeReady.fire();
}
}
// Try to XHR the cordova_plugins.json file asynchronously.
try { // we commented we were going to try, so let us actually try and catch
try { // we commented we were going to try, so let us actually try and catch
var xhr = new context.XMLHttpRequest();
xhr.onload = function() {
xhr.onreadystatechange = function() {
if (this.readyState != 4) { // not DONE
return;
}
// If the response is a JSON string which composes an array, call handlePluginsObject.
// If the request fails, or the response is not a JSON array, just call finishPluginLoading.
var obj = this.responseText && JSON.parse(this.responseText);
if (obj && obj instanceof Array && obj.length > 0) {
handlePluginsObject(obj);
if (this.status == 200) {
var obj = JSON.parse(this.responseText);
if (obj && obj instanceof Array && obj.length > 0) {
handlePluginsObject(obj);
} else {
finishPluginLoading();
}
} else {
finishPluginLoading();
}
};
xhr.onerror = function() {
finishPluginLoading();
};
xhr.open('GET', 'cordova_plugins.json', true); // Async
xhr.send();
}
catch(err){
catch(err) {
finishPluginLoading();
}
}(window));
})();
})();

View File

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

View File

@@ -42,7 +42,6 @@ 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;
@@ -397,21 +396,19 @@ 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 mimeType = FileHelper.getMimeType(uriString, this.cordova);
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);
// If we don't have a valid image so quit.
if (!("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType))) {
if (imagePath == null || mimeType == null ||
!(mimeType.equalsIgnoreCase("image/jpeg") || mimeType.equalsIgnoreCase("image/png"))) {
Log.d(LOG_TAG, "I either have a null image path or bitmap");
this.failPicture("Unable to retrieve path to picture!");
return;
}
Bitmap bitmap = null;
try {
bitmap = getScaledBitmap(uriString);
} catch (IOException e) {
e.printStackTrace();
}
Bitmap bitmap = getScaledBitmap(imagePath);
if (bitmap == null) {
Log.d(LOG_TAG, "I either have a null image path or bitmap");
this.failPicture("Unable to create bitmap!");
@@ -419,7 +416,14 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
}
if (this.correctOrientation) {
rotate = getImageOrientation(uri);
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();
}
if (rotate != 0) {
Matrix matrix = new Matrix();
matrix.setRotate(rotate);
@@ -439,17 +443,15 @@ 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();
if (realPath != null && this.encodingType == JPEG) {
try {
exif.createInFile(realPath);
try {
if (this.encodingType == JPEG) {
exif.createInFile(FileHelper.getRealPath(uri, this.cordova));
exif.readExifData();
rotate = exif.getOrientation();
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
OutputStream os = new FileOutputStream(resizePath);
@@ -457,7 +459,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
os.close();
// Restore exif data to file
if (realPath != null && this.encodingType == JPEG) {
if (this.encodingType == JPEG) {
exif.createOutFile(resizePath);
exif.writeExifData();
}
@@ -491,19 +493,6 @@ 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
@@ -574,18 +563,17 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
*
* @param imagePath
* @return
* @throws IOException
*/
private Bitmap getScaledBitmap(String imageUrl) throws IOException {
private Bitmap getScaledBitmap(String imagePath) {
// If no new width or height were specified return the original bitmap
if (this.targetWidth <= 0 && this.targetHeight <= 0) {
return BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova));
return BitmapFactory.decodeFile(imagePath);
}
// figure out the original width and height of the image
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
BitmapFactory.decodeFile(imagePath, options);
//CB-2292: WTF? Why is the width null?
if(options.outWidth == 0 || options.outHeight == 0)
@@ -599,7 +587,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.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
Bitmap unscaledBitmap = BitmapFactory.decodeFile(imagePath, 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,33 +220,19 @@ 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) {
// Check for http or https protocols
// 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?://(.*\\.)?")));
}
// 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 {
} else {
this.whiteList.add(Pattern.compile("^https?://(.*\\.)?" + origin));
}
LOG.d(TAG, "Origin to allow with subdomains: %s", origin);
} else {
// Check for http or https protocols
// 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?://")));
}
// 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 {
} else {
this.whiteList.add(Pattern.compile("^https?://" + origin));
}
LOG.d(TAG, "Origin to allow: %s", origin);

View File

@@ -22,8 +22,6 @@ 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;
@@ -44,8 +42,6 @@ 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]";
@@ -56,12 +52,11 @@ 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, false);
this.owner.fail(code, message, callbackContext);
}
if(this.owner.isGlobalListener(this) && this.watches.size() == 0)
if(this.owner.isGlobalListener(this))
{
Log.d(TAG, "Stopping global listener");
this.stop();
@@ -70,17 +65,16 @@ public class CordovaLocationListener implements LocationListener {
Iterator<CallbackContext> it = this.watches.values().iterator();
while (it.hasNext()) {
this.owner.fail(code, message, it.next(), true);
this.owner.fail(code, message, it.next());
}
}
private void win(Location loc) {
this.cancelTimer();
for (CallbackContext callbackContext: this.callbacks)
{
this.owner.win(loc, callbackContext, false);
this.owner.win(loc, callbackContext);
}
if(this.owner.isGlobalListener(this) && this.watches.size() == 0)
if(this.owner.isGlobalListener(this))
{
Log.d(TAG, "Stopping global listener");
this.stop();
@@ -89,7 +83,7 @@ public class CordovaLocationListener implements LocationListener {
Iterator<CallbackContext> it = this.watches.values().iterator();
while (it.hasNext()) {
this.owner.win(loc, it.next(), true);
this.owner.win(loc, it.next());
}
}
@@ -161,12 +155,8 @@ public class CordovaLocationListener implements LocationListener {
this.start();
}
}
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);
public void addCallback(CallbackContext callbackContext) {
this.callbacks.add(callbackContext);
if (this.size() == 1) {
this.start();
}
@@ -183,7 +173,7 @@ public class CordovaLocationListener implements LocationListener {
/**
* Destroy listener.
*/
public void destroy() {
public void destroy() {
this.stop();
}
@@ -209,43 +199,9 @@ 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,7 +24,6 @@ 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;
@@ -238,11 +237,7 @@ 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 });
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"))
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
{
gingerbread_getMethod.invoke(settings, true);
}
@@ -267,8 +262,11 @@ 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();
settings.setDatabaseEnabled(true);
settings.setDatabasePath(databasePath);
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
{
settings.setDatabaseEnabled(true);
settings.setDatabasePath(databasePath);
}
settings.setGeolocationDatabasePath(databasePath);

View File

@@ -314,6 +314,15 @@ 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.7.0"; // Cordova version
public static String cordovaVersion = "2.6.0"; // Cordova version
public static String platform = "Android"; // Device OS
public static String uuid; // Device UUID
@@ -77,6 +77,7 @@ 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,7 +51,6 @@ 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;
@@ -718,7 +717,7 @@ public class DroidGap extends Activity implements CordovaInterface {
appView.handleDestroy();
}
else {
this.activityState = ACTIVITY_EXITING;
this.endActivity();
}
}
@@ -1032,13 +1031,7 @@ 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));
// 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);
root.setBackgroundResource(that.splashscreen);
// Create and show the dialog
splashDialog = new Dialog(that, android.R.style.Theme_Translucent_NoTitleBar);

View File

@@ -20,7 +20,6 @@ package org.apache.cordova;
import android.webkit.JavascriptInterface;
import org.apache.cordova.api.PluginManager;
import org.apache.cordova.api.PluginResult;
import org.json.JSONException;
/**
@@ -40,12 +39,6 @@ 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,8 +28,6 @@ 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";
@@ -94,8 +92,7 @@ public class FileHelper {
Uri uri = Uri.parse(uriString);
return cordova.getActivity().getContentResolver().openInputStream(uri);
} else if (uriString.startsWith("file:///android_asset/")) {
Uri uri = Uri.parse(uriString);
String relativePath = uri.getPath().substring(15);
String relativePath = uriString.substring(22);
return cordova.getActivity().getAssets().open(relativePath);
} else {
return new FileInputStream(getRealPath(uriString, cordova));
@@ -125,18 +122,14 @@ 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() 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();
// 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);
if (extension.equals("3ga")) {
mimeType = "audio/3gpp";
} else {

View File

@@ -41,8 +41,6 @@ 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;
@@ -101,84 +99,11 @@ 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 TrackingHTTPInputStream {
private static final class DoneHandlerInputStream extends FilterInputStream {
private boolean done;
public DoneHandlerInputStream(InputStream stream) {
@@ -279,7 +204,6 @@ 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);
@@ -289,7 +213,6 @@ 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 {
@@ -357,7 +280,7 @@ public class FileTransfer extends CordovaPlugin {
conn.setUseCaches(false);
// Use a post method.
conn.setRequestMethod(httpMethod);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
// Set the cookies on the response
@@ -484,7 +407,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());
TrackingInputStream inStream = null;
InputStream inStream = null;
try {
inStream = getInputStream(conn);
synchronized (context) {
@@ -560,15 +483,11 @@ public class FileTransfer extends CordovaPlugin {
}
}
private static TrackingInputStream getInputStream(URLConnection conn) throws IOException {
private static InputStream getInputStream(URLConnection conn) throws IOException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return new DoneHandlerInputStream(conn.getInputStream());
}
String encoding = conn.getContentEncoding();
if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
return new TrackingGZIPInputStream(new ExposedGZIPInputStream(conn.getInputStream()));
}
return new TrackingHTTPInputStream(conn.getInputStream());
return conn.getInputStream();
}
// always verify the host - don't check for certificate
@@ -779,9 +698,6 @@ 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) {
@@ -793,15 +709,14 @@ public class FileTransfer extends CordovaPlugin {
Log.d(LOG_TAG, "Download file:" + url);
FileProgressResult progress = new FileProgressResult();
if (connection.getContentEncoding() == null || connection.getContentEncoding().equalsIgnoreCase("gzip")) {
// Only trust content-length header if we understand
// the encoding -- identity or gzip
if (connection.getContentEncoding() == null) {
// Only trust content-length header if no gzip etc
progress.setLengthComputable(true);
progress.setTotal(connection.getContentLength());
}
FileOutputStream outputStream = null;
TrackingInputStream inputStream = null;
InputStream inputStream = null;
try {
inputStream = getInputStream(connection);
@@ -816,10 +731,12 @@ 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(inputStream.getTotalRawBytesRead());
progress.setLoaded(totalBytes);
PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
progressResult.setKeepCallback(true);
context.sendPluginResult(progressResult);

18
framework/src/org/apache/cordova/GeoBroker.java Normal file → Executable 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, args.optInt(2, 60000));
this.getCurrentLocation(callbackContext, enableHighAccuracy);
}
}
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, int timeout) {
private void getCurrentLocation(CallbackContext callbackContext, boolean enableHighAccuracy) {
if (enableHighAccuracy) {
this.gpsListener.addCallback(callbackContext, timeout);
this.gpsListener.addCallback(callbackContext);
} else {
this.networkListener.addCallback(callbackContext, timeout);
this.networkListener.addCallback(callbackContext);
}
}
@@ -160,9 +160,8 @@ public class GeoBroker extends CordovaPlugin {
return o;
}
public void win(Location loc, CallbackContext callbackContext, boolean keepCallback) {
PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc));
result.setKeepCallback(keepCallback);
public void win(Location loc, CallbackContext callbackContext) {
PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc));
callbackContext.sendPluginResult(result);
}
@@ -173,7 +172,7 @@ public class GeoBroker extends CordovaPlugin {
* @param msg The error message
* @throws JSONException
*/
public void fail(int code, String msg, CallbackContext callbackContext, boolean keepCallback) {
public void fail(int code, String msg, CallbackContext callbackContext) {
JSONObject obj = new JSONObject();
String backup = null;
try {
@@ -190,7 +189,6 @@ public class GeoBroker extends CordovaPlugin {
result = new PluginResult(PluginResult.Status.ERROR, backup);
}
result.setKeepCallback(keepCallback);
callbackContext.sendPluginResult(result);
}

View File

@@ -24,12 +24,11 @@ import java.io.InputStream;
import org.apache.cordova.api.CordovaInterface;
import org.apache.cordova.api.LOG;
import android.annotation.TargetApi;
import android.os.Build;
import android.content.res.AssetManager;
import android.net.Uri;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
@@ -43,20 +42,35 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String 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);
if(url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url)){
return generateWebResourceResponse(url);
} else {
return super.shouldInterceptRequest(view, url);
}
return ret;
}
private WebResourceResponse generateWebResourceResponse(String url) {
if (url.startsWith("file:///android_asset/")) {
String mimetype = FileHelper.getMimeType(url, cordova);
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";
}
try {
InputStream stream = FileHelper.getInputStreamFromUriString(url, cordova);
AssetManager assets = cordova.getActivity().getAssets();
Uri uri = Uri.parse(niceUrl);
InputStream stream = assets.open(uri.getPath(), AssetManager.ACCESS_STREAMING);
WebResourceResponse response = new WebResourceResponse(mimetype, "UTF-8", stream);
return response;
} catch (IOException e) {

View File

@@ -51,7 +51,6 @@ 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;
@@ -93,9 +92,12 @@ 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)) {
@@ -106,7 +108,6 @@ public class InAppBrowser extends CordovaPlugin {
Log.d(LOG_TAG, "target = " + target);
url = updateUrl(url);
String result = "";
// SELF
if (SELF.equals(target)) {
@@ -142,89 +143,41 @@ 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();
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
pluginResult.setKeepCallback(false);
this.callbackContext.sendPluginResult(pluginResult);
}
else if (action.equals("injectScriptCode")) {
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);
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);
}
else {
return false;
status = PluginResult.Status.INVALID_ACTION;
}
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
*
@@ -491,7 +444,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(thatWebView));
inAppWebView.setWebChromeClient(new InAppChromeClient());
WebViewClient client = new InAppBrowserClient(thatWebView, edittext);
inAppWebView.setWebViewClient(client);
WebSettings settings = inAppWebView.getSettings();
@@ -574,15 +527,8 @@ 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.
*
@@ -625,57 +571,6 @@ 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,10 +50,13 @@ public class NativeToJsMessageQueue {
// exec() is asynchronous. Set this to true when running bridge benchmarks.
static final boolean DISABLE_EXEC_CHAINING = false;
// 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
// 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
// to allow it to break up messages.
private static int MAX_PAYLOAD_SIZE = 50 * 1024 * 10240;
private static int MAX_PAYLOAD_SIZE = -1; //50 * 1024 * 10240;
/**
* The index into registeredListeners to treat as active.

View File

@@ -0,0 +1,177 @@
/*
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);
}
}