Commit f18487cf authored by Vincent Bourgmayer's avatar Vincent Bourgmayer 🎼
Browse files

rewrote begin() & startScan(boolean) from ObserverService. Make Davclient a...

rewrote begin() & startScan(boolean) from ObserverService. Make Davclient a local  var instead of a class's field
parent 51dcb107
Pipeline #28753 passed with stage
in 1 minute and 47 seconds
...@@ -16,7 +16,7 @@ android { ...@@ -16,7 +16,7 @@ android {
applicationId "foundation.e.drive" applicationId "foundation.e.drive"
minSdkVersion 24 minSdkVersion 24
versionCode 1 versionCode 1
versionName "alpha-${versionMajor}-build-${buildTime()}" versionName "beta-${versionMajor}-build-n-${buildTime()}"
setProperty("archivesBaseName", "$applicationId.$versionName") setProperty("archivesBaseName", "$applicationId.$versionName")
} }
......
...@@ -8,12 +8,15 @@ ...@@ -8,12 +8,15 @@
package foundation.e.drive.models; package foundation.e.drive.models;
import android.os.Parcel;
import android.os.Parcelable;
/** /**
* @author Vincent Bourgmayer * @author Vincent Bourgmayer
* Describe a file state which will be Synchronized (= Synced) or which has already been synced one times * Describe a file state which will be Synchronized (= Synced) or which has already been synced one times
*/ */
public class SyncedFileState { public class SyncedFileState implements Parcelable {
protected SyncedFileState(){}; //@ToRemove. Test Only. It's to allow to make a mock SyncedFileState Class in test. protected SyncedFileState(){}; //@ToRemove. Test Only. It's to allow to make a mock SyncedFileState Class in test.
private int id; private int id;
...@@ -46,6 +49,42 @@ public class SyncedFileState { ...@@ -46,6 +49,42 @@ public class SyncedFileState {
this.isMediaType = isMediaType; this.isMediaType = isMediaType;
} }
protected SyncedFileState(Parcel in) {
id = in.readInt();
name = in.readString();
localPath = in.readString();
remotePath = in.readString();
lastETAG = in.readString();
localLastModified = in.readLong();
syncedFolderId = in.readLong();
isMediaType = in.readByte() != 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
dest.writeString(localPath);
dest.writeString(remotePath);
dest.writeString(lastETAG);
dest.writeLong(localLastModified);
dest.writeLong(syncedFolderId);
dest.writeByte((byte) (isMediaType ? 1 : 0));
}
public static final Creator<SyncedFileState> CREATOR = new Creator<SyncedFileState>() {
@Override
public SyncedFileState createFromParcel(Parcel in) {
return new SyncedFileState(in);
}
@Override
public SyncedFileState[] newArray(int size) {
return new SyncedFileState[size];
}
};
public int getId() { public int getId() {
return id; return id;
} }
...@@ -125,4 +164,9 @@ public class SyncedFileState { ...@@ -125,4 +164,9 @@ public class SyncedFileState {
+"\nSyncedFolderId: "+this.syncedFolderId +"\nSyncedFolderId: "+this.syncedFolderId
+"\nisMediaType: "+this.isMediaType; +"\nisMediaType: "+this.isMediaType;
} }
@Override
public int describeContents() {
return 0;
}
} }
...@@ -4,18 +4,6 @@ import com.owncloud.android.lib.common.operations.RemoteOperation; ...@@ -4,18 +4,6 @@ import com.owncloud.android.lib.common.operations.RemoteOperation;
public interface ComparableOperation { public interface ComparableOperation {
/**
* Return the path that point on a remote file
* @return String URI of the file
*/
public String getRemotePath();
/**
* Return the path that point on a local file
* @return String URI of the file
*/
public String getLocalPath();
/** /**
* Say if File affected by operation is a media or a settings * Say if File affected by operation is a media or a settings
* @return * @return
......
...@@ -9,16 +9,15 @@ ...@@ -9,16 +9,15 @@
package foundation.e.drive.operations; package foundation.e.drive.operations;
import android.content.Context; import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log; import android.util.Log;
import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.files.FileUtils; import com.owncloud.android.lib.resources.files.FileUtils;
import com.owncloud.android.lib.resources.files.model.RemoteFile; import com.owncloud.android.lib.resources.files.model.RemoteFile;
import java.io.File; import java.io.File;
import foundation.e.drive.database.DbHelper; import foundation.e.drive.database.DbHelper;
import foundation.e.drive.models.SyncedFileState; import foundation.e.drive.models.SyncedFileState;
import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.CommonUtils;
...@@ -28,61 +27,68 @@ import foundation.e.drive.utils.CommonUtils; ...@@ -28,61 +27,68 @@ import foundation.e.drive.utils.CommonUtils;
* Encapsulate a global download process for a file * Encapsulate a global download process for a file
*/ */
public class DownloadFileOperation extends RemoteOperation implements ComparableOperation{ public class DownloadFileOperation extends RemoteOperation implements ComparableOperation, Parcelable {
private final static String TAG = DownloadFileOperation.class.getSimpleName(); private final static String TAG = DownloadFileOperation.class.getSimpleName();
private final RemoteFile mRFile; private final RemoteFile mRFile;
private final Context mContext; private Context mContext;
private String mTargetPath; private String mTargetPath;
private int restartCounter =0; private int restartCounter =0;
private SyncedFileState mSyncedState; private SyncedFileState mSyncedState;
private String previousEtag; private String previousEtag;
/** /**
* Constructor download operation for new file * COnstructor of download operation where syncedFileState is already known
* @param remoteFile Must not be null. File to download * @param remoteFile remote file to Download
* @param targetPath Local Path where to download the file Must not be null or empty * @param syncedFileState SyncedFileState corresponding to remote file
* @param context context of the app not service context
*/ */
public DownloadFileOperation(RemoteFile remoteFile, String targetPath, Long syncedFolderId,boolean syncedFolderIsMediaType, Context context){ public DownloadFileOperation(RemoteFile remoteFile, SyncedFileState syncedFileState){
this.mContext = context;
this.mRFile = remoteFile; this.mRFile = remoteFile;
String remotePath = remoteFile.getRemotePath(); this.mSyncedState = syncedFileState;
this.mSyncedState = DbHelper.loadSyncedFile(mContext, remotePath, false );
this.mTargetPath = targetPath;
if(this.mSyncedState == null){ //It's the first synchronisation of this file
Log.d(TAG, " no SyncedFileState stored in DB for: "+remoteFile.getRemotePath()
+"\n so it's first synchronisation of this file");
this.mSyncedState = new SyncedFileState(-1,
CommonUtils.getFileNameFromPath( remotePath ), //No need to check if null. It has already be done in ObserverService
this.mTargetPath,
remotePath,
this.mRFile.getEtag(),
0L,
syncedFolderId, syncedFolderIsMediaType);
}
this.previousEtag = mSyncedState.getLastETAG(); this.previousEtag = mSyncedState.getLastETAG();
this.mTargetPath = this.mSyncedState.getLocalPath();
}
protected DownloadFileOperation(Parcel in) {
mRFile = in.readParcelable(RemoteFile.class.getClassLoader());
mTargetPath = in.readString();
restartCounter = in.readInt();
mSyncedState = in.readParcelable(SyncedFileState.class.getClassLoader());
previousEtag = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(mRFile, flags);
dest.writeString(mTargetPath);
dest.writeInt(restartCounter);
dest.writeParcelable(mSyncedState, flags);
dest.writeString(previousEtag);
} }
public static final Creator<DownloadFileOperation> CREATOR = new Creator<DownloadFileOperation>() {
@Override
public DownloadFileOperation createFromParcel(Parcel in) {
return new DownloadFileOperation(in);
}
@Override
public DownloadFileOperation[] newArray(int size) {
return new DownloadFileOperation[size];
}
};
/** /**
* COnstructor of download operation where syncedFileState is already known * Set the context required to use DB
* @param remoteFile remote file to Download * @param context
* @param targetPath can be null if defined in syncedFileState
* @param context calling context
* @param syncedFileState SyncedFileState corresponding to remote file
*/ */
public DownloadFileOperation(RemoteFile remoteFile, String targetPath, Context context, SyncedFileState syncedFileState){ public void setContext(Context context){
this.mRFile = remoteFile;
this.mContext = context; this.mContext = context;
this.mSyncedState = syncedFileState;
this.previousEtag = mSyncedState.getLastETAG();
this.mTargetPath = (targetPath == null)?this.mSyncedState.getLocalPath(): targetPath;
} }
@Override @Override
protected RemoteOperationResult run(OwnCloudClient ownCloudClient) { protected RemoteOperationResult run(OwnCloudClient ownCloudClient) {
Log.i(TAG, "run(ownCloudClient)"); Log.i(TAG, "run(ownCloudClient)");
...@@ -181,17 +187,12 @@ public class DownloadFileOperation extends RemoteOperation implements Comparable ...@@ -181,17 +187,12 @@ public class DownloadFileOperation extends RemoteOperation implements Comparable
} }
@Override @Override
public String getRemotePath() { public RemoteOperation toRemoteOperation() {
return mSyncedState.getRemotePath(); return this;
}
@Override
public String getLocalPath() {
return mTargetPath;
} }
@Override @Override
public RemoteOperation toRemoteOperation() { public int describeContents() {
return this; return 0;
} }
} }
...@@ -8,17 +8,18 @@ ...@@ -8,17 +8,18 @@
package foundation.e.drive.operations; package foundation.e.drive.operations;
import android.os.Parcel;
import android.os.Parcelable;
import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.resources.files.RemoveFileRemoteOperation; import com.owncloud.android.lib.resources.files.RemoveFileRemoteOperation;
import foundation.e.drive.models.SyncedFileState; import foundation.e.drive.models.SyncedFileState;
/** /**
*
* @author Vincent Bourgmayer * @author Vincent Bourgmayer
* Created by Vincent on 19/06/2018. * Created by Vincent on 19/06/2018.
* Class to be able to wrap concerned SyncedFileState in operation, so it can be retrieve at the end * Class to be able to wrap concerned SyncedFileState in operation, so it can be retrieve at the end
*/ */
public class RemoveFileOperation extends RemoveFileRemoteOperation implements ComparableOperation{ public class RemoveFileOperation extends RemoveFileRemoteOperation implements ComparableOperation, Parcelable {
private SyncedFileState mSyncedFileState; private SyncedFileState mSyncedFileState;
...@@ -27,6 +28,29 @@ public class RemoveFileOperation extends RemoveFileRemoteOperation implements Co ...@@ -27,6 +28,29 @@ public class RemoveFileOperation extends RemoveFileRemoteOperation implements Co
this.mSyncedFileState = syncedFileState; this.mSyncedFileState = syncedFileState;
} }
protected RemoveFileOperation(Parcel in) {
super(in.readString());
this.mSyncedFileState = in.readParcelable(SyncedFileState.class.getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mSyncedFileState.getRemotePath());
dest.writeParcelable(this.mSyncedFileState, flags);
}
public static final Creator<RemoveFileOperation> CREATOR = new Creator<RemoveFileOperation>() {
@Override
public RemoveFileOperation createFromParcel(Parcel in) {
return new RemoveFileOperation(in);
}
@Override
public RemoveFileOperation[] newArray(int size) {
return new RemoveFileOperation[size];
}
};
public SyncedFileState getSyncedFileState() { public SyncedFileState getSyncedFileState() {
return mSyncedFileState; return mSyncedFileState;
} }
...@@ -41,19 +65,12 @@ public class RemoveFileOperation extends RemoveFileRemoteOperation implements Co ...@@ -41,19 +65,12 @@ public class RemoveFileOperation extends RemoveFileRemoteOperation implements Co
} }
@Override @Override
public String getRemotePath() { public RemoteOperation toRemoteOperation() {
return this.mSyncedFileState.getRemotePath(); return this;
} }
/**
* @inherited
*/
@Override @Override
public String getLocalPath() { public int describeContents() {
return getSyncedFileState().getLocalPath(); return 0;
}
@Override
public RemoteOperation toRemoteOperation() {
return this;
} }
} }
...@@ -9,8 +9,11 @@ ...@@ -9,8 +9,11 @@
package foundation.e.drive.operations; package foundation.e.drive.operations;
import android.content.Context; import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log; import android.util.Log;
import java.io.File; import java.io.File;
import java.security.InvalidParameterException;
import java.util.ArrayList; import java.util.ArrayList;
import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.UserInfo; import com.owncloud.android.lib.common.UserInfo;
...@@ -29,71 +32,61 @@ import foundation.e.drive.utils.CommonUtils; ...@@ -29,71 +32,61 @@ import foundation.e.drive.utils.CommonUtils;
* @author Vincent Bourgmayer * @author Vincent Bourgmayer
* High level Operation which upload a local file to a remote cloud storage * High level Operation which upload a local file to a remote cloud storage
*/ */
public class UploadFileOperation extends RemoteOperation implements ComparableOperation{ public class UploadFileOperation extends RemoteOperation implements ComparableOperation, Parcelable {
private final static String TAG = UploadFileOperation.class.getSimpleName(); private final static String TAG = UploadFileOperation.class.getSimpleName();
private int restartCounter =0; private int restartCounter =0;
private long previousLastModified; //get to restore real value if all trials fails private long previousLastModified; //get to restore real value if all trials fails
private boolean checkEtag; private boolean checkEtag;
private String mTargetPath; private Context mContext;
private final File mFile;
private final Context mContext;
private SyncedFileState mSyncedState; private SyncedFileState mSyncedState;
private long availableQuota = -1; private long availableQuota = -1;
@Override protected UploadFileOperation(Parcel in) {
public RemoteOperation toRemoteOperation() { restartCounter = in.readInt();
return this; previousLastModified = in.readLong();
checkEtag = in.readByte() != 0;
mSyncedState = in.readParcelable(SyncedFileState.class.getClassLoader());
availableQuota = in.readLong();
} }
/** public static final Creator<UploadFileOperation> CREATOR = new Creator<UploadFileOperation>() {
* Constructor of uploadFileOperation when there is no syncedFileState provide @Override
* @param file The local file to synchronize public UploadFileOperation createFromParcel(Parcel in) {
* @param targetPath target path to upload filte. must not be null. return new UploadFileOperation(in);
* @param syncedFolderId needed for new file to upload }
* @param context executing context
*/
public UploadFileOperation(File file, String targetPath, Long syncedFolderId,boolean syncedFolderIsMediaType, Context context){
this.mFile = file;
this.mContext = context;
this.mTargetPath = targetPath;
String localPath = CommonUtils.getLocalPath( mFile );
//Try to load syncedFileState from DB
this.mSyncedState = DbHelper.loadSyncedFile( mContext,
localPath, true );
//Create a new instance and stored it if not stored in DB before @Override
if( this.mSyncedState == null ){ public UploadFileOperation[] newArray(int size) {
//It's the first synchronisation of this file return new UploadFileOperation[size];
Log.d( TAG, "it's first synchronisation of:"+mFile.getName() );
this.mSyncedState = new SyncedFileState(-1, mFile.getName(),
localPath,
mTargetPath ,
"",
0,
syncedFolderId, syncedFolderIsMediaType);
} }
Log.v(TAG, ""+mSyncedState.getLocalLastModified() ); };
this.previousLastModified = mSyncedState.getLocalLastModified();
@Override
public RemoteOperation toRemoteOperation() {
return this;
} }
/** /**
* Construct an upload operation with an already known syncedFileState * Construct an upload operation with an already known syncedFileState
* @param file File to upload
* @param context context in which to upload
* @param syncedFileState syncedFileState corresponding to file. * @param syncedFileState syncedFileState corresponding to file.
* @param checkEtag if we should use IF MATCH header with etag * @param checkEtag if we should use IF MATCH header with etag
*/ */
public UploadFileOperation (File file, Context context, SyncedFileState syncedFileState, boolean checkEtag){ public UploadFileOperation (SyncedFileState syncedFileState, boolean checkEtag){
this.mFile = file;
this.mContext = context;
this.mSyncedState = syncedFileState; this.mSyncedState = syncedFileState;
this.mTargetPath = syncedFileState.getRemotePath();
this.previousLastModified = mSyncedState.getLocalLastModified(); this.previousLastModified = mSyncedState.getLocalLastModified();
this.checkEtag = checkEtag; this.checkEtag = checkEtag;
} }
public void setContext(Context context){
this.mContext = context;
}
/** /**
* Execute the operation: * Execute the operation:
* *
...@@ -108,29 +101,34 @@ public class UploadFileOperation extends RemoteOperation implements ComparableOp ...@@ -108,29 +101,34 @@ public class UploadFileOperation extends RemoteOperation implements ComparableOp
@Override @Override
protected RemoteOperationResult run( OwnCloudClient client ) { protected RemoteOperationResult run( OwnCloudClient client ) {
//as operation isn't executed immediatly, file might have been deleted since creation of operation //as operation isn't executed immediatly, file might have been deleted since creation of operation
if(mSyncedState == null || mTargetPath == null || !mFile.exists()){ if(mSyncedState == null){
Log.e(TAG, "run(client): no syncedFileState or target path, can't perform upload operation"); Log.e(TAG, "run(client): no syncedFileState or target path, can't perform upload operation");
return new RemoteOperationResult(ResultCode.FORBIDDEN); return new RemoteOperationResult(ResultCode.FORBIDDEN);
} }
if(mSyncedState.getId() == -1){
this.mSyncedState.setId( DbHelper.manageSyncedFileStateDB(this.mSyncedState, "INSERT", mContext) ); File file = new File(mSyncedState.getLocalPath());
if(file == null || !file.exists()){
Log.w(TAG, "Can't get the file. It might have been deleted");
return new RemoteOperationResult(ResultCode.FORBIDDEN);
} }
String targetPath = mSyncedState.getRemotePath();
//If an Etag is already Stored and LastModified from DB is the same as real file //If an Etag is already Stored and LastModified from DB is the same as real file
if (mSyncedState.isLastEtagStored() if (mSyncedState.isLastEtagStored()
&& mSyncedState.getLocalLastModified() == mFile.lastModified()) { && mSyncedState.getLocalLastModified() == file.lastModified()) {
Log.d(TAG, "mySyncedState last modified: "+mSyncedState.getLocalLastModified()+" <=> mFile last modified: "+mFile.lastModified() +": So return sync_conflict"); Log.d(TAG, "mySyncedState last modified: "+mSyncedState.getLocalLastModified()+" <=> mFile last modified: "+file.lastModified() +": So return sync_conflict");
return new RemoteOperationResult(ResultCode.SYNC_CONFLICT); return new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
} }
if(this.availableQuota == -1){ if(this.availableQuota == -1){
RemoteOperationResult checkQuotaResult = checkAvailableSpace(client); RemoteOperationResult checkQuotaResult = checkAvailableSpace(client, file.length());
if( checkQuotaResult.getCode() != ResultCode.OK ){