From b1f2c0cbef783ed721eb673c5239a90997c10669 Mon Sep 17 00:00:00 2001 From: davigonz Date: Fri, 15 Jun 2018 13:59:06 +0200 Subject: [PATCH] Implement upload progress --- .../lib/common/network/FileRequestBody.java | 89 +++++++++++++++---- .../lib/common/network/FileRequestEntity.java | 11 +-- .../OnDatatransferProgressListener.java | 4 +- .../network/ProgressiveDataTransferer.java | 1 - .../files/UploadRemoteFileOperation.java | 46 +++++----- 5 files changed, 99 insertions(+), 52 deletions(-) diff --git a/src/com/owncloud/android/lib/common/network/FileRequestBody.java b/src/com/owncloud/android/lib/common/network/FileRequestBody.java index d8e65acc..cd938562 100644 --- a/src/com/owncloud/android/lib/common/network/FileRequestBody.java +++ b/src/com/owncloud/android/lib/common/network/FileRequestBody.java @@ -1,26 +1,55 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2018 ownCloud GmbH. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + package com.owncloud.android.lib.common.network; -import android.util.Log; - import java.io.File; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; import okhttp3.MediaType; import okhttp3.RequestBody; -import okio.Buffer; import okio.BufferedSink; import okio.Okio; import okio.Source; -import static android.content.ContentValues.TAG; +/** + * A Request body that represents a file and include information about the progress when uploading it + * + * @author David González Verdugo + */ +public class FileRequestBody extends RequestBody implements ProgressiveDataTransferer { -public class FileRequestBody extends RequestBody { + private File mFile; + private MediaType mContentType; + Set mDataTransferListeners = new HashSet<>(); - MediaType mContentType; - File mFile; - - FileRequestBody(MediaType contentType, File file) { - mContentType = contentType; + public FileRequestBody(File file, MediaType contentType) { mFile = file; + mContentType = contentType; } @Override @@ -31,18 +60,46 @@ public class FileRequestBody extends RequestBody { @Override public void writeTo(BufferedSink sink) { Source source; + Iterator it; try { source = Okio.source(mFile); - //sink.writeAll(source); - Buffer buffer = new Buffer(); - Long remaining = contentLength(); + long transferred = 0; + long read; - for (long readCount; (readCount = source.read(buffer, 2048)) != -1;) { - sink.write(buffer, readCount); - Log.d(TAG, "source size: " + contentLength() + " remaining bytes: " + (remaining -= readCount)); + while ((read = source.read(sink.buffer(), 2048)) != -1) { + transferred += read; + sink.flush(); + synchronized (mDataTransferListeners) { + it = mDataTransferListeners.iterator(); + while (it.hasNext()) { + it.next().onTransferProgress(read, transferred, mFile.length(), mFile.getAbsolutePath()); + } + } } + } catch (Exception e) { e.printStackTrace(); } } + + @Override + public void addDatatransferProgressListener(OnDatatransferProgressListener listener) { + synchronized (mDataTransferListeners) { + mDataTransferListeners.add(listener); + } + } + + @Override + public void addDatatransferProgressListeners(Collection listeners) { + synchronized (mDataTransferListeners) { + mDataTransferListeners.addAll(listeners); + } + } + + @Override + public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) { + synchronized (mDataTransferListeners) { + mDataTransferListeners.remove(listener); + } + } } \ No newline at end of file diff --git a/src/com/owncloud/android/lib/common/network/FileRequestEntity.java b/src/com/owncloud/android/lib/common/network/FileRequestEntity.java index a7d6fd0e..3548dd5e 100644 --- a/src/com/owncloud/android/lib/common/network/FileRequestEntity.java +++ b/src/com/owncloud/android/lib/common/network/FileRequestEntity.java @@ -25,6 +25,8 @@ package com.owncloud.android.lib.common.network; +import org.apache.commons.httpclient.methods.RequestEntity; + import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -37,10 +39,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Set; -import org.apache.commons.httpclient.methods.RequestEntity; - -import com.owncloud.android.lib.common.utils.Log_OC; - /** @@ -51,7 +49,7 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer final File mFile; final String mContentType; - Set mDataTransferListeners = new HashSet(); + Set mDataTransferListeners = new HashSet<>(); public FileRequestEntity(final File file, final String contentType) { super(); @@ -162,5 +160,4 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer return mWrapped; } } - -} +} \ No newline at end of file diff --git a/src/com/owncloud/android/lib/common/network/OnDatatransferProgressListener.java b/src/com/owncloud/android/lib/common/network/OnDatatransferProgressListener.java index a36694cf..e78320cd 100644 --- a/src/com/owncloud/android/lib/common/network/OnDatatransferProgressListener.java +++ b/src/com/owncloud/android/lib/common/network/OnDatatransferProgressListener.java @@ -26,5 +26,5 @@ package com.owncloud.android.lib.common.network; public interface OnDatatransferProgressListener { - public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileAbsoluteName); -} + void onTransferProgress(long read, long transferred, long percent, String absolutePath); +} \ No newline at end of file diff --git a/src/com/owncloud/android/lib/common/network/ProgressiveDataTransferer.java b/src/com/owncloud/android/lib/common/network/ProgressiveDataTransferer.java index 2868ac8c..979e8082 100644 --- a/src/com/owncloud/android/lib/common/network/ProgressiveDataTransferer.java +++ b/src/com/owncloud/android/lib/common/network/ProgressiveDataTransferer.java @@ -27,7 +27,6 @@ package com.owncloud.android.lib.common.network; import java.util.Collection; - public interface ProgressiveDataTransferer { public void addDatatransferProgressListener (OnDatatransferProgressListener listener); diff --git a/src/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java index 72855cc0..635fbd17 100644 --- a/src/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java +++ b/src/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java @@ -27,20 +27,13 @@ package com.owncloud.android.lib.resources.files; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.http.HttpConstants; import com.owncloud.android.lib.common.http.HttpUtils; +import com.owncloud.android.lib.common.http.methods.webdav.PutMethod; import com.owncloud.android.lib.common.network.FileRequestBody; -import com.owncloud.android.lib.common.network.FileRequestEntity; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; -import com.owncloud.android.lib.common.network.ProgressiveDataTransferer; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.OperationCancelledException; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import com.owncloud.android.lib.common.http.methods.webdav.PutMethod; - -import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.methods.RequestEntity; -import org.apache.commons.httpclient.params.HttpMethodParams; import java.io.File; import java.io.IOException; @@ -49,6 +42,7 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import okhttp3.MediaType; +import okhttp3.MultipartBody; import okhttp3.RequestBody; import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK; @@ -75,7 +69,7 @@ public class UploadRemoteFileOperation extends RemoteOperation { protected final AtomicBoolean mCancellationRequested = new AtomicBoolean(false); protected Set mDataTransferListeners = new HashSet(); - protected RequestEntity mEntity = null; + protected FileRequestBody mFileRequestBody = null; public UploadRemoteFileOperation(String localPath, String remotePath, String mimeType, String fileLastModifTimestamp) { @@ -138,13 +132,15 @@ public class UploadRemoteFileOperation extends RemoteOperation { protected RemoteOperationResult uploadFile(OwnCloudClient client) throws IOException { RemoteOperationResult result; try { - // Headers File fileToUpload = new File(mLocalPath); - // TODO -// synchronized (mDataTransferListeners) { -// ((ProgressiveDataTransferer)mEntity) -// .addDatatransferProgressListeners(mDataTransferListeners); -// } + + MediaType mediaType = MediaType.parse(mMimeType); + + mFileRequestBody = new FileRequestBody(fileToUpload, mediaType); + + synchronized (mDataTransferListeners) { + mFileRequestBody.addDatatransferProgressListeners(mDataTransferListeners); + } if (mRequiredEtag != null && mRequiredEtag.length() > 0) { mPutMethod.addRequestHeader(HttpConstants.IF_MATCH_HEADER, "\"" + mRequiredEtag + "\""); @@ -154,12 +150,12 @@ public class UploadRemoteFileOperation extends RemoteOperation { mPutMethod.addRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER, mFileLastModifTimestamp); - // Request body - MediaType mediaType = MediaType.parse(mMimeType); + RequestBody requestBody = new MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addPart(mFileRequestBody) + .build(); - mPutMethod.setRequestBody( - FileRequestBody.create(mediaType, fileToUpload) - ); + mPutMethod.setRequestBody(requestBody); int status = client.executeHttpMethod(mPutMethod); @@ -170,8 +166,6 @@ public class UploadRemoteFileOperation extends RemoteOperation { result = new RemoteOperationResult(mPutMethod); } - client.exhaustResponse(mPutMethod.getResponseAsStream()); - } catch (Exception e) { result = new RemoteOperationResult(e); } @@ -186,8 +180,8 @@ public class UploadRemoteFileOperation extends RemoteOperation { synchronized (mDataTransferListeners) { mDataTransferListeners.add(listener); } - if (mEntity != null) { - ((ProgressiveDataTransferer)mEntity).addDatatransferProgressListener(listener); + if (mFileRequestBody != null) { + mFileRequestBody.addDatatransferProgressListener(listener); } } @@ -195,8 +189,8 @@ public class UploadRemoteFileOperation extends RemoteOperation { synchronized (mDataTransferListeners) { mDataTransferListeners.remove(listener); } - if (mEntity != null) { - ((ProgressiveDataTransferer)mEntity).removeDatatransferProgressListener(listener); + if (mFileRequestBody != null) { + mFileRequestBody.removeDatatransferProgressListener(listener); } }