mirror of
https://github.com/nextcloud/android.git
synced 2024-11-30 18:21:10 +03:00
Merge pull request #803 from owncloud/download_folder_cancel
Add cancellation of folder synchronizations to OperationsService.
This commit is contained in:
commit
47559478ba
3 changed files with 179 additions and 27 deletions
|
@ -278,9 +278,13 @@ public class FileOperationsHelper {
|
|||
mFileActivity.showLoadingDialog();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cancel the transference in downloads (files/folders) and file uploads
|
||||
* @param file OCFile
|
||||
*/
|
||||
public void cancelTransference(OCFile file) {
|
||||
Account account = mFileActivity.getAccount();
|
||||
if (!file.isFolder()) {
|
||||
FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
|
||||
FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
|
||||
if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) {
|
||||
|
@ -296,6 +300,13 @@ public class FileOperationsHelper {
|
|||
} else if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
|
||||
uploaderBinder.cancel(account, file);
|
||||
}
|
||||
} else {
|
||||
Intent intent = new Intent(mFileActivity, OperationsService.class);
|
||||
intent.setAction(OperationsService.ACTION_CANCEL_SYNC_FOLDER);
|
||||
intent.putExtra(OperationsService.EXTRA_ACCOUNT, account);
|
||||
intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
|
||||
mFileActivity.startService(intent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,7 @@ 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.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.operations.OperationCancelledException;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
@ -48,6 +49,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
//import android.support.v4.content.LocalBroadcastManager;
|
||||
|
||||
|
@ -96,6 +98,7 @@ public class SynchronizeFolderOperation extends SyncOperation {
|
|||
|
||||
/** 'True' means that the remote folder changed and should be fetched */
|
||||
private boolean mRemoteFolderChanged;
|
||||
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -150,6 +153,13 @@ public class SynchronizeFolderOperation extends SyncOperation {
|
|||
mConflictsFound = 0;
|
||||
mForgottenLocalFiles.clear();
|
||||
|
||||
/// perform the download
|
||||
synchronized(mCancellationRequested) {
|
||||
if (mCancellationRequested.get()) {
|
||||
return new RemoteOperationResult(new OperationCancelledException());
|
||||
}
|
||||
}
|
||||
|
||||
result = checkForChanges(client);
|
||||
|
||||
if (result.isSuccess()) {
|
||||
|
@ -514,6 +524,14 @@ public class SynchronizeFolderOperation extends SyncOperation {
|
|||
mContext.startService(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel operation
|
||||
*/
|
||||
public void cancel(){
|
||||
// WIP Cancel the sync operation
|
||||
mCancellationRequested.set(true);
|
||||
}
|
||||
|
||||
public boolean getRemoteFolderChanged() {
|
||||
return mRemoteFolderChanged;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.concurrent.ConcurrentMap;
|
|||
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.lib.common.OwnCloudAccount;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
|
||||
|
@ -101,6 +102,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_MOVE_FILE = "MOVE_FILE";
|
||||
|
||||
public static final String ACTION_OPERATION_ADDED = OperationsService.class.getName() + ".OPERATION_ADDED";
|
||||
|
@ -133,7 +135,7 @@ public class OperationsService extends Service {
|
|||
private ServiceHandler mOperationsHandler;
|
||||
private OperationsServiceBinder mOperationsBinder;
|
||||
|
||||
private ServiceHandler mSyncFolderHandler;
|
||||
private SyncFolderHandler mSyncFolderHandler;
|
||||
|
||||
/**
|
||||
* Service initialization
|
||||
|
@ -150,7 +152,7 @@ public class OperationsService extends Service {
|
|||
/// Separated worker thread for download of folders (WIP)
|
||||
thread = new HandlerThread("Syncfolder thread", Process.THREAD_PRIORITY_BACKGROUND);
|
||||
thread.start();
|
||||
mSyncFolderHandler = new ServiceHandler(thread.getLooper(), this);
|
||||
mSyncFolderHandler = new SyncFolderHandler(thread.getLooper(), this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -162,17 +164,36 @@ public class OperationsService extends Service {
|
|||
*/
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
// WIP: for the moment, only SYNC_FOLDER and CANCEL_SYNC_FOLDER is expected here;
|
||||
// the rest of the operations are requested through the Binder
|
||||
if (ACTION_SYNC_FOLDER.equals(intent.getAction())) {
|
||||
// WIP: for the moment, only SYNC_FOLDER is expected here; the rest of the operations are requested through
|
||||
// the Binder
|
||||
if (!intent.hasExtra(EXTRA_ACCOUNT) || !intent.hasExtra(EXTRA_REMOTE_PATH)) {
|
||||
Log_OC.e(TAG, "Not enough information provided in intent");
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
|
||||
String remotePath = intent.getStringExtra(EXTRA_REMOTE_PATH);
|
||||
|
||||
Pair<Account, String> itemSyncKey = new Pair<Account , String>(account, remotePath);
|
||||
|
||||
Pair<Target, RemoteOperation> itemToQueue = newOperation(intent);
|
||||
if (itemToQueue != null) {
|
||||
mSyncFolderHandler.mPendingOperations.add(itemToQueue);
|
||||
mSyncFolderHandler.add(account, remotePath, (SynchronizeFolderOperation)itemToQueue.second);
|
||||
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)) {
|
||||
Log_OC.e(TAG, "Not enough information provided in intent");
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
|
||||
String remotePath = intent.getStringExtra(EXTRA_REMOTE_PATH);
|
||||
|
||||
// Cancel operation
|
||||
mSyncFolderHandler.cancel(account,remotePath);
|
||||
} else {
|
||||
Message msg = mOperationsHandler.obtainMessage();
|
||||
msg.arg1 = startId;
|
||||
|
@ -208,7 +229,6 @@ public class OperationsService extends Service {
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provides a binder object that clients can use to perform actions on the queue of operations,
|
||||
* except the addition of new operations.
|
||||
|
@ -343,6 +363,111 @@ public class OperationsService extends Service {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* SyncFolder worker. Performs the pending operations in the order they were requested.
|
||||
*
|
||||
* Created with the Looper of a new thread, started in {@link OperationsService#onCreate()}.
|
||||
*/
|
||||
private static class SyncFolderHandler extends Handler {
|
||||
|
||||
// don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak
|
||||
|
||||
OperationsService mService;
|
||||
|
||||
private ConcurrentMap<String,SynchronizeFolderOperation> mPendingOperations =
|
||||
new ConcurrentHashMap<String,SynchronizeFolderOperation>();
|
||||
private OwnCloudClient mOwnCloudClient = null;
|
||||
private FileDataStorageManager mStorageManager;
|
||||
private SynchronizeFolderOperation mCurrentSyncOperation;
|
||||
|
||||
|
||||
public SyncFolderHandler(Looper looper, OperationsService service) {
|
||||
super(looper);
|
||||
if (service == null) {
|
||||
throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");
|
||||
}
|
||||
mService = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
Pair<Account, String> itemSyncKey = (Pair<Account, String>) msg.obj;
|
||||
doOperation(itemSyncKey.first, itemSyncKey.second);
|
||||
mService.stopSelf(msg.arg1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs the next operation in the queue
|
||||
*/
|
||||
private void doOperation(Account account, String remotePath) {
|
||||
|
||||
String syncKey = buildRemoteName(account,remotePath);
|
||||
|
||||
synchronized(mPendingOperations) {
|
||||
mCurrentSyncOperation = mPendingOperations.get(syncKey);
|
||||
}
|
||||
|
||||
if (mCurrentSyncOperation != null) {
|
||||
|
||||
try {
|
||||
|
||||
OwnCloudAccount ocAccount = new OwnCloudAccount(account, mService);
|
||||
mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
|
||||
getClientFor(ocAccount, mService);
|
||||
mStorageManager = new FileDataStorageManager(
|
||||
account,
|
||||
mService.getContentResolver()
|
||||
);
|
||||
|
||||
mCurrentSyncOperation.execute(mOwnCloudClient, mStorageManager);
|
||||
|
||||
} catch (AccountsException e) {
|
||||
Log_OC.e(TAG, "Error while trying to get autorization", e);
|
||||
} catch (IOException e) {
|
||||
Log_OC.e(TAG, "Error while trying to get autorization", e);
|
||||
} finally {
|
||||
synchronized(mPendingOperations) {
|
||||
mPendingOperations.remove(syncKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* @param account Owncloud account where the remote file is stored.
|
||||
* @param remotePath A remote file path
|
||||
*/
|
||||
public void cancel(Account account, String remotePath) {
|
||||
SynchronizeFolderOperation syncOperation = null;
|
||||
synchronized (mPendingOperations) {
|
||||
syncOperation = mPendingOperations.remove(buildRemoteName(account, remotePath));
|
||||
}
|
||||
if (syncOperation != null) {
|
||||
syncOperation.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Operations worker. Performs the pending operations in the order they were requested.
|
||||
*
|
||||
|
@ -687,6 +812,4 @@ public class OperationsService extends Service {
|
|||
}
|
||||
Log_OC.d(TAG, "Called " + count + " listeners");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue