From: masensio Date: Wed, 25 Feb 2015 07:56:00 +0000 (+0100) Subject: Merge branch 'develop' into cancel_transfer_for_deleted_users X-Git-Tag: oc-android-1.7.1_signed^2~40^2~1 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/2abceb0ed5abefefc3655fb27d234b81de3873ab?hp=72bd1c17a585df6fdf60bc69afbbd310d5850c63 Merge branch 'develop' into cancel_transfer_for_deleted_users --- diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 780875b7..f0d1e9dc 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3,7 +3,7 @@ ownCloud Android client application Copyright (C) 2012 Bartek Przybylski - Copyright (C) 2012-2014 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, @@ -86,7 +86,6 @@ android:name=".ui.activity.Preferences" android:theme="@style/Theme.ownCloud" > - diff --git a/src/com/owncloud/android/files/services/FileDownloader.java b/src/com/owncloud/android/files/services/FileDownloader.java index cd7afa62..c76ab79d 100644 --- a/src/com/owncloud/android/files/services/FileDownloader.java +++ b/src/com/owncloud/android/files/services/FileDownloader.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Vector; import com.owncloud.android.R; +import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.authentication.AuthenticatorActivity; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; @@ -49,7 +50,9 @@ import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.utils.ErrorMessageAdapter; import android.accounts.Account; +import android.accounts.AccountManager; import android.accounts.AccountsException; +import android.accounts.OnAccountsUpdateListener; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; @@ -64,19 +67,20 @@ import android.os.Process; import android.support.v4.app.NotificationCompat; import android.util.Pair; -public class FileDownloader extends Service implements OnDatatransferProgressListener { - +public class FileDownloader extends Service + implements OnDatatransferProgressListener, OnAccountsUpdateListener { + public static final String EXTRA_ACCOUNT = "ACCOUNT"; public static final String EXTRA_FILE = "FILE"; 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"; + public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; public static final String EXTRA_FILE_PATH = "FILE_PATH"; public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO"; public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; - + private static final String TAG = "FileDownloader"; private Looper mServiceLooper; @@ -85,24 +89,24 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis private OwnCloudClient mDownloadClient = null; private Account mCurrentAccount = null; private FileDataStorageManager mStorageManager; - + private IndexedForest mPendingDownloads = new IndexedForest(); private DownloadFileOperation mCurrentDownload = null; - + private NotificationManager mNotificationManager; private NotificationCompat.Builder mNotificationBuilder; private int mLastPercent; - + public static String getDownloadAddedMessage() { return FileDownloader.class.getName() + DOWNLOAD_ADDED_MESSAGE; } - + public static String getDownloadFinishMessage() { return FileDownloader.class.getName() + DOWNLOAD_FINISH_MESSAGE; } - + /** * Service initialization */ @@ -116,6 +120,10 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper, this); mBinder = new FileDownloaderBinder(); + + // add AccountsUpdatedListener + AccountManager am = AccountManager.get(getApplicationContext()); + am.addOnAccountsUpdatedListener(this, null, false); } @@ -124,19 +132,24 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis */ @Override public void onDestroy() { - Log_OC.v(TAG, "Destroying service" ); + Log_OC.v(TAG, "Destroying service"); mBinder = null; mServiceHandler = null; mServiceLooper.quit(); mServiceLooper = null; mNotificationManager = null; + + // remove AccountsUpdatedListener + AccountManager am = AccountManager.get(getApplicationContext()); + am.removeOnAccountsUpdatedListener(this); + super.onDestroy(); } /** * Entry point to add one or several files to the queue of downloads. - * + *

* New downloads are added calling to startService(), resulting in a call to this method. * This ensures the service will keep on working although the caller activity goes away. */ @@ -144,9 +157,9 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis public int onStartCommand(Intent intent, int flags, int startId) { Log_OC.d(TAG, "Starting command with id " + startId); - if ( !intent.hasExtra(EXTRA_ACCOUNT) || + if (!intent.hasExtra(EXTRA_ACCOUNT) || !intent.hasExtra(EXTRA_FILE) - ) { + ) { Log_OC.e(TAG, "Not enough information provided in intent"); return START_NOT_STICKY; } else { @@ -158,22 +171,22 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis "Received request to download file" );*/ - AbstractList requestedDownloads = new Vector(); - try { - DownloadFileOperation newDownload = new DownloadFileOperation(account, file); - newDownload.addDatatransferProgressListener(this); - newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder); - Pair putResult = mPendingDownloads.putIfAbsent( + 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; - requestedDownloads.add(downloadKey); + ); + String downloadKey = putResult.first; + requestedDownloads.add(downloadKey); /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(), "Download on " + file.getRemotePath() + " added to queue" );*/ - // Store file on db with state 'downloading' + // Store file on db with state 'downloading' /* TODO - check if helps with UI responsiveness, letting only folders use FileDownloaderBinder to check FileDataStorageManager storageManager = new FileDataStorageManager(account, getContentResolver()); @@ -181,19 +194,19 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis storageManager.saveFile(file); */ - sendBroadcastNewDownload(newDownload, putResult.second); + sendBroadcastNewDownload(newDownload, putResult.second); - } catch (IllegalArgumentException e) { - Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage()); - return START_NOT_STICKY; - } + } catch (IllegalArgumentException e) { + Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage()); + return START_NOT_STICKY; + } - if (requestedDownloads.size() > 0) { - Message msg = mServiceHandler.obtainMessage(); - msg.arg1 = startId; - msg.obj = requestedDownloads; - mServiceHandler.sendMessage(msg); - } + if (requestedDownloads.size() > 0) { + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + msg.obj = requestedDownloads; + mServiceHandler.sendMessage(msg); + } //} } @@ -204,7 +217,7 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis /** * Provides a binder object that clients can use to perform operations on the queue of downloads, * excepting the addition of new files. - * + *

* Implemented to perform cancellation, pause and resume of existing downloads. */ @Override @@ -218,19 +231,29 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis */ @Override public boolean onUnbind(Intent intent) { - ((FileDownloaderBinder)mBinder).clearListeners(); + ((FileDownloaderBinder) mBinder).clearListeners(); return false; // not accepting rebinding (default behaviour) } + @Override + public void onAccountsUpdated(Account[] accounts) { + //review the current download and cancel it if its account doesn't exist + if (mCurrentDownload != null && + !AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) { + mCurrentDownload.cancel(); + } + // The rest of downloads are cancelled when they try to start + } + /** - * Binder to let client components to perform operations on the queue of downloads. - * - * It provides by itself the available operations. + * Binder to let client components to perform operations on the queue of downloads. + *

+ * It provides by itself the available operations. */ public class FileDownloaderBinder extends Binder implements OnDatatransferProgressListener { - - /** + + /** * Map of listeners that will be reported about progress of downloads from a {@link FileDownloaderBinder} * instance. */ @@ -241,8 +264,8 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis /** * Cancels a pending or current download of a remote file. * - * @param account ownCloud account where the remote file is stored. - * @param file A file in the queue of pending downloads + * @param account ownCloud account where the remote file is stored. + * @param file A file in the queue of pending downloads */ public void cancel(Account account, OCFile file) { /*Log_OC.v( @@ -251,7 +274,8 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis ); Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(), "Removing download of " + file.getRemotePath());*/ - Pair removeResult = mPendingDownloads.remove(account, file.getRemotePath()); + Pair removeResult = + mPendingDownloads.remove(account, file.getRemotePath()); DownloadFileOperation download = removeResult.first; if (download != null) { /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(), @@ -267,8 +291,25 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis } } } - - + + /** + * Cancels a pending or current upload for an account + * + * @param account Owncloud accountName where the remote file will be stored. + */ + public void cancel(Account account) { + Log_OC.d(TAG, "Account= " + account.name); + + if (mCurrentDownload != null) { + Log_OC.d(TAG, "Current Download Account= " + mCurrentDownload.getAccount().name); + if (mCurrentDownload.getAccount().name.equals(account.name)) { + mCurrentDownload.cancel(); + } + } + // Cancel pending downloads + cancelDownloadsForAccount(account); + } + public void clearListeners() { mBoundListeners.clear(); } @@ -277,43 +318,43 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis /** * 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 any 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 in the queue of downloads. + * + * @param account ownCloud account where the remote file is stored. + * @param file A file that could be in the queue of downloads. */ public boolean isDownloading(Account account, OCFile file) { if (account == null || file == null) return false; return (mPendingDownloads.contains(account, file.getRemotePath())); } - + /** * Adds a listener interested in the progress of the download for a concrete file. - * - * @param listener Object to notify about progress of transfer. - * @param account ownCloud account holding the file of interest. - * @param file {@link OCFile} of interest for listener. + * + * @param listener Object to notify about progress of transfer. + * @param account ownCloud account holding the file of interest. + * @param file {@link OCFile} of interest for listener. */ - public void addDatatransferProgressListener ( + public void addDatatransferProgressListener( OnDatatransferProgressListener listener, Account account, OCFile file ) { if (account == null || file == null || listener == null) return; //String targetKey = buildKey(account, file.getRemotePath()); mBoundListeners.put(file.getFileId(), listener); } - - + + /** * Removes a listener interested in the progress of the download for a concrete file. - * - * @param listener Object to notify about progress of transfer. - * @param account ownCloud account holding the file of interest. - * @param file {@link OCFile} of interest for listener. + * + * @param listener Object to notify about progress of transfer. + * @param account ownCloud account holding the file of interest. + * @param file {@link OCFile} of interest for listener. */ - public void removeDatatransferProgressListener ( + public void removeDatatransferProgressListener( OnDatatransferProgressListener listener, Account account, OCFile file ) { if (account == null || file == null || listener == null) return; @@ -326,25 +367,37 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis @Override public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, - String fileName) { + String fileName) { //String key = buildKey(mCurrentDownload.getAccount(), mCurrentDownload.getFile().getRemotePath()); OnDatatransferProgressListener boundListener = mBoundListeners.get(mCurrentDownload.getFile().getFileId()); if (boundListener != null) { boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName); } } - + + /** + * Review downloads and cancel it if its account doesn't exist + */ + public void checkAccountOfCurrentDownload() { + if (mCurrentDownload != null && + !AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) { + mCurrentDownload.cancel(); + } + // The rest of downloads are cancelled when they try to start + } + } - - - /** - * Download worker. Performs the pending downloads in the order they were requested. - * - * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. + + + /** + * Download worker. Performs the pending downloads in the order they were requested. + *

+ * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. */ private static class ServiceHandler extends Handler { // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak FileDownloader mService; + public ServiceHandler(Looper looper, FileDownloader service) { super(looper); if (service == null) @@ -367,12 +420,12 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis mService.stopSelf(msg.arg1); } } - + /** * Core download method: requests a file to download and stores it. - * - * @param downloadKey Key to access the download to perform, contained in mPendingDownloads + * + * @param downloadKey Key to access the download to perform, contained in mPendingDownloads */ private void downloadFile(String downloadKey) { @@ -381,54 +434,61 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis mCurrentDownload = mPendingDownloads.get(downloadKey); if (mCurrentDownload != null) { - - notifyDownloadStart(mCurrentDownload); + // Detect if the account exists + if (AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) { + Log_OC.d(TAG, "Account " + mCurrentDownload.getAccount().name + " exists"); + notifyDownloadStart(mCurrentDownload); - RemoteOperationResult downloadResult = null; - try { - /// prepare client object to send the request to the ownCloud server - if (mCurrentAccount == null || !mCurrentAccount.equals(mCurrentDownload.getAccount())) { - mCurrentAccount = mCurrentDownload.getAccount(); - mStorageManager = new FileDataStorageManager( - 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(mCurrentAccount, this); - mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, this); - - - /// perform the download - /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(), + RemoteOperationResult downloadResult = null; + try { + /// prepare client object to send the request to the ownCloud server + if (mCurrentAccount == null || !mCurrentAccount.equals(mCurrentDownload.getAccount())) { + mCurrentAccount = mCurrentDownload.getAccount(); + mStorageManager = new FileDataStorageManager( + 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(mCurrentAccount, this); + mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton(). + getClientFor(ocAccount, this); + + + /// perform the download + /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(), "Executing download of " + mCurrentDownload.getRemotePath());*/ - downloadResult = mCurrentDownload.execute(mDownloadClient); - if (downloadResult.isSuccess()) { - saveDownloadedFile(); - } - - } catch (AccountsException 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 " + mCurrentAccount.name, e); - downloadResult = new RemoteOperationResult(e); - - } finally { + downloadResult = mCurrentDownload.execute(mDownloadClient); + if (downloadResult.isSuccess()) { + saveDownloadedFile(); + } + + } catch (AccountsException 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 " + mCurrentAccount.name, e); + downloadResult = new RemoteOperationResult(e); + + } finally { /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(), "Removing payload " + mCurrentDownload.getRemotePath());*/ - Pair removeResult = - mPendingDownloads.removePayload(mCurrentAccount, mCurrentDownload.getRemotePath()); + Pair removeResult = + mPendingDownloads.removePayload(mCurrentAccount, mCurrentDownload.getRemotePath()); - /// notify result - notifyDownloadResult(mCurrentDownload, downloadResult); + /// notify result + notifyDownloadResult(mCurrentDownload, downloadResult); - sendBroadcastDownloadFinished(mCurrentDownload, downloadResult, removeResult.second); - } + sendBroadcastDownloadFinished(mCurrentDownload, downloadResult, removeResult.second); + } + } else { + // Cancel the transfer + Log_OC.d(TAG, "Account " + mCurrentDownload.getAccount().toString() + " doesn't exist"); + cancelDownloadsForAccount(mCurrentDownload.getAccount()); + } } } @@ -465,13 +525,13 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis /** * Creates a status notification to show the download progress - * - * @param download Download operation starting. + * + * @param download Download operation starting. */ private void notifyDownloadStart(DownloadFileOperation download) { /// create status notification with a progress bar mLastPercent = 0; - mNotificationBuilder = + mNotificationBuilder = NotificationBuilderWithProgressBar.newNotificationBuilderWithProgressBar(this); mNotificationBuilder .setSmallIcon(R.drawable.notification_icon) @@ -483,7 +543,7 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis String.format(getString(R.string.downloader_download_in_progress_content), 0, new File(download.getSavePath()).getName()) ); - + /// includes a pending intent in the notification showing the details view of the file Intent showDetailsIntent = null; if (PreviewImageFragment.canBePreviewed(download.getFile())) { @@ -494,22 +554,21 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.getFile()); showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, download.getAccount()); showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - + mNotificationBuilder.setContentIntent(PendingIntent.getActivity( - this, (int) System.currentTimeMillis(), showDetailsIntent, 0 + this, (int) System.currentTimeMillis(), showDetailsIntent, 0 )); mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build()); } - + /** * Callback method to update the progress bar in the status notification. */ @Override - public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filePath) - { - int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer)); + public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filePath) { + int percent = (int) (100.0 * ((double) totalTransferredSoFar) / ((double) totalToTransfer)); if (percent != mLastPercent) { mNotificationBuilder.setProgress(100, percent, totalToTransfer < 0); String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1); @@ -519,36 +578,36 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis } mLastPercent = percent; } - - + + /** * Updates the status notification with the result of a download operation. - * - * @param downloadResult Result of the download operation. - * @param download Finished download operation + * + * @param downloadResult Result of the download operation. + * @param download Finished download operation */ private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) { mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker); if (!downloadResult.isCancelled()) { - int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : - R.string.downloader_download_failed_ticker; - + int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : + R.string.downloader_download_failed_ticker; + boolean needsToUpdateCredentials = ( downloadResult.getCode() == ResultCode.UNAUTHORIZED || - downloadResult.isIdPRedirection() + downloadResult.isIdPRedirection() ); - tickerId = (needsToUpdateCredentials) ? + tickerId = (needsToUpdateCredentials) ? R.string.downloader_download_failed_credentials_error : tickerId; - + mNotificationBuilder - .setTicker(getString(tickerId)) - .setContentTitle(getString(tickerId)) - .setAutoCancel(true) - .setOngoing(false) - .setProgress(0, 0, false); - + .setTicker(getString(tickerId)) + .setContentTitle(getString(tickerId)) + .setAutoCancel(true) + .setOngoing(false) + .setProgress(0, 0, false); + if (needsToUpdateCredentials) { - + // let the user update credentials with one click Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class); updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, download.getAccount()); @@ -559,41 +618,41 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND); mNotificationBuilder - .setContentIntent(PendingIntent.getActivity( - this, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT)); - + .setContentIntent(PendingIntent.getActivity( + this, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT)); + } else { // TODO put something smart in showDetailsIntent - Intent showDetailsIntent = new Intent(); + Intent showDetailsIntent = new Intent(); mNotificationBuilder - .setContentIntent(PendingIntent.getActivity( - this, (int) System.currentTimeMillis(), showDetailsIntent, 0)); + .setContentIntent(PendingIntent.getActivity( + this, (int) System.currentTimeMillis(), showDetailsIntent, 0)); } - + mNotificationBuilder.setContentText( ErrorMessageAdapter.getErrorCauseMessage(downloadResult, download, getResources()) ); mNotificationManager.notify(tickerId, mNotificationBuilder.build()); - + // Remove success notification - if (downloadResult.isSuccess()) { + if (downloadResult.isSuccess()) { // Sleep 2 seconds, so show the notification before remove it NotificationDelayer.cancelWithDelay( - mNotificationManager, - R.string.downloader_download_succeeded_ticker, + mNotificationManager, + R.string.downloader_download_succeeded_ticker, 2000); } - + } } - - + + /** * Sends a broadcast when a download finishes in order to the interested activities can update their view - * - * @param download Finished download operation - * @param downloadResult Result of the download operation - * @param unlinkedFromRemotePath Path in the downloads tree where the download was unlinked from + * + * @param download Finished download operation + * @param downloadResult Result of the download operation + * @param unlinkedFromRemotePath Path in the downloads tree where the download was unlinked from */ private void sendBroadcastDownloadFinished( DownloadFileOperation download, @@ -609,13 +668,13 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis } sendStickyBroadcast(end); } - - + + /** * Sends a broadcast when a new download is added to the queue. - * - * @param download Added download operation - * @param linkedToRemotePath Path in the downloads tree where the download was linked to + * + * @param download Added download operation + * @param linkedToRemotePath Path in the downloads tree where the download was linked to */ private void sendBroadcastNewDownload(DownloadFileOperation download, String linkedToRemotePath) { Intent added = new Intent(getDownloadAddedMessage()); @@ -626,4 +685,13 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis sendStickyBroadcast(added); } + /** + * Remove downloads of an account + * + * @param account Downloads account to remove + */ + private void cancelDownloadsForAccount(Account account) { + // Cancel pending downloads + mPendingDownloads.remove(account); + } } diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index 6f77a9c1..8a04be3b 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.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, @@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentMap; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountsException; +import android.accounts.OnAccountsUpdateListener; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; @@ -76,8 +77,8 @@ import com.owncloud.android.utils.ErrorMessageAdapter; import com.owncloud.android.utils.UriUtils; - -public class FileUploader extends Service implements OnDatatransferProgressListener { +public class FileUploader extends Service + implements OnDatatransferProgressListener, OnAccountsUpdateListener { private static final String UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH"; public static final String EXTRA_UPLOAD_RESULT = "RESULT"; @@ -124,14 +125,14 @@ public class FileUploader extends Service implements OnDatatransferProgressListe private static final String MIME_TYPE_PDF = "application/pdf"; private static final String FILE_EXTENSION_PDF = ".pdf"; - + public static String getUploadFinishMessage() { return FileUploader.class.getName().toString() + UPLOAD_FINISH_MESSAGE; } - + /** * 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 */ @@ -145,7 +146,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe /** * 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 @@ -168,6 +169,10 @@ public class FileUploader extends Service implements OnDatatransferProgressListe mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper, this); mBinder = new FileUploaderBinder(); + + // add AccountsUpdatedListener + AccountManager am = AccountManager.get(getApplicationContext()); + am.addOnAccountsUpdatedListener(this, null, false); } /** @@ -181,13 +186,18 @@ public class FileUploader extends Service implements OnDatatransferProgressListe mServiceLooper.quit(); mServiceLooper = null; mNotificationManager = null; + + // remove AccountsUpdatedListener + AccountManager am = AccountManager.get(getApplicationContext()); + am.removeOnAccountsUpdatedListener(this); + super.onDestroy(); } /** * Entry point to add one or several files to the queue of uploads. - * + * * New uploads are added calling to startService(), resulting in a call to * this method. This ensures the service will keep on working although the * caller activity goes away. @@ -246,7 +256,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe boolean forceOverwrite = intent.getBooleanExtra(KEY_FORCE_OVERWRITE, false); boolean isInstant = intent.getBooleanExtra(KEY_INSTANT_UPLOAD, false); int localAction = intent.getIntExtra(KEY_LOCAL_BEHAVIOUR, LOCAL_BEHAVIOUR_COPY); - + if (intent.hasExtra(KEY_FILE) && files == null) { Log_OC.e(TAG, "Incorrect array for OCFiles provided in upload intent"); return Service.START_NOT_STICKY; @@ -279,7 +289,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe AccountManager aMgr = AccountManager.get(this); String version = aMgr.getUserData(account, Constants.KEY_OC_VERSION); OwnCloudVersion ocv = new OwnCloudVersion(version); - + boolean chunked = FileUploader.chunkedUploadIsSupported(ocv); AbstractList requestedUploads = new Vector(); String uploadKey = null; @@ -287,7 +297,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe try { for (int i = 0; i < files.length; i++) { uploadKey = buildRemoteName(account, files[i].getRemotePath()); - newUpload = new UploadFileOperation(account, files[i], chunked, isInstant, forceOverwrite, localAction, + newUpload = new UploadFileOperation(account, files[i], chunked, isInstant, forceOverwrite, localAction, getApplicationContext()); if (isInstant) { newUpload.setRemoteFolderToBeCreated(); @@ -326,7 +336,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe /** * Provides a binder object that clients can use to perform operations on * the queue of uploads, excepting the addition of new files. - * + * * Implemented to perform cancellation, pause and resume of existing * uploads. */ @@ -334,7 +344,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe public IBinder onBind(Intent arg0) { return mBinder; } - + /** * Called when ALL the bound clients were onbound. */ @@ -343,24 +353,33 @@ public class FileUploader extends Service implements OnDatatransferProgressListe ((FileUploaderBinder)mBinder).clearListeners(); return false; // not accepting rebinding (default behaviour) } - + + @Override + public void onAccountsUpdated(Account[] accounts) { + // Review current upload, and cancel it if its account doen't exist + if (mCurrentUpload != null && + !AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) { + mCurrentUpload.cancel(); + } + // The rest of uploads are cancelled when they try to start + } /** * Binder to let client components to perform operations on the queue of * uploads. - * + * * It provides by itself the available operations. */ public class FileUploaderBinder extends Binder implements OnDatatransferProgressListener { - - /** + + /** * Map of listeners that will be reported about progress of uploads from a {@link FileUploaderBinder} instance */ private Map mBoundListeners = new HashMap(); - + /** * 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 */ @@ -373,22 +392,35 @@ public class FileUploader extends Service implements OnDatatransferProgressListe upload.cancel(); } } - - - + + /** + * Cancels a pending or current upload for an account + * + * @param account Owncloud accountName where the remote file will be stored. + */ + public void cancel(Account account) { + Log_OC.d(TAG, "Account= " + account.name); + + if (mCurrentUpload != null) { + Log_OC.d(TAG, "Current Upload Account= " + mCurrentUpload.getAccount().name); + if (mCurrentUpload.getAccount().name.equals(account.name)) { + mCurrentUpload.cancel(); + } + } + // Cancel pending uploads + cancelUploadForAccount(account.name); + } + public void clearListeners() { mBoundListeners.clear(); } - - - /** * 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 uploading or waiting to upload. - * + * * @param account ownCloud account where the remote file will be stored. * @param file A file that could be in the queue of pending uploads */ @@ -414,7 +446,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe /** * Adds a listener interested in the progress of the upload for a concrete file. - * + * * @param listener Object to notify about progress of transfer. * @param account ownCloud account holding the file of interest. * @param file {@link OCFile} of interest for listener. @@ -424,12 +456,12 @@ public class FileUploader extends Service implements OnDatatransferProgressListe String targetKey = buildRemoteName(account, file); mBoundListeners.put(targetKey, listener); } - - - + + + /** * Removes a listener interested in the progress of the upload for a concrete file. - * + * * @param listener Object to notify about progress of transfer. * @param account ownCloud account holding the file of interest. * @param file {@link OCFile} of interest for listener. @@ -445,20 +477,30 @@ public class FileUploader extends Service implements OnDatatransferProgressListe @Override public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, - String fileName) { + String fileName) { String key = buildRemoteName(mCurrentUpload.getAccount(), mCurrentUpload.getFile()); OnDatatransferProgressListener boundListener = mBoundListeners.get(key); if (boundListener != null) { boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName); } } - + + /** + * Review uploads and cancel it if its account doesn't exist + */ + public void checkAccountOfCurrentUpload() { + if (mCurrentUpload != null && + !AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) { + mCurrentUpload.cancel(); + } + // The rest of uploads are cancelled when they try to start + } } /** * Upload worker. Performs the pending uploads in the order they were * requested. - * + * * Created with the Looper of a new thread, started in * {@link FileUploader#onCreate()}. */ @@ -491,7 +533,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe /** * Core upload method: sends the file(s) to upload - * + * * @param uploadKey Key to access the upload to perform, contained in * mPendingUploads */ @@ -503,63 +545,73 @@ public class FileUploader extends Service implements OnDatatransferProgressListe if (mCurrentUpload != null) { - notifyUploadStart(mCurrentUpload); + // Detect if the account exists + if (AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) { + Log_OC.d(TAG, "Account " + mCurrentUpload.getAccount().name + " exists"); - RemoteOperationResult uploadResult = null, grantResult = null; - - 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()); - OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this); - mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, this); - } - - /// check the existence of the parent folder for the file to upload - String remoteParentPath = new File(mCurrentUpload.getRemotePath()).getParent(); - remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ? remoteParentPath : remoteParentPath + OCFile.PATH_SEPARATOR; - grantResult = grantFolderExistence(remoteParentPath); - - /// perform the upload - if (grantResult.isSuccess()) { - OCFile parent = mStorageManager.getFileByPath(remoteParentPath); - mCurrentUpload.getFile().setParentId(parent.getFileId()); - uploadResult = mCurrentUpload.execute(mUploadClient); - if (uploadResult.isSuccess()) { - saveUploadedFile(); + notifyUploadStart(mCurrentUpload); + + RemoteOperationResult uploadResult = null, grantResult = null; + + 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()); + OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this); + mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton(). + getClientFor(ocAccount, this); + } + + /// check the existence of the parent folder for the file to upload + String remoteParentPath = new File(mCurrentUpload.getRemotePath()).getParent(); + remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ? + remoteParentPath : remoteParentPath + OCFile.PATH_SEPARATOR; + grantResult = grantFolderExistence(remoteParentPath); + + /// perform the upload + if (grantResult.isSuccess()) { + OCFile parent = mStorageManager.getFileByPath(remoteParentPath); + mCurrentUpload.getFile().setParentId(parent.getFileId()); + uploadResult = mCurrentUpload.execute(mUploadClient); + if (uploadResult.isSuccess()) { + saveUploadedFile(); + } + } 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); + uploadResult = new RemoteOperationResult(e); + + } finally { + synchronized (mPendingUploads) { + mPendingUploads.remove(uploadKey); + Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map."); + } + if (uploadResult.isException()) { + // enforce the creation of a new client object for next uploads; this grant that a new socket will + // be created in the future if the current exception is due to an abrupt lose of network connection + mUploadClient = null; } - } 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); - uploadResult = new RemoteOperationResult(e); - - } finally { - synchronized (mPendingUploads) { - mPendingUploads.remove(uploadKey); - Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map."); - } - if (uploadResult.isException()) { - // enforce the creation of a new client object for next uploads; this grant that a new socket will - // be created in the future if the current exception is due to an abrupt lose of network connection - mUploadClient = null; } - } - - /// notify result - - notifyUploadResult(uploadResult, mCurrentUpload); - sendFinalBroadcast(mCurrentUpload, uploadResult); + /// notify result + notifyUploadResult(uploadResult, mCurrentUpload); + sendFinalBroadcast(mCurrentUpload, uploadResult); + + } else { + // Cancel the transfer + Log_OC.d(TAG, "Account " + mCurrentUpload.getAccount().toString() + " doesn't exist"); + cancelUploadForAccount(mCurrentUpload.getAccount().name); + + } } } @@ -567,17 +619,18 @@ public class FileUploader extends Service implements OnDatatransferProgressListe /** * Checks the existence of the folder where the current file will be uploaded both in the remote server * and in the local database. - * + * * If the upload is set to enforce the creation of the folder, the method tries to create it both remote * and locally. - * + * * @param pathToGrant Full remote path whose existence will be granted. * @return An {@link OCFile} instance corresponding to the folder where the file will be uploaded. */ private RemoteOperationResult grantFolderExistence(String pathToGrant) { RemoteOperation operation = new ExistenceCheckRemoteOperation(pathToGrant, this, false); RemoteOperationResult result = operation.execute(mUploadClient); - if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND && mCurrentUpload.isRemoteFolderToBeCreated()) { + if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND && + mCurrentUpload.isRemoteFolderToBeCreated()) { SyncOperation syncOp = new CreateFolderOperation( pathToGrant, true); result = syncOp.execute(mUploadClient, mStorageManager); } @@ -595,10 +648,11 @@ public class FileUploader extends Service implements OnDatatransferProgressListe return result; } - + private OCFile createLocalFolder(String remotePath) { String parentPath = new File(remotePath).getParent(); - parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR; + parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? + parentPath : parentPath + OCFile.PATH_SEPARATOR; OCFile parent = mStorageManager.getFileByPath(parentPath); if (parent == null) { parent = createLocalFolder(parentPath); @@ -612,15 +666,15 @@ public class FileUploader extends Service implements OnDatatransferProgressListe } return null; } - + /** * Saves a OC File after a successful upload. - * + * * A PROPFIND is necessary to keep the props in the local database * synchronized with the server, specially the modification time and Etag * (where available) - * + * * TODO refactor this ugly thing */ private void saveUploadedFile() { @@ -639,7 +693,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe updateOCFile(file, (RemoteFile) result.getData().get(0)); file.setLastSyncDateForProperties(syncDate); } - + // / maybe this would be better as part of UploadFileOperation... or // maybe all this method if (mCurrentUpload.wasRenamed()) { @@ -649,8 +703,8 @@ public class FileUploader extends Service implements OnDatatransferProgressListe 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() + // coincidence; nothing else is needed, the storagePath is right + // in the instance returned by mCurrentUpload.getFile() } file.setNeedsUpdateThumbnail(true); mStorageManager.saveFile(file); @@ -667,7 +721,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe } private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType, - FileDataStorageManager storageManager) { + FileDataStorageManager storageManager) { // MIME type if (mimeType == null || mimeType.length() <= 0) { @@ -697,7 +751,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe newFile.setFileLength(localFile.length()); newFile.setLastSyncDateForData(localFile.lastModified()); } // don't worry about not assigning size, the problems with localPath - // are checked when the UploadFileOperation instance is created + // are checked when the UploadFileOperation instance is created newFile.setMimetype(mimeType); @@ -707,13 +761,13 @@ public class FileUploader extends Service implements OnDatatransferProgressListe /** * Creates a status notification to show the upload progress - * + * * @param upload Upload operation starting. */ private void notifyUploadStart(UploadFileOperation upload) { // / create status notification with a progress bar mLastPercent = 0; - mNotificationBuilder = + mNotificationBuilder = NotificationBuilderWithProgressBar.newNotificationBuilderWithProgressBar(this); mNotificationBuilder .setOngoing(true) @@ -730,7 +784,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, upload.getAccount()); showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); mNotificationBuilder.setContentIntent(PendingIntent.getActivity( - this, (int) System.currentTimeMillis(), showDetailsIntent, 0 + this, (int) System.currentTimeMillis(), showDetailsIntent, 0 )); mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotificationBuilder.build()); @@ -754,7 +808,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe /** * Updates the status notification with the result of an upload operation. - * + * * @param uploadResult Result of the upload operation. * @param upload Finished upload operation */ @@ -763,33 +817,33 @@ public class FileUploader extends Service implements OnDatatransferProgressListe Log_OC.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode()); // / cancelled operation or success -> silent removal of progress notification mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker); - + // Show the result: success or fail notification if (!uploadResult.isCancelled()) { - int tickerId = (uploadResult.isSuccess()) ? R.string.uploader_upload_succeeded_ticker : - R.string.uploader_upload_failed_ticker; - + int tickerId = (uploadResult.isSuccess()) ? R.string.uploader_upload_succeeded_ticker : + R.string.uploader_upload_failed_ticker; + String content = null; // check credentials error boolean needsToUpdateCredentials = ( - uploadResult.getCode() == ResultCode.UNAUTHORIZED || - uploadResult.isIdPRedirection() + uploadResult.getCode() == ResultCode.UNAUTHORIZED || + uploadResult.isIdPRedirection() ); - tickerId = (needsToUpdateCredentials) ? + tickerId = (needsToUpdateCredentials) ? R.string.uploader_upload_failed_credentials_error : tickerId; mNotificationBuilder - .setTicker(getString(tickerId)) - .setContentTitle(getString(tickerId)) - .setAutoCancel(true) - .setOngoing(false) - .setProgress(0, 0, false); - + .setTicker(getString(tickerId)) + .setContentTitle(getString(tickerId)) + .setAutoCancel(true) + .setOngoing(false) + .setProgress(0, 0, false); + content = ErrorMessageAdapter.getErrorCauseMessage( uploadResult, upload, getResources() ); - + if (needsToUpdateCredentials) { // let the user update credentials with one click Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class); @@ -797,24 +851,24 @@ public class FileUploader extends Service implements OnDatatransferProgressListe AuthenticatorActivity.EXTRA_ACCOUNT, upload.getAccount() ); updateAccountCredentials.putExtra( - AuthenticatorActivity.EXTRA_ACTION, + AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN ); updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND); mNotificationBuilder.setContentIntent(PendingIntent.getActivity( - this, - (int) System.currentTimeMillis(), - updateAccountCredentials, - PendingIntent.FLAG_ONE_SHOT + this, + (int) System.currentTimeMillis(), + updateAccountCredentials, + PendingIntent.FLAG_ONE_SHOT )); - - mUploadClient = null; - // grant that future retries on the same account will get the fresh credentials + + mUploadClient = null; + // grant that future retries on the same account will get the fresh credentials } else { mNotificationBuilder.setContentText(content); - + if (upload.isInstant()) { DbHandler db = null; try { @@ -825,12 +879,12 @@ public class FileUploader extends Service implements OnDatatransferProgressListe if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) { //message = getString(R.string.failed_upload_quota_exceeded_text); if (db.updateFileState( - upload.getOriginalStoragePath(), + upload.getOriginalStoragePath(), DbHandler.UPLOAD_STATUS_UPLOAD_FAILED, message) == 0) { db.putFileForLater( - upload.getOriginalStoragePath(), - upload.getAccount().name, + upload.getOriginalStoragePath(), + upload.getAccount().name, message ); } @@ -842,22 +896,22 @@ public class FileUploader extends Service implements OnDatatransferProgressListe } } } - + mNotificationBuilder.setContentText(content); mNotificationManager.notify(tickerId, mNotificationBuilder.build()); - + if (uploadResult.isSuccess()) { - + DbHandler db = new DbHandler(this.getBaseContext()); db.removeIUPendingFile(mCurrentUpload.getOriginalStoragePath()); db.close(); // remove success notification, with a delay of 2 seconds NotificationDelayer.cancelWithDelay( - mNotificationManager, - R.string.uploader_upload_succeeded_ticker, + mNotificationManager, + R.string.uploader_upload_succeeded_ticker, 2000); - + } } } @@ -865,17 +919,17 @@ public class FileUploader extends Service implements OnDatatransferProgressListe /** * Sends a broadcast in order to the interested activities can update their * view - * + * * @param upload Finished upload operation * @param uploadResult Result of the upload operation */ private void sendFinalBroadcast(UploadFileOperation upload, RemoteOperationResult uploadResult) { Intent end = new Intent(getUploadFinishMessage()); end.putExtra(EXTRA_REMOTE_PATH, upload.getRemotePath()); // real remote - // path, after - // possible - // automatic - // renaming + // path, after + // possible + // automatic + // renaming if (upload.wasRenamed()) { end.putExtra(EXTRA_OLD_REMOTE_PATH, upload.getOldFile().getRemotePath()); } @@ -893,9 +947,27 @@ public class FileUploader extends Service implements OnDatatransferProgressListe * @return true if is needed to add the pdf file extension to the file */ private boolean isPdfFileFromContentProviderWithoutExtension(String localPath, String mimeType) { - return localPath.startsWith(UriUtils.URI_CONTENT_SCHEME) && - mimeType.equals(MIME_TYPE_PDF) && + return localPath.startsWith(UriUtils.URI_CONTENT_SCHEME) && + mimeType.equals(MIME_TYPE_PDF) && !localPath.endsWith(FILE_EXTENSION_PDF); } + /** + * Remove uploads of an account + * @param accountName + */ + private void cancelUploadForAccount(String accountName){ + // this can be slow if there are many uploads :( + Iterator it = mPendingUploads.keySet().iterator(); + Log_OC.d(TAG, "Number of pending updloads= " + mPendingUploads.size()); + while (it.hasNext()) { + String key = it.next(); + Log_OC.d(TAG, "mPendingUploads CANCELLED " + key); + if (key.startsWith(accountName)) { + synchronized (mPendingUploads) { + mPendingUploads.remove(key); + } + } + } + } } diff --git a/src/com/owncloud/android/files/services/IndexedForest.java b/src/com/owncloud/android/files/services/IndexedForest.java index e2e9cb85..c40cece3 100644 --- a/src/com/owncloud/android/files/services/IndexedForest.java +++ b/src/com/owncloud/android/files/services/IndexedForest.java @@ -21,6 +21,7 @@ import android.accounts.Account; import android.util.Pair; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.lib.common.utils.Log_OC; import java.io.File; import java.util.HashSet; @@ -211,6 +212,21 @@ public class IndexedForest { /** + * Remove the elements that contains account as a part of its key + * @param account + */ + public void remove(Account account){ + Iterator it = mMap.keySet().iterator(); + while (it.hasNext()) { + String key = it.next(); + Log_OC.d("IndexedForest", "Number of pending downloads= " + mMap.size()); + if (key.startsWith(account.name)) { + mMap.remove(key); + } + } + } + + /** * Builds a key to index files * * @param account Account where the file to download is stored @@ -220,6 +236,4 @@ public class IndexedForest { return account.name + remotePath; } - - } diff --git a/src/com/owncloud/android/operations/DownloadFileOperation.java b/src/com/owncloud/android/operations/DownloadFileOperation.java index 0a5ff94c..f6bee5d4 100644 --- a/src/com/owncloud/android/operations/DownloadFileOperation.java +++ b/src/com/owncloud/android/operations/DownloadFileOperation.java @@ -177,5 +177,4 @@ public class DownloadFileOperation extends RemoteOperation { mDataTransferListeners.remove(listener); } } - } diff --git a/src/com/owncloud/android/operations/UploadFileOperation.java b/src/com/owncloud/android/operations/UploadFileOperation.java index 1536a604..3c7917e8 100644 --- a/src/com/owncloud/android/operations/UploadFileOperation.java +++ b/src/com/owncloud/android/operations/UploadFileOperation.java @@ -1,5 +1,5 @@ /* ownCloud Android client application - * 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, @@ -26,6 +26,7 @@ import java.io.OutputStream; import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import java.util.concurrent.CancellationException; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.httpclient.methods.PutMethod; @@ -76,7 +77,7 @@ public class UploadFileOperation extends RemoteOperation { private String mOriginalStoragePath = null; PutMethod mPutMethod = null; private Set mDataTransferListeners = new HashSet(); - private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false); + private AtomicBoolean mCancellationRequested = new AtomicBoolean(false); private Context mContext; private UploadRemoteFileOperation mUploadOperation; @@ -212,7 +213,8 @@ public class UploadFileOperation extends RemoteOperation { // check location of local file; if not the expected, copy to a // temporal file before upload (if COPY is the expected behaviour) - if (!mOriginalStoragePath.equals(expectedPath) && mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY) { + if (!mOriginalStoragePath.equals(expectedPath) && + mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY) { if (FileStorageUtils.getUsableSpace(mAccount.name) < originalFile.length()) { result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_FULL); @@ -221,7 +223,8 @@ public class UploadFileOperation extends RemoteOperation { } else { - String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath(); + String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + + mFile.getRemotePath(); mFile.setStoragePath(temporalPath); temporalFile = new File(temporalPath); @@ -251,10 +254,10 @@ public class UploadFileOperation extends RemoteOperation { int nRead; byte[] data = new byte[16384]; - while ((nRead = in.read(data, 0, data.length)) != -1) { + while (!mCancellationRequested.get() && + (nRead = in.read(data, 0, data.length)) != -1) { out.write(data, 0, nRead); } - out.flush(); } else { @@ -268,12 +271,17 @@ public class UploadFileOperation extends RemoteOperation { out = new FileOutputStream(temporalFile); byte[] buf = new byte[1024]; int len; - while ((len = in.read(buf)) > 0) { + while (!mCancellationRequested.get() && (len = in.read(buf)) > 0) { out.write(buf, 0, len); } } } + if (mCancellationRequested.get()) { + result = new RemoteOperationResult(new OperationCancelledException()); + } + + } catch (Exception e) { result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_COPIED); return result; @@ -283,63 +291,69 @@ public class UploadFileOperation extends RemoteOperation { if (in != null) in.close(); } catch (Exception e) { - Log_OC.d(TAG, "Weird exception while closing input stream for " + mOriginalStoragePath + " (ignoring)", e); + Log_OC.d(TAG, "Weird exception while closing input stream for " + + mOriginalStoragePath + " (ignoring)", e); } try { if (out != null) out.close(); } catch (Exception e) { - Log_OC.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e); + Log_OC.d(TAG, "Weird exception while closing output stream for " + + expectedPath + " (ignoring)", e); } } } } - localCopyPassed = true; + localCopyPassed = result.isSuccess(); /// perform the upload - if ( mChunked && (new File(mFile.getStoragePath())).length() > ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) { - mUploadOperation = new ChunkedUploadRemoteFileOperation(mFile.getStoragePath(), mFile.getRemotePath(), - mFile.getMimetype()); + if ( mChunked && + (new File(mFile.getStoragePath())).length() > + ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) { + mUploadOperation = new ChunkedUploadRemoteFileOperation(mFile.getStoragePath(), + mFile.getRemotePath(), mFile.getMimetype()); } else { - mUploadOperation = new UploadRemoteFileOperation(mFile.getStoragePath(), mFile.getRemotePath(), - mFile.getMimetype()); + mUploadOperation = new UploadRemoteFileOperation(mFile.getStoragePath(), + mFile.getRemotePath(), mFile.getMimetype()); } Iterator listener = mDataTransferListeners.iterator(); while (listener.hasNext()) { mUploadOperation.addDatatransferProgressListener(listener.next()); } - result = mUploadOperation.execute(client); - - /// move local temporal file or original file to its corresponding - // location in the ownCloud local folder - if (result.isSuccess()) { - if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) { - mFile.setStoragePath(null); - - } else { - mFile.setStoragePath(expectedPath); - File fileToMove = null; - if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY - // ; see where temporalFile was - // set - fileToMove = temporalFile; - } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE - fileToMove = originalFile; - } - if (!expectedFile.equals(fileToMove)) { - File expectedFolder = expectedFile.getParentFile(); - expectedFolder.mkdirs(); - if (!expectedFolder.isDirectory() || !fileToMove.renameTo(expectedFile)) { - mFile.setStoragePath(null); // forget the local file - // by now, treat this as a success; the file was - // uploaded; the user won't like that the local file - // is not linked, but this should be a very rare - // fail; - // the best option could be show a warning message - // (but not a fail) - // result = new - // RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_MOVED); - // return result; + if (!mCancellationRequested.get()) { + result = mUploadOperation.execute(client); + + /// move local temporal file or original file to its corresponding + // location in the ownCloud local folder + if (result.isSuccess()) { + if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) { + mFile.setStoragePath(null); + + } else { + mFile.setStoragePath(expectedPath); + File fileToMove = null; + if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY + // ; see where temporalFile was + // set + fileToMove = temporalFile; + } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE + fileToMove = originalFile; + } + if (!expectedFile.equals(fileToMove)) { + File expectedFolder = expectedFile.getParentFile(); + expectedFolder.mkdirs(); + if (!expectedFolder.isDirectory() || !fileToMove.renameTo(expectedFile)) { + mFile.setStoragePath(null); // forget the local file + // by now, treat this as a success; the file was + // uploaded; the user won't like that the local file + // is not linked, but this should be a very rare + // fail; + // the best option could be show a warning message + // (but not a fail) + // result = new + // RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_MOVED); + // return result; + } } } } @@ -358,19 +372,23 @@ public class UploadFileOperation extends RemoteOperation { temporalFile.delete(); } if (result.isSuccess()) { - Log_OC.i(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + + result.getLogMessage()); } else { if (result.getException() != null) { String complement = ""; if (!nameCheckPassed) { complement = " (while checking file existence in server)"; } else if (!localCopyPassed) { - complement = " (while copying local file to " + FileStorageUtils.getSavePath(mAccount.name) + complement = " (while copying local file to " + + FileStorageUtils.getSavePath(mAccount.name) + ")"; } - Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage() + complement, result.getException()); + Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + + ": " + result.getLogMessage() + complement, result.getException()); } else { - Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage()); + Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + + ": " + result.getLogMessage()); } } } @@ -385,7 +403,8 @@ public class UploadFileOperation extends RemoteOperation { newFile.setFileLength(mFile.getFileLength()); newFile.setMimetype(mFile.getMimetype()); newFile.setModificationTimestamp(mFile.getModificationTimestamp()); - newFile.setModificationTimestampAtLastSyncForData(mFile.getModificationTimestampAtLastSyncForData()); + newFile.setModificationTimestampAtLastSyncForData( + mFile.getModificationTimestampAtLastSyncForData()); // newFile.setEtag(mFile.getEtag()) newFile.setKeepInSync(mFile.keepInSync()); newFile.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties()); @@ -400,7 +419,8 @@ public class UploadFileOperation extends RemoteOperation { * Checks if remotePath does not exist in the server and returns it, or adds * a suffix to it in order to avoid the server file is overwritten. * - * @param string + * @param wc + * @param remotePath * @return */ private String getAvailableRemotePath(OwnCloudClient wc, String remotePath) throws Exception { @@ -436,12 +456,16 @@ public class UploadFileOperation extends RemoteOperation { } private boolean existsFile(OwnCloudClient client, String remotePath){ - ExistenceCheckRemoteOperation existsOperation = new ExistenceCheckRemoteOperation(remotePath, mContext, false); + ExistenceCheckRemoteOperation existsOperation = + new ExistenceCheckRemoteOperation(remotePath, mContext, false); RemoteOperationResult result = existsOperation.execute(client); return result.isSuccess(); } public void cancel() { - mUploadOperation.cancel(); + mCancellationRequested = new AtomicBoolean(true); + if (mUploadOperation != null) { + mUploadOperation.cancel(); + } } } diff --git a/src/com/owncloud/android/ui/activity/FileActivity.java b/src/com/owncloud/android/ui/activity/FileActivity.java index 536800bd..97c5606e 100644 --- a/src/com/owncloud/android/ui/activity/FileActivity.java +++ b/src/com/owncloud/android/ui/activity/FileActivity.java @@ -1,6 +1,6 @@ /* ownCloud Android client application * Copyright (C) 2011 Bartek Przybylski - * Copyright (C) 2012-2014 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, @@ -56,7 +56,6 @@ import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.operations.CreateShareOperation; import com.owncloud.android.operations.SynchronizeFolderOperation; import com.owncloud.android.operations.UnshareLinkOperation; - import com.owncloud.android.services.OperationsService; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; import com.owncloud.android.ui.dialog.LoadingDialog; @@ -68,8 +67,8 @@ import com.owncloud.android.utils.ErrorMessageAdapter; * * @author David A. Velasco */ -public class FileActivity extends SherlockFragmentActivity -implements OnRemoteOperationListener, ComponentsGetter { +public class FileActivity extends SherlockFragmentActivity + implements OnRemoteOperationListener, ComponentsGetter { public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE"; public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT"; @@ -79,7 +78,7 @@ implements OnRemoteOperationListener, ComponentsGetter { public static final String TAG = FileActivity.class.getSimpleName(); private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT"; - private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";; + private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID"; protected static final long DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS = 200; @@ -158,7 +157,7 @@ implements OnRemoteOperationListener, ComponentsGetter { if (mUploadServiceConnection != null) { bindService(new Intent(this, FileUploader.class), mUploadServiceConnection, Context.BIND_AUTO_CREATE); } - + } @@ -221,6 +220,7 @@ implements OnRemoteOperationListener, ComponentsGetter { unbindService(mUploadServiceConnection); mUploadServiceConnection = null; } + super.onDestroy(); } @@ -256,8 +256,6 @@ implements OnRemoteOperationListener, ComponentsGetter { * to create a new ownCloud {@link Account}. * * POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}. - * - * @return 'True' if the checked {@link Account} was valid. */ private void swapToDefaultAccount() { // default to the most recently used account @@ -356,7 +354,6 @@ implements OnRemoteOperationListener, ComponentsGetter { protected ServiceConnection newTransferenceServiceConnection() { return null; } - /** * Helper class handling a callback from the {@link AccountManager} after the creation of @@ -605,7 +602,7 @@ implements OnRemoteOperationListener, ComponentsGetter { @Override public FileUploaderBinder getFileUploaderBinder() { return mUploaderBinder; - }; + } } diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 18b87cae..7b8af0f8 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1,6 +1,6 @@ /* ownCloud Android client application * Copyright (C) 2011 Bartek Przybylski - * Copyright (C) 2012-2014 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, @@ -96,7 +96,6 @@ import com.owncloud.android.operations.RefreshFolderOperation; import com.owncloud.android.operations.UnshareLinkOperation; import com.owncloud.android.services.observer.FileObserverService; import com.owncloud.android.syncadapter.FileSyncAdapter; -import com.owncloud.android.ui.adapter.FileListListAdapter; import com.owncloud.android.ui.dialog.CreateFolderDialogFragment; import com.owncloud.android.ui.dialog.SslUntrustedCertDialog; import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener; @@ -649,6 +648,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { if (filePaths != null) { String[] remotePaths = new String[filePaths.length]; String remotePathBase = ""; + for (int j = mDirectories.getCount() - 2; j >= 0; --j) { remotePathBase += OCFile.PATH_SEPARATOR + mDirectories.getItem(j); } diff --git a/src/com/owncloud/android/ui/activity/Preferences.java b/src/com/owncloud/android/ui/activity/Preferences.java index 7a290738..4fafb480 100644 --- a/src/com/owncloud/android/ui/activity/Preferences.java +++ b/src/com/owncloud/android/ui/activity/Preferences.java @@ -1,6 +1,6 @@ /* ownCloud Android client application * Copyright (C) 2011 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,13 +21,17 @@ import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerCallback; import android.accounts.AccountManagerFuture; +import android.content.ComponentName; +import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; @@ -50,12 +54,19 @@ import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.authentication.AuthenticatorActivity; +import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.db.DbHandler; +import com.owncloud.android.files.FileOperationsHelper; +import com.owncloud.android.files.services.FileDownloader; +import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.services.OperationsService; import com.owncloud.android.ui.RadioButtonPreference; import com.owncloud.android.utils.DisplayUtils; +import java.io.File; + /** * An Activity that allows the user to change the application's settings. @@ -63,7 +74,8 @@ import com.owncloud.android.utils.DisplayUtils; * @author Bartek Przybylski * @author David A. Velasco */ -public class Preferences extends SherlockPreferenceActivity implements AccountManagerCallback { +public class Preferences extends SherlockPreferenceActivity + implements AccountManagerCallback, ComponentsGetter { private static final String TAG = "OwnCloudPreferences"; @@ -88,6 +100,9 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa private Preference mPrefInstantVideoUploadPathWiFi; private String mUploadVideoPath; + protected FileDownloader.FileDownloaderBinder mDownloaderBinder = null; + protected FileUploader.FileUploaderBinder mUploaderBinder = null; + private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null; @SuppressWarnings("deprecation") @Override @@ -199,13 +214,13 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa String username = currentAccount.name.substring(0, currentAccount.name.lastIndexOf('@')); String recommendSubject = String.format(getString(R.string.recommend_subject), appName); - String recommendText = String.format(getString(R.string.recommend_text), appName, downloadUrl, username); + String recommendText = String.format(getString(R.string.recommend_text), + appName, downloadUrl, username); intent.putExtra(Intent.EXTRA_SUBJECT, recommendSubject); intent.putExtra(Intent.EXTRA_TEXT, recommendText); startActivity(intent); - return(true); } @@ -337,6 +352,18 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa loadInstantUploadPath(); loadInstantUploadVideoPath(); + /* ComponentsGetter */ + mDownloadServiceConnection = newTransferenceServiceConnection(); + if (mDownloadServiceConnection != null) { + bindService(new Intent(this, FileDownloader.class), mDownloadServiceConnection, + Context.BIND_AUTO_CREATE); + } + mUploadServiceConnection = newTransferenceServiceConnection(); + if (mUploadServiceConnection != null) { + bindService(new Intent(this, FileUploader.class), mUploadServiceConnection, + Context.BIND_AUTO_CREATE); + } + } private void toggleInstantPictureOptions(Boolean value){ @@ -402,6 +429,7 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa // Remove account am.removeAccount(a, this, mHandler); + Log_OC.d(TAG, "Remove an account " + a.name); } } } @@ -412,6 +440,18 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa @Override public void run(AccountManagerFuture future) { if (future.isDone()) { + // after remove account + Account account = new Account(mAccountName, MainApp.getAccountType()); + if (!AccountUtils.exists(account, MainApp.getAppContext())) { + // Cancel tranfers + if (mUploaderBinder != null) { + mUploaderBinder.cancel(account); + } + if (mDownloaderBinder != null) { + mDownloaderBinder.cancel(account); + } + } + Account a = AccountUtils.getCurrentOwnCloudAccount(this); String accountName = ""; if (a == null) { @@ -494,6 +534,16 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa @Override protected void onDestroy() { mDbHandler.close(); + + if (mDownloadServiceConnection != null) { + unbindService(mDownloadServiceConnection); + mDownloadServiceConnection = null; + } + if (mUploadServiceConnection != null) { + unbindService(mUploadServiceConnection); + mUploadServiceConnection = null; + } + super.onDestroy(); } @@ -637,4 +687,65 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa editor.putString("instant_video_upload_path", mUploadVideoPath); editor.commit(); } + + // Methods for ComponetsGetter + @Override + public FileDownloader.FileDownloaderBinder getFileDownloaderBinder() { + return mDownloaderBinder; + } + + + @Override + public FileUploader.FileUploaderBinder getFileUploaderBinder() { + return mUploaderBinder; + } + + @Override + public OperationsService.OperationsServiceBinder getOperationsServiceBinder() { + return null; + } + + @Override + public FileDataStorageManager getStorageManager() { + return null; + } + + @Override + public FileOperationsHelper getFileOperationsHelper() { + return null; + } + + protected ServiceConnection newTransferenceServiceConnection() { + return new PreferencesServiceConnection(); + } + + /** Defines callbacks for service binding, passed to bindService() */ + private class PreferencesServiceConnection implements ServiceConnection { + + @Override + public void onServiceConnected(ComponentName component, IBinder service) { + + if (component.equals(new ComponentName(Preferences.this, FileDownloader.class))) { + mDownloaderBinder = (FileDownloader.FileDownloaderBinder) service; + + } else if (component.equals(new ComponentName(Preferences.this, FileUploader.class))) { + Log_OC.d(TAG, "Upload service connected"); + mUploaderBinder = (FileUploader.FileUploaderBinder) service; + } else { + return; + } + + } + + @Override + public void onServiceDisconnected(ComponentName component) { + if (component.equals(new ComponentName(Preferences.this, FileDownloader.class))) { + Log_OC.d(TAG, "Download service suddenly disconnected"); + mDownloaderBinder = null; + } else if (component.equals(new ComponentName(Preferences.this, FileUploader.class))) { + Log_OC.d(TAG, "Upload service suddenly disconnected"); + mUploaderBinder = null; + } + } + }; }