X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/407f64f5e062cbd59b82043406923f082c6fa911..d8ac7b2241bc99df58b5f4be4c3c4d83fc9efaf6:/src/com/owncloud/android/services/OperationsService.java diff --git a/src/com/owncloud/android/services/OperationsService.java b/src/com/owncloud/android/services/OperationsService.java index d3b6df34..779e5b6a 100644 --- a/src/com/owncloud/android/services/OperationsService.java +++ b/src/com/owncloud/android/services/OperationsService.java @@ -18,6 +18,7 @@ package com.owncloud.android.services; import java.io.IOException; +import java.util.ArrayList; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; @@ -27,6 +28,7 @@ import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; @@ -51,6 +53,7 @@ import com.owncloud.android.operations.RenameFileOperation; import com.owncloud.android.operations.SynchronizeFileOperation; import com.owncloud.android.operations.SynchronizeFolderOperation; import com.owncloud.android.operations.UnshareLinkOperation; +import com.owncloud.android.utils.FileStorageUtils; import android.accounts.Account; import android.accounts.AccountsException; @@ -83,7 +86,8 @@ public class OperationsService extends Service { public static final String EXTRA_SYNC_FILE_CONTENTS = "SYNC_FILE_CONTENTS"; public static final String EXTRA_RESULT = "RESULT"; public static final String EXTRA_NEW_PARENT_PATH = "NEW_PARENT_PATH"; - + public static final String EXTRA_FILE = "FILE"; + // TODO review if ALL OF THEM are necessary public static final String EXTRA_SUCCESS_IF_ABSENT = "SUCCESS_IF_ABSENT"; public static final String EXTRA_USERNAME = "USERNAME"; @@ -172,27 +176,34 @@ public class OperationsService extends Service { return START_NOT_STICKY; } Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); - OCFile file = intent.getParcelableExtra(EXTRA_REMOTE_PATH); - Pair itemSyncKey = new Pair(account, file); + String remotePath = intent.getStringExtra(EXTRA_REMOTE_PATH); + + Pair itemSyncKey = new Pair(account, remotePath); Pair itemToQueue = newOperation(intent); if (itemToQueue != null) { - mSyncFolderHandler.add(account, file, (SynchronizeFolderOperation)itemToQueue.second); + mSyncFolderHandler.add(account, remotePath, (SynchronizeFolderOperation)itemToQueue.second); + mSyncFolderHandler.sendBroadcastNewSyncFolder(account, remotePath); Message msg = mSyncFolderHandler.obtainMessage(); msg.arg1 = startId; msg.obj = itemSyncKey; mSyncFolderHandler.sendMessage(msg); } } else if (ACTION_CANCEL_SYNC_FOLDER.equals(intent.getAction())) { - if (!intent.hasExtra(EXTRA_ACCOUNT) || !intent.hasExtra(EXTRA_REMOTE_PATH)) { + if (!intent.hasExtra(EXTRA_ACCOUNT) || !intent.hasExtra(EXTRA_FILE)) { Log_OC.e(TAG, "Not enough information provided in intent"); return START_NOT_STICKY; } - Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); - OCFile file = intent.getParcelableExtra(EXTRA_REMOTE_PATH); - + final Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); + final OCFile file = intent.getParcelableExtra(EXTRA_FILE); // Cancel operation - mSyncFolderHandler.cancel(account,file); + new Thread(new Runnable() { + public void run() { + // Cancel the download + mSyncFolderHandler.cancel(account,file); + } + }).start(); + } else { Message msg = mOperationsHandler.obtainMessage(); msg.arg1 = startId; @@ -358,6 +369,21 @@ public class OperationsService extends Service { //Log_OC.wtf(TAG, "Not finished yet"); } } + + + /** + * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download. + * + * 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 is stored. + * @param file A file that could be affected + */ + /* + public boolean isSynchronizing(Account account, String remotePath) { + return mSyncFolderHandler.isSynchronizing(account, remotePath); + } + */ } @@ -375,7 +401,6 @@ public class OperationsService extends Service { private ConcurrentMap mPendingOperations = new ConcurrentHashMap(); - private RemoteOperation mCurrentOperation = null; private OwnCloudClient mOwnCloudClient = null; private FileDataStorageManager mStorageManager; private SynchronizeFolderOperation mCurrentSyncOperation; @@ -389,10 +414,26 @@ public class OperationsService extends Service { mService = service; } + + public boolean isSynchronizing(Account account, String remotePath) { + if (account == null || remotePath == null) return false; + String targetKey = buildRemoteName(account, remotePath); + synchronized (mPendingOperations) { + // TODO - this can be slow when synchronizing a big tree - need a better data structure + Iterator it = mPendingOperations.keySet().iterator(); + boolean found = false; + while (it.hasNext() && !found) { + found = it.next().startsWith(targetKey); + } + return found; + } + } + + @Override public void handleMessage(Message msg) { - Pair itemSyncKey = (Pair) msg.obj; - nextOperation(itemSyncKey.first,itemSyncKey.second); + Pair itemSyncKey = (Pair) msg.obj; + doOperation(itemSyncKey.first, itemSyncKey.second); mService.stopSelf(msg.arg1); } @@ -400,17 +441,17 @@ public class OperationsService extends Service { /** * Performs the next operation in the queue */ - private void nextOperation(Account account, OCFile file) { + private void doOperation(Account account, String remotePath) { - String syncKey = buildRemoteName(account,file); + String syncKey = buildRemoteName(account,remotePath); synchronized(mPendingOperations) { mCurrentSyncOperation = mPendingOperations.get(syncKey); } if (mCurrentSyncOperation != null) { + RemoteOperationResult result = null; - RemoteOperationResult operationResult = null; try { OwnCloudAccount ocAccount = new OwnCloudAccount(account, mService); @@ -421,62 +462,112 @@ public class OperationsService extends Service { mService.getContentResolver() ); - - /// perform the operation - if (mCurrentOperation instanceof SyncOperation) { - operationResult = ((SyncOperation)mCurrentOperation).execute(mOwnCloudClient, mStorageManager); - } else { - operationResult = mCurrentOperation.execute(mOwnCloudClient); - } + result = mCurrentSyncOperation.execute(mOwnCloudClient, mStorageManager); } catch (AccountsException e) { Log_OC.e(TAG, "Error while trying to get autorization", e); - operationResult = new RemoteOperationResult(e); } catch (IOException e) { Log_OC.e(TAG, "Error while trying to get autorization", e); - operationResult = new RemoteOperationResult(e); - } finally { synchronized(mPendingOperations) { mPendingOperations.remove(syncKey); } - } - - /// TODO notify operation result if needed + mService.dispatchResultToOperationListeners(null, mCurrentSyncOperation, result); + + sendBroadcastFinishedSyncFolder(account, remotePath, result.isSuccess()); + } } } - public void add(Account account, OCFile file, SynchronizeFolderOperation syncFolderOperation){ - String syncKey = buildRemoteName(account,file); + public void add(Account account, String remotePath, SynchronizeFolderOperation syncFolderOperation){ + String syncKey = buildRemoteName(account,remotePath); mPendingOperations.putIfAbsent(syncKey,syncFolderOperation); } /** - * Cancels a pending or current sync operation. - * + * Cancels sync operations. * @param account Owncloud account where the remote file is stored. - * @param file A file in the queue of pending downloads + * @param file File OCFile */ - public void cancel(Account account, OCFile file) { + public void cancel(Account account, OCFile file){ SynchronizeFolderOperation syncOperation = null; + String targetKey = buildRemoteName(account, file.getRemotePath()); + ArrayList keyItems = new ArrayList(); synchronized (mPendingOperations) { - syncOperation = mPendingOperations.remove(buildRemoteName(account, file)); - } - if (syncOperation != null) { - syncOperation.cancel(); + if (file.isFolder()) { + Log_OC.d(TAG, "Canceling pending sync operations"); + Iterator it = mPendingOperations.keySet().iterator(); + boolean found = false; + while (it.hasNext()) { + String keySyncOperation = it.next(); + found = keySyncOperation.startsWith(targetKey); + if (found) { + keyItems.add(keySyncOperation); + } + } + + } else { + // this is not really expected... + Log_OC.d(TAG, "Canceling sync operation"); + keyItems.add(buildRemoteName(account, file.getRemotePath())); + } + for (String item: keyItems) { + syncOperation = mPendingOperations.remove(item); + if (syncOperation != null) { + syncOperation.cancel(); + } + } } + + //sendBroadcastFinishedSyncFolder(account, file.getRemotePath()); + + /// cancellation of download needs to be done separately in any case; a SynchronizeFolderOperation + // may finish much sooner than the real download of the files in the folder + Intent intent = new Intent(mService, FileDownloader.class); + intent.setAction(FileDownloader.ACTION_CANCEL_FILE_DOWNLOAD); + intent.putExtra(FileDownloader.EXTRA_ACCOUNT, account); + intent.putExtra(FileDownloader.EXTRA_FILE, file); + mService.startService(intent); } /** * Builds a key from the account and file to download * * @param account Account where the file to download is stored - * @param file File to download + * @param path File path + */ + private String buildRemoteName(Account account, String path) { + return account.name + path; + } + + + /** + * TODO review this method when "folder synchronization" replaces "folder download"; this is a fast and ugly + * patch. + */ + private void sendBroadcastNewSyncFolder(Account account, String remotePath) { + Intent added = new Intent(FileDownloader.getDownloadAddedMessage()); + added.putExtra(FileDownloader.ACCOUNT_NAME, account.name); + added.putExtra(FileDownloader.EXTRA_REMOTE_PATH, remotePath); + added.putExtra(FileDownloader.EXTRA_FILE_PATH, FileStorageUtils.getSavePath(account.name) + remotePath); + mService.sendStickyBroadcast(added); + } + + /** + * TODO review this method when "folder synchronization" replaces "folder download"; this is a fast and ugly + * patch. */ - private String buildRemoteName(Account account, OCFile file) { - return account.name + file.getRemotePath(); + private void sendBroadcastFinishedSyncFolder(Account account, String remotePath, boolean success) { + Intent finished = new Intent(FileDownloader.getDownloadFinishMessage()); + finished.putExtra(FileDownloader.ACCOUNT_NAME, account.name); + finished.putExtra(FileDownloader.EXTRA_REMOTE_PATH, remotePath); + finished.putExtra(FileDownloader.EXTRA_FILE_PATH, FileStorageUtils.getSavePath(account.name) + remotePath); + finished.putExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, success); + mService.sendStickyBroadcast(finished); } + + } @@ -652,7 +743,7 @@ public class OperationsService extends Service { String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); Intent sendIntent = operationIntent.getParcelableExtra(EXTRA_SEND_INTENT); if (remotePath.length() > 0) { - operation = new CreateShareOperation(remotePath, ShareType.PUBLIC_LINK, + operation = new CreateShareOperation(OperationsService.this, remotePath, ShareType.PUBLIC_LINK, "", false, "", 1, sendIntent); } @@ -794,7 +885,7 @@ public class OperationsService extends Service { /** * Notifies the currently subscribed listeners about the end of an operation. - * + * * @param target Account or URL pointing to an OC server. * @param operation Finished operation. * @param result Result of the operation.