From: David A. Velasco Date: Mon, 26 Jan 2015 08:42:44 +0000 (+0100) Subject: Added indexed tree of synchronizing folders to SyncFolderHandler X-Git-Tag: oc-android-1.7.0_signed~23^2~3 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/d860ae7cd462d08e3de523e2a6f29850bb8d2e96 Added indexed tree of synchronizing folders to SyncFolderHandler --- diff --git a/src/com/owncloud/android/files/FileMenuFilter.java b/src/com/owncloud/android/files/FileMenuFilter.java index b63446ba..89b00dc6 100644 --- a/src/com/owncloud/android/files/FileMenuFilter.java +++ b/src/com/owncloud/android/files/FileMenuFilter.java @@ -31,6 +31,7 @@ import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; +import com.owncloud.android.services.OperationsService; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; import com.owncloud.android.ui.activity.ComponentsGetter; @@ -140,9 +141,10 @@ public class FileMenuFilter { boolean downloading = false; boolean uploading = false; if (mComponentsGetter != null && mFile != null && mAccount != null) { - //downloading = mFile.isDownloading() || mFile.isSynchronizing(); FileDownloaderBinder downloaderBinder = mComponentsGetter.getFileDownloaderBinder(); downloading = (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)); + OperationsServiceBinder opsBinder = mComponentsGetter.getOperationsServiceBinder(); + downloading |= (opsBinder != null && opsBinder.isSynchronizing(mAccount, mFile.getRemotePath())); FileUploaderBinder uploaderBinder = mComponentsGetter.getFileUploaderBinder(); uploading = (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)); } diff --git a/src/com/owncloud/android/files/FileOperationsHelper.java b/src/com/owncloud/android/files/FileOperationsHelper.java index 35b69247..22be2a78 100644 --- a/src/com/owncloud/android/files/FileOperationsHelper.java +++ b/src/com/owncloud/android/files/FileOperationsHelper.java @@ -285,18 +285,15 @@ public class FileOperationsHelper { public void cancelTransference(OCFile file) { Account account = mFileActivity.getAccount(); if (file.isFolder()) { - // this goes to the queue!! :S - Intent intent = new Intent(mFileActivity, OperationsService.class); - intent.setAction(OperationsService.ACTION_CANCEL_SYNC_FOLDER); - intent.putExtra(OperationsService.EXTRA_ACCOUNT, account); - intent.putExtra(OperationsService.EXTRA_FILE, file); - mFileActivity.startService(intent); + OperationsService.OperationsServiceBinder opsBinder = mFileActivity.getOperationsServiceBinder(); + if (opsBinder != null) { + opsBinder.cancel(account, file); + } } // for both files and folders FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder(); - //if (downloaderBinder != null && file.isDownloading()) { if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) { downloaderBinder.cancel(account, file); diff --git a/src/com/owncloud/android/files/services/FileDownloader.java b/src/com/owncloud/android/files/services/FileDownloader.java index 1ecae2ca..06ebc0b2 100644 --- a/src/com/owncloud/android/files/services/FileDownloader.java +++ b/src/com/owncloud/android/files/services/FileDownloader.java @@ -1,6 +1,6 @@ /* ownCloud Android client application * Copyright (C) 2012 Bartek Przybylski - * Copyright (C) 2012-2013 ownCloud Inc. + * Copyright (C) 2012-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, @@ -21,7 +21,6 @@ package com.owncloud.android.files.services; import java.io.File; import java.io.IOException; import java.util.AbstractList; -import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -70,8 +69,6 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis public static final String EXTRA_ACCOUNT = "ACCOUNT"; public static final String EXTRA_FILE = "FILE"; - public static final String ACTION_CANCEL_FILE_DOWNLOAD = "CANCEL_FILE_DOWNLOAD"; - private static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED"; private static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; @@ -86,7 +83,7 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis private ServiceHandler mServiceHandler; private IBinder mBinder; private OwnCloudClient mDownloadClient = null; - private Account mLastAccount = null; + private Account mCurrentAccount = null; private FileDataStorageManager mStorageManager; private IndexedForest mPendingDownloads = new IndexedForest(); @@ -154,12 +151,12 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis AbstractList requestedDownloads = new Vector(); try { DownloadFileOperation newDownload = new DownloadFileOperation(account, file); + newDownload.addDatatransferProgressListener(this); + newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder); Pair putResult = mPendingDownloads.putIfAbsent( account, file.getRemotePath(), newDownload ); String downloadKey = putResult.first; - newDownload.addDatatransferProgressListener(this); - newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder); requestedDownloads.add(downloadKey); // Store file on db with state 'downloading' @@ -239,9 +236,9 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis if (download != null) { download.cancel(); } else { - // TODO synchronize - if (mCurrentDownload.getRemotePath().startsWith(file.getRemotePath()) && - account.name.equals(mLastAccount.name)) { + if (mCurrentDownload != null && mCurrentAccount != null && + mCurrentDownload.getRemotePath().startsWith(file.getRemotePath()) && + account.name.equals(mCurrentAccount.name)) { mCurrentDownload.cancel(); } } @@ -362,11 +359,11 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis RemoteOperationResult downloadResult = null; try { /// prepare client object to send the request to the ownCloud server - if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) { - mLastAccount = mCurrentDownload.getAccount(); + if (mDownloadClient == null || !mCurrentAccount.equals(mCurrentDownload.getAccount())) { + mCurrentAccount = mCurrentDownload.getAccount(); mStorageManager = - new FileDataStorageManager(mLastAccount, getContentResolver()); - OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this); + new FileDataStorageManager(mCurrentAccount, getContentResolver()); + OwnCloudAccount ocAccount = new OwnCloudAccount(mCurrentAccount, this); mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton(). getClientFor(ocAccount, this); } @@ -381,15 +378,15 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis } } catch (AccountsException e) { - Log_OC.e(TAG, "Error while trying to get authorization for " + mLastAccount.name, e); + Log_OC.e(TAG, "Error while trying to get authorization for " + mCurrentAccount.name, e); downloadResult = new RemoteOperationResult(e); } catch (IOException e) { - Log_OC.e(TAG, "Error while trying to get authorization for " + mLastAccount.name, e); + Log_OC.e(TAG, "Error while trying to get authorization for " + mCurrentAccount.name, e); downloadResult = new RemoteOperationResult(e); } finally { Pair removeResult = - mPendingDownloads.remove(mLastAccount, mCurrentDownload.getRemotePath()); + mPendingDownloads.removePayload(mCurrentAccount, mCurrentDownload.getRemotePath()); /// notify result notifyDownloadResult(mCurrentDownload, downloadResult); diff --git a/src/com/owncloud/android/files/services/IndexedForest.java b/src/com/owncloud/android/files/services/IndexedForest.java index 0f737aad..e2e9cb85 100644 --- a/src/com/owncloud/android/files/services/IndexedForest.java +++ b/src/com/owncloud/android/files/services/IndexedForest.java @@ -89,6 +89,10 @@ public class IndexedForest { public void removeChild(Node removed) { mChildren.remove(removed); } + + public void clearPayload() { + mPayload = null; + } } @@ -129,6 +133,20 @@ public class IndexedForest { return new Pair(targetKey, linkedTo); }; + + public Pair removePayload(Account account, String remotePath) { + String targetKey = buildKey(account, remotePath); + Node target = mMap.get(targetKey); + if (target != null) { + target.clearPayload(); + if (!target.hasChildren()) { + return remove(account, remotePath); + } + } + return new Pair(null, null); + } + + public /* synchronized */ Pair remove(Account account, String remotePath) { String targetKey = buildKey(account, remotePath); Node firstRemoved = mMap.remove(targetKey); @@ -155,14 +173,11 @@ public class IndexedForest { if (parent != null) { unlinkedFrom = parent.getKey().substring(account.name.length()); } - } - if (firstRemoved != null) { return new Pair(firstRemoved.getPayload(), unlinkedFrom); - } else { - return new Pair(null, unlinkedFrom); } + return new Pair(null, null); } private void removeDescendants(Node removed) { @@ -189,6 +204,11 @@ public class IndexedForest { } } + public V get(Account account, String remotePath) { + String key = buildKey(account, remotePath); + return get(key); + } + /** * Builds a key to index files diff --git a/src/com/owncloud/android/services/OperationsService.java b/src/com/owncloud/android/services/OperationsService.java index db303557..a47385b3 100644 --- a/src/com/owncloud/android/services/OperationsService.java +++ b/src/com/owncloud/android/services/OperationsService.java @@ -103,7 +103,7 @@ public class OperationsService extends Service { public static final String ACTION_CREATE_FOLDER = "CREATE_FOLDER"; public static final String ACTION_SYNC_FILE = "SYNC_FILE"; public static final String ACTION_SYNC_FOLDER = "SYNC_FOLDER"; // for the moment, just to download - public static final String ACTION_CANCEL_SYNC_FOLDER = "CANCEL_SYNC_FOLDER"; // for the moment, just to download + //public static final String ACTION_CANCEL_SYNC_FOLDER = "CANCEL_SYNC_FOLDER"; // for the moment, just to download public static final String ACTION_MOVE_FILE = "MOVE_FILE"; public static final String ACTION_OPERATION_ADDED = OperationsService.class.getName() + ".OPERATION_ADDED"; @@ -187,21 +187,6 @@ public class OperationsService extends Service { mSyncFolderHandler.sendMessage(msg); } - } else if (ACTION_CANCEL_SYNC_FOLDER.equals(intent.getAction())) { - if (!intent.hasExtra(EXTRA_ACCOUNT) || !intent.hasExtra(EXTRA_FILE)) { - Log_OC.e(TAG, "Not enough information provided in intent"); - return START_NOT_STICKY; - } - final Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); - final OCFile file = intent.getParcelableExtra(EXTRA_FILE); - // Cancel operation - new Thread(new Runnable() { - public void run() { - // Cancel the download - mSyncFolderHandler.cancel(account,file); - } - }).start(); - } else { Message msg = mOperationsHandler.obtainMessage(); msg.arg1 = startId; @@ -272,23 +257,23 @@ public class OperationsService extends Service { new ConcurrentHashMap(); private ServiceHandler mServiceHandler = null; - - + public OperationsServiceBinder(ServiceHandler serviceHandler) { mServiceHandler = serviceHandler; } /** - * Cancels an operation + * Cancels a pending or current synchronization. * - * TODO + * @param account ownCloud account where the remote folder is stored. + * @param file A folder in the queue of pending synchronizations */ - public void cancel() { - // TODO + public void cancel(Account account, OCFile file) { + mSyncFolderHandler.cancel(account, file); } - - + + public void clearListeners() { mBoundListeners.clear(); diff --git a/src/com/owncloud/android/services/SyncFolderHandler.java b/src/com/owncloud/android/services/SyncFolderHandler.java index 171a2f2d..b0116b32 100644 --- a/src/com/owncloud/android/services/SyncFolderHandler.java +++ b/src/com/owncloud/android/services/SyncFolderHandler.java @@ -28,6 +28,7 @@ import android.util.Pair; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileDownloader; +import com.owncloud.android.files.services.IndexedForest; import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; @@ -37,10 +38,6 @@ import com.owncloud.android.operations.SynchronizeFolderOperation; import com.owncloud.android.utils.FileStorageUtils; import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; /** * SyncFolder worker. Performs the pending operations in the order they were requested. @@ -55,9 +52,11 @@ class SyncFolderHandler extends Handler { OperationsService mService; - private ConcurrentMap mPendingOperations = - new ConcurrentHashMap(); + private IndexedForest mPendingOperations = + new IndexedForest(); + private OwnCloudClient mOwnCloudClient = null; + private Account mCurrentAccount = null; private FileDataStorageManager mStorageManager; private SynchronizeFolderOperation mCurrentSyncOperation; @@ -71,18 +70,16 @@ class SyncFolderHandler extends Handler { } + /** + * Returns True when the folder located in 'remotePath' in the ownCloud account 'account', or any of its + * descendants, is being synchronized (or waiting for it). + * + * @param account ownCloud account where the remote folder is stored. + * @param remotePath The path to a folder that could be in the queue of synchronizations. + */ 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; - } + return (mPendingOperations.contains(account, remotePath)); } @@ -99,24 +96,24 @@ class SyncFolderHandler extends Handler { */ private void doOperation(Account account, String remotePath) { - String syncKey = buildRemoteName(account,remotePath); - - synchronized(mPendingOperations) { - mCurrentSyncOperation = mPendingOperations.get(syncKey); - } + mCurrentSyncOperation = mPendingOperations.get(account, remotePath); if (mCurrentSyncOperation != null) { RemoteOperationResult result = null; try { - - OwnCloudAccount ocAccount = new OwnCloudAccount(account, mService); - mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, mService); - mStorageManager = new FileDataStorageManager( - account, - mService.getContentResolver() - ); + if (mOwnCloudClient == null || !account.equals(mCurrentAccount)) { + /// get client object to send the request to the ownCloud server, if cannot + mCurrentAccount = account; + mStorageManager = new FileDataStorageManager( + account, + mService.getContentResolver() + ); + OwnCloudAccount ocAccount = new OwnCloudAccount(account, mService); + mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton(). + getClientFor(ocAccount, mService); + + } // else, reuse client from previous operation result = mCurrentSyncOperation.execute(mOwnCloudClient, mStorageManager); @@ -125,23 +122,7 @@ class SyncFolderHandler extends Handler { } catch (IOException e) { Log_OC.e(TAG, "Error while trying to get autorization", e); } finally { - synchronized (mPendingOperations) { - mPendingOperations.remove(syncKey); - /* - SynchronizeFolderOperation checkedOp = mCurrentSyncOperation; - String checkedKey = syncKey; - while (checkedOp.getPendingChildrenCount() <= 0) { - // while (!checkedOp.hasChildren()) { - mPendingOperations.remove(checkedKey); - String parentKey = buildRemoteName(account, (new File(checkedOp.getFolderPath())).getParent()); - // String parentKey = buildRemoteName(account, checkedOp.getParentPath()); - SynchronizeFolderOperation parentOp = mPendingOperations.get(parentKey); - if (parentOp != null) { - parentOp.decreasePendingChildrenCount(); - } - } - */ - } + mPendingOperations.removePayload(account, remotePath); mService.dispatchResultToOperationListeners(null, mCurrentSyncOperation, result); @@ -151,43 +132,33 @@ class SyncFolderHandler extends Handler { } public void add(Account account, String remotePath, SynchronizeFolderOperation syncFolderOperation){ - String syncKey = buildRemoteName(account,remotePath); - mPendingOperations.putIfAbsent(syncKey,syncFolderOperation); - sendBroadcastNewSyncFolder(account, remotePath); + mPendingOperations.putIfAbsent(account, remotePath, syncFolderOperation); + sendBroadcastNewSyncFolder(account, remotePath); // TODO upgrade! } + /** - * Cancels sync operations. - * @param account Owncloud account where the remote file is stored. - * @param file File OCFile + * Cancels a pending or current sync' operation. + * + * @param account ownCloud account where the remote file is stored. + * @param file A file in the queue of pending synchronizations */ public void cancel(Account account, OCFile file){ - SynchronizeFolderOperation syncOperation = null; - String targetKey = buildRemoteName(account, file.getRemotePath()); - ArrayList keyItems = new ArrayList(); - synchronized (mPendingOperations) { - 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(); - } + if (account == null || file == null) { + Log_OC.e(TAG, "Cannot cancel with NULL parameters"); + return; + } + Pair removeResult = + mPendingOperations.remove(account, file.getRemotePath()); + SynchronizeFolderOperation synchronization = removeResult.first; + if (synchronization != null) { + synchronization.cancel(); + } else { + // TODO synchronize + if (mCurrentSyncOperation != null && mCurrentAccount != null && + mCurrentSyncOperation.getFolderPath().startsWith(file.getRemotePath()) && + account.name.equals(mCurrentAccount.name)) { + mCurrentSyncOperation.cancel(); } } @@ -195,17 +166,6 @@ class SyncFolderHandler extends Handler { } /** - * Builds a key from the account and file to download - * - * @param account Account where the file to download is stored - * @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. */ diff --git a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java index 33f16c83..df05ba4d 100644 --- a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java @@ -43,6 +43,7 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; +import com.owncloud.android.services.OperationsService.OperationsServiceBinder; import com.owncloud.android.ui.activity.ComponentsGetter; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileStorageUtils; @@ -154,8 +155,10 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { localStateView.bringToFront(); FileDownloaderBinder downloaderBinder = mTransferServiceGetter.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = mTransferServiceGetter.getFileUploaderBinder(); - //if (file.isSynchronizing() || file.isDownloading()) { - if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) { + boolean downloading = (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)); + OperationsServiceBinder opsBinder = mTransferServiceGetter.getOperationsServiceBinder(); + downloading |= (opsBinder != null && opsBinder.isSynchronizing(mAccount, file.getRemotePath())); + if (downloading) { localStateView.setImageResource(R.drawable.downloading_file_indicator); localStateView.setVisibility(View.VISIBLE); } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file)) {