package com.owncloud.android.files.services;
import java.io.File;
-import java.io.IOException;
import java.util.AbstractList;
import java.util.HashMap;
import java.util.Iterator;
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.accounts.AccountsException;
import android.accounts.OnAccountsUpdateListener;
import android.app.NotificationManager;
import android.app.PendingIntent;
private ServiceHandler mServiceHandler;
private IBinder mBinder;
private OwnCloudClient mUploadClient = null;
- private Account mLastAccount = null;
+ private Account mCurrentAccount = null;
private FileDataStorageManager mStorageManager;
private IndexedForest<UploadFileOperation> mPendingUploads = new IndexedForest<UploadFileOperation>();
}
/**
- * Builds a key for mPendingUploads from the account and file to upload
- *
- * @param account Account where the file to upload is stored
- * @param file File to upload
- */
- private String buildRemoteName(Account account, OCFile file) {
- return account.name + file.getRemotePath();
- }
-
- private String buildRemoteName(Account account, String remotePath) {
- return account.name + remotePath;
- }
-
- /**
* Checks if an ownCloud server version should support chunked uploads.
*
* @param version OwnCloud version instance corresponding to an ownCloud
* server.
* @return 'True' if the ownCloud server with version supports chunked
* uploads.
+ *
+ * TODO - move to OCClient
*/
private static boolean chunkedUploadIsSupported(OwnCloudVersion version) {
return (version != null && version.compareTo(OwnCloudVersion.owncloud_v4_5) >= 0);
files = new OCFile[localPaths.length];
for (int i = 0; i < localPaths.length; i++) {
files[i] = obtainNewOCFileToUpload(remotePaths[i], localPaths[i],
- ((mimeTypes != null) ? mimeTypes[i] : null), storageManager);
+ ((mimeTypes != null) ? mimeTypes[i] : null));
if (files[i] == null) {
// TODO @andomaex add failure Notification
return Service.START_NOT_STICKY;
/**
* Cancels a pending or current upload of a remote file.
*
- * @param account Owncloud account where the remote file will be stored.
- * @param file A file in the queue of pending uploads
+ * @param account ownCloud account where the remote file will be stored.
+ * @param file A file in the queue of pending uploads
*/
public void cancel(Account account, OCFile file) {
- UploadFileOperation upload;
- //synchronized (mPendingUploads) {
- Pair<UploadFileOperation, String> removeResult = mPendingUploads.remove(account, file.getRemotePath());
- upload = removeResult.first;
- //}
+ Pair<UploadFileOperation, String> removeResult = mPendingUploads.remove(account, file.getRemotePath());
+ UploadFileOperation upload = removeResult.first;
if (upload != null) {
upload.cancel();
+ } else {
+ if (mCurrentUpload != null && mCurrentAccount != null &&
+ mCurrentUpload.getRemotePath().startsWith(file.getRemotePath()) &&
+ account.name.equals(mCurrentAccount.name)) {
+ mCurrentUpload.cancel();
+ }
}
}
/**
- * Cancels a pending or current upload for an account
+ * Cancels all the uploads for an account
*
- * @param account Owncloud accountName where the remote file will be stored.
+ * @param account ownCloud account.
*/
public void cancel(Account account) {
Log_OC.d(TAG, "Account= " + account.name);
mBoundListeners.clear();
}
+
/**
* Returns True when the file described by 'file' is being uploaded to
* the ownCloud account 'account' or waiting for it
* @param file A file that could be in the queue of pending uploads
*/
public boolean isUploading(Account account, OCFile file) {
- /*
- if (account == null || file == null)
- return false;
- String targetKey = buildRemoteName(account, file);
- synchronized (mPendingUploads) {
- if (file.isFolder()) {
- // this can be slow if there are many uploads :(
- Iterator<String> it = mPendingUploads.keySet().iterator();
- boolean found = false;
- while (it.hasNext() && !found) {
- found = it.next().startsWith(targetKey);
- }
- return found;
- } else {
- return (mPendingUploads.containsKey(targetKey));
- }
- }*/
if (account == null || file == null) return false;
return (mPendingUploads.contains(account, file.getRemotePath()));
}
}
/**
- * Review uploads and cancel it if its account doesn't exist
+ * Builds a key for the map of listeners.
+ *
+ * TODO remove and replace key with file.getFileId() after changing current policy (upload file, then
+ * add to local database) to better policy (add to local database, then upload)
+ *
+ * @param account ownCloud account where the file to upload belongs.
+ * @param file File to upload
+ * @return Key
*/
- public void checkAccountOfCurrentUpload() {
- if (mCurrentUpload != null &&
- !AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) {
- mCurrentUpload.cancel();
- }
- // The rest of uploads are cancelled when they try to start
+ private String buildRemoteName(Account account, OCFile file) {
+ return account.name + file.getRemotePath();
}
+
}
/**
*/
public void uploadFile(String uploadKey) {
- Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Getting upload of " + uploadKey);
mCurrentUpload = mPendingUploads.get(uploadKey);
if (mCurrentUpload != null) {
try {
/// prepare client object to send the request to the ownCloud server
- if (mLastAccount == null || !mLastAccount.equals(mCurrentUpload.getAccount())) {
- mLastAccount = mCurrentUpload.getAccount();
+ if (mCurrentAccount == null || !mCurrentAccount.equals(mCurrentUpload.getAccount())) {
+ mCurrentAccount = mCurrentUpload.getAccount();
mStorageManager = new FileDataStorageManager(
- mLastAccount,
+ mCurrentAccount,
getContentResolver()
);
} // else, reuse storage manager from previous operation
// always get client from client manager, to get fresh credentials in case of update
- OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this);
+ OwnCloudAccount ocAccount = new OwnCloudAccount(mCurrentAccount, this);
mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
getClientFor(ocAccount, this);
/// perform the upload
if (grantResult.isSuccess()) {
- Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Executing upload of " + mCurrentUpload.getRemotePath());
OCFile parent = mStorageManager.getFileByPath(remoteParentPath);
mCurrentUpload.getFile().setParentId(parent.getFileId());
uploadResult = mCurrentUpload.execute(mUploadClient);
if (uploadResult.isSuccess()) {
saveUploadedFile();
+
+ } else if (uploadResult.getCode() == ResultCode.SYNC_CONFLICT) {
+ mStorageManager.saveConflict(mCurrentUpload.getFile(),
+ mCurrentUpload.getFile().getEtagInConflict());
}
} else {
uploadResult = grantResult;
}
- } catch (AccountsException e) {
- Log_OC.e(TAG, "Error while trying to get autorization for " +
- mLastAccount.name, e);
- uploadResult = new RemoteOperationResult(e);
-
- } catch (IOException e) {
- Log_OC.e(TAG, "Error while trying to get autorization for " +
- mLastAccount.name, e);
+ } catch (Exception e) {
+ Log_OC.e(TAG, "Error uploading", e);
uploadResult = new RemoteOperationResult(e);
} finally {
- Log_OC.v("NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Removing payload " + mCurrentUpload.getRemotePath());
- Pair<UploadFileOperation, String> removeResult =
- mPendingUploads.removePayload(mLastAccount, mCurrentUpload.getRemotePath());
+ Pair<UploadFileOperation, String> removeResult;
+ if (mCurrentUpload.wasRenamed()) {
+ removeResult = mPendingUploads.removePayload(
+ mCurrentAccount,
+ mCurrentUpload.getOldFile().getRemotePath()
+ );
+ } else {
+ removeResult = mPendingUploads.removePayload(
+ mCurrentAccount,
+ mCurrentUpload.getRemotePath()
+ );
+ }
/// notify result
notifyUploadResult(mCurrentUpload, uploadResult);
* synchronized with the server, specially the modification time and Etag
* (where available)
*
- * TODO refactor this ugly thing
+ * TODO move into UploadFileOperation
*/
private void saveUploadedFile() {
OCFile file = mCurrentUpload.getFile();
if (result.isSuccess()) {
updateOCFile(file, (RemoteFile) result.getData().get(0));
file.setLastSyncDateForProperties(syncDate);
+ } else {
+ Log_OC.e(TAG, "Error reading properties of file after successful upload; this is gonna hurt...");
}
// / maybe this would be better as part of UploadFileOperation... or
if (oldFile.fileExists()) {
oldFile.setStoragePath(null);
mStorageManager.saveFile(oldFile);
+ mStorageManager.saveConflict(oldFile, null);
} // else: it was just an automatic renaming due to a name
// coincidence; nothing else is needed, the storagePath is right
}
file.setNeedsUpdateThumbnail(true);
mStorageManager.saveFile(file);
+ mStorageManager.saveConflict(file, null);
+
+ mStorageManager.triggerMediaScan(file.getStoragePath());
+
}
private void updateOCFile(OCFile file, RemoteFile remoteFile) {
file.setMimetype(remoteFile.getMimeType());
file.setModificationTimestamp(remoteFile.getModifiedTimestamp());
file.setModificationTimestampAtLastSyncForData(remoteFile.getModifiedTimestamp());
- // file.setEtag(remoteFile.getEtag()); // TODO Etag, where available
+ file.setEtag(remoteFile.getEtag());
file.setRemoteId(remoteFile.getRemoteId());
}
- private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType,
- FileDataStorageManager storageManager) {
+ private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType) {
// MIME type
if (mimeType == null || mimeType.length() <= 0) {
* @param localPath Full path to a file in the local file system.
* @param mimeType MIME type of the file.
* @return true if is needed to add the pdf file extension to the file
+ *
+ * TODO - move to OCFile or Utils class
*/
private boolean isPdfFileFromContentProviderWithoutExtension(String localPath,
String mimeType) {