/**
* ownCloud Android client application
*
* @author LukeOwncloud
* @author masensio
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
package com.owncloud.android.db;
import android.accounts.Account;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.datamodel.UploadsStorageManager;
import com.owncloud.android.datamodel.UploadsStorageManager.UploadStatus;
import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.utils.MimetypeIconUtil;
import com.owncloud.android.utils.UploadUtils;
import java.io.File;
import java.util.Date;
/**
* Stores all information in order to start upload operations. PersistentUploadObject can
* be stored persistently by {@link UploadsStorageManager}.
*
*/
public class OCUpload implements Parcelable {
/** Generated - should be refreshed every time the class changes!! */
// private static final long serialVersionUID = 2647551318657321611L;
private static final String TAG = OCUpload.class.getSimpleName();
private long mId;
//private OCFile mFile;
/**
* Absolute path in the local file system to the file to be uploaded
*/
private String mLocalPath;
/**
* Absolute path in the remote account to set to the uploaded file (not for its parent folder!)
*/
private String mRemotePath;
/**
* Name of Owncloud account to upload file to.
*/
private String mAccountName;
/**
* Local action for upload. (0 - COPY, 1 - MOVE, 2 - FORGET)
*/
private int mLocalAction;
/**
* Overwrite destination file?
*/
private boolean mForceOverwrite;
/**
* Create destination folder?
*/
private boolean mIsCreateRemoteFolder;
/**
* Upload only via wifi?
*/
private boolean mIsUseWifiOnly;
/**
* Upload only if phone being charged?
*/
private boolean mIsWhileChargingOnly;
/**
* Status of upload (later, in_progress, ...).
*/
private UploadStatus mUploadStatus;
/**
* Result from last upload operation. Can be null.
*/
private UploadResult mLastResult;
/**
* Main constructor
*
* @param localPath Absolute path in the local file system to the file to be uploaded.
* @param remotePath Absolute path in the remote account to set to the uploaded file.
* @param accountName Name of an ownCloud account to update the file to.
*/
public OCUpload(String localPath, String remotePath, String accountName) {
if (localPath == null || !localPath.startsWith(File.separator)) {
throw new IllegalArgumentException("Local path must be an absolute path in the local file system");
}
if (remotePath == null || !remotePath.startsWith(OCFile.PATH_SEPARATOR)) {
throw new IllegalArgumentException("Remote path must be an absolute path in the local file system");
}
if (accountName == null || accountName.length() < 1) {
throw new IllegalArgumentException("Invalid account name");
}
resetData();
mLocalPath = localPath;
mRemotePath = remotePath;
mAccountName = accountName;
}
/**
* Convenience constructor to reupload already existing {@link OCFile}s
*
* @param ocFile {@link OCFile} instance to update in the remote server.
* @param account ownCloud {@link Account} where ocFile is contained.
*/
public OCUpload(OCFile ocFile, Account account) {
this(ocFile.getStoragePath(), ocFile.getRemotePath(), account.name);
}
/**
* Reset all the fields to default values.
*/
private void resetData() {
mRemotePath = "";
mLocalPath = "";
mAccountName = "";
mId = -1;
mLocalAction = FileUploader.LOCAL_BEHAVIOUR_COPY;
mForceOverwrite = false;
mIsCreateRemoteFolder = false;
mIsUseWifiOnly = true;
mIsWhileChargingOnly = false;
mUploadStatus = UploadStatus.UPLOAD_LATER;
mLastResult = UploadResult.UNKNOWN;
}
// Getters & Setters
public void setUploadId(long id) {
mId = id;
}
public long getUploadId() {
return mId;
}
/**
* @return the uploadStatus
*/
public UploadStatus getUploadStatus() {
return mUploadStatus;
}
/**
* Sets uploadStatus AND SETS lastResult = null;
* @param uploadStatus the uploadStatus to set
*/
public void setUploadStatus(UploadStatus uploadStatus) {
this.mUploadStatus = uploadStatus;
setLastResult(UploadResult.UNKNOWN);
}
/**
* @return the lastResult
*/
public UploadResult getLastResult() {
return mLastResult;
}
/**
* @param lastResult the lastResult to set
*/
public void setLastResult(UploadResult lastResult) {
this.mLastResult = lastResult;
}
/**
* @return the localPath
*/
public String getLocalPath() {
return mLocalPath;
}
public void setLocalPath(String localPath) {
mLocalPath = localPath;
}
/**
* @return the remotePath
*/
public String getRemotePath() {
return mRemotePath;
}
/**
* @return the mimeType
*/
public String getMimeType() {
return MimetypeIconUtil.getBestMimeTypeByFilename(mLocalPath);
}
/**
* @return the localAction
*/
public int getLocalAction() {
return mLocalAction;
}
/**
* @param localAction the localAction to set
*/
public void setLocalAction(int localAction) {
this.mLocalAction = localAction;
}
/**
* @return the forceOverwrite
*/
public boolean isForceOverwrite() {
return mForceOverwrite;
}
/**
* @param forceOverwrite the forceOverwrite to set
*/
public void setForceOverwrite(boolean forceOverwrite) {
this.mForceOverwrite = forceOverwrite;
}
/**
* @return the isCreateRemoteFolder
*/
public boolean isCreateRemoteFolder() {
return mIsCreateRemoteFolder;
}
/**
* @param isCreateRemoteFolder the isCreateRemoteFolder to set
*/
public void setCreateRemoteFolder(boolean isCreateRemoteFolder) {
this.mIsCreateRemoteFolder = isCreateRemoteFolder;
}
/**
* @return the isUseWifiOnly
*/
public boolean isUseWifiOnly() {
return mIsUseWifiOnly;
}
/**
* @param isUseWifiOnly the isUseWifiOnly to set
*/
public void setUseWifiOnly(boolean isUseWifiOnly) {
this.mIsUseWifiOnly = isUseWifiOnly;
}
/**
* @return the accountName
*/
public String getAccountName() {
return mAccountName;
}
/**
* Returns owncloud account as {@link Account} object.
*/
public Account getAccount(Context context) {
return AccountUtils.getOwnCloudAccountByName(context, getAccountName());
}
public void setWhileChargingOnly(boolean isWhileChargingOnly) {
this.mIsWhileChargingOnly = isWhileChargingOnly;
}
public boolean isWhileChargingOnly() {
return mIsWhileChargingOnly;
}
/**
* For debugging purposes only.
*/
public String toFormattedString() {
try {
String localPath = getLocalPath() != null ? getLocalPath() : "";
return localPath + " status:" + getUploadStatus() + " result:" +
(getLastResult() == null ? "null" : getLastResult().getValue());
} catch (NullPointerException e){
Log_OC.d(TAG, "Exception " + e.toString() );
return (e.toString());
}
}
/**
* Removes all uploads restrictions. After calling this function upload is performed immediately if requested.
*/
public void removeAllUploadRestrictions() {
setUseWifiOnly(false);
setWhileChargingOnly(false);
//setUploadTimestamp(0);
}
/**
* Returns true when user is able to cancel this upload. That is, when
* upload is currently in progress or scheduled for upload.
*/
public boolean userCanCancelUpload() {
switch (this.getUploadStatus()) {
case UPLOAD_IN_PROGRESS:
case UPLOAD_LATER:
return true;
default:
return false;
}
}
/**
* Returns true when user can choose to retry this upload. That is, when
* user cancelled upload before or when upload has failed.
*/
public boolean userCanRetryUpload() {
switch (this.getUploadStatus()) {
case UPLOAD_CANCELLED:
case UPLOAD_FAILED_RETRY://automatically retried. no need for user option.
case UPLOAD_FAILED_GIVE_UP: //TODO this case needs to be handled as described by
// https://github.com/owncloud/android/issues/765#issuecomment-66490312
case UPLOAD_LATER: //upload is already schedule but allow user to increase priority
return true;
default:
return false;
}
}
/****
*
*/
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
@Override
public OCUpload createFromParcel(Parcel source) {
return new OCUpload(source);
}
@Override
public OCUpload[] newArray(int size) {
return new OCUpload[size];
}
};
/**
* Reconstruct from parcel
*
* @param source The source parcel
*/
protected OCUpload(Parcel source) {
readFromParcel(source);
}
public void readFromParcel(Parcel source) {
mId = source.readLong();
mLocalPath = source.readString();
mRemotePath = source.readString();
mAccountName = source.readString();
mLocalAction = source.readInt();
mForceOverwrite = (source.readInt() == 1);
mIsCreateRemoteFolder = (source.readInt() == 1);
mIsUseWifiOnly = (source.readInt() == 1);
mIsWhileChargingOnly = (source.readInt() == 1);
try {
mUploadStatus = UploadStatus.valueOf(source.readString());
} catch (IllegalArgumentException x) {
mUploadStatus = UploadStatus.UPLOAD_LATER;
}
try {
mLastResult = UploadResult.valueOf(source.readString());
} catch (IllegalArgumentException x) {
mLastResult = UploadResult.UNKNOWN;
}
}
@Override
public int describeContents() {
return this.hashCode();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(mId);
dest.writeString(mLocalPath);
dest.writeString(mRemotePath);
dest.writeString(mAccountName);
dest.writeInt(mLocalAction);
dest.writeInt(mForceOverwrite ? 1 : 0);
dest.writeInt(mIsCreateRemoteFolder ? 1 : 0);
dest.writeInt(mIsUseWifiOnly ? 1 : 0);
dest.writeInt(mIsWhileChargingOnly ? 1 : 0);
dest.writeString(mUploadStatus.name());
dest.writeString(((mLastResult == null) ? "" : mLastResult.name()));
}
enum CanUploadFileNowStatus {NOW, LATER, FILE_GONE, ERROR};
/**
* Returns true when the file may be uploaded now. This methods checks all
* restraints of the passed {@link OCUpload}, these include
* isUseWifiOnly(), check if local file exists, check if file was already
* uploaded...
*
* If return value is CanUploadFileNowStatus.NOW, uploadFile() may be
* called.
*
* @return CanUploadFileNowStatus.NOW is upload may proceed,
* CanUploadFileNowStatus.LATER if upload should be performed at a
* later time,
* CanUploadFileNowStatus.ERROR if a severe error happened, calling
* entity should remove upload from queue.
*
*/
private CanUploadFileNowStatus canUploadFileNow(Context context) {
if (getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED) {
Log_OC.w(TAG, "Already succeeded uploadObject was again scheduled for upload. Fix that!");
return CanUploadFileNowStatus.ERROR;
}
if (isUseWifiOnly()
&& !UploadUtils.isConnectedViaWiFi(context)) {
Log_OC.d(TAG, "Do not start upload because it is wifi-only.");
return CanUploadFileNowStatus.LATER;
}
if(isWhileChargingOnly() && !UploadUtils.isCharging(context)) {
Log_OC.d(TAG, "Do not start upload because it is while charging only.");
return CanUploadFileNowStatus.LATER;
}
if (!new File(getLocalPath()).exists()) {
Log_OC.d(TAG, "Do not start upload because local file does not exist.");
return CanUploadFileNowStatus.FILE_GONE;
}
return CanUploadFileNowStatus.NOW;
}
/**
* Returns the reason as String why state of OCUpload is LATER. If
* upload state != LATER return null.
*/
public String getUploadLaterReason(Context context) {
StringBuilder reason = new StringBuilder();
Date now = new Date();
if (isUseWifiOnly() && !UploadUtils.isConnectedViaWiFi(context)) {
if (reason.length() > 0) {
reason.append(context.getString(R.string.uploads_view_later_reason_add_wifi_reason));
} else {
reason.append(context.getString(R.string.uploads_view_later_reason_waiting_for_wifi));
}
}
if (isWhileChargingOnly() && !UploadUtils.isCharging(context)) {
if (reason.length() > 0) {
reason.append(context.getString(R.string.uploads_view_later_reason_add_charging_reason));
} else {
reason.append(context.getString(R.string.uploads_view_later_reason_waiting_for_charging));
}
}
reason.append(".");
if (reason.length() > 1) {
return reason.toString();
}
if (getUploadStatus() == UploadStatus.UPLOAD_LATER) {
return context.getString(R.string.uploads_view_later_waiting_to_upload);
}
return null;
}
}