1
0
mirror of https://github.com/owncloud/android-library.git synced 2025-06-08 00:16:09 +00:00

Merge pull request #112 from owncloud/reliable_uploads_actions_uploads_view

Update to support changes for uploads view in OC app
This commit is contained in:
David A. Velasco 2016-03-30 13:45:23 +02:00
commit 39e3ddaa07
6 changed files with 101 additions and 25 deletions

View File

@ -25,6 +25,7 @@
package com.owncloud.android.lib.common.network; package com.owncloud.android.lib.common.network;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -58,7 +59,9 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres
Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>(); Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
private ByteBuffer mBuffer = ByteBuffer.allocate(4096); private ByteBuffer mBuffer = ByteBuffer.allocate(4096);
public ChunkFromFileChannelRequestEntity(final FileChannel channel, final String contentType, long chunkSize, final File file) { public ChunkFromFileChannelRequestEntity(
final FileChannel channel, final String contentType, long chunkSize, final File file
) {
super(); super();
if (channel == null) { if (channel == null) {
throw new IllegalArgumentException("File may not be null"); throw new IllegalArgumentException("File may not be null");
@ -120,14 +123,19 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres
int readCount = 0; int readCount = 0;
Iterator<OnDatatransferProgressListener> it = null; Iterator<OnDatatransferProgressListener> it = null;
try { try {
mChannel.position(mOffset); mChannel.position(mOffset);
long size = mFile.length(); long size = mFile.length();
if (size == 0) size = -1; if (size == 0) size = -1;
long maxCount = Math.min(mOffset + mChunkSize, mChannel.size()); long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
while (mChannel.position() < maxCount) { while (mChannel.position() < maxCount) {
readCount = mChannel.read(mBuffer); readCount = mChannel.read(mBuffer);
out.write(mBuffer.array(), 0, readCount); try {
out.write(mBuffer.array(), 0, readCount);
} catch (IOException io) {
// work-around try catch to filter exception in writing
throw new FileRequestEntity.WriteException(io);
}
mBuffer.clear(); mBuffer.clear();
if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
mTransferred += readCount; mTransferred += readCount;
@ -141,10 +149,19 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres
} }
} catch (IOException io) { } catch (IOException io) {
Log_OC.e(TAG, io.getMessage()); // any read problem will be handled as if the file is not there
throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io); if (io instanceof FileNotFoundException) {
throw io;
} else {
FileNotFoundException fnf = new FileNotFoundException("Exception reading source file");
fnf.initCause(io);
throw fnf;
}
} catch (FileRequestEntity.WriteException we) {
throw we.getWrapped();
} }
} }
} }

View File

@ -26,6 +26,7 @@
package com.owncloud.android.lib.common.network; package com.owncloud.android.lib.common.network;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
@ -100,12 +101,9 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer
@Override @Override
public void writeRequest(final OutputStream out) throws IOException { public void writeRequest(final OutputStream out) throws IOException {
//byte[] tmp = new byte[4096];
ByteBuffer tmp = ByteBuffer.allocate(4096); ByteBuffer tmp = ByteBuffer.allocate(4096);
int readResult = 0; int readResult = 0;
// TODO(bprzybylski): each mem allocation can throw OutOfMemoryError we need to handle it
// globally in some fashionable manner
RandomAccessFile raf = new RandomAccessFile(mFile, "r"); RandomAccessFile raf = new RandomAccessFile(mFile, "r");
FileChannel channel = raf.getChannel(); FileChannel channel = raf.getChannel();
Iterator<OnDatatransferProgressListener> it = null; Iterator<OnDatatransferProgressListener> it = null;
@ -114,7 +112,12 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer
if (size == 0) size = -1; if (size == 0) size = -1;
try { try {
while ((readResult = channel.read(tmp)) >= 0) { while ((readResult = channel.read(tmp)) >= 0) {
out.write(tmp.array(), 0, readResult); try {
out.write(tmp.array(), 0, readResult);
} catch (IOException io) {
// work-around try catch to filter exception in writing
throw new WriteException(io);
}
tmp.clear(); tmp.clear();
transferred += readResult; transferred += readResult;
synchronized (mDataTransferListeners) { synchronized (mDataTransferListeners) {
@ -126,12 +129,37 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer
} }
} catch (IOException io) { } catch (IOException io) {
Log_OC.e("FileRequestException", io.getMessage()); // any read problem will be handled as if the file is not there
throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io); if (io instanceof FileNotFoundException) {
throw io;
} else {
FileNotFoundException fnf = new FileNotFoundException("Exception reading source file");
fnf.initCause(io);
throw fnf;
}
} catch (WriteException we) {
throw we.getWrapped();
} finally { } finally {
channel.close(); try {
raf.close(); channel.close();
raf.close();
} catch (IOException io) {
// ignore failures closing source file
}
}
}
protected static class WriteException extends Exception {
IOException mWrapped;
WriteException(IOException wrapped) {
mWrapped = wrapped;
}
public IOException getWrapped() {
return mWrapped;
} }
} }

View File

@ -307,7 +307,8 @@ public abstract class RemoteOperation implements Runnable {
* to trigger authentication update */ * to trigger authentication update */
if (mCallerActivity != null && mAccount != null && mContext != null && if (mCallerActivity != null && mAccount != null && mContext != null &&
!result.isSuccess() && !result.isSuccess() &&
(result.getCode() == ResultCode.UNAUTHORIZED || result.isIdPRedirection())) { ResultCode.UNAUTHORIZED.equals(result.getCode())
) {
/// possible fail due to lack of authorization /// possible fail due to lack of authorization
// in an operation performed in foreground // in an operation performed in foreground
OwnCloudCredentials cred = mClient.getCredentials(); OwnCloudCredentials cred = mClient.getCredentials();

View File

@ -25,6 +25,7 @@
package com.owncloud.android.lib.common.operations; package com.owncloud.android.lib.common.operations;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Serializable; import java.io.Serializable;
@ -108,7 +109,10 @@ public class RemoteOperationResult implements Serializable {
PARTIAL_MOVE_DONE, PARTIAL_MOVE_DONE,
PARTIAL_COPY_DONE, PARTIAL_COPY_DONE,
SHARE_WRONG_PARAMETER, SHARE_WRONG_PARAMETER,
WRONG_SERVER_RESPONSE, INVALID_CHARACTER_DETECT_IN_SERVER WRONG_SERVER_RESPONSE,
INVALID_CHARACTER_DETECT_IN_SERVER,
DELAYED_FOR_WIFI,
LOCAL_FILE_NOT_FOUND
} }
private boolean mSuccess = false; private boolean mSuccess = false;
@ -180,6 +184,9 @@ public class RemoteOperationResult implements Serializable {
} }
} }
} }
if (isIdPRedirection()) {
mCode = ResultCode.UNAUTHORIZED; // overrides default ResultCode.UNKNOWN
}
} }
public RemoteOperationResult(boolean success, String bodyResponse, int httpCode) { public RemoteOperationResult(boolean success, String bodyResponse, int httpCode) {
@ -254,6 +261,9 @@ public class RemoteOperationResult implements Serializable {
mCode = ResultCode.SSL_ERROR; mCode = ResultCode.SSL_ERROR;
} }
} else if (e instanceof FileNotFoundException) {
mCode = ResultCode.LOCAL_FILE_NOT_FOUND;
} else { } else {
mCode = ResultCode.UNKNOWN_ERROR; mCode = ResultCode.UNKNOWN_ERROR;
} }

View File

@ -32,9 +32,11 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.params.HttpMethodParams;
import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.FileRequestEntity; import com.owncloud.android.lib.common.network.FileRequestEntity;
@ -87,8 +89,16 @@ public class UploadRemoteFileOperation extends RemoteOperation {
@Override @Override
protected RemoteOperationResult run(OwnCloudClient client) { protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null; RemoteOperationResult result = null;
DefaultHttpMethodRetryHandler oldRetryHandler =
(DefaultHttpMethodRetryHandler) client.getParams().getParameter(HttpMethodParams.RETRY_HANDLER);
try { try {
// prevent that uploads are retried automatically by network library
client.getParams().setParameter(
HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler(0, false)
);
mPutMethod = new PutMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath)); mPutMethod = new PutMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath));
if (mCancellationRequested.get()) { if (mCancellationRequested.get()) {
@ -114,6 +124,12 @@ public class UploadRemoteFileOperation extends RemoteOperation {
} else { } else {
result = new RemoteOperationResult(e); result = new RemoteOperationResult(e);
} }
} finally {
// reset previous retry handler
client.getParams().setParameter(
HttpMethodParams.RETRY_HANDLER,
oldRetryHandler
);
} }
return result; return result;
} }

View File

@ -37,6 +37,8 @@ public class OwnCloudVersion implements Comparable<OwnCloudVersion> {
public static final OwnCloudVersion owncloud_v4_5 = new OwnCloudVersion( public static final OwnCloudVersion owncloud_v4_5 = new OwnCloudVersion(
0x04050000); 0x04050000);
public static final int MINIMUN_VERSION_FOR_CHUNKED_UPLOADS = 0x04050000; // 4.5
public static final int MINIMUM_VERSION_FOR_SHARING_API = 0x05001B00; // 5.0.27 public static final int MINIMUM_VERSION_FOR_SHARING_API = 0x05001B00; // 5.0.27
public static final int MINIMUM_VERSION_WITH_FORBIDDEN_CHARS = 0x08010000; // 8.1 public static final int MINIMUM_VERSION_WITH_FORBIDDEN_CHARS = 0x08010000; // 8.1
@ -127,6 +129,10 @@ public class OwnCloudVersion implements Comparable<OwnCloudVersion> {
} }
public boolean isChunkedUploadSupported() {
return (mVersion >= MINIMUN_VERSION_FOR_CHUNKED_UPLOADS);
}
public boolean isSharedSupported() { public boolean isSharedSupported() {
return (mVersion >= MINIMUM_VERSION_FOR_SHARING_API); return (mVersion >= MINIMUM_VERSION_FOR_SHARING_API);
} }
@ -150,6 +156,4 @@ public class OwnCloudVersion implements Comparable<OwnCloudVersion> {
public boolean isVersionWithCapabilitiesAPI(){ public boolean isVersionWithCapabilitiesAPI(){
return (mVersion>= MINIMUM_VERSION_CAPABILITIES_API); return (mVersion>= MINIMUM_VERSION_CAPABILITIES_API);
} }
} }