From 78fa89302709875e43f08a1a860512761bf661b9 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 10 Jul 2014 14:05:10 +0200 Subject: [PATCH 01/23] Accept 200 as a valid response for PROPFIND --- .../lib/resources/files/ReadRemoteFileOperation.java | 7 +++++-- .../lib/resources/files/ReadRemoteFolderOperation.java | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java index 347e7395..5b997829 100644 --- a/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java +++ b/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java @@ -82,8 +82,11 @@ public class ReadRemoteFileOperation extends RemoteOperation { int status; status = client.executeMethod(propfind, SYNC_READ_TIMEOUT, SYNC_CONNECTION_TIMEOUT); - boolean isMultiStatus = status == HttpStatus.SC_MULTI_STATUS; - if (isMultiStatus) { + boolean isSuccess = ( + status == HttpStatus.SC_MULTI_STATUS || + status == HttpStatus.SC_OK + ); + if (isSuccess) { // Parse response MultiStatus resp = propfind.getResponseBodyAsMultiStatus(); WebdavEntry we = new WebdavEntry(resp.getResponses()[0], client.getWebdavUri().getPath()); diff --git a/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java b/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java index 922b7c9f..e1d79b0f 100644 --- a/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java +++ b/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java @@ -80,7 +80,11 @@ public class ReadRemoteFolderOperation extends RemoteOperation { int status = client.executeMethod(query); // check and process response - if (isMultiStatus(status)) { + boolean isSuccess = ( + status == HttpStatus.SC_MULTI_STATUS || + status == HttpStatus.SC_OK + ); + if (isSuccess) { // get data from remote folder MultiStatus dataInServer = query.getResponseBodyAsMultiStatus(); readData(dataInServer, client); From 0862c66b7d1fbb822e51bb94bf7ea77ce427967a Mon Sep 17 00:00:00 2001 From: jabarros Date: Thu, 10 Jul 2014 16:31:32 +0200 Subject: [PATCH 02/23] Update RemoteOperation.ResultCode to include enum value for FORBIDDEN results --- .../lib/common/operations/RemoteOperationResult.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index e8b0be88..54f47a55 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -41,13 +41,13 @@ import org.apache.commons.httpclient.HttpStatus; import org.apache.jackrabbit.webdav.DavException; import org.json.JSONException; -import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; -import com.owncloud.android.lib.common.network.CertificateCombinedException; - import android.accounts.Account; import android.accounts.AccountsException; import android.util.Log; +import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; +import com.owncloud.android.lib.common.network.CertificateCombinedException; + /** * The result of a remote operation required to an ownCloud server. @@ -98,7 +98,8 @@ public class RemoteOperationResult implements Serializable { ACCOUNT_NOT_THE_SAME, INVALID_CHARACTER_IN_NAME, SHARE_NOT_FOUND, - LOCAL_STORAGE_NOT_REMOVED + LOCAL_STORAGE_NOT_REMOVED, + FORBIDDEN } private boolean mSuccess = false; @@ -140,6 +141,9 @@ public class RemoteOperationResult implements Serializable { case HttpStatus.SC_INSUFFICIENT_STORAGE: mCode = ResultCode.QUOTA_EXCEEDED; break; + case HttpStatus.SC_FORBIDDEN: + mCode = ResultCode.FORBIDDEN; + break; default: mCode = ResultCode.UNHANDLED_HTTP_CODE; Log.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " + httpCode); From 7636d9e0373bafd63dfd79c032ef927d87d0872e Mon Sep 17 00:00:00 2001 From: jabarros Date: Thu, 10 Jul 2014 17:29:43 +0200 Subject: [PATCH 03/23] Update ErrorMessageAdapter class to generate appropiate error messages for operations failed due to lack of permissions (ResultCode.FORBIDDEN) --- .../android/lib/common/operations/RemoteOperationResult.java | 3 ++- .../lib/resources/shares/CreateRemoteShareOperation.java | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 54f47a55..3b6b99a4 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -99,7 +99,8 @@ public class RemoteOperationResult implements Serializable { INVALID_CHARACTER_IN_NAME, SHARE_NOT_FOUND, LOCAL_STORAGE_NOT_REMOVED, - FORBIDDEN + FORBIDDEN, + SHARE_FORBIDDEN } private boolean mSuccess = false; diff --git a/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java b/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java index 67a1ba51..55b5b7db 100644 --- a/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java +++ b/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java @@ -142,6 +142,9 @@ public class CreateRemoteShareOperation extends RemoteOperation { } else if (xmlParser.isFileNotFound()){ result = new RemoteOperationResult(ResultCode.SHARE_NOT_FOUND); + } else if (xmlParser.isFailure()) { + result = new RemoteOperationResult(ResultCode.SHARE_FORBIDDEN); + } else { result = new RemoteOperationResult(false, status, post.getResponseHeaders()); } From fe6f99ea6a7334f565caa4d6ee5a29d1436b4c4f Mon Sep 17 00:00:00 2001 From: jabarros Date: Mon, 4 Aug 2014 10:18:21 +0200 Subject: [PATCH 04/23] Detect when there is a change bewwen a https connection to a non-secure one and generated a new erro code. --- .../operations/RemoteOperationResult.java | 18 +++++++- .../status/GetRemoteStatusOperation.java | 46 +++++++++++++++---- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 3b6b99a4..9bb0d4c7 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -100,7 +100,8 @@ public class RemoteOperationResult implements Serializable { SHARE_NOT_FOUND, LOCAL_STORAGE_NOT_REMOVED, FORBIDDEN, - SHARE_FORBIDDEN + SHARE_FORBIDDEN, + OK_REDIRECT_TO_NON_SECURE_CONNECTION } private boolean mSuccess = false; @@ -114,7 +115,7 @@ public class RemoteOperationResult implements Serializable { public RemoteOperationResult(ResultCode code) { mCode = code; - mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL || code == ResultCode.OK_NO_SSL); + mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL || code == ResultCode.OK_NO_SSL || code == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION); mData = null; } @@ -250,6 +251,10 @@ public class RemoteOperationResult implements Serializable { return mCode == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED; } + public boolean isRedirectToNonSecureConnection() { + return mCode == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION; + } + private CertificateCombinedException getCertificateCombinedException(Exception e) { CertificateCombinedException result = null; if (e instanceof CertificateCombinedException) { @@ -371,6 +376,15 @@ public class RemoteOperationResult implements Serializable { mRedirectedLocation.toLowerCase().contains("wayf"))); } + /** + * Checks if is a non https connection + * + * @return boolean true/false + */ + public boolean isNonSecureRedirection() { + return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://"))); + } + public String getAuthenticateHeader() { return mAuthenticate; } diff --git a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java index 458a91d3..b101aafd 100644 --- a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java +++ b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java @@ -31,16 +31,17 @@ import org.apache.commons.httpclient.methods.GetMethod; import org.json.JSONException; import org.json.JSONObject; -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.accounts.AccountUtils; -import com.owncloud.android.lib.common.operations.RemoteOperation; -import com.owncloud.android.lib.common.operations.RemoteOperationResult; - import android.content.Context; import android.net.ConnectivityManager; import android.net.Uri; import android.util.Log; +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.accounts.AccountUtils; +import com.owncloud.android.lib.common.operations.RemoteOperation; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation; + /** * Checks if the server is valid and if the server supports the Share API * @@ -93,10 +94,35 @@ public class GetRemoteStatusOperation extends RemoteOperation { RemoteOperationResult.ResultCode.OK_NO_SSL ); - ArrayList data = new ArrayList(); - data.add(ocVersion); - mLatestResult.setData(data); - retval = true; + RemoteOperation operation = new ExistenceCheckRemoteOperation("", mContext, false); + client.setFollowRedirects(false); + boolean isRedirectToNonSecureConnection = false; + + // checks if there are any reconnection to a non secure + // connection + RemoteOperationResult result = operation.execute(client); + String redirectedLocation = result.getRedirectedLocation(); + while (baseUrlSt.startsWith("https://") && redirectedLocation != null + && redirectedLocation.length() > 0 + && result.isNonSecureRedirection()) { + client.setBaseUri(Uri.parse(result.getRedirectedLocation())); + result = operation.execute(client); + redirectedLocation = result.getRedirectedLocation(); + + isRedirectToNonSecureConnection = true; + break; + } + + if (isRedirectToNonSecureConnection) { + mLatestResult = new RemoteOperationResult( + RemoteOperationResult.ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION); + } else { + retval = true; + } + + ArrayList data = new ArrayList(); + data.add(ocVersion); + mLatestResult.setData(data); } } @@ -148,7 +174,7 @@ public class GetRemoteStatusOperation extends RemoteOperation { } else { client.setBaseUri(Uri.parse("https://" + baseUriStr)); boolean httpsSuccess = tryConnection(client); - if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) { + if (!httpsSuccess && !mLatestResult.isSslRecoverableException() && mLatestResult.isNonSecureRedirection()) { Log.d(TAG, "establishing secure connection failed, trying non secure connection"); client.setBaseUri(Uri.parse("http://" + baseUriStr)); tryConnection(client); From 585054092df5ad4c8fe67bd395d6f17cacf3b3c2 Mon Sep 17 00:00:00 2001 From: jabarros Date: Mon, 4 Aug 2014 14:25:31 +0200 Subject: [PATCH 05/23] Fixed bug. It is not possible to connect to a http server --- .../lib/resources/status/GetRemoteStatusOperation.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java index b101aafd..e51f7566 100644 --- a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java +++ b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java @@ -116,13 +116,12 @@ public class GetRemoteStatusOperation extends RemoteOperation { if (isRedirectToNonSecureConnection) { mLatestResult = new RemoteOperationResult( RemoteOperationResult.ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION); - } else { - retval = true; } ArrayList data = new ArrayList(); data.add(ocVersion); mLatestResult.setData(data); + retval = true; } } @@ -174,7 +173,7 @@ public class GetRemoteStatusOperation extends RemoteOperation { } else { client.setBaseUri(Uri.parse("https://" + baseUriStr)); boolean httpsSuccess = tryConnection(client); - if (!httpsSuccess && !mLatestResult.isSslRecoverableException() && mLatestResult.isNonSecureRedirection()) { + if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) { Log.d(TAG, "establishing secure connection failed, trying non secure connection"); client.setBaseUri(Uri.parse("http://" + baseUriStr)); tryConnection(client); From 07f3d9caaebee7469d92f5d12c55e4464cc992cc Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Wed, 6 Aug 2014 10:59:33 +0200 Subject: [PATCH 06/23] Fixed check of HTTPS downgrade so that works with multiple redirections, and done without an extra request --- .../status/GetRemoteStatusOperation.java | 80 +++++++++++-------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java index e51f7566..0bdfa78b 100644 --- a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java +++ b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java @@ -40,7 +40,6 @@ import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation; /** * Checks if the server is valid and if the server supports the Share API @@ -52,7 +51,10 @@ import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation; public class GetRemoteStatusOperation extends RemoteOperation { - /** Maximum time to wait for a response from the server when the connection is being tested, in MILLISECONDs. */ + /** + * Maximum time to wait for a response from the server when the connection is being tested, + * in MILLISECONDs. + */ public static final int TRY_CONNECTION_TIMEOUT = 5000; private static final String TAG = GetRemoteStatusOperation.class.getSimpleName(); @@ -73,7 +75,36 @@ public class GetRemoteStatusOperation extends RemoteOperation { String baseUrlSt = client.getBaseUri().toString(); try { get = new GetMethod(baseUrlSt + AccountUtils.STATUS_PATH); + + client.setFollowRedirects(false); + boolean isRedirectToNonSecureConnection = false; int status = client.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT); + mLatestResult = new RemoteOperationResult( + (status == HttpStatus.SC_OK), + status, + get.getResponseHeaders() + ); + + if (baseUrlSt.startsWith("https://")) { + String redirectedLocation = mLatestResult.getRedirectedLocation(); + while (redirectedLocation != null && redirectedLocation.length() > 0 + && !mLatestResult.isSuccess()) { + + isRedirectToNonSecureConnection = redirectedLocation.startsWith("http://"); + get.releaseConnection(); + get = new GetMethod(redirectedLocation); + status = client.executeMethod( + get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT + ); + mLatestResult = new RemoteOperationResult( + (status == HttpStatus.SC_OK), + status, + get.getResponseHeaders() + ); + redirectedLocation = mLatestResult.getRedirectedLocation(); + } + } + String response = get.getResponseBodyAsString(); if (status == HttpStatus.SC_OK) { JSONObject json = new JSONObject(response); @@ -88,35 +119,19 @@ public class GetRemoteStatusOperation extends RemoteOperation { RemoteOperationResult.ResultCode.BAD_OC_VERSION); } else { - mLatestResult = new RemoteOperationResult( - baseUrlSt.startsWith("https://") ? - RemoteOperationResult.ResultCode.OK_SSL : - RemoteOperationResult.ResultCode.OK_NO_SSL - ); - - RemoteOperation operation = new ExistenceCheckRemoteOperation("", mContext, false); - client.setFollowRedirects(false); - boolean isRedirectToNonSecureConnection = false; - - // checks if there are any reconnection to a non secure - // connection - RemoteOperationResult result = operation.execute(client); - String redirectedLocation = result.getRedirectedLocation(); - while (baseUrlSt.startsWith("https://") && redirectedLocation != null - && redirectedLocation.length() > 0 - && result.isNonSecureRedirection()) { - client.setBaseUri(Uri.parse(result.getRedirectedLocation())); - result = operation.execute(client); - redirectedLocation = result.getRedirectedLocation(); - - isRedirectToNonSecureConnection = true; - break; - } - - if (isRedirectToNonSecureConnection) { - mLatestResult = new RemoteOperationResult( - RemoteOperationResult.ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION); - } + // success + if (isRedirectToNonSecureConnection) { + mLatestResult = new RemoteOperationResult( + RemoteOperationResult.ResultCode. + OK_REDIRECT_TO_NON_SECURE_CONNECTION + ); + } else { + mLatestResult = new RemoteOperationResult( + baseUrlSt.startsWith("https://") ? + RemoteOperationResult.ResultCode.OK_SSL : + RemoteOperationResult.ResultCode.OK_NO_SSL + ); + } ArrayList data = new ArrayList(); data.add(ocVersion); @@ -145,7 +160,8 @@ public class GetRemoteStatusOperation extends RemoteOperation { Log.i(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage()); } else if (mLatestResult.getException() != null) { - Log.e(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException()); + Log.e(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage(), + mLatestResult.getException()); } else { Log.e(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage()); From e43e43f51a895c591b72aaef8f36ef5595d18dba Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Wed, 6 Aug 2014 11:16:17 +0200 Subject: [PATCH 07/23] Fixed logic of HTTPS downgrade detection for multiple redirections, and grant that redirection if followed for HTTP servers --- .../status/GetRemoteStatusOperation.java | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java index 0bdfa78b..a9a16bde 100644 --- a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java +++ b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java @@ -85,25 +85,26 @@ public class GetRemoteStatusOperation extends RemoteOperation { get.getResponseHeaders() ); - if (baseUrlSt.startsWith("https://")) { - String redirectedLocation = mLatestResult.getRedirectedLocation(); - while (redirectedLocation != null && redirectedLocation.length() > 0 - && !mLatestResult.isSuccess()) { - - isRedirectToNonSecureConnection = redirectedLocation.startsWith("http://"); - get.releaseConnection(); - get = new GetMethod(redirectedLocation); - status = client.executeMethod( - get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT - ); - mLatestResult = new RemoteOperationResult( - (status == HttpStatus.SC_OK), - status, - get.getResponseHeaders() - ); - redirectedLocation = mLatestResult.getRedirectedLocation(); - } - } + String redirectedLocation = mLatestResult.getRedirectedLocation(); + while (redirectedLocation != null && redirectedLocation.length() > 0 + && !mLatestResult.isSuccess()) { + + isRedirectToNonSecureConnection |= ( + baseUrlSt.startsWith("https://") && + redirectedLocation.startsWith("http://") + ); + get.releaseConnection(); + get = new GetMethod(redirectedLocation); + status = client.executeMethod( + get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT + ); + mLatestResult = new RemoteOperationResult( + (status == HttpStatus.SC_OK), + status, + get.getResponseHeaders() + ); + redirectedLocation = mLatestResult.getRedirectedLocation(); + } String response = get.getResponseBodyAsString(); if (status == HttpStatus.SC_OK) { From b4e974491e31e08f6909c650d4037f94567d5971 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 21 Aug 2014 17:36:16 +0200 Subject: [PATCH 08/23] Added operation to move remote files --- .../operations/RemoteOperationResult.java | 4 +- .../files/MoveRemoteFileOperation.java | 213 ++++++++++++++++++ 2 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 9bb0d4c7..86537a70 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -101,7 +101,9 @@ public class RemoteOperationResult implements Serializable { LOCAL_STORAGE_NOT_REMOVED, FORBIDDEN, SHARE_FORBIDDEN, - OK_REDIRECT_TO_NON_SECURE_CONNECTION + OK_REDIRECT_TO_NON_SECURE_CONNECTION, + INVALID_MOVE_INTO_DESCENDANT, + PARTIAL_MOVE_DONE } private boolean mSuccess = false; diff --git a/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java new file mode 100644 index 00000000..258087c3 --- /dev/null +++ b/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java @@ -0,0 +1,213 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2014 ownCloud Inc. + * + * 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.resources.files; + +import java.io.IOException; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.jackrabbit.webdav.DavException; +import org.apache.jackrabbit.webdav.MultiStatusResponse; +import org.apache.jackrabbit.webdav.Status; +import org.apache.jackrabbit.webdav.client.methods.MoveMethod; + +import android.util.Log; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.network.WebdavUtils; +import com.owncloud.android.lib.common.operations.RemoteOperation; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; + + +/** + * Remote operation moving a remote file or folder in the ownCloud server to a different folder + * in the same account. + * + * Allows renaming the moving file/folder at the same time. + * + * @author David A. Velasco + */ +public class MoveRemoteFileOperation extends RemoteOperation { + + private static final String TAG = MoveRemoteFileOperation.class.getSimpleName(); + + private static final int RENAME_READ_TIMEOUT = 10000; + private static final int RENAME_CONNECTION_TIMEOUT = 5000; + + private String mSrcRemotePath; + private String mTargetRemotePath; + + private boolean mOverwrite; + + + /** + * Constructor. + * + * TODO Paths should finish in "/" in the case of folders. ? + * + * @param srcRemotePath Remote path of the file/folder to move. + * @param targetRemotePath Remove path desired for the file/folder after moving it. + */ + public MoveRemoteFileOperation( + String srcRemotePath, String targetRemotePath, boolean overwrite + ) { + + mSrcRemotePath = srcRemotePath; + mTargetRemotePath = targetRemotePath; + mOverwrite = overwrite; + } + + + /** + * Performs the rename operation. + * + * @param client Client object to communicate with the remote ownCloud server. + */ + @Override + protected RemoteOperationResult run(OwnCloudClient client) { + + /// check parameters + if (!FileUtils.isValidPath(mTargetRemotePath)) { + return new RemoteOperationResult(ResultCode.INVALID_CHARACTER_IN_NAME); + } + + if (mTargetRemotePath.equals(mSrcRemotePath)) { + // nothing to do! + return new RemoteOperationResult(ResultCode.OK); + } + + if (mTargetRemotePath.startsWith(mSrcRemotePath)) { + return new RemoteOperationResult(ResultCode.INVALID_MOVE_INTO_DESCENDANT); + } + + + /// perform remote operation + //LocalMoveMethod move = null; + MoveMethod move = null; + RemoteOperationResult result = null; + try { + move = new MoveMethod( + client.getWebdavUri() + WebdavUtils.encodePath(mSrcRemotePath), + client.getWebdavUri() + WebdavUtils.encodePath(mTargetRemotePath), + mOverwrite + ); + int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT); + + /// process response + if (status == HttpStatus.SC_MULTI_STATUS) { + result = processPartialError(move); + + } else if (status == HttpStatus.SC_PRECONDITION_FAILED && !mOverwrite) { + + result = new RemoteOperationResult(ResultCode.INVALID_OVERWRITE); + client.exhaustResponse(move.getResponseBodyAsStream()); + + + /// for other errors that could be explicitly handled, check first: + /// http://www.webdav.org/specs/rfc4918.html#rfc.section.9.9.4 + + } else { + + result = new RemoteOperationResult( + isSuccess(status), // move.succeeded()? trustful? + status, + move.getResponseHeaders() + ); + client.exhaustResponse(move.getResponseBodyAsStream()); + } + + Log.i(TAG, "Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + + result.getLogMessage()); + + } catch (Exception e) { + result = new RemoteOperationResult(e); + Log.e(TAG, "Move " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + + result.getLogMessage(), e); + + } finally { + if (move != null) + move.releaseConnection(); + } + + return result; + } + + + /** + * Analyzes a multistatus response from the OC server to generate an appropriate result. + * + * In WebDAV, a MOVE request on collections (folders) can be PARTIALLY successful: some + * children are moved, some other aren't. + * + * According to the WebDAV specification, a multistatus response SHOULD NOT include partial + * successes (201, 204) nor for descendants of already failed children (424) in the response + * entity. But SHOULD NOT != MUST NOT, so take carefully. + * + * @param move Move operation just finished with a multistatus response + * @return A result for the {@link MoveRemoteFileOperation} caller + * + * @throws IOException If the response body could not be parsed + * @throws DavException If the status code is other than MultiStatus or if obtaining + * the response XML document fails + */ + private RemoteOperationResult processPartialError(MoveMethod move) + throws IOException, DavException { + // Adding a list of failed descendants to the result could be interesting; or maybe not. + // For the moment, let's take the easy way. + + /// check that some error really occurred + MultiStatusResponse[] responses = move.getResponseBodyAsMultiStatus().getResponses(); + Status[] status = null; + boolean failFound = false; + for (int i = 0; i < responses.length && !failFound; i++ ) { + status = responses[i].getStatus(); + failFound = ( + status != null && + status.length > 0 && + status[0].getStatusCode() > 299 + ); + } + + RemoteOperationResult result; + if (failFound) { + result = new RemoteOperationResult(ResultCode.PARTIAL_MOVE_DONE); + } else { + result = new RemoteOperationResult( + true, + HttpStatus.SC_MULTI_STATUS, + move.getResponseHeaders() + ); + } + + return result; + + } + + + protected boolean isSuccess(int status) { + return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT; + } + +} From d4af8a6a33bd048bb2aba8749228639036613039 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 21 Aug 2014 17:37:16 +0200 Subject: [PATCH 09/23] Added unit tests for MoveRemoteFileOperation (WIP), with new approach dependant on AndroidTest instead of InstrumentationActivityTest --- .../lib/test_project/TestActivity.java | 119 +++++++++---- .../lib/test_project/test/MoveFileTest.java | 167 ++++++++++++++++++ 2 files changed, 254 insertions(+), 32 deletions(-) create mode 100644 test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java diff --git a/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java b/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java index 66ff274e..905fa511 100644 --- a/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java +++ b/test_client/src/com/owncloud/android/lib/test_project/TestActivity.java @@ -33,16 +33,24 @@ import java.security.GeneralSecurityException; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; -import com.owncloud.android.lib.common.OwnCloudClientFactory; +import android.app.Activity; +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.util.Log; +import android.view.Menu; + import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; -import com.owncloud.android.lib.resources.files.RemoteFile; import com.owncloud.android.lib.common.network.NetworkUtils; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.files.ChunkedUploadRemoteFileOperation; import com.owncloud.android.lib.resources.files.CreateRemoteFolderOperation; import com.owncloud.android.lib.resources.files.DownloadRemoteFileOperation; import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation; +import com.owncloud.android.lib.resources.files.RemoteFile; import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation; import com.owncloud.android.lib.resources.files.RenameRemoteFileOperation; import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation; @@ -50,14 +58,6 @@ import com.owncloud.android.lib.resources.shares.CreateRemoteShareOperation; import com.owncloud.android.lib.resources.shares.GetRemoteSharesOperation; import com.owncloud.android.lib.resources.shares.RemoveRemoteShareOperation; import com.owncloud.android.lib.resources.shares.ShareType; -import com.owncloud.android.lib.test_project.R; - -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.app.Activity; -import android.util.Log; -import android.view.Menu; /** * Activity to test OC framework @@ -72,7 +72,6 @@ public class TestActivity extends Activity { private String mServerUri; private String mUser; private String mPass; - private boolean mChunked; private static final int BUFFER_SIZE = 1024; @@ -91,7 +90,6 @@ public class TestActivity extends Activity { mServerUri = getString(R.string.server_base_url); mUser = getString(R.string.username); mPass = getString(R.string.password); - mChunked = getResources().getBoolean(R.bool.chunked); Protocol pr = Protocol.getProtocol("https"); if (pr == null || !(pr.getSocketFactory() instanceof SelfSignedConfidentSslSocketFactory)) { @@ -133,14 +131,32 @@ public class TestActivity extends Activity { /** * Access to the library method to Create a Folder * @param remotePath Full path to the new directory to create in the remote server. - * @param createFullPath 'True' means that all the ancestor folders should be created if don't exist yet. + * @param createFullPath 'True' means that all the ancestor folders should be created if + * don't exist yet. * * @return */ public RemoteOperationResult createFolder(String remotePath, boolean createFullPath) { - CreateRemoteFolderOperation createOperation = new CreateRemoteFolderOperation(remotePath, createFullPath); - RemoteOperationResult result = createOperation.execute(mClient); + return TestActivity.createFolder(remotePath, createFullPath, mClient); + } + + /** + * Access to the library method to Create a Folder + * @param remotePath Full path to the new directory to create in the remote server. + * @param createFullPath 'True' means that all the ancestor folders should be created if + * don't exist yet. + * @param client Client instance configured to access the target OC server. + * + * @return Result of the operation + */ + public static RemoteOperationResult createFolder( + String remotePath, boolean createFullPath, OwnCloudClient client + ) { + + CreateRemoteFolderOperation createOperation = + new CreateRemoteFolderOperation(remotePath, createFullPath); + RemoteOperationResult result = createOperation.execute(client); return result; } @@ -170,13 +186,24 @@ public class TestActivity extends Activity { * @return */ public RemoteOperationResult removeFile(String remotePath) { - RemoveRemoteFileOperation removeOperation = new RemoveRemoteFileOperation(remotePath); RemoteOperationResult result = removeOperation.execute(mClient); - + return TestActivity.removeFile(remotePath, mClient); + } + + /** + * Access to the library method to Remove a File or Folder + * + * @param remotePath Remote path of the file or folder in the server. + * @return + */ + public static RemoteOperationResult removeFile(String remotePath, OwnCloudClient client) { + RemoveRemoteFileOperation removeOperation = new RemoveRemoteFileOperation(remotePath); + RemoteOperationResult result = removeOperation.execute(client); return result; } + /** * Access to the library method to Read a Folder (PROPFIND DEPTH 1) * @param remotePath @@ -217,21 +244,39 @@ public class TestActivity extends Activity { * * @return */ - public RemoteOperationResult uploadFile(String storagePath, String remotePath, String mimeType) { - - UploadRemoteFileOperation uploadOperation; - if ( mChunked && (new File(storagePath)).length() > ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) { - uploadOperation = new ChunkedUploadRemoteFileOperation(storagePath, remotePath, mimeType); - } else { - uploadOperation = new UploadRemoteFileOperation(storagePath, remotePath, mimeType); - } - - RemoteOperationResult result = uploadOperation.execute(mClient); - - return result; + public RemoteOperationResult uploadFile( + String storagePath, String remotePath, String mimeType + ) { + return TestActivity.uploadFile(storagePath, remotePath, mimeType, mClient); } + /** Access to the library method to Upload a File + * @param storagePath + * @param remotePath + * @param mimeType + * @param client Client instance configured to access the target OC server. + * + * @return + */ + public static RemoteOperationResult uploadFile( + String storagePath, String remotePath, String mimeType, OwnCloudClient client + ) { + UploadRemoteFileOperation uploadOperation; + if ((new File(storagePath)).length() > ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) { + uploadOperation = new ChunkedUploadRemoteFileOperation( + storagePath, remotePath, mimeType + ); + } else { + uploadOperation = new UploadRemoteFileOperation( + storagePath, remotePath, mimeType + ); + } + + RemoteOperationResult result = uploadOperation.execute(client); + return result; + } + /** Access to the library method to Get Shares * * @return @@ -295,11 +340,22 @@ public class TestActivity extends Activity { * @return File instance of the extracted file. */ public File extractAsset(String fileName) throws IOException { - File extractedFile = new File(getCacheDir() + File.separator + fileName); + return TestActivity.extractAsset(fileName, this); + } + + /** + * Extracts file from AssetManager to cache folder. + * + * @param fileName Name of the asset file to extract. + * @param context Android context to access assets and file system. + * @return File instance of the extracted file. + */ + public static File extractAsset(String fileName, Context context) throws IOException { + File extractedFile = new File(context.getCacheDir() + File.separator + fileName); if (!extractedFile.exists()) { InputStream in = null; FileOutputStream out = null; - in = getAssets().open(fileName); + in = context.getAssets().open(fileName); out = new FileOutputStream(extractedFile); byte[] buffer = new byte[BUFFER_SIZE]; int readCount; @@ -312,7 +368,6 @@ public class TestActivity extends Activity { } return extractedFile; } - } diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java new file mode 100644 index 00000000..985e20bb --- /dev/null +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java @@ -0,0 +1,167 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2014 ownCloud Inc. + * + * 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.test_project.test; + +import java.security.GeneralSecurityException; +import java.util.Vector; + +import junit.framework.AssertionFailedError; + +import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientFactory; +import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; +import com.owncloud.android.lib.common.network.NetworkUtils; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.resources.files.MoveRemoteFileOperation; +import com.owncloud.android.lib.test_project.R; +import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory; +import com.owncloud.android.lib.test_project.TestActivity; + +import android.net.Uri; +import android.test.AndroidTestCase; +import android.util.Log; + +/** + * Class to test MoveRemoteFileOperation + * + * @author David A. Velasco + */ + +public class MoveFileTest extends AndroidTestCase { + + private static final String LOG_TAG = MoveFileTest.class.getCanonicalName(); + + /* Paths for tests on folders */ + private static final String SRC_FOLDER_NAME = "folderToMove"; + private static final String SRC_FOLDER_PARENT_PATH = "/src/"; + private static final String SRC_FOLDER_PATH = SRC_FOLDER_PARENT_PATH + SRC_FOLDER_NAME; + private static final String TARGET_FOLDER_PARENT_PATH = "/target/"; + private static final String TARGET_FOLDER_PATH = TARGET_FOLDER_PARENT_PATH + SRC_FOLDER_NAME; + + private static boolean mGlobalSetupDone = false; + + String mServerUri, mUser, mPass; + OwnCloudClient mClient = null; + + private Vector mToCleanUpInServer = new Vector(2); + + public MoveFileTest() { + super(); + + mGlobalSetupDone = false; + + Protocol pr = Protocol.getProtocol("https"); + if (pr == null || !(pr.getSocketFactory() instanceof SelfSignedConfidentSslSocketFactory)) { + try { + ProtocolSocketFactory psf = new SelfSignedConfidentSslSocketFactory(); + Protocol.registerProtocol( + "https", + new Protocol("https", psf, 443)); + + } catch (GeneralSecurityException e) { + throw new AssertionFailedError( + "Self-signed confident SSL context could not be loaded"); + } + } + + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + if (!mGlobalSetupDone) { + + mServerUri = getContext().getString(R.string.server_base_url); + mUser = getContext().getString(R.string.username); + mPass = getContext().getString(R.string.password); + + mClient = new OwnCloudClient( + Uri.parse(mServerUri), + NetworkUtils.getMultiThreadedConnManager() + ); + mClient.setDefaultTimeouts( + OwnCloudClientFactory.DEFAULT_DATA_TIMEOUT, + OwnCloudClientFactory.DEFAULT_CONNECTION_TIMEOUT); + mClient.setFollowRedirects(true); + mClient.setCredentials( + OwnCloudCredentialsFactory.newBasicCredentials( + mUser, + mPass + ) + ); + + Log.v(LOG_TAG, "Starting global set up"); + RemoteOperationResult result = + TestActivity.createFolder(SRC_FOLDER_PATH, true, mClient); + if (!result.isSuccess()) { + Utils.logAndThrow(LOG_TAG, result); + } + result = TestActivity.createFolder(TARGET_FOLDER_PARENT_PATH, true, mClient); + if (!result.isSuccess()) { + Utils.logAndThrow(LOG_TAG, result); + } + + Log.v(LOG_TAG, "Global set up done"); + + mGlobalSetupDone = true; + } + } + + /** + * Test move folder + */ + public void testMoveFolder() { + + mToCleanUpInServer.add(SRC_FOLDER_PARENT_PATH); + mToCleanUpInServer.add(TARGET_FOLDER_PARENT_PATH); + + MoveRemoteFileOperation renameOperation = new MoveRemoteFileOperation( + SRC_FOLDER_PATH, + TARGET_FOLDER_PATH, + false + ); + + RemoteOperationResult result = renameOperation.execute(mClient); + assertTrue(result.isSuccess()); + } + + @Override + protected void tearDown() throws Exception { + for (String path : mToCleanUpInServer) { + RemoteOperationResult removeResult = + TestActivity.removeFile(path, mClient); + if (!removeResult.isSuccess()) { + Utils.logAndThrow(LOG_TAG, removeResult); + } + } + mToCleanUpInServer.clear(); + super.tearDown(); + } + +} From dc2639264711ad43c240ca088a12185b722493aa Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 21 Aug 2014 18:04:14 +0200 Subject: [PATCH 10/23] Fixed MoveFileTest.java --- test_client/res/values/setup.xml | 4 +- .../lib/test_project/test/MoveFileTest.java | 38 +++++++++---------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/test_client/res/values/setup.xml b/test_client/res/values/setup.xml index aeb08218..ac5cedde 100644 --- a/test_client/res/values/setup.xml +++ b/test_client/res/values/setup.xml @@ -24,9 +24,7 @@ --> - - /remote.php/webdav + - true diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java index 985e20bb..26912616 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java @@ -95,27 +95,27 @@ public class MoveFileTest extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); + mServerUri = getContext().getString(R.string.server_base_url); + mUser = getContext().getString(R.string.username); + mPass = getContext().getString(R.string.password); + + mClient = new OwnCloudClient( + Uri.parse(mServerUri), + NetworkUtils.getMultiThreadedConnManager() + ); + mClient.setDefaultTimeouts( + OwnCloudClientFactory.DEFAULT_DATA_TIMEOUT, + OwnCloudClientFactory.DEFAULT_CONNECTION_TIMEOUT); + mClient.setFollowRedirects(true); + mClient.setCredentials( + OwnCloudCredentialsFactory.newBasicCredentials( + mUser, + mPass + ) + ); + if (!mGlobalSetupDone) { - mServerUri = getContext().getString(R.string.server_base_url); - mUser = getContext().getString(R.string.username); - mPass = getContext().getString(R.string.password); - - mClient = new OwnCloudClient( - Uri.parse(mServerUri), - NetworkUtils.getMultiThreadedConnManager() - ); - mClient.setDefaultTimeouts( - OwnCloudClientFactory.DEFAULT_DATA_TIMEOUT, - OwnCloudClientFactory.DEFAULT_CONNECTION_TIMEOUT); - mClient.setFollowRedirects(true); - mClient.setCredentials( - OwnCloudCredentialsFactory.newBasicCredentials( - mUser, - mPass - ) - ); - Log.v(LOG_TAG, "Starting global set up"); RemoteOperationResult result = TestActivity.createFolder(SRC_FOLDER_PATH, true, mClient); From 9d286636d5674f348a456cb697962f1c78fa306a Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Fri, 22 Aug 2014 15:29:20 +0200 Subject: [PATCH 11/23] Added success cases to MoveFileTest --- .../lib/test_project/test/MoveFileTest.java | 338 ++++++++++++++---- 1 file changed, 270 insertions(+), 68 deletions(-) diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java index 26912616..5008fe98 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java @@ -24,8 +24,8 @@ package com.owncloud.android.lib.test_project.test; +import java.io.File; import java.security.GeneralSecurityException; -import java.util.Vector; import junit.framework.AssertionFailedError; @@ -42,38 +42,130 @@ import com.owncloud.android.lib.test_project.R; import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory; import com.owncloud.android.lib.test_project.TestActivity; +import android.content.Context; import android.net.Uri; -import android.test.AndroidTestCase; +import android.test.ActivityInstrumentationTestCase2; +//import android.test.AndroidTestCase; import android.util.Log; /** * Class to test MoveRemoteFileOperation + * + * With this TestCase we are experimenting a bit to improve the test suite design, in two aspects: * + * - Reduce the dependency from the set of test cases on the "test project" needed to + * have an instrumented APK to install in the device, as required by the testing framework + * provided by Android. To get there, this class avoids calling TestActivity methods in the test + * method. + * + * - Reduce the impact of creating a remote fixture over the Internet, while the structure of the + * TestCase is kept easy to maintain. To get this, all the tests are done in a single test method, + * granting this way that setUp and tearDown are run only once. + * + * * @author David A. Velasco */ -public class MoveFileTest extends AndroidTestCase { - +//public class MoveFileTest extends AndroidTestCase { +public class MoveFileTest extends ActivityInstrumentationTestCase2 { + private static final String LOG_TAG = MoveFileTest.class.getCanonicalName(); - /* Paths for tests on folders */ - private static final String SRC_FOLDER_NAME = "folderToMove"; - private static final String SRC_FOLDER_PARENT_PATH = "/src/"; - private static final String SRC_FOLDER_PATH = SRC_FOLDER_PARENT_PATH + SRC_FOLDER_NAME; - private static final String TARGET_FOLDER_PARENT_PATH = "/target/"; - private static final String TARGET_FOLDER_PATH = TARGET_FOLDER_PARENT_PATH + SRC_FOLDER_NAME; - private static boolean mGlobalSetupDone = false; + /// Paths to files and folders in fixture + + private static final String SRC_BASE_FOLDER = "/src/"; + private static final String TARGET_BASE_FOLDER = "/target/"; + private static final String FILE1 = "file1.txt"; + private static final String FILE2 = "file2.txt"; + private static final String FILE3 = "file3.txt"; + private static final String FILE4 = "file4.txt"; + private static final String EMPTY = "empty/"; + private static final String FOLDER1 = "folder1/"; + private static final String FOLDER2 = "folder2/"; + private static final String FOLDER3 = "folder3/"; + + private static final String SRC_PATH_TO_FILE_1 = SRC_BASE_FOLDER + FILE1; + private static final String TARGET_PATH_TO_FILE_1 = TARGET_BASE_FOLDER + FILE1; + + private static final String SRC_PATH_TO_FILE_2 = SRC_BASE_FOLDER + FILE2; + private static final String TARGET_PATH_TO_FILE_2_RENAMED = + TARGET_BASE_FOLDER + "renamed_" + FILE2; + + private static final String SRC_PATH_TO_FILE_3 = SRC_BASE_FOLDER + FILE3; + private static final String SRC_PATH_TO_FILE_3_RENAMED = SRC_BASE_FOLDER + "renamed_" + FILE3; + + private static final String SRC_PATH_TO_FILE_4 = SRC_BASE_FOLDER + FILE4; + + private static final String SRC_PATH_TO_EMPTY_FOLDER = SRC_BASE_FOLDER + EMPTY; + private static final String TARGET_PATH_TO_EMPTY_FOLDER = TARGET_BASE_FOLDER + EMPTY; + + private static final String SRC_PATH_TO_FULL_FOLDER_1 = SRC_BASE_FOLDER + FOLDER1; + private static final String TARGET_PATH_TO_FULL_FOLDER_1 = TARGET_BASE_FOLDER + FOLDER1; + + private static final String SRC_PATH_TO_FULL_FOLDER_2 = SRC_BASE_FOLDER + FOLDER2; + + private static final String TARGET_PATH_TO_FULL_FOLDER_2_RENAMED = + TARGET_BASE_FOLDER + "renamed_" + FOLDER2; + + private static final String SRC_PATH_TO_FULL_FOLDER_3 = SRC_BASE_FOLDER + FOLDER3; + + private static final String SRC_PATH_TO_FULL_FOLDER_3_RENAMED = + SRC_BASE_FOLDER + "renamed_" + FOLDER3; + + + private static final String[] FOLDERS_IN_FIXTURE = { + SRC_PATH_TO_EMPTY_FOLDER, + + SRC_PATH_TO_FULL_FOLDER_1, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FOLDER2, + + SRC_PATH_TO_FULL_FOLDER_2, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FOLDER2, + + SRC_PATH_TO_FULL_FOLDER_3, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2, + + TARGET_BASE_FOLDER + }; + + private static final String[] FILES_IN_FIXTURE = { + SRC_PATH_TO_FILE_1, + SRC_PATH_TO_FILE_2, + SRC_PATH_TO_FILE_3, + SRC_PATH_TO_FILE_4, + + SRC_PATH_TO_FULL_FOLDER_1 + FILE1, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FILE1, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FILE2, + SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FOLDER2 + FILE2, + + SRC_PATH_TO_FULL_FOLDER_2 + FILE1, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FILE1, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FILE2, + SRC_PATH_TO_FULL_FOLDER_2 + FOLDER2 + FOLDER2 + FILE2, + + SRC_PATH_TO_FULL_FOLDER_3 + FILE1, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FILE1, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FILE2, + SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2 + FILE2, + }; + String mServerUri, mUser, mPass; OwnCloudClient mClient = null; - private Vector mToCleanUpInServer = new Vector(2); - public MoveFileTest() { - super(); - - mGlobalSetupDone = false; + super(TestActivity.class); Protocol pr = Protocol.getProtocol("https"); if (pr == null || !(pr.getSocketFactory() instanceof SelfSignedConfidentSslSocketFactory)) { @@ -90,14 +182,169 @@ public class MoveFileTest extends AndroidTestCase { } } + + + protected Context getContext() { + return getActivity(); + } @Override - protected void setUp() throws Exception { + protected void setUp() throws Exception { super.setUp(); + + // Next initialization cannot be done in the constructor because getContext() is not + // ready yet, returns NULL. + initAccessToServer(getContext()); - mServerUri = getContext().getString(R.string.server_base_url); - mUser = getContext().getString(R.string.username); - mPass = getContext().getString(R.string.password); + Log.v(LOG_TAG, "Setting up the remote fixture..."); + + RemoteOperationResult result = null; + for (String folderPath : FOLDERS_IN_FIXTURE) { + result = TestActivity.createFolder(folderPath, true, mClient); + if (!result.isSuccess()) { + Utils.logAndThrow(LOG_TAG, result); + } + } + + File txtFile = TestActivity.extractAsset( + TestActivity.ASSETS__TEXT_FILE_NAME, getContext() + ); + for (String filePath : FILES_IN_FIXTURE) { + result = TestActivity.uploadFile( + txtFile.getAbsolutePath(), filePath, "txt/plain", mClient + ); + if (!result.isSuccess()) { + Utils.logAndThrow(LOG_TAG, result); + } + } + + Log.v(LOG_TAG, "Remote fixture created."); + + } + + + /** + * Test move folder + */ + public void testMoveRemoteFileOperation() { + Log.v(LOG_TAG, "testMoveFolder in"); + + /// successful cases + + // move file + MoveRemoteFileOperation moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FILE_1, + TARGET_PATH_TO_FILE_1, + false + ); + RemoteOperationResult result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move & rename file, different location + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FILE_2, + TARGET_PATH_TO_FILE_2_RENAMED, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move & rename file, same location (rename file) + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FILE_3, + SRC_PATH_TO_FILE_3_RENAMED, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move empty folder + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_EMPTY_FOLDER, + TARGET_PATH_TO_EMPTY_FOLDER, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move non-empty folder + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_1, + TARGET_PATH_TO_FULL_FOLDER_1, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move & rename folder, different location + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_2, + TARGET_PATH_TO_FULL_FOLDER_2_RENAMED, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move & rename folder, same location (rename folder) + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_3, + SRC_PATH_TO_FULL_FOLDER_3_RENAMED, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + // move for nothing (success, but no interaction with network) + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FILE_4, + SRC_PATH_TO_FILE_4, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + + /// TODO failed cases + + // file to move does not exist + + // folder to move into does no exist + + // target location (renaming) has invalid characters + + // name collision + + } + + @Override + protected void tearDown() throws Exception { + Log.v(LOG_TAG, "Deleting remote fixture..."); + + String[] mPathsToCleanUp = { + SRC_BASE_FOLDER, + TARGET_BASE_FOLDER + }; + + for (String path : mPathsToCleanUp) { + RemoteOperationResult removeResult = + TestActivity.removeFile(path, mClient); + if (!removeResult.isSuccess()) { + Utils.logAndThrow(LOG_TAG, removeResult); + } + } + + super.tearDown(); + + Log.v(LOG_TAG, "Remote fixture delete."); + } + + + private void initAccessToServer(Context context) { + Log.v(LOG_TAG, "Setting up client instance to access OC server..."); + + mServerUri = context.getString(R.string.server_base_url); + mUser = context.getString(R.string.username); + mPass = context.getString(R.string.password); mClient = new OwnCloudClient( Uri.parse(mServerUri), @@ -113,55 +360,10 @@ public class MoveFileTest extends AndroidTestCase { mPass ) ); - - if (!mGlobalSetupDone) { - - Log.v(LOG_TAG, "Starting global set up"); - RemoteOperationResult result = - TestActivity.createFolder(SRC_FOLDER_PATH, true, mClient); - if (!result.isSuccess()) { - Utils.logAndThrow(LOG_TAG, result); - } - result = TestActivity.createFolder(TARGET_FOLDER_PARENT_PATH, true, mClient); - if (!result.isSuccess()) { - Utils.logAndThrow(LOG_TAG, result); - } - - Log.v(LOG_TAG, "Global set up done"); - - mGlobalSetupDone = true; - } + + Log.v(LOG_TAG, "Client instance set up."); + } - /** - * Test move folder - */ - public void testMoveFolder() { - - mToCleanUpInServer.add(SRC_FOLDER_PARENT_PATH); - mToCleanUpInServer.add(TARGET_FOLDER_PARENT_PATH); - - MoveRemoteFileOperation renameOperation = new MoveRemoteFileOperation( - SRC_FOLDER_PATH, - TARGET_FOLDER_PATH, - false - ); - - RemoteOperationResult result = renameOperation.execute(mClient); - assertTrue(result.isSuccess()); - } - - @Override - protected void tearDown() throws Exception { - for (String path : mToCleanUpInServer) { - RemoteOperationResult removeResult = - TestActivity.removeFile(path, mClient); - if (!removeResult.isSuccess()) { - Utils.logAndThrow(LOG_TAG, removeResult); - } - } - mToCleanUpInServer.clear(); - super.tearDown(); - } } From e5010c1a6b6e7f23824e0f07e93030cabc05b593 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Wed, 27 Aug 2014 12:18:56 +0200 Subject: [PATCH 12/23] Fixed library demo client --- .../com/owncloud/android/lib/sampleclient/MainActivity.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java b/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java index 8e24c15e..06210073 100644 --- a/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java +++ b/sample_client/src/com/owncloud/android/lib/sampleclient/MainActivity.java @@ -32,7 +32,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudClient; @@ -79,7 +78,7 @@ public class MainActivity extends Activity implements OnRemoteOperationListener, mHandler = new Handler(); - Uri serverUri = Uri.parse(getString(R.string.server_base_url) + AccountUtils.WEBDAV_PATH_4_0); + Uri serverUri = Uri.parse(getString(R.string.server_base_url)); mClient = OwnCloudClientFactory.createOwnCloudClient(serverUri, this, true); mClient.setCredentials( OwnCloudCredentialsFactory.newBasicCredentials( From 3a5df9dcdf3a5d3a4f4c5dbe83783feec01cabf1 Mon Sep 17 00:00:00 2001 From: jabarros Date: Wed, 27 Aug 2014 17:17:04 +0200 Subject: [PATCH 13/23] Add failed test cases into moving file test --- .../lib/test_project/test/MoveFileTest.java | 76 +++++++++++++++++-- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java index 5008fe98..175fc230 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java @@ -37,6 +37,7 @@ import com.owncloud.android.lib.common.OwnCloudClientFactory; import com.owncloud.android.lib.common.OwnCloudCredentialsFactory; import com.owncloud.android.lib.common.network.NetworkUtils; import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.resources.files.MoveRemoteFileOperation; import com.owncloud.android.lib.test_project.R; import com.owncloud.android.lib.test_project.SelfSignedConfidentSslSocketFactory; @@ -75,15 +76,19 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 /// Paths to files and folders in fixture private static final String SRC_BASE_FOLDER = "/src/"; + private static final String SRC_BASE_FOLDER_NON_CREATED = "/src_non_created/"; private static final String TARGET_BASE_FOLDER = "/target/"; private static final String FILE1 = "file1.txt"; private static final String FILE2 = "file2.txt"; private static final String FILE3 = "file3.txt"; private static final String FILE4 = "file4.txt"; + private static final String FILE5 = "file5.txt"; private static final String EMPTY = "empty/"; private static final String FOLDER1 = "folder1/"; private static final String FOLDER2 = "folder2/"; private static final String FOLDER3 = "folder3/"; + private static final String FOLDER4 = "folder4/"; + private static final String FOLDER5 = "folder5/"; private static final String SRC_PATH_TO_FILE_1 = SRC_BASE_FOLDER + FILE1; private static final String TARGET_PATH_TO_FILE_1 = TARGET_BASE_FOLDER + FILE1; @@ -97,6 +102,8 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 private static final String SRC_PATH_TO_FILE_4 = SRC_BASE_FOLDER + FILE4; + private static final String SRC_PATH_TO_FILE_NON_EXISTS = SRC_BASE_FOLDER + FILE5; + private static final String SRC_PATH_TO_EMPTY_FOLDER = SRC_BASE_FOLDER + EMPTY; private static final String TARGET_PATH_TO_EMPTY_FOLDER = TARGET_BASE_FOLDER + EMPTY; @@ -109,10 +116,18 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 TARGET_BASE_FOLDER + "renamed_" + FOLDER2; private static final String SRC_PATH_TO_FULL_FOLDER_3 = SRC_BASE_FOLDER + FOLDER3; + private static final String SRC_PATH_TO_FULL_FOLDER_4 = SRC_BASE_FOLDER + FOLDER4; + private static final String SRC_PATH_TO_FULL_FOLDER_5 = SRC_BASE_FOLDER + FOLDER5; private static final String SRC_PATH_TO_FULL_FOLDER_3_RENAMED = SRC_BASE_FOLDER + "renamed_" + FOLDER3; + private static final String SRC_PATH_TO_FULL_FOLDER_4_RENAMED_INVALID_CHARS = + SRC_BASE_FOLDER + "renamed:??_" + FOLDER4; + + private static final String SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4 = SRC_BASE_FOLDER + + FOLDER4 + FOLDER5; + private static final String[] FOLDERS_IN_FIXTURE = { SRC_PATH_TO_EMPTY_FOLDER, @@ -135,7 +150,10 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER1, SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2, - TARGET_BASE_FOLDER + SRC_PATH_TO_FULL_FOLDER_5, + SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + + TARGET_BASE_FOLDER, }; private static final String[] FILES_IN_FIXTURE = { @@ -303,16 +321,62 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 result = moveOperation.execute(mClient); assertTrue(result.isSuccess()); - - /// TODO failed cases + // move to the same name folder but overwrite it + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_5, + SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + true + ); + result = moveOperation.execute(mClient); + assertTrue(result.isSuccess()); + + + // Failed cases // file to move does not exist - + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FILE_NON_EXISTS, + SRC_PATH_TO_FULL_FOLDER_4, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.getCode() == ResultCode.INVALID_OVERWRITE); + // folder to move into does no exist - + moveOperation = new MoveRemoteFileOperation( + SRC_BASE_FOLDER_NON_CREATED, + SRC_PATH_TO_FILE_4, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.getCode() == ResultCode.INVALID_OVERWRITE); + // target location (renaming) has invalid characters - + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_4, + SRC_PATH_TO_FULL_FOLDER_4_RENAMED_INVALID_CHARS, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME); + // name collision + moveOperation = new MoveRemoteFileOperation( + SRC_PATH_TO_FULL_FOLDER_5, + SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.getCode() == ResultCode.INVALID_OVERWRITE); + + // move a folder into a descendant + moveOperation = new MoveRemoteFileOperation( + SRC_BASE_FOLDER, + SRC_PATH_TO_FULL_FOLDER_4, + false + ); + result = moveOperation.execute(mClient); + assertTrue(result.getCode() == ResultCode.INVALID_MOVE_INTO_DESCENDANT); } From 80cbe24524dc7cd9bb96d7d6d7eaebb18d0e01c2 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Mon, 1 Sep 2014 14:53:13 +0200 Subject: [PATCH 14/23] Greater timeouts for moving and renaming folders --- .../lib/resources/files/MoveRemoteFileOperation.java | 6 +++--- .../lib/resources/files/RenameRemoteFileOperation.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java index 258087c3..844c727e 100644 --- a/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java +++ b/src/com/owncloud/android/lib/resources/files/MoveRemoteFileOperation.java @@ -53,8 +53,8 @@ public class MoveRemoteFileOperation extends RemoteOperation { private static final String TAG = MoveRemoteFileOperation.class.getSimpleName(); - private static final int RENAME_READ_TIMEOUT = 10000; - private static final int RENAME_CONNECTION_TIMEOUT = 5000; + private static final int MOVE_READ_TIMEOUT = 600000; + private static final int MOVE_CONNECTION_TIMEOUT = 5000; private String mSrcRemotePath; private String mTargetRemotePath; @@ -113,7 +113,7 @@ public class MoveRemoteFileOperation extends RemoteOperation { client.getWebdavUri() + WebdavUtils.encodePath(mTargetRemotePath), mOverwrite ); - int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT); + int status = client.executeMethod(move, MOVE_READ_TIMEOUT, MOVE_CONNECTION_TIMEOUT); /// process response if (status == HttpStatus.SC_MULTI_STATUS) { diff --git a/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java index a42543b0..be7b90e3 100644 --- a/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java +++ b/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java @@ -47,7 +47,7 @@ public class RenameRemoteFileOperation extends RemoteOperation { private static final String TAG = RenameRemoteFileOperation.class.getSimpleName(); - private static final int RENAME_READ_TIMEOUT = 10000; + private static final int RENAME_READ_TIMEOUT = 600000; private static final int RENAME_CONNECTION_TIMEOUT = 5000; private String mOldName; From df84917376e9d804897822cb138aaf0ba879d854 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Wed, 3 Sep 2014 11:42:23 +0200 Subject: [PATCH 15/23] Redirect 'destination' header in custom redirections --- .../android/lib/common/OwnCloudClient.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index 7b48bbc0..1e4f48f1 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -225,6 +225,26 @@ public class OwnCloudClient extends HttpClient { Log.d(TAG + " #" + mInstanceNumber, "Location to redirect: " + location.getValue()); method.setURI(new URI(location.getValue(), true)); + Header destination = method.getRequestHeader("Destination"); + if (destination == null) { + destination = method.getRequestHeader("destination"); + } + if (destination != null) { + String locationStr = location.getValue(); + int suffixIndex = locationStr.lastIndexOf( + (mCredentials instanceof OwnCloudBearerCredentials) ? + AccountUtils.ODAV_PATH : + AccountUtils.WEBDAV_PATH_4_0 + ); + String redirectionBase = locationStr.substring(0, suffixIndex); + + String destinationStr = destination.getValue(); + String destinationPath = destinationStr.substring(mBaseUri.toString().length()); + String redirectedDestination = redirectionBase + destinationPath; + + destination.setValue(redirectedDestination); + method.setRequestHeader(destination); + } status = super.executeMethod(method); redirectionsCount++; From 5d146c923620523a871a0fe50bdcbc3b7559df8c Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Thu, 4 Sep 2014 13:53:51 +0200 Subject: [PATCH 16/23] Some improvementes in tests on failed move operations --- .../lib/test_project/test/MoveFileTest.java | 78 ++++++++++++------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java index 175fc230..e5ec8a37 100644 --- a/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java +++ b/test_client/tests/src/com/owncloud/android/lib/test_project/test/MoveFileTest.java @@ -29,6 +29,7 @@ import java.security.GeneralSecurityException; import junit.framework.AssertionFailedError; +import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; @@ -76,19 +77,21 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 /// Paths to files and folders in fixture private static final String SRC_BASE_FOLDER = "/src/"; - private static final String SRC_BASE_FOLDER_NON_CREATED = "/src_non_created/"; private static final String TARGET_BASE_FOLDER = "/target/"; + private static final String NO_FILE = "nofile.txt"; private static final String FILE1 = "file1.txt"; private static final String FILE2 = "file2.txt"; private static final String FILE3 = "file3.txt"; private static final String FILE4 = "file4.txt"; private static final String FILE5 = "file5.txt"; + private static final String FILE6 = "file6.txt"; + private static final String FILE7 = "file7.txt"; private static final String EMPTY = "empty/"; + private static final String NO_FOLDER = "nofolder/"; private static final String FOLDER1 = "folder1/"; private static final String FOLDER2 = "folder2/"; private static final String FOLDER3 = "folder3/"; private static final String FOLDER4 = "folder4/"; - private static final String FOLDER5 = "folder5/"; private static final String SRC_PATH_TO_FILE_1 = SRC_BASE_FOLDER + FILE1; private static final String TARGET_PATH_TO_FILE_1 = TARGET_BASE_FOLDER + FILE1; @@ -102,7 +105,13 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 private static final String SRC_PATH_TO_FILE_4 = SRC_BASE_FOLDER + FILE4; - private static final String SRC_PATH_TO_FILE_NON_EXISTS = SRC_BASE_FOLDER + FILE5; + private static final String SRC_PATH_TO_FILE_5 = SRC_BASE_FOLDER + FILE5; + + private static final String SRC_PATH_TO_FILE_6 = SRC_BASE_FOLDER + FILE6; + + private static final String SRC_PATH_TO_FILE_7 = SRC_BASE_FOLDER + FILE7; + + private static final String SRC_PATH_TO_NON_EXISTENT_FILE = SRC_BASE_FOLDER + NO_FILE; private static final String SRC_PATH_TO_EMPTY_FOLDER = SRC_BASE_FOLDER + EMPTY; private static final String TARGET_PATH_TO_EMPTY_FOLDER = TARGET_BASE_FOLDER + EMPTY; @@ -117,17 +126,22 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 private static final String SRC_PATH_TO_FULL_FOLDER_3 = SRC_BASE_FOLDER + FOLDER3; private static final String SRC_PATH_TO_FULL_FOLDER_4 = SRC_BASE_FOLDER + FOLDER4; - private static final String SRC_PATH_TO_FULL_FOLDER_5 = SRC_BASE_FOLDER + FOLDER5; private static final String SRC_PATH_TO_FULL_FOLDER_3_RENAMED = SRC_BASE_FOLDER + "renamed_" + FOLDER3; - private static final String SRC_PATH_TO_FULL_FOLDER_4_RENAMED_INVALID_CHARS = - SRC_BASE_FOLDER + "renamed:??_" + FOLDER4; + private static final String TARGET_PATH_RENAMED_WITH_INVALID_CHARS = + SRC_BASE_FOLDER + "renamed:??_" + FILE6; - private static final String SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4 = SRC_BASE_FOLDER - + FOLDER4 + FOLDER5; + private static final String TARGET_PATH_TO_ALREADY_EXISTENT_EMPTY_FOLDER_4 = TARGET_BASE_FOLDER + + FOLDER4; + + private static final String TARGET_PATH_TO_NON_EXISTENT_FILE = TARGET_BASE_FOLDER + NO_FILE; + private static final String TARGET_PATH_TO_FILE_5_INTO_NON_EXISTENT_FOLDER = + TARGET_BASE_FOLDER + NO_FOLDER + FILE5; + + private static final String TARGET_PATH_TO_ALREADY_EXISTENT_FILE_7 = TARGET_BASE_FOLDER + FILE7; private static final String[] FOLDERS_IN_FIXTURE = { SRC_PATH_TO_EMPTY_FOLDER, @@ -150,10 +164,14 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER1, SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2, - SRC_PATH_TO_FULL_FOLDER_5, - SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + SRC_PATH_TO_FULL_FOLDER_4, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FOLDER1, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FOLDER2, TARGET_BASE_FOLDER, + TARGET_PATH_TO_ALREADY_EXISTENT_EMPTY_FOLDER_4 }; private static final String[] FILES_IN_FIXTURE = { @@ -161,6 +179,7 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 SRC_PATH_TO_FILE_2, SRC_PATH_TO_FILE_3, SRC_PATH_TO_FILE_4, + SRC_PATH_TO_FILE_5, SRC_PATH_TO_FULL_FOLDER_1 + FILE1, SRC_PATH_TO_FULL_FOLDER_1 + FOLDER2 + FILE1, @@ -176,6 +195,13 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FILE1, SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FILE2, SRC_PATH_TO_FULL_FOLDER_3 + FOLDER2 + FOLDER2 + FILE2, + + SRC_PATH_TO_FULL_FOLDER_4 + FILE1, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FILE1, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FILE2, + SRC_PATH_TO_FULL_FOLDER_4 + FOLDER2 + FOLDER2 + FILE2, + + TARGET_PATH_TO_ALREADY_EXISTENT_FILE_7 }; @@ -321,40 +347,40 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 result = moveOperation.execute(mClient); assertTrue(result.isSuccess()); - // move to the same name folder but overwrite it + // move overwriting moveOperation = new MoveRemoteFileOperation( - SRC_PATH_TO_FULL_FOLDER_5, - SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + SRC_PATH_TO_FULL_FOLDER_4, + TARGET_PATH_TO_ALREADY_EXISTENT_EMPTY_FOLDER_4, true ); result = moveOperation.execute(mClient); assertTrue(result.isSuccess()); - // Failed cases + /// Failed cases // file to move does not exist moveOperation = new MoveRemoteFileOperation( - SRC_PATH_TO_FILE_NON_EXISTS, - SRC_PATH_TO_FULL_FOLDER_4, + SRC_PATH_TO_NON_EXISTENT_FILE, + TARGET_PATH_TO_NON_EXISTENT_FILE, false ); result = moveOperation.execute(mClient); - assertTrue(result.getCode() == ResultCode.INVALID_OVERWRITE); + assertTrue(result.getCode() == ResultCode.FILE_NOT_FOUND); // folder to move into does no exist moveOperation = new MoveRemoteFileOperation( - SRC_BASE_FOLDER_NON_CREATED, - SRC_PATH_TO_FILE_4, + SRC_PATH_TO_FILE_5, + TARGET_PATH_TO_FILE_5_INTO_NON_EXISTENT_FOLDER, false ); result = moveOperation.execute(mClient); - assertTrue(result.getCode() == ResultCode.INVALID_OVERWRITE); + assertTrue(result.getHttpCode() == HttpStatus.SC_CONFLICT); // target location (renaming) has invalid characters moveOperation = new MoveRemoteFileOperation( - SRC_PATH_TO_FULL_FOLDER_4, - SRC_PATH_TO_FULL_FOLDER_4_RENAMED_INVALID_CHARS, + SRC_PATH_TO_FILE_6, + TARGET_PATH_RENAMED_WITH_INVALID_CHARS, false ); result = moveOperation.execute(mClient); @@ -362,8 +388,8 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 // name collision moveOperation = new MoveRemoteFileOperation( - SRC_PATH_TO_FULL_FOLDER_5, - SRC_PATH_TO_FULL_FOLDER_5_INSIDE_FOLDER_4, + SRC_PATH_TO_FILE_7, + TARGET_PATH_TO_ALREADY_EXISTENT_FILE_7, false ); result = moveOperation.execute(mClient); @@ -372,7 +398,7 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 // move a folder into a descendant moveOperation = new MoveRemoteFileOperation( SRC_BASE_FOLDER, - SRC_PATH_TO_FULL_FOLDER_4, + SRC_PATH_TO_EMPTY_FOLDER, false ); result = moveOperation.execute(mClient); @@ -392,7 +418,7 @@ public class MoveFileTest extends ActivityInstrumentationTestCase2 for (String path : mPathsToCleanUp) { RemoteOperationResult removeResult = TestActivity.removeFile(path, mClient); - if (!removeResult.isSuccess()) { + if (!removeResult.isSuccess() && removeResult.getCode() != ResultCode.TIMEOUT ) { Utils.logAndThrow(LOG_TAG, removeResult); } } From b0fe841c3e9113e5f1c91609d533fddcbe8eb4ec Mon Sep 17 00:00:00 2001 From: jabarros Date: Fri, 12 Sep 2014 09:30:54 +0200 Subject: [PATCH 17/23] Add Log_OC class and update the log references --- .../android/lib/common/OwnCloudClient.java | 46 ++--- .../lib/common/OwnCloudClientFactory.java | 16 +- .../lib/common/SimpleFactoryManager.java | 10 +- .../lib/common/SingleSessionManager.java | 28 ++- .../lib/common/accounts/AccountUtils.java | 8 +- .../network/AdvancedSslSocketFactory.java | 38 ++-- .../network/AdvancedX509TrustManager.java | 4 +- .../lib/common/network/BearerAuthScheme.java | 8 +- .../ChunkFromFileChannelRequestEntity.java | 5 +- .../lib/common/network/FileRequestEntity.java | 4 +- .../lib/common/network/NetworkUtils.java | 7 +- .../common/network/ServerNameIndicator.java | 18 +- .../lib/common/network/WebdavEntry.java | 5 +- .../common/operations/RemoteOperation.java | 24 ++- .../operations/RemoteOperationResult.java | 4 +- .../android/lib/common/utils/Log_OC.java | 169 ++++++++++++++++++ .../ChunkedUploadRemoteFileOperation.java | 6 +- .../files/CreateRemoteFolderOperation.java | 7 +- .../files/DownloadRemoteFileOperation.java | 7 +- .../files/ExistenceCheckRemoteOperation.java | 12 +- .../lib/resources/files/FileUtils.java | 6 +- .../files/ReadRemoteFileOperation.java | 5 +- .../files/ReadRemoteFolderOperation.java | 9 +- .../files/RemoveRemoteFileOperation.java | 7 +- .../files/RenameRemoteFileOperation.java | 7 +- .../shares/CreateRemoteShareOperation.java | 9 +- .../GetRemoteSharesForFileOperation.java | 7 +- .../shares/GetRemoteSharesOperation.java | 7 +- .../android/lib/resources/shares/OCShare.java | 8 +- .../shares/RemoveRemoteShareOperation.java | 7 +- .../lib/resources/shares/ShareXMLParser.java | 8 +- .../status/GetRemoteStatusOperation.java | 10 +- .../users/GetRemoteUserNameOperation.java | 15 +- 33 files changed, 340 insertions(+), 191 deletions(-) create mode 100644 src/com/owncloud/android/lib/common/utils/Log_OC.java diff --git a/src/com/owncloud/android/lib/common/OwnCloudClient.java b/src/com/owncloud/android/lib/common/OwnCloudClient.java index 7b48bbc0..927e0fa1 100644 --- a/src/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/src/com/owncloud/android/lib/common/OwnCloudClient.java @@ -44,11 +44,11 @@ import org.apache.http.HttpStatus; import org.apache.http.params.CoreProtocolPNames; import android.net.Uri; -import android.util.Log; import com.owncloud.android.lib.common.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.network.WebdavUtils; +import com.owncloud.android.lib.common.utils.Log_OC; public class OwnCloudClient extends HttpClient { @@ -79,7 +79,7 @@ public class OwnCloudClient extends HttpClient { mBaseUri = baseUri; mInstanceNumber = sIntanceCounter++; - Log.d(TAG + " #" + mInstanceNumber, "Creating OwnCloudClient"); + Log_OC.d(TAG + " #" + mInstanceNumber, "Creating OwnCloudClient"); getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT); getParams().setParameter( @@ -125,7 +125,7 @@ public class OwnCloudClient extends HttpClient { HeadMethod head = new HeadMethod(getWebdavUri() + WebdavUtils.encodePath(path)); try { int status = executeMethod(head); - Log.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + + Log_OC.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":"")); exhaustResponse(head.getResponseBodyAsStream()); return (status == HttpStatus.SC_OK); @@ -185,7 +185,7 @@ public class OwnCloudClient extends HttpClient { customRedirectionNeeded = mFollowRedirects; } - Log.d(TAG + " #" + mInstanceNumber, "REQUEST " + + Log_OC.d(TAG + " #" + mInstanceNumber, "REQUEST " + method.getName() + " " + method.getPath()); // logCookiesAtRequest(method.getRequestHeaders(), "before"); @@ -204,7 +204,7 @@ public class OwnCloudClient extends HttpClient { return status; } catch (IOException e) { - Log.d(TAG + " #" + mInstanceNumber, "Exception occured", e); + Log_OC.d(TAG + " #" + mInstanceNumber, "Exception occured", e); throw e; } } @@ -222,14 +222,14 @@ public class OwnCloudClient extends HttpClient { location = method.getResponseHeader("location"); } if (location != null) { - Log.d(TAG + " #" + mInstanceNumber, + Log_OC.d(TAG + " #" + mInstanceNumber, "Location to redirect: " + location.getValue()); method.setURI(new URI(location.getValue(), true)); status = super.executeMethod(method); redirectionsCount++; } else { - Log.d(TAG + " #" + mInstanceNumber, "No location to redirect!"); + Log_OC.d(TAG + " #" + mInstanceNumber, "No location to redirect!"); status = HttpStatus.SC_NOT_FOUND; } } @@ -248,7 +248,7 @@ public class OwnCloudClient extends HttpClient { responseBodyAsStream.close(); } catch (IOException io) { - Log.e(TAG, "Unexpected exception while exhausting not interesting HTTP response;" + + Log_OC.e(TAG, "Unexpected exception while exhausting not interesting HTTP response;" + " will be IGNORED", io); } } @@ -306,24 +306,24 @@ public class OwnCloudClient extends HttpClient { int counter = 0; for (int i=0; i Build.VERSION_CODES.FROYO) { - Log.v(TAG, "SUPPORTED SSL PARAMETERS"); + Log_OCv(TAG, "SUPPORTED SSL PARAMETERS"); logSslParameters(mSslContext.getSupportedSSLParameters()); - Log.v(TAG, "DEFAULT SSL PARAMETERS"); + Log_OCv(TAG, "DEFAULT SSL PARAMETERS"); logSslParameters(mSslContext.getDefaultSSLParameters()); - Log.i(TAG, "CURRENT PARAMETERS"); - Log.i(TAG, "Protocol: " + mSslContext.getProtocol()); + Log_OCi(TAG, "CURRENT PARAMETERS"); + Log_OCi(TAG, "Protocol: " + mSslContext.getProtocol()); } - Log.i(TAG, "PROVIDER"); + Log_OCi(TAG, "PROVIDER"); logSecurityProvider(mSslContext.getProvider()); } private void logSecurityProvider(Provider provider) { - Log.i(TAG, "name: " + provider.getName()); - Log.i(TAG, "version: " + provider.getVersion()); - Log.i(TAG, "info: " + provider.getInfo()); + Log_OCi(TAG, "name: " + provider.getName()); + Log_OCi(TAG, "version: " + provider.getVersion()); + Log_OCi(TAG, "info: " + provider.getInfo()); Enumeration keys = provider.propertyNames(); String key; while (keys.hasMoreElements()) { key = (String) keys.nextElement(); - Log.i(TAG, " property " + key + " : " + provider.getProperty(key)); + Log_OCi(TAG, " property " + key + " : " + provider.getProperty(key)); } } private void logSslParameters(SSLParameters params) { - Log.v(TAG, "Cipher suites: "); + Log_OCv(TAG, "Cipher suites: "); String [] elements = params.getCipherSuites(); for (int i=0; i sslSocketClass) { - Log.i(TAG, "SSLSocket implementation: " + sslSocketClass.getCanonicalName()); + Log_OC.i(TAG, "SSLSocket implementation: " + sslSocketClass.getCanonicalName()); Method setHostnameMethod = null; try { setHostnameMethod = sslSocketClass.getMethod(METHOD_NAME, String.class); } catch (SecurityException e) { - Log.e(TAG, "Could not access to SSLSocket#setHostname(String) method ", e); + Log_OC.e(TAG, "Could not access to SSLSocket#setHostname(String) method ", e); } catch (NoSuchMethodException e) { - Log.i(TAG, "Could not find SSLSocket#setHostname(String) method - SNI not supported"); + Log_OC.i(TAG, "Could not find SSLSocket#setHostname(String) method - SNI not supported"); } mSingleInstance.set(new ServerNameIndicator(sslSocketClass, setHostnameMethod)); return setHostnameMethod; diff --git a/src/com/owncloud/android/lib/common/network/WebdavEntry.java b/src/com/owncloud/android/lib/common/network/WebdavEntry.java index d6fe7a54..d8b88fa8 100644 --- a/src/com/owncloud/android/lib/common/network/WebdavEntry.java +++ b/src/com/owncloud/android/lib/common/network/WebdavEntry.java @@ -33,7 +33,8 @@ import org.apache.jackrabbit.webdav.property.DavPropertySet; import org.apache.jackrabbit.webdav.xml.Namespace; import android.net.Uri; -import android.util.Log; + +import com.owncloud.android.lib.common.utils.Log_OC; public class WebdavEntry { private static final String NAMESPACE_OC = "http://owncloud.org/ns"; @@ -125,7 +126,7 @@ public class WebdavEntry { } } else { - Log.e("WebdavEntry", + Log_OC.e("WebdavEntry", "General fuckup, no status for webdav response"); } } diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java index bef4b86c..d3eea6ee 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java @@ -26,6 +26,13 @@ package com.owncloud.android.lib.common.operations; import java.io.IOException; +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AccountsException; +import android.app.Activity; +import android.content.Context; +import android.os.Handler; + import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientFactory; @@ -33,16 +40,7 @@ import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.OwnCloudCredentials; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; - - - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AccountsException; -import android.app.Activity; -import android.content.Context; -import android.os.Handler; -import android.util.Log; +import com.owncloud.android.lib.common.utils.Log_OC; /** @@ -110,7 +108,7 @@ public abstract class RemoteOperation implements Runnable { mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). getClientFor(ocAccount, mContext); } catch (Exception e) { - Log.e(TAG, "Error while trying to access to " + mAccount.name, e); + Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e); return new RemoteOperationResult(e); } return run(mClient); @@ -266,11 +264,11 @@ public abstract class RemoteOperation implements Runnable { } } catch (IOException e) { - Log.e(TAG, "Error while trying to access to " + mAccount.name, new AccountsException("I/O exception while trying to authorize the account", e)); + Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, new AccountsException("I/O exception while trying to authorize the account", e)); result = new RemoteOperationResult(e); } catch (AccountsException e) { - Log.e(TAG, "Error while trying to access to " + mAccount.name, e); + Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e); result = new RemoteOperationResult(e); } diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 9bb0d4c7..0b86322e 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -43,10 +43,10 @@ import org.json.JSONException; import android.accounts.Account; import android.accounts.AccountsException; -import android.util.Log; import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; import com.owncloud.android.lib.common.network.CertificateCombinedException; +import com.owncloud.android.lib.common.utils.Log_OC; /** @@ -148,7 +148,7 @@ public class RemoteOperationResult implements Serializable { break; default: mCode = ResultCode.UNHANDLED_HTTP_CODE; - Log.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " + httpCode); + Log_OC.d(TAG, "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " + httpCode); } } } diff --git a/src/com/owncloud/android/lib/common/utils/Log_OC.java b/src/com/owncloud/android/lib/common/utils/Log_OC.java new file mode 100644 index 00000000..f3035dfa --- /dev/null +++ b/src/com/owncloud/android/lib/common/utils/Log_OC.java @@ -0,0 +1,169 @@ +package com.owncloud.android.lib.common.utils; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Calendar; + +import android.os.Environment; +import android.util.Log; + + +public class Log_OC { + private static final String SIMPLE_DATE_FORMAT = "yyyy/MM/dd HH:mm:ss"; + private static final String OWNCLOUD_DATA_FOLDER = "owncloud"; + private static final long MAX_FILE_SIZE = 1000000; // 1MB + + private static File mLogFile; + private static File mFolder; + private static BufferedWriter mBuf; + + private static String[] mLogFileNames = {"currentLog.txt", "olderLog.txt"}; + private static String mLogPath = Environment.getExternalStorageDirectory() + File.separator + + OWNCLOUD_DATA_FOLDER + File.separator + "log"; + + private static boolean isMaxFileSizeReached = false; + + public static void i(String TAG, String message){ + + // Write the log message to the file + appendLog(TAG+" : "+ message); + } + + public static void d(String TAG, String message){ + Log.d(TAG, message); + appendLog(TAG + " : " + message); + } + public static void d(String TAG, String message, Exception e) { + Log.d(TAG, message, e); + appendLog(TAG + " : " + message + " Exception : "+ e.getStackTrace()); + } + public static void e(String TAG, String message){ + Log.e(TAG, message); + appendLog(TAG + " : " + message); + } + + public static void e(String TAG, String message, Throwable e) { + Log.e(TAG, message, e); + appendLog(TAG+" : " + message +" Exception : " + e.getStackTrace()); + } + + public static void v(String TAG, String message){ + Log.v(TAG, message); + appendLog(TAG+" : "+ message); + } + + public static void w(String TAG, String message) { + Log.w(TAG,message); + appendLog(TAG+" : "+ message); + } + + public static void wtf(String TAG, String message) { + Log.wtf(TAG,message); + appendLog(TAG+" : "+ message); + } + + /** + * Start doing logging + * @param logPath : path of log file + */ + public static void startLogging(String logPath) { + mFolder = new File(logPath); + mLogFile = new File(mFolder + File.separator + mLogFileNames[0]); + + boolean isFileCreated = false; + + if (!mFolder.exists()) { + mFolder.mkdirs(); + isFileCreated = true; + Log_OC.d("LOG_OC", "Log file created"); + } + + try { + + if (isMaxFileSizeReached) { + + // Move current log file info to another file (old logs) + File olderFile = new File(mFolder + File.separator + mLogFileNames[1]); + if (mLogFile.exists()) { + mLogFile.renameTo(olderFile); + } + + // Construct a new file for current log info + mLogFile = new File(mFolder + File.separator + mLogFileNames[0]); + isMaxFileSizeReached = false; + } + + // Create the current log file if does not exist + mLogFile.createNewFile(); + mBuf = new BufferedWriter(new FileWriter(mLogFile, true)); + if (isFileCreated) { + appendPhoneInfo(); + } + + // Check if current log file size is bigger than the max file size defined + if (mLogFile.length() > MAX_FILE_SIZE) { + isMaxFileSizeReached = true; + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Delete history logging + */ + public static void deleteHistoryLogging() { + File folderLogs = new File(mFolder + File.separator); + if(folderLogs.isDirectory()){ + String[] myFiles = folderLogs.list(); + for (int i=0; i") || fileName.contains(":") || fileName.contains("\"") || fileName.contains("|") || @@ -65,7 +65,7 @@ public class FileUtils { public static boolean isValidPath(String path) { boolean result = true; - Log.d("FileUtils", "path ....... " + path); + Log_OC.d("FileUtils", "path ....... " + path); if (path.contains("\\") || path.contains("<") || path.contains(">") || path.contains(":") || path.contains("\"") || path.contains("|") || path.contains("?") || path.contains("*")) { diff --git a/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java index 5b997829..50a62596 100644 --- a/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java +++ b/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java @@ -30,13 +30,12 @@ import org.apache.jackrabbit.webdav.DavConstants; import org.apache.jackrabbit.webdav.MultiStatus; import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; -import android.util.Log; - import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.network.WebdavEntry; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; /** @@ -106,7 +105,7 @@ public class ReadRemoteFileOperation extends RemoteOperation { } catch (Exception e) { result = new RemoteOperationResult(e); e.printStackTrace(); - Log.e(TAG, "Synchronizing file " + mRemotePath + ": " + result.getLogMessage(), result.getException()); + Log_OC.e(TAG, "Synchronizing file " + mRemotePath + ": " + result.getLogMessage(), result.getException()); } finally { if (propfind != null) propfind.releaseConnection(); diff --git a/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java b/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java index e1d79b0f..af92d8fe 100644 --- a/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java +++ b/src/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java @@ -31,13 +31,12 @@ import org.apache.jackrabbit.webdav.DavConstants; import org.apache.jackrabbit.webdav.MultiStatus; import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; -import android.util.Log; - import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.network.WebdavEntry; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; /** * Remote operation performing the read of remote file or folder in the ownCloud server. @@ -109,12 +108,12 @@ public class ReadRemoteFolderOperation extends RemoteOperation { if (query != null) query.releaseConnection(); // let the connection available for other methods if (result.isSuccess()) { - Log.i(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage()); } else { if (result.isException()) { - Log.e(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage(), result.getException()); + Log_OC.e(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage(), result.getException()); } else { - Log.e(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage()); + Log_OC.e(TAG, "Synchronized " + mRemotePath + ": " + result.getLogMessage()); } } diff --git a/src/com/owncloud/android/lib/resources/files/RemoveRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/RemoveRemoteFileOperation.java index ed8158a0..acd524b9 100644 --- a/src/com/owncloud/android/lib/resources/files/RemoveRemoteFileOperation.java +++ b/src/com/owncloud/android/lib/resources/files/RemoveRemoteFileOperation.java @@ -27,12 +27,11 @@ package com.owncloud.android.lib.resources.files; import org.apache.commons.httpclient.HttpStatus; import org.apache.jackrabbit.webdav.client.methods.DeleteMethod; -import android.util.Log; - import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; /** * Remote operation performing the removal of a remote file or folder in the ownCloud server. @@ -73,11 +72,11 @@ public class RemoveRemoteFileOperation extends RemoteOperation { delete.getResponseBodyAsString(); // exhaust the response, although not interesting result = new RemoteOperationResult((delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), status, delete.getResponseHeaders()); - Log.i(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage(), e); + Log_OC.e(TAG, "Remove " + mRemotePath + ": " + result.getLogMessage(), e); } finally { if (delete != null) diff --git a/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java index a42543b0..8a9cd60f 100644 --- a/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java +++ b/src/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java @@ -28,13 +28,12 @@ import java.io.File; import org.apache.jackrabbit.webdav.client.methods.DavMethodBase; -import android.util.Log; - import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.lib.common.utils.Log_OC; /** @@ -109,11 +108,11 @@ public class RenameRemoteFileOperation extends RemoteOperation { move.getResponseBodyAsString(); // exhaust response, although not interesting result = new RemoteOperationResult(move.succeeded(), status, move.getResponseHeaders()); - Log.i(TAG, "Rename " + mOldRemotePath + " to " + mNewRemotePath + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Rename " + mOldRemotePath + " to " + mNewRemotePath + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Rename " + mOldRemotePath + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e); + Log_OC.e(TAG, "Rename " + mOldRemotePath + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e); } finally { if (move != null) diff --git a/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java b/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java index 55b5b7db..9bb06bc2 100644 --- a/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java +++ b/src/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.java @@ -31,12 +31,11 @@ import java.util.ArrayList; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.http.HttpStatus; -import android.util.Log; - import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.lib.common.utils.Log_OC; /** * Creates a new share. This allows sharing with a user or group or as a link. @@ -103,7 +102,7 @@ public class CreateRemoteShareOperation extends RemoteOperation { try { // Post Method post = new PostMethod(client.getBaseUri() + ShareUtils.SHARING_API_PATH); - //Log.d(TAG, "URL ------> " + client.getBaseUri() + ShareUtils.SHARING_API_PATH); + //Log_OC.d(TAG, "URL ------> " + client.getBaseUri() + ShareUtils.SHARING_API_PATH); post.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); // necessary for special characters post.addParameter(PARAM_PATH, mRemoteFilePath); @@ -131,7 +130,7 @@ public class CreateRemoteShareOperation extends RemoteOperation { mShares = xmlParser.parseXMLResponse(is); if (xmlParser.isSuccess()) { if (mShares != null) { - Log.d(TAG, "Created " + mShares.size() + " share(s)"); + Log_OC.d(TAG, "Created " + mShares.size() + " share(s)"); result = new RemoteOperationResult(ResultCode.OK); ArrayList sharesObjects = new ArrayList(); for (OCShare share: mShares) { @@ -155,7 +154,7 @@ public class CreateRemoteShareOperation extends RemoteOperation { } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Exception while Creating New Share", e); + Log_OC.e(TAG, "Exception while Creating New Share", e); } finally { if (post != null) { diff --git a/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.java b/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.java index bca3e257..21ef0ec7 100644 --- a/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.java +++ b/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.java @@ -32,12 +32,11 @@ import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.http.HttpStatus; -import android.util.Log; - import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.lib.common.utils.Log_OC; /** * Provide a list shares for a specific file. @@ -110,7 +109,7 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation { ShareXMLParser xmlParser = new ShareXMLParser(); mShares = xmlParser.parseXMLResponse(is); if (mShares != null) { - Log.d(TAG, "Got " + mShares.size() + " shares"); + Log_OC.d(TAG, "Got " + mShares.size() + " shares"); result = new RemoteOperationResult(ResultCode.OK); ArrayList sharesObjects = new ArrayList(); for (OCShare share: mShares) { @@ -129,7 +128,7 @@ public class GetRemoteSharesForFileOperation extends RemoteOperation { } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Exception while getting shares", e); + Log_OC.e(TAG, "Exception while getting shares", e); } finally { if (get != null) { diff --git a/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesOperation.java b/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesOperation.java index 05ceb710..5a97136f 100644 --- a/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesOperation.java +++ b/src/com/owncloud/android/lib/resources/shares/GetRemoteSharesOperation.java @@ -35,8 +35,7 @@ import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; - -import android.util.Log; +import com.owncloud.android.lib.common.utils.Log_OC; /** @@ -78,7 +77,7 @@ public class GetRemoteSharesOperation extends RemoteOperation { ShareXMLParser xmlParser = new ShareXMLParser(); mShares = xmlParser.parseXMLResponse(is); if (mShares != null) { - Log.d(TAG, "Got " + mShares.size() + " shares"); + Log_OC.d(TAG, "Got " + mShares.size() + " shares"); result = new RemoteOperationResult(ResultCode.OK); ArrayList sharesObjects = new ArrayList(); for (OCShare share: mShares) { @@ -92,7 +91,7 @@ public class GetRemoteSharesOperation extends RemoteOperation { } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Exception while getting remote shares ", e); + Log_OC.e(TAG, "Exception while getting remote shares ", e); } finally { if (get != null) { diff --git a/src/com/owncloud/android/lib/resources/shares/OCShare.java b/src/com/owncloud/android/lib/resources/shares/OCShare.java index 1bf6cc1a..638fd1b9 100644 --- a/src/com/owncloud/android/lib/resources/shares/OCShare.java +++ b/src/com/owncloud/android/lib/resources/shares/OCShare.java @@ -26,11 +26,11 @@ package com.owncloud.android.lib.resources.shares; import java.io.Serializable; -import com.owncloud.android.lib.resources.files.FileUtils; - import android.os.Parcel; import android.os.Parcelable; -import android.util.Log; + +import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.files.FileUtils; /** @@ -70,7 +70,7 @@ public class OCShare implements Parcelable, Serializable { public OCShare(String path) { resetData(); if (path == null || path.length() <= 0 || !path.startsWith(FileUtils.PATH_SEPARATOR)) { - Log.e(TAG, "Trying to create a OCShare with a non valid path"); + Log_OC.e(TAG, "Trying to create a OCShare with a non valid path"); throw new IllegalArgumentException("Trying to create a OCShare with a non valid path: " + path); } mPath = path; diff --git a/src/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.java b/src/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.java index db7a6d60..9b8c8b03 100644 --- a/src/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.java +++ b/src/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.java @@ -30,12 +30,11 @@ import java.io.InputStream; import org.apache.commons.httpclient.HttpStatus; import org.apache.jackrabbit.webdav.client.methods.DeleteMethod; -import android.util.Log; - import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.lib.common.utils.Log_OC; /** * Remove a share @@ -94,13 +93,13 @@ public class RemoveRemoteShareOperation extends RemoteOperation { result = new RemoteOperationResult(false, status, delete.getResponseHeaders()); } - Log.d(TAG, "Unshare " + id + ": " + result.getLogMessage()); + Log_OC.d(TAG, "Unshare " + id + ": " + result.getLogMessage()); } else { result = new RemoteOperationResult(false, status, delete.getResponseHeaders()); } } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Unshare Link Exception " + result.getLogMessage(), e); + Log_OC.e(TAG, "Unshare Link Exception " + result.getLogMessage(), e); } finally { if (delete != null) diff --git a/src/com/owncloud/android/lib/resources/shares/ShareXMLParser.java b/src/com/owncloud/android/lib/resources/shares/ShareXMLParser.java index 48a8358e..e45f206b 100644 --- a/src/com/owncloud/android/lib/resources/shares/ShareXMLParser.java +++ b/src/com/owncloud/android/lib/resources/shares/ShareXMLParser.java @@ -182,7 +182,7 @@ public class ShareXMLParser { */ private void readMeta(XmlPullParser parser) throws XmlPullParserException, IOException { parser.require(XmlPullParser.START_TAG, ns, NODE_META); - //Log.d(TAG, "---- NODE META ---"); + //Log_OC.d(TAG, "---- NODE META ---"); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) { continue; @@ -214,7 +214,7 @@ public class ShareXMLParser { OCShare share = null; parser.require(XmlPullParser.START_TAG, ns, NODE_DATA); - //Log.d(TAG, "---- NODE DATA ---"); + //Log_OC.d(TAG, "---- NODE DATA ---"); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) { continue; @@ -264,7 +264,7 @@ public class ShareXMLParser { OCShare share = new OCShare(); - //Log.d(TAG, "---- NODE ELEMENT ---"); + //Log_OC.d(TAG, "---- NODE ELEMENT ---"); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) { continue; @@ -360,7 +360,7 @@ public class ShareXMLParser { private String readNode (XmlPullParser parser, String node) throws XmlPullParserException, IOException{ parser.require(XmlPullParser.START_TAG, ns, node); String value = readText(parser); - //Log.d(TAG, "node= " + node + ", value= " + value); + //Log_OC.d(TAG, "node= " + node + ", value= " + value); parser.require(XmlPullParser.END_TAG, ns, node); return value; } diff --git a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java index a9a16bde..a32f9161 100644 --- a/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java +++ b/src/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java @@ -34,12 +34,12 @@ import org.json.JSONObject; import android.content.Context; import android.net.ConnectivityManager; import android.net.Uri; -import android.util.Log; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; /** * Checks if the server is valid and if the server supports the Share API @@ -158,14 +158,14 @@ public class GetRemoteStatusOperation extends RemoteOperation { } if (mLatestResult.isSuccess()) { - Log.i(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage()); + Log_OC.i(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage()); } else if (mLatestResult.getException() != null) { - Log.e(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage(), + Log_OC.e(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException()); } else { - Log.e(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage()); + Log_OC.e(TAG, "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage()); } return retval; @@ -191,7 +191,7 @@ public class GetRemoteStatusOperation extends RemoteOperation { client.setBaseUri(Uri.parse("https://" + baseUriStr)); boolean httpsSuccess = tryConnection(client); if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) { - Log.d(TAG, "establishing secure connection failed, trying non secure connection"); + Log_OC.d(TAG, "establishing secure connection failed, trying non secure connection"); client.setBaseUri(Uri.parse("http://" + baseUriStr)); tryConnection(client); } diff --git a/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java b/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java index f153be44..36ce7ffc 100644 --- a/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java +++ b/src/com/owncloud/android/lib/resources/users/GetRemoteUserNameOperation.java @@ -30,11 +30,10 @@ import org.apache.commons.httpclient.methods.GetMethod; import org.apache.http.HttpStatus; import org.json.JSONObject; -import android.util.Log; - import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; /** @@ -83,7 +82,7 @@ public class GetRemoteUserNameOperation extends RemoteOperation { status = client.executeMethod(get); if(isSuccess(status)) { String response = get.getResponseBodyAsString(); - Log.d(TAG, "Successful response: " + response); + Log_OC.d(TAG, "Successful response: " + response); // Parse the response JSONObject respJSON = new JSONObject(response); @@ -101,21 +100,21 @@ public class GetRemoteUserNameOperation extends RemoteOperation { result.setData(data); mUserName = displayName; - Log.d(TAG, "*** Parsed user information: " + id + " - " + displayName + " - " + email); + Log_OC.d(TAG, "*** Parsed user information: " + id + " - " + displayName + " - " + email); } else { result = new RemoteOperationResult(false, status, get.getResponseHeaders()); String response = get.getResponseBodyAsString(); - Log.e(TAG, "Failed response while getting user information "); + Log_OC.e(TAG, "Failed response while getting user information "); if (response != null) { - Log.e(TAG, "*** status code: " + status + " ; response message: " + response); + Log_OC.e(TAG, "*** status code: " + status + " ; response message: " + response); } else { - Log.e(TAG, "*** status code: " + status); + Log_OC.e(TAG, "*** status code: " + status); } } } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Exception while getting OC user information", e); + Log_OC.e(TAG, "Exception while getting OC user information", e); } finally { get.releaseConnection(); From cb7b547cd71f3b58628c292fbc92677aaf18cb47 Mon Sep 17 00:00:00 2001 From: jabarros Date: Fri, 12 Sep 2014 11:22:46 +0200 Subject: [PATCH 18/23] Create method for making available the change of the log folder --- .../android/lib/common/utils/Log_OC.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/com/owncloud/android/lib/common/utils/Log_OC.java b/src/com/owncloud/android/lib/common/utils/Log_OC.java index f3035dfa..91b5f98f 100644 --- a/src/com/owncloud/android/lib/common/utils/Log_OC.java +++ b/src/com/owncloud/android/lib/common/utils/Log_OC.java @@ -13,19 +13,23 @@ import android.util.Log; public class Log_OC { private static final String SIMPLE_DATE_FORMAT = "yyyy/MM/dd HH:mm:ss"; - private static final String OWNCLOUD_DATA_FOLDER = "owncloud"; + private static final String LOG_FOLDER_NAME = "log"; private static final long MAX_FILE_SIZE = 1000000; // 1MB + private static String mOwncloudDataFolderLog = "owncloud_log"; + private static File mLogFile; private static File mFolder; private static BufferedWriter mBuf; private static String[] mLogFileNames = {"currentLog.txt", "olderLog.txt"}; - private static String mLogPath = Environment.getExternalStorageDirectory() + File.separator + - OWNCLOUD_DATA_FOLDER + File.separator + "log"; private static boolean isMaxFileSizeReached = false; + public static void setLogDataFolder(String logFolder){ + mOwncloudDataFolderLog = logFolder; + } + public static void i(String TAG, String message){ // Write the log message to the file @@ -69,7 +73,9 @@ public class Log_OC { * Start doing logging * @param logPath : path of log file */ - public static void startLogging(String logPath) { + public static void startLogging() { + String logPath = Environment.getExternalStorageDirectory() + File.separator + + mOwncloudDataFolderLog + File.separator + LOG_FOLDER_NAME; mFolder = new File(logPath); mLogFile = new File(mFolder + File.separator + mLogFileNames[0]); @@ -78,7 +84,7 @@ public class Log_OC { if (!mFolder.exists()) { mFolder.mkdirs(); isFileCreated = true; - Log_OC.d("LOG_OC", "Log file created"); + Log.d("LOG_OC", "Log file created"); } try { @@ -143,7 +149,9 @@ public class Log_OC { * @param text : text for adding to the log file */ private static void appendLog(String text) { - startLogging(mLogPath); + + startLogging(); + String timeStamp = new SimpleDateFormat(SIMPLE_DATE_FORMAT).format(Calendar.getInstance().getTime()); try { From 092427766267fceb5572fa1a64870c3fe40d8849 Mon Sep 17 00:00:00 2001 From: jabarros Date: Fri, 12 Sep 2014 13:33:07 +0200 Subject: [PATCH 19/23] Update logger for not start logging each time it is something appended --- .../android/lib/common/utils/Log_OC.java | 74 ++++++++++--------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/src/com/owncloud/android/lib/common/utils/Log_OC.java b/src/com/owncloud/android/lib/common/utils/Log_OC.java index 91b5f98f..ed2fe6ee 100644 --- a/src/com/owncloud/android/lib/common/utils/Log_OC.java +++ b/src/com/owncloud/android/lib/common/utils/Log_OC.java @@ -25,6 +25,7 @@ public class Log_OC { private static String[] mLogFileNames = {"currentLog.txt", "olderLog.txt"}; private static boolean isMaxFileSizeReached = false; + private static boolean isEnabled = false; public static void setLogDataFolder(String logFolder){ mOwncloudDataFolderLog = logFolder; @@ -78,9 +79,9 @@ public class Log_OC { mOwncloudDataFolderLog + File.separator + LOG_FOLDER_NAME; mFolder = new File(logPath); mLogFile = new File(mFolder + File.separator + mLogFileNames[0]); - + boolean isFileCreated = false; - + if (!mFolder.exists()) { mFolder.mkdirs(); isFileCreated = true; @@ -89,35 +90,20 @@ public class Log_OC { try { - if (isMaxFileSizeReached) { - - // Move current log file info to another file (old logs) - File olderFile = new File(mFolder + File.separator + mLogFileNames[1]); - if (mLogFile.exists()) { - mLogFile.renameTo(olderFile); - } - - // Construct a new file for current log info - mLogFile = new File(mFolder + File.separator + mLogFileNames[0]); - isMaxFileSizeReached = false; - } - // Create the current log file if does not exist mLogFile.createNewFile(); mBuf = new BufferedWriter(new FileWriter(mLogFile, true)); + isEnabled = true; + if (isFileCreated) { appendPhoneInfo(); } - // Check if current log file size is bigger than the max file size defined - if (mLogFile.length() > MAX_FILE_SIZE) { - isMaxFileSizeReached = true; - } } catch (IOException e) { e.printStackTrace(); } } - + /** * Delete history logging */ @@ -150,28 +136,44 @@ public class Log_OC { */ private static void appendLog(String text) { - startLogging(); + if (isEnabled) { - String timeStamp = new SimpleDateFormat(SIMPLE_DATE_FORMAT).format(Calendar.getInstance().getTime()); + if (isMaxFileSizeReached) { - try { - mBuf = new BufferedWriter(new FileWriter(mLogFile, true)); - mBuf.newLine(); - mBuf.write(timeStamp); - mBuf.newLine(); - mBuf.write(text); - mBuf.newLine(); - mBuf.close(); - } catch (IOException e) { - e.printStackTrace(); - } + // Move current log file info to another file (old logs) + File olderFile = new File(mFolder + File.separator + mLogFileNames[1]); + if (mLogFile.exists()) { + mLogFile.renameTo(olderFile); + } + + // Construct a new file for current log info + mLogFile = new File(mFolder + File.separator + mLogFileNames[0]); + isMaxFileSizeReached = false; + } + + String timeStamp = new SimpleDateFormat(SIMPLE_DATE_FORMAT).format(Calendar.getInstance().getTime()); + + try { + mBuf = new BufferedWriter(new FileWriter(mLogFile, true)); + mBuf.newLine(); + mBuf.write(timeStamp); + mBuf.newLine(); + mBuf.write(text); + mBuf.newLine(); + mBuf.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + // Check if current log file size is bigger than the max file size defined + if (mLogFile.length() > MAX_FILE_SIZE) { + isMaxFileSizeReached = true; + } + } } public static String[] getLogFileNames() { return mLogFileNames; } - public static void setmLogFileNames(String[] logFileNames) { - Log_OC.mLogFileNames = logFileNames; - } } From b7508d8462fc1c38a17f265a40909acc48f164f8 Mon Sep 17 00:00:00 2001 From: jabarros Date: Wed, 17 Sep 2014 09:24:54 +0200 Subject: [PATCH 20/23] Fixed error in logs in AdvancedSslSockectFactory class after CR --- .../network/AdvancedSslSocketFactory.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/com/owncloud/android/lib/common/network/AdvancedSslSocketFactory.java b/src/com/owncloud/android/lib/common/network/AdvancedSslSocketFactory.java index b5662696..7b41282b 100644 --- a/src/com/owncloud/android/lib/common/network/AdvancedSslSocketFactory.java +++ b/src/com/owncloud/android/lib/common/network/AdvancedSslSocketFactory.java @@ -93,39 +93,39 @@ public class AdvancedSslSocketFactory implements ProtocolSocketFactory { /* private void logSslInfo() { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) { - Log_OCv(TAG, "SUPPORTED SSL PARAMETERS"); + Log_OC.v(TAG, "SUPPORTED SSL PARAMETERS"); logSslParameters(mSslContext.getSupportedSSLParameters()); - Log_OCv(TAG, "DEFAULT SSL PARAMETERS"); + Log_OC.v(TAG, "DEFAULT SSL PARAMETERS"); logSslParameters(mSslContext.getDefaultSSLParameters()); - Log_OCi(TAG, "CURRENT PARAMETERS"); - Log_OCi(TAG, "Protocol: " + mSslContext.getProtocol()); + Log_OC.i(TAG, "CURRENT PARAMETERS"); + Log_OC.i(TAG, "Protocol: " + mSslContext.getProtocol()); } - Log_OCi(TAG, "PROVIDER"); + Log_OC.i(TAG, "PROVIDER"); logSecurityProvider(mSslContext.getProvider()); } private void logSecurityProvider(Provider provider) { - Log_OCi(TAG, "name: " + provider.getName()); - Log_OCi(TAG, "version: " + provider.getVersion()); - Log_OCi(TAG, "info: " + provider.getInfo()); + Log_OC.i(TAG, "name: " + provider.getName()); + Log_OC.i(TAG, "version: " + provider.getVersion()); + Log_OC.i(TAG, "info: " + provider.getInfo()); Enumeration keys = provider.propertyNames(); String key; while (keys.hasMoreElements()) { key = (String) keys.nextElement(); - Log_OCi(TAG, " property " + key + " : " + provider.getProperty(key)); + Log_OC.i(TAG, " property " + key + " : " + provider.getProperty(key)); } } private void logSslParameters(SSLParameters params) { - Log_OCv(TAG, "Cipher suites: "); + Log_OC.v(TAG, "Cipher suites: "); String [] elements = params.getCipherSuites(); for (int i=0; i Date: Wed, 1 Oct 2014 12:44:02 +0200 Subject: [PATCH 21/23] Increase SYN_READ_TIMEOUT in ReadRemoteFileOperation until 40000 milliseconds --- .../android/lib/resources/files/ReadRemoteFileOperation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java index 50a62596..3fb695a4 100644 --- a/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java +++ b/src/com/owncloud/android/lib/resources/files/ReadRemoteFileOperation.java @@ -48,7 +48,7 @@ import com.owncloud.android.lib.common.utils.Log_OC; public class ReadRemoteFileOperation extends RemoteOperation { private static final String TAG = ReadRemoteFileOperation.class.getSimpleName(); - private static final int SYNC_READ_TIMEOUT = 10000; + private static final int SYNC_READ_TIMEOUT = 40000; private static final int SYNC_CONNECTION_TIMEOUT = 5000; private String mRemotePath; From 67c41d8ec3bdad77e65280bee9498413b53c8d5f Mon Sep 17 00:00:00 2001 From: jabarros Date: Mon, 20 Oct 2014 10:42:26 +0200 Subject: [PATCH 22/23] Check Travis update --- src/com/owncloud/android/lib/common/utils/Log_OC.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/com/owncloud/android/lib/common/utils/Log_OC.java b/src/com/owncloud/android/lib/common/utils/Log_OC.java index ed2fe6ee..8ed8c52c 100644 --- a/src/com/owncloud/android/lib/common/utils/Log_OC.java +++ b/src/com/owncloud/android/lib/common/utils/Log_OC.java @@ -175,5 +175,4 @@ public class Log_OC { public static String[] getLogFileNames() { return mLogFileNames; } - } From 8764ac8f63323b8739a645a701ed75fdc62339c3 Mon Sep 17 00:00:00 2001 From: jabarros Date: Mon, 20 Oct 2014 11:24:12 +0200 Subject: [PATCH 23/23] Update travis.yml file for building with new Android support in Travis --- .travis.yml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2920d050..3619bd9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,16 @@ -language: java +language: android +android: + components: + - build-tools-20.0.0 + - android-19 + - android-17 + - android-14 + - extra-android-support + licenses: + - 'android-sdk-license-5be876d5' + - 'android-sdk-license-598b93a6' jdk: oraclejdk7 before_install: -- sudo apt-get update -qq -- sudo apt-get install -qq libstdc++6:i386 lib32z1 expect -- export LICENSES="android-sdk-license-5be876d5|android-sdk-license-598b93a6" -- curl -3L https://raw.github.com/embarkmobile/android-sdk-installer/version-2/android-sdk-installer - | bash /dev/stdin --install=$COMPONENTS --accept=$LICENSES -- source ~/.android-sdk-installer/env - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI -c 20M - emulator -avd test -no-skin -no-audio -no-window & - rm pom.xml @@ -25,4 +29,4 @@ env: - secure: aF4U20Xlu/rfrbxCmoJAiGh1doYTAZ10UEDmajuinT+ZGSJLivuqD7DDY/00sI6IXWg+J1vL+7jJm4JSYusHPg38UHZ4q92k6RmZycW2ATUzZnGT54O5FRnY67MfVwgVpIMK9UOL/6NEciBHEjlIOL0wbKQiJB++1YtBZOQLGL4= - secure: N+ECSwNg8v2GsAFJ2y/tCiffauHDpN76zuFI2pDqf0fjmCtJZHu4BH5ArXBHjyHKmgn20a/8eZXcwJaH1HsJ80bo7vDJ2miShjGIQ90hPcdmUiB2XVJcew4f04CtvMDH5o7DRt4ykWArlbPL2rhVag0jotlSidolHBwRFnbDhDY= matrix: - - COMPONENTS=build-tools-20.0.0,android-19,sys-img-armeabi-v7a-android-19 ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a + - ANDROID_TARGET=android-19 ANDROID_ABI=armeabi-v7a