mirror of
https://github.com/apache/cordova-android.git
synced 2025-01-19 07:02:51 +08:00
Merge branch 'master' into 4.0.x (multipart PluginResult)
This commit is contained in:
commit
2af8daff1d
110
framework/assets/www/cordova.js
vendored
110
framework/assets/www/cordova.js
vendored
@ -1,5 +1,5 @@
|
||||
// Platform: android
|
||||
// 8ca0f3b2b87e0759c5236b91c80f18438544409c
|
||||
// 1fc2526faa6197e1637ecb48ebe0f876f008ba0f
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
@ -263,11 +263,7 @@ var cordova = {
|
||||
* Called by native code when returning successful result from an action.
|
||||
*/
|
||||
callbackSuccess: function(callbackId, args) {
|
||||
try {
|
||||
cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
|
||||
} catch (e) {
|
||||
console.log("Error in success callback: " + callbackId + " = "+e);
|
||||
}
|
||||
cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -276,30 +272,34 @@ var cordova = {
|
||||
callbackError: function(callbackId, args) {
|
||||
// TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
|
||||
// Derive success from status.
|
||||
try {
|
||||
cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
|
||||
} catch (e) {
|
||||
console.log("Error in error callback: " + callbackId + " = "+e);
|
||||
}
|
||||
cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by native code when returning the result from an action.
|
||||
*/
|
||||
callbackFromNative: function(callbackId, success, status, args, keepCallback) {
|
||||
var callback = cordova.callbacks[callbackId];
|
||||
if (callback) {
|
||||
if (success && status == cordova.callbackStatus.OK) {
|
||||
callback.success && callback.success.apply(null, args);
|
||||
} else if (!success) {
|
||||
callback.fail && callback.fail.apply(null, args);
|
||||
}
|
||||
callbackFromNative: function(callbackId, isSuccess, status, args, keepCallback) {
|
||||
try {
|
||||
var callback = cordova.callbacks[callbackId];
|
||||
if (callback) {
|
||||
if (isSuccess && status == cordova.callbackStatus.OK) {
|
||||
callback.success && callback.success.apply(null, args);
|
||||
} else {
|
||||
callback.fail && callback.fail.apply(null, args);
|
||||
}
|
||||
|
||||
// Clear callback if not expecting any more results
|
||||
if (!keepCallback) {
|
||||
delete cordova.callbacks[callbackId];
|
||||
// Clear callback if not expecting any more results
|
||||
if (!keepCallback) {
|
||||
delete cordova.callbacks[callbackId];
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
var msg = "Error in " + (isSuccess ? "Success" : "Error") + " callbackId: " + callbackId + " : " + err;
|
||||
console && console.log && console.log(msg);
|
||||
cordova.fireWindowEvent("cordovacallbackerror", { 'message': msg });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
addConstructor: function(func) {
|
||||
channel.onCordovaReady.subscribe(function() {
|
||||
@ -1013,6 +1013,42 @@ androidExec.setNativeToJsBridgeMode = function(mode) {
|
||||
}
|
||||
};
|
||||
|
||||
function buildPayload(payload, message) {
|
||||
var payloadKind = message.charAt(0);
|
||||
if (payloadKind == 's') {
|
||||
payload.push(message.slice(1));
|
||||
} else if (payloadKind == 't') {
|
||||
payload.push(true);
|
||||
} else if (payloadKind == 'f') {
|
||||
payload.push(false);
|
||||
} else if (payloadKind == 'N') {
|
||||
payload.push(null);
|
||||
} else if (payloadKind == 'n') {
|
||||
payload.push(+message.slice(1));
|
||||
} else if (payloadKind == 'A') {
|
||||
var data = message.slice(1);
|
||||
var bytes = window.atob(data);
|
||||
var arraybuffer = new Uint8Array(bytes.length);
|
||||
for (var i = 0; i < bytes.length; i++) {
|
||||
arraybuffer[i] = bytes.charCodeAt(i);
|
||||
}
|
||||
payload.push(arraybuffer.buffer);
|
||||
} else if (payloadKind == 'S') {
|
||||
payload.push(window.atob(message.slice(1)));
|
||||
} else if (payloadKind == 'M') {
|
||||
var multipartMessages = message.slice(1);
|
||||
while (multipartMessages !== "") {
|
||||
var spaceIdx = multipartMessages.indexOf(' ');
|
||||
var msgLen = +multipartMessages.slice(0, spaceIdx);
|
||||
var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen);
|
||||
multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1);
|
||||
buildPayload(payload, multipartMessage);
|
||||
}
|
||||
} else {
|
||||
payload.push(JSON.parse(message));
|
||||
}
|
||||
}
|
||||
|
||||
// Processes a single message, as encoded by NativeToJsMessageQueue.java.
|
||||
function processMessage(message) {
|
||||
try {
|
||||
@ -1026,32 +1062,10 @@ function processMessage(message) {
|
||||
var status = +message.slice(2, spaceIdx);
|
||||
var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
|
||||
var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
|
||||
var payloadKind = message.charAt(nextSpaceIdx + 1);
|
||||
var payload;
|
||||
if (payloadKind == 's') {
|
||||
payload = message.slice(nextSpaceIdx + 2);
|
||||
} else if (payloadKind == 't') {
|
||||
payload = true;
|
||||
} else if (payloadKind == 'f') {
|
||||
payload = false;
|
||||
} else if (payloadKind == 'N') {
|
||||
payload = null;
|
||||
} else if (payloadKind == 'n') {
|
||||
payload = +message.slice(nextSpaceIdx + 2);
|
||||
} else if (payloadKind == 'A') {
|
||||
var data = message.slice(nextSpaceIdx + 2);
|
||||
var bytes = window.atob(data);
|
||||
var arraybuffer = new Uint8Array(bytes.length);
|
||||
for (var i = 0; i < bytes.length; i++) {
|
||||
arraybuffer[i] = bytes.charCodeAt(i);
|
||||
}
|
||||
payload = arraybuffer.buffer;
|
||||
} else if (payloadKind == 'S') {
|
||||
payload = window.atob(message.slice(nextSpaceIdx + 2));
|
||||
} else {
|
||||
payload = JSON.parse(message.slice(nextSpaceIdx + 1));
|
||||
}
|
||||
cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
|
||||
var payloadMessage = message.slice(nextSpaceIdx + 1);
|
||||
var payload = [];
|
||||
buildPayload(payload, payloadMessage);
|
||||
cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
|
||||
} else {
|
||||
console.log("processMessage failed: invalid message: " + JSON.stringify(message));
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ public class NativeToJsMessageQueue {
|
||||
|
||||
// Set this to true to force plugin results to be encoding as
|
||||
// JS instead of the custom format (useful for benchmarking).
|
||||
// Doesn't work for multipart messages.
|
||||
private static final boolean FORCE_ENCODE_USING_EVAL = false;
|
||||
|
||||
// Disable sending back native->JS messages during an exec() when the active
|
||||
@ -419,53 +420,43 @@ public class NativeToJsMessageQueue {
|
||||
this.pluginResult = pluginResult;
|
||||
}
|
||||
|
||||
static int calculateEncodedLengthHelper(PluginResult pluginResult) {
|
||||
switch (pluginResult.getMessageType()) {
|
||||
case PluginResult.MESSAGE_TYPE_BOOLEAN: // f or t
|
||||
case PluginResult.MESSAGE_TYPE_NULL: // N
|
||||
return 1;
|
||||
case PluginResult.MESSAGE_TYPE_NUMBER: // n
|
||||
return 1 + pluginResult.getMessage().length();
|
||||
case PluginResult.MESSAGE_TYPE_STRING: // s
|
||||
return 1 + pluginResult.getStrMessage().length();
|
||||
case PluginResult.MESSAGE_TYPE_BINARYSTRING:
|
||||
return 1 + pluginResult.getMessage().length();
|
||||
case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
|
||||
return 1 + pluginResult.getMessage().length();
|
||||
case PluginResult.MESSAGE_TYPE_MULTIPART:
|
||||
int ret = 1;
|
||||
for (int i = 0; i < pluginResult.getMultipartMessagesSize(); i++) {
|
||||
int length = calculateEncodedLengthHelper(pluginResult.getMultipartMessage(i));
|
||||
int argLength = String.valueOf(length).length();
|
||||
ret += argLength + 1 + length;
|
||||
}
|
||||
return ret;
|
||||
case PluginResult.MESSAGE_TYPE_JSON:
|
||||
default:
|
||||
return pluginResult.getMessage().length();
|
||||
}
|
||||
}
|
||||
|
||||
int calculateEncodedLength() {
|
||||
if (pluginResult == null) {
|
||||
return jsPayloadOrCallbackId.length() + 1;
|
||||
}
|
||||
int statusLen = String.valueOf(pluginResult.getStatus()).length();
|
||||
int ret = 2 + statusLen + 1 + jsPayloadOrCallbackId.length() + 1;
|
||||
switch (pluginResult.getMessageType()) {
|
||||
case PluginResult.MESSAGE_TYPE_BOOLEAN: // f or t
|
||||
case PluginResult.MESSAGE_TYPE_NULL: // N
|
||||
ret += 1;
|
||||
break;
|
||||
case PluginResult.MESSAGE_TYPE_NUMBER: // n
|
||||
ret += 1 + pluginResult.getMessage().length();
|
||||
break;
|
||||
case PluginResult.MESSAGE_TYPE_STRING: // s
|
||||
ret += 1 + pluginResult.getStrMessage().length();
|
||||
break;
|
||||
case PluginResult.MESSAGE_TYPE_BINARYSTRING:
|
||||
ret += 1 + pluginResult.getMessage().length();
|
||||
break;
|
||||
case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
|
||||
ret += 1 + pluginResult.getMessage().length();
|
||||
break;
|
||||
case PluginResult.MESSAGE_TYPE_JSON:
|
||||
default:
|
||||
ret += pluginResult.getMessage().length();
|
||||
return ret + calculateEncodedLengthHelper(pluginResult);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void encodeAsMessage(StringBuilder sb) {
|
||||
if (pluginResult == null) {
|
||||
sb.append('J')
|
||||
.append(jsPayloadOrCallbackId);
|
||||
return;
|
||||
}
|
||||
int status = pluginResult.getStatus();
|
||||
boolean noResult = status == PluginResult.Status.NO_RESULT.ordinal();
|
||||
boolean resultOk = status == PluginResult.Status.OK.ordinal();
|
||||
boolean keepCallback = pluginResult.getKeepCallback();
|
||||
|
||||
sb.append((noResult || resultOk) ? 'S' : 'F')
|
||||
.append(keepCallback ? '1' : '0')
|
||||
.append(status)
|
||||
.append(' ')
|
||||
.append(jsPayloadOrCallbackId)
|
||||
.append(' ');
|
||||
static void encodeAsMessageHelper(StringBuilder sb, PluginResult pluginResult) {
|
||||
switch (pluginResult.getMessageType()) {
|
||||
case PluginResult.MESSAGE_TYPE_BOOLEAN:
|
||||
sb.append(pluginResult.getMessage().charAt(0)); // t or f.
|
||||
@ -489,12 +480,42 @@ public class NativeToJsMessageQueue {
|
||||
sb.append('A');
|
||||
sb.append(pluginResult.getMessage());
|
||||
break;
|
||||
case PluginResult.MESSAGE_TYPE_MULTIPART:
|
||||
sb.append('M');
|
||||
for (int i = 0; i < pluginResult.getMultipartMessagesSize(); i++) {
|
||||
PluginResult multipartMessage = pluginResult.getMultipartMessage(i);
|
||||
sb.append(String.valueOf(calculateEncodedLengthHelper(multipartMessage)));
|
||||
sb.append(' ');
|
||||
encodeAsMessageHelper(sb, multipartMessage);
|
||||
}
|
||||
break;
|
||||
case PluginResult.MESSAGE_TYPE_JSON:
|
||||
default:
|
||||
sb.append(pluginResult.getMessage()); // [ or {
|
||||
}
|
||||
}
|
||||
|
||||
void encodeAsMessage(StringBuilder sb) {
|
||||
if (pluginResult == null) {
|
||||
sb.append('J')
|
||||
.append(jsPayloadOrCallbackId);
|
||||
return;
|
||||
}
|
||||
int status = pluginResult.getStatus();
|
||||
boolean noResult = status == PluginResult.Status.NO_RESULT.ordinal();
|
||||
boolean resultOk = status == PluginResult.Status.OK.ordinal();
|
||||
boolean keepCallback = pluginResult.getKeepCallback();
|
||||
|
||||
sb.append((noResult || resultOk) ? 'S' : 'F')
|
||||
.append(keepCallback ? '1' : '0')
|
||||
.append(status)
|
||||
.append(' ')
|
||||
.append(jsPayloadOrCallbackId)
|
||||
.append(' ');
|
||||
|
||||
encodeAsMessageHelper(sb, pluginResult);
|
||||
}
|
||||
|
||||
void encodeAsJsMessage(StringBuilder sb) {
|
||||
if (pluginResult == null) {
|
||||
sb.append(jsPayloadOrCallbackId);
|
||||
|
19
framework/src/org/apache/cordova/PluginResult.java
Executable file → Normal file
19
framework/src/org/apache/cordova/PluginResult.java
Executable file → Normal file
@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.apache.cordova;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@ -29,6 +31,7 @@ public class PluginResult {
|
||||
private boolean keepCallback = false;
|
||||
private String strMessage;
|
||||
private String encodedMessage;
|
||||
private List<PluginResult> multipartMessages;
|
||||
|
||||
public PluginResult(Status status) {
|
||||
this(status, PluginResult.StatusMessages[status.ordinal()]);
|
||||
@ -80,6 +83,13 @@ public class PluginResult {
|
||||
this.encodedMessage = Base64.encodeToString(data, Base64.NO_WRAP);
|
||||
}
|
||||
|
||||
// The keepCallback and status of multipartMessages are ignored.
|
||||
public PluginResult(Status status, List<PluginResult> multipartMessages) {
|
||||
this.status = status.ordinal();
|
||||
this.messageType = MESSAGE_TYPE_MULTIPART;
|
||||
this.multipartMessages = multipartMessages;
|
||||
}
|
||||
|
||||
public void setKeepCallback(boolean b) {
|
||||
this.keepCallback = b;
|
||||
}
|
||||
@ -99,6 +109,14 @@ public class PluginResult {
|
||||
return encodedMessage;
|
||||
}
|
||||
|
||||
public int getMultipartMessagesSize() {
|
||||
return multipartMessages.size();
|
||||
}
|
||||
|
||||
public PluginResult getMultipartMessage(int index) {
|
||||
return multipartMessages.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* If messageType == MESSAGE_TYPE_STRING, then returns the message string.
|
||||
* Otherwise, returns null.
|
||||
@ -150,6 +168,7 @@ public class PluginResult {
|
||||
// Use BINARYSTRING when your string may contain null characters.
|
||||
// This is required to work around a bug in the platform :(.
|
||||
public static final int MESSAGE_TYPE_BINARYSTRING = 7;
|
||||
public static final int MESSAGE_TYPE_MULTIPART = 8;
|
||||
|
||||
public static String[] StatusMessages = new String[] {
|
||||
"No result",
|
||||
|
Loading…
Reference in New Issue
Block a user