X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/f03852032f7114750573dfb06a1783596c2afe2f..ac07e35d8ab68bf94d5cd8b45680ea69247fcc9f:/src/com/owncloud/android/files/services/FileUploader.java diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index a841361d..524f4c10 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -19,6 +19,7 @@ package com.owncloud.android.files.services; import java.io.File; +import java.io.IOException; import java.util.AbstractList; import java.util.Iterator; import java.util.Vector; @@ -34,11 +35,13 @@ import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.InstantUploadBroadcastReceiver; import com.owncloud.android.operations.ChunkedUploadFileOperation; +import com.owncloud.android.operations.CreateFolderOperation; +import com.owncloud.android.operations.RemoteOperation; import com.owncloud.android.operations.RemoteOperationResult; import com.owncloud.android.operations.UploadFileOperation; +import com.owncloud.android.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.ui.activity.FileDetailActivity; import com.owncloud.android.ui.fragment.FileDetailFragment; -import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.OwnCloudVersion; import eu.alefzero.webdav.OnDatatransferProgressListener; @@ -49,6 +52,7 @@ import com.owncloud.android.network.OwnCloudClientUtils; import android.accounts.Account; import android.accounts.AccountManager; +import android.accounts.AccountsException; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -71,16 +75,15 @@ import eu.alefzero.webdav.WebdavClient; public class FileUploader extends Service implements OnDatatransferProgressListener { public static final String UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH"; - public static final String EXTRA_PARENT_DIR_ID = "PARENT_DIR_ID"; public static final String EXTRA_UPLOAD_RESULT = "RESULT"; public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; public static final String EXTRA_OLD_REMOTE_PATH = "OLD_REMOTE_PATH"; - public static final String EXTRA_FILE_PATH = "FILE_PATH"; + public static final String EXTRA_OLD_FILE_PATH = "OLD_FILE_PATH"; public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; public static final String KEY_FILE = "FILE"; - public static final String KEY_LOCAL_FILE = "LOCAL_FILE"; // TODO remove this as a possible input argument ; use KEY_FILE everywhere - public static final String KEY_REMOTE_FILE = "REMOTE_FILE"; // TODO remove this as a possible input argument ; use KEY_FILE everywhere + public static final String KEY_LOCAL_FILE = "LOCAL_FILE"; + public static final String KEY_REMOTE_FILE = "REMOTE_FILE"; public static final String KEY_MIME_TYPE = "MIME_TYPE"; public static final String KEY_ACCOUNT = "ACCOUNT"; @@ -88,6 +91,11 @@ public class FileUploader extends Service implements OnDatatransferProgressListe public static final String KEY_UPLOAD_TYPE = "UPLOAD_TYPE"; public static final String KEY_FORCE_OVERWRITE = "KEY_FORCE_OVERWRITE"; public static final String KEY_INSTANT_UPLOAD = "INSTANT_UPLOAD"; + public static final String KEY_LOCAL_BEHAVIOUR = "BEHAVIOUR"; + + public static final int LOCAL_BEHAVIOUR_COPY = 0; + public static final int LOCAL_BEHAVIOUR_MOVE = 1; + public static final int LOCAL_BEHAVIOUR_FORGET = 2; public static final int UPLOAD_SINGLE_FILE = 0; public static final int UPLOAD_MULTIPLE_FILES = 1; @@ -200,7 +208,8 @@ public class FileUploader extends Service implements OnDatatransferProgressListe FileDataStorageManager storageManager = new FileDataStorageManager(account, getContentResolver()); boolean forceOverwrite = intent.getBooleanExtra(KEY_FORCE_OVERWRITE, false); - boolean isInstant = intent.getBooleanExtra(KEY_INSTANT_UPLOAD, false); + boolean isInstant = intent.getBooleanExtra(KEY_INSTANT_UPLOAD, false); + int localAction = intent.getIntExtra(KEY_LOCAL_BEHAVIOUR, LOCAL_BEHAVIOUR_COPY); boolean fixed = false; if (isInstant) { fixed = checkAndFixInstantUploadDirectory(storageManager); // MUST be done BEFORE calling obtainNewOCFileToUpload @@ -239,9 +248,9 @@ public class FileUploader extends Service implements OnDatatransferProgressListe for (int i=0; i < files.length; i++) { uploadKey = buildRemoteName(account, files[i].getRemotePath()); if (chunked) { - newUpload = new ChunkedUploadFileOperation(account, files[i], isInstant, forceOverwrite); + newUpload = new ChunkedUploadFileOperation(account, files[i], isInstant, forceOverwrite, localAction); } else { - newUpload = new UploadFileOperation(account, files[i], isInstant, forceOverwrite); + newUpload = new UploadFileOperation(account, files[i], isInstant, forceOverwrite, localAction); } if (fixed && i==0) { newUpload.setRemoteFolderToBeCreated(); @@ -313,12 +322,26 @@ public class FileUploader extends Service implements OnDatatransferProgressListe /** * Returns True when the file described by 'file' is being uploaded to the ownCloud account 'account' or waiting for it * + * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. + * * @param account Owncloud account where the remote file will be stored. * @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) { - return (mPendingUploads.containsKey(buildRemoteName(account, file))); + if (file.isDirectory()) { + // this can be slow if there are many downloads :( + Iterator it = mPendingUploads.keySet().iterator(); + boolean found = false; + while (it.hasNext() && !found) { + found = it.next().startsWith(targetKey); + } + return found; + } else { + return (mPendingUploads.containsKey(targetKey)); + } } } } @@ -373,34 +396,45 @@ public class FileUploader extends Service implements OnDatatransferProgressListe notifyUploadStart(mCurrentUpload); + RemoteOperationResult uploadResult = null; - /// prepare client object to send requests to the ownCloud server - if (mUploadClient == null || !mLastAccount.equals(mCurrentUpload.getAccount())) { - mLastAccount = mCurrentUpload.getAccount(); - mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver()); - mUploadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext()); - } + try { + /// prepare client object to send requests to the ownCloud server + if (mUploadClient == null || !mLastAccount.equals(mCurrentUpload.getAccount())) { + mLastAccount = mCurrentUpload.getAccount(); + mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver()); + mUploadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext()); + } - /// create remote folder for instant uploads - if (mCurrentUpload.isRemoteFolderToBeCreated()) { - mUploadClient.createDirectory(InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR); // ignoring result; fail could just mean that it already exists, but local database is not synchronized; the upload will be tried anyway - } + /// create remote folder for instant uploads + if (mCurrentUpload.isRemoteFolderToBeCreated()) { + RemoteOperation operation = new CreateFolderOperation( InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR, + mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR).getFileId(), // TODO generalize this : INSTANT_UPLOAD_DIR could not be a child of root + mStorageManager); + operation.execute(mUploadClient); // ignoring result; fail could just mean that it already exists, but local database is not synchronized; the upload will be tried anyway + } - /// perform the upload - RemoteOperationResult uploadResult = null; - try { + /// perform the upload uploadResult = mCurrentUpload.execute(mUploadClient); if (uploadResult.isSuccess()) { saveUploadedFile(); } + } catch (AccountsException e) { + Log.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e); + uploadResult = new RemoteOperationResult(e); + + } catch (IOException e) { + Log.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e); + uploadResult = new RemoteOperationResult(e); + } finally { synchronized(mPendingUploads) { mPendingUploads.remove(uploadKey); } } - + /// notify result notifyUploadResult(uploadResult, mCurrentUpload); @@ -446,42 +480,21 @@ public class FileUploader extends Service implements OnDatatransferProgressListe } catch (Exception e) { result = new RemoteOperationResult(e); - Log.i(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": " + result.getLogMessage(), e); + Log.e(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": " + result.getLogMessage(), e); } finally { if (propfind != null) propfind.releaseConnection(); } - + /// maybe this would be better as part of UploadFileOperation... or maybe all this method if (mCurrentUpload.wasRenamed()) { OCFile oldFile = mCurrentUpload.getOldFile(); - if (!oldFile.fileExists()) { - // just a name coincidence - file.setStoragePath(oldFile.getStoragePath()); - - } else { - // conflict resolved with 'Keep both' by the user - File localFile = new File(oldFile.getStoragePath()); - File newLocalFile = new File(FileStorageUtils.getDefaultSavePathFor(mCurrentUpload.getAccount().name, file)); - boolean renameSuccessed = localFile.renameTo(newLocalFile); - if (renameSuccessed) { - file.setStoragePath(newLocalFile.getAbsolutePath()); - - } else { - // poor solution - Log.d(TAG, "DAMN IT: local rename failed after uploading a file with a new name already existing both in the remote account and the local database (should be due to a conflict solved with 'keep both'"); - file.setStoragePath(null); - // not so fine: - // - local file will be kept there as 'trash' until is download (and overwritten) again from the server; - // - user will see as 'not down' a file that was just upload - // BUT: - // - no loss of data happened - // - when the user downloads again the renamed and original file from the server, local file names and contents will be correctly synchronized with names and contents in server - } + if (oldFile.fileExists()) { oldFile.setStoragePath(null); mStorageManager.saveFile(oldFile); - } + + } // else: it was just an automatic renaming due to a name coincidence; nothing else is needed, the storagePath is right in the instance returned by mCurrentUpload.getFile() } mStorageManager.saveFile(file); @@ -492,7 +505,8 @@ public class FileUploader extends Service implements OnDatatransferProgressListe file.setCreationTimestamp(we.createTimestamp()); file.setFileLength(we.contentLength()); file.setMimetype(we.contentType()); - file.setModificationTimestamp(we.modifiedTimesamp()); + file.setModificationTimestamp(we.modifiedTimestamp()); + file.setModificationTimestampAtLastSyncForData(we.modifiedTimestamp()); // file.setEtag(mCurrentDownload.getEtag()); // TODO Etag, where available } @@ -541,7 +555,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe // parent dir String parentPath = new File(remotePath).getParent(); - parentPath = parentPath.endsWith("/")?parentPath:parentPath+"/" ; + parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR ; OCFile parentDir = storageManager.getFileByPath(parentPath); if (parentDir == null) { throw new IllegalStateException("Can not upload a file to a non existing remote location: " + parentPath); @@ -565,7 +579,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe mDefaultNotificationContentView = mNotification.contentView; mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout); mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, false); - mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.uploader_upload_in_progress_content), 0, new File(upload.getStoragePath()).getName())); + mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.uploader_upload_in_progress_content), 0, upload.getFileName())); mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon); /// includes a pending intent in the notification showing the details view of the file @@ -630,7 +644,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe mNotification.setLatestEventInfo( getApplicationContext(), getString(R.string.uploader_upload_succeeded_ticker), - String.format(getString(R.string.uploader_upload_succeeded_content_single), (new File(upload.getStoragePath())).getName()), + String.format(getString(R.string.uploader_upload_succeeded_content_single), upload.getFileName()), mNotification.contentIntent); mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification); // NOT AN ERROR; uploader_upload_in_progress_ticker is the target, not a new notification @@ -649,9 +663,18 @@ public class FileUploader extends Service implements OnDatatransferProgressListe finalNotification.flags |= Notification.FLAG_AUTO_CANCEL; // TODO put something smart in the contentIntent below finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0); + + String content = null; + if (uploadResult.getCode() == ResultCode.LOCAL_STORAGE_FULL || + uploadResult.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) { + // TODO we need a class to provide error messages for the users from a RemoteOperationResult and a RemoteOperation + content = String.format(getString(R.string.error__upload__local_file_not_copied), upload.getFileName(), getString(R.string.app_name)); + } else { + content = String.format(getString(R.string.uploader_upload_failed_content_single), upload.getFileName()); + } finalNotification.setLatestEventInfo( getApplicationContext(), getString(R.string.uploader_upload_failed_ticker), - String.format(getString(R.string.uploader_upload_failed_content_single), (new File(upload.getStoragePath())).getName()), + content, finalNotification.contentIntent); mNotificationManager.notify(R.string.uploader_upload_failed_ticker, finalNotification); @@ -679,11 +702,10 @@ public class FileUploader extends Service implements OnDatatransferProgressListe if (upload.wasRenamed()) { end.putExtra(EXTRA_OLD_REMOTE_PATH, upload.getOldFile().getRemotePath()); } - end.putExtra(EXTRA_FILE_PATH, upload.getStoragePath()); + end.putExtra(EXTRA_OLD_FILE_PATH, upload.getOriginalStoragePath()); end.putExtra(ACCOUNT_NAME, upload.getAccount().name); end.putExtra(EXTRA_UPLOAD_RESULT, uploadResult.isSuccess()); - end.putExtra(EXTRA_PARENT_DIR_ID, upload.getFile().getParentId()); - sendBroadcast(end); + sendStickyBroadcast(end); }