You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2012/09/21 05:41:56 UTC
[3/3] android commit: Add progress callbacks,
abort for FileTransfer.upload and FileTransfer.download
Add progress callbacks, abort for FileTransfer.upload and FileTransfer.download
Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/commit/610e0c98
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/tree/610e0c98
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/diff/610e0c98
Branch: refs/heads/master
Commit: 610e0c984a9cb9c6e202a0f6e2a711f8e326d9d6
Parents: 3688fca
Author: Brion Vibber <br...@pobox.com>
Authored: Sun Aug 26 16:07:17 2012 -0700
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Thu Sep 20 21:53:30 2012 -0400
----------------------------------------------------------------------
.../src/org/apache/cordova/FileProgressResult.java | 63 ++++++++
framework/src/org/apache/cordova/FileTransfer.java | 112 +++++++++++++--
.../src/org/apache/cordova/FileUploadResult.java | 12 ++-
3 files changed, 171 insertions(+), 16 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/610e0c98/framework/src/org/apache/cordova/FileProgressResult.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileProgressResult.java b/framework/src/org/apache/cordova/FileProgressResult.java
new file mode 100644
index 0000000..d981175
--- /dev/null
+++ b/framework/src/org/apache/cordova/FileProgressResult.java
@@ -0,0 +1,63 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+package org.apache.cordova;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Encapsulates in-progress status of uploading or downloading a file to a remote server.
+ */
+public class FileProgressResult {
+
+ private boolean lengthComputable = false; // declares whether total is known
+ private long loaded = 0; // bytes sent so far
+ private long total = 0; // bytes total, if known
+
+ public boolean getLengthComputable() {
+ return lengthComputable;
+ }
+
+ public void setLengthComputable(boolean computable) {
+ this.lengthComputable = computable;
+ }
+
+ public long getLoaded() {
+ return loaded;
+ }
+
+ public void setLoaded(long bytes) {
+ this.loaded = bytes;
+ }
+
+ public long getTotal() {
+ return total;
+ }
+
+ public void setTotal(long bytes) {
+ this.total = bytes;
+ }
+
+ public JSONObject toJSONObject() throws JSONException {
+ return new JSONObject(
+ "{loaded:" + loaded +
+ ",total:" + total +
+ ",lengthComputable:" + (lengthComputable ? "true" : "false") + "}");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/610e0c98/framework/src/org/apache/cordova/FileTransfer.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileTransfer.java b/framework/src/org/apache/cordova/FileTransfer.java
index 881caa5..ebce784 100644
--- a/framework/src/org/apache/cordova/FileTransfer.java
+++ b/framework/src/org/apache/cordova/FileTransfer.java
@@ -32,6 +32,7 @@ import java.net.URL;
import java.net.URLDecoder;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.util.HashSet;
import java.util.Iterator;
import javax.net.ssl.HostnameVerifier;
@@ -63,29 +64,44 @@ public class FileTransfer extends Plugin {
public static int FILE_NOT_FOUND_ERR = 1;
public static int INVALID_URL_ERR = 2;
public static int CONNECTION_ERR = 3;
+ public static int ABORTED_ERR = 4;
+
+ private static HashSet abortTriggered = new HashSet();
private SSLSocketFactory defaultSSLSocketFactory = null;
private HostnameVerifier defaultHostnameVerifier = null;
+ static class AbortException extends Exception {
+ public AbortException(String str) {
+ super(str);
+ }
+ }
+
/* (non-Javadoc)
* @see org.apache.cordova.api.Plugin#execute(java.lang.String, org.json.JSONArray, java.lang.String)
*/
@Override
public PluginResult execute(String action, JSONArray args, String callbackId) {
- String source = null;
- String target = null;
- try {
- source = args.getString(0);
- target = args.getString(1);
- } catch (JSONException e) {
- Log.d(LOG_TAG, "Missing source or target");
- return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Missing source or target");
- }
+ if (action.equals("upload") || action.equals("download")) {
+ String source = null;
+ String target = null;
+ try {
+ source = args.getString(0);
+ target = args.getString(1);
+ } catch (JSONException e) {
+ Log.d(LOG_TAG, "Missing source or target");
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Missing source or target");
+ }
- if (action.equals("upload")) {
- return upload(URLDecoder.decode(source), target, args);
- } else if (action.equals("download")) {
- return download(source, target, args.optBoolean(2));
+ if (action.equals("upload")) {
+ return upload(URLDecoder.decode(source), target, args, callbackId);
+ } else if (action.equals("download")) {
+ String objectId = args.getString(2);
+ boolean trustEveryone = args.optBoolean(3);
+ return download(source, target, trustEveryone, objectId, callbackId);
+ }
+ } else if (action.equals("abort")) {
+ return abort(args);
} else {
return new PluginResult(PluginResult.Status.INVALID_ACTION);
}
@@ -96,6 +112,7 @@ public class FileTransfer extends Plugin {
* @param source Full path of the file on the file system
* @param target URL of the server to receive the file
* @param args JSON Array of args
+ * @param callbackId callback id for optional progress reports
*
* args[2] fileKey Name of file request parameter
* args[3] fileName File name to be used on server
@@ -103,7 +120,7 @@ public class FileTransfer extends Plugin {
* args[5] params key:value pairs of user-defined parameters
* @return FileUploadResult containing result of upload request
*/
- private PluginResult upload(String source, String target, JSONArray args) {
+ private PluginResult upload(String source, String target, JSONArray args, String callbackId) {
Log.d(LOG_TAG, "upload " + source + " to " + target);
HttpURLConnection conn = null;
@@ -121,6 +138,7 @@ public class FileTransfer extends Plugin {
if (headers == null && params != null) {
headers = params.optJSONObject("headers");
}
+ String objectId = args.getString(9);
Log.d(LOG_TAG, "fileKey: " + fileKey);
Log.d(LOG_TAG, "fileName: " + fileName);
@@ -129,9 +147,11 @@ public class FileTransfer extends Plugin {
Log.d(LOG_TAG, "trustEveryone: " + trustEveryone);
Log.d(LOG_TAG, "chunkedMode: " + chunkedMode);
Log.d(LOG_TAG, "headers: " + headers);
+ Log.d(LOG_TAG, "objectId: " + objectId);
// Create return object
FileUploadResult result = new FileUploadResult();
+ FileProgressResult progress = new FileProgressResult();
// Get a input stream of the file on the phone
FileInputStream fileInputStream = (FileInputStream) getPathFromUri(source);
@@ -285,6 +305,21 @@ public class FileTransfer extends Plugin {
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
+ if (objectId != null) {
+ // Only send progress callbacks if the JS code sent us an object ID,
+ // so we don't spam old versions with unrecognized callbacks.
+ Log.d(LOG_TAG, "****** About to send a progress result from upload");
+ progress.setLoaded(totalBytes);
+ PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
+ progressResult.setKeepCallback(true);
+ success(progressResult, callbackId);
+ }
+ synchronized (abortTriggered) {
+ if (objectId != null && abortTriggered.contains(objectId)) {
+ abortTriggered.remove(objectId);
+ throw new AbortException("upload aborted");
+ }
+ }
}
// send multipart form data necessary after file data...
@@ -342,6 +377,10 @@ public class FileTransfer extends Plugin {
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+ } catch (AbortException e) {
+ JSONObject error = createFileTransferError(ABORTED_ERR, source, target, conn);
+ Log.e(LOG_TAG, error.toString(), e);
+ return new PluginResult(PluginResult.Status.ERROR, error);
} catch (Throwable t) {
// Shouldn't happen, but will
JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
@@ -459,7 +498,7 @@ public class FileTransfer extends Plugin {
* @param target Full path of the file on the file system
* @return JSONObject the downloaded file
*/
- private PluginResult download(String source, String target, boolean trustEveryone) {
+ private PluginResult download(String source, String target, boolean trustEveryone, String objectId, String callbackId) {
Log.d(LOG_TAG, "download " + source + " to " + target);
HttpURLConnection connection = null;
@@ -523,12 +562,36 @@ public class FileTransfer extends Plugin {
byte[] buffer = new byte[1024];
int bytesRead = 0;
+ long totalBytes = 0;
+ FileProgressResult progress = new FileProgressResult();
+
+ if (connection.getContentEncoding() == null) {
+ // Only trust content-length header if no gzip etc
+ progress.setLengthComputable(true);
+ progress.setTotal(connection.getContentLength());
+ }
FileOutputStream outputStream = new FileOutputStream(file);
// write bytes to file
while ((bytesRead = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, bytesRead);
+ totalBytes += bytesRead;
+ if (objectId != null) {
+ // Only send progress callbacks if the JS code sent us an object ID,
+ // so we don't spam old versions with unrecognized callbacks.
+ Log.d(LOG_TAG, "****** About to send a progress result from download");
+ progress.setLoaded(totalBytes);
+ PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
+ progressResult.setKeepCallback(true);
+ success(progressResult, callbackId);
+ }
+ synchronized (abortTriggered) {
+ if (objectId != null && abortTriggered.contains(objectId)) {
+ abortTriggered.remove(objectId);
+ throw new AbortException("download aborted");
+ }
+ }
}
outputStream.close();
@@ -621,4 +684,23 @@ public class FileTransfer extends Plugin {
return file;
}
+
+ /**
+ * Abort an ongoing upload or download.
+ *
+ * @param args args
+ */
+ private PluginResult abort(JSONArray args) {
+ String objectId;
+ try {
+ objectId = args.getString(0);
+ } catch (JSONException e) {
+ Log.d(LOG_TAG, "Missing objectId");
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Missing objectId");
+ }
+ synchronized (abortTriggered) {
+ abortTriggered.add(objectId);
+ }
+ return new PluginResult(PluginResult.Status.OK);
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/610e0c98/framework/src/org/apache/cordova/FileUploadResult.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileUploadResult.java b/framework/src/org/apache/cordova/FileUploadResult.java
index 36fae93..b556869 100644
--- a/framework/src/org/apache/cordova/FileUploadResult.java
+++ b/framework/src/org/apache/cordova/FileUploadResult.java
@@ -29,6 +29,7 @@ public class FileUploadResult {
private long bytesSent = 0; // bytes sent
private int responseCode = -1; // HTTP response code
private String response = null; // HTTP response
+ private String objectId = null; // FileTransfer object id
public long getBytesSent() {
return bytesSent;
@@ -54,10 +55,19 @@ public class FileUploadResult {
this.response = response;
}
+ public String getObjectId() {
+ return objectId;
+ }
+
+ public void setObjectId(String objectId) {
+ this.objectId = objectId;
+ }
+
public JSONObject toJSONObject() throws JSONException {
return new JSONObject(
"{bytesSent:" + bytesSent +
",responseCode:" + responseCode +
- ",response:" + JSONObject.quote(response) + "}");
+ ",response:" + JSONObject.quote(response) +
+ ",objectId:" + JSONObject.quote(objectId) + "}");
}
}