2  *   ownCloud Android client application 
   4  *   Copyright (C) 2015 ownCloud Inc. 
   6  *   This program is free software: you can redistribute it and/or modify 
   7  *   it under the terms of the GNU General Public License version 2, 
   8  *   as published by the Free Software Foundation. 
  10  *   This program is distributed in the hope that it will be useful, 
  11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
  12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  13  *   GNU General Public License for more details. 
  15  *   You should have received a copy of the GNU General Public License 
  16  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  20 package com
.owncloud
.android
.services
; 
  22 import android
.accounts
.Account
; 
  23 import android
.accounts
.AccountsException
; 
  24 import android
.content
.Intent
; 
  25 import android
.os
.Handler
; 
  26 import android
.os
.Looper
; 
  27 import android
.os
.Message
; 
  28 import android
.util
.Pair
; 
  30 import com
.owncloud
.android
.MainApp
; 
  31 import com
.owncloud
.android
.datamodel
.FileDataStorageManager
; 
  32 import com
.owncloud
.android
.datamodel
.OCFile
; 
  33 import com
.owncloud
.android
.files
.services
.FileDownloader
; 
  34 import com
.owncloud
.android
.files
.services
.IndexedForest
; 
  35 import com
.owncloud
.android
.lib
.common
.OwnCloudAccount
; 
  36 import com
.owncloud
.android
.lib
.common
.OwnCloudClient
; 
  37 import com
.owncloud
.android
.lib
.common
.OwnCloudClientManagerFactory
; 
  38 import com
.owncloud
.android
.lib
.common
.operations
.RemoteOperationResult
; 
  39 import com
.owncloud
.android
.lib
.common
.utils
.Log_OC
; 
  40 import com
.owncloud
.android
.operations
.SynchronizeFolderOperation
; 
  41 import com
.owncloud
.android
.utils
.FileStorageUtils
; 
  43 import java
.io
.IOException
; 
  46  * SyncFolder worker. Performs the pending operations in the order they were requested. 
  48  * Created with the Looper of a new thread, started in 
  49  * {@link com.owncloud.android.services.OperationsService#onCreate()}. 
  51 class SyncFolderHandler 
extends Handler 
{ 
  53     private static final String TAG 
= SyncFolderHandler
.class.getSimpleName(); 
  56     OperationsService mService
; 
  58     private IndexedForest
<SynchronizeFolderOperation
> mPendingOperations 
= 
  59             new IndexedForest
<SynchronizeFolderOperation
>(); 
  61     private OwnCloudClient mOwnCloudClient 
= null
; 
  62     private Account mCurrentAccount 
= null
; 
  63     private FileDataStorageManager mStorageManager
; 
  64     private SynchronizeFolderOperation mCurrentSyncOperation
; 
  67     public SyncFolderHandler(Looper looper
, OperationsService service
) { 
  69         if (service 
== null
) { 
  70             throw new IllegalArgumentException("Received invalid NULL in parameter 'service'"); 
  77      * Returns True when the folder located in 'remotePath' in the ownCloud account 'account', or any of its 
  78      * descendants, is being synchronized (or waiting for it). 
  80      * @param account       ownCloud account where the remote folder is stored. 
  81      * @param remotePath    The path to a folder that could be in the queue of synchronizations. 
  83     public boolean isSynchronizing(Account account
, String remotePath
) { 
  84         if (account 
== null 
|| remotePath 
== null
) return false
; 
  85         return (mPendingOperations
.contains(account
, remotePath
)); 
  90     public void handleMessage(Message msg
) { 
  91         Pair
<Account
, String
> itemSyncKey 
= (Pair
<Account
, String
>) msg
.obj
; 
  92         doOperation(itemSyncKey
.first
, itemSyncKey
.second
); 
  93         Log_OC
.d(TAG
, "Stopping after command with id " + msg
.arg1
); 
  94         mService
.stopSelf(msg
.arg1
); 
  99      * Performs the next operation in the queue 
 101     private void doOperation(Account account
, String remotePath
) { 
 103         mCurrentSyncOperation 
= mPendingOperations
.get(account
, remotePath
); 
 105         if (mCurrentSyncOperation 
!= null
) { 
 106             RemoteOperationResult result 
= null
; 
 110                 if (mCurrentAccount 
== null 
|| !mCurrentAccount
.equals(account
)) { 
 111                     mCurrentAccount 
= account
; 
 112                     mStorageManager 
= new FileDataStorageManager( 
 114                             mService
.getContentResolver() 
 116                 }   // else, reuse storage manager from previous operation 
 118                 // always get client from client manager, to get fresh credentials in case of update 
 119                 OwnCloudAccount ocAccount 
= new OwnCloudAccount(account
, mService
); 
 120                 mOwnCloudClient 
= OwnCloudClientManagerFactory
.getDefaultSingleton(). 
 121                         getClientFor(ocAccount
, mService
, MainApp
.getUserAgent()); 
 123                 result 
= mCurrentSyncOperation
.execute(mOwnCloudClient
, mStorageManager
); 
 125             } catch (AccountsException e
) { 
 126                 Log_OC
.e(TAG
, "Error while trying to get authorization", e
); 
 127             } catch (IOException e
) { 
 128                 Log_OC
.e(TAG
, "Error while trying to get authorization", e
); 
 130                 mPendingOperations
.removePayload(account
, remotePath
); 
 132                 mService
.dispatchResultToOperationListeners(mCurrentSyncOperation
, result
); 
 134                 sendBroadcastFinishedSyncFolder(account
, remotePath
, result
.isSuccess()); 
 139     public void add(Account account
, String remotePath
, 
 140                     SynchronizeFolderOperation syncFolderOperation
){ 
 141         mPendingOperations
.putIfAbsent(account
, remotePath
, syncFolderOperation
); 
 142         sendBroadcastNewSyncFolder(account
, remotePath
);    // TODO upgrade! 
 147      * Cancels a pending or current sync' operation. 
 149      * @param account       ownCloud account where the remote file is stored. 
 150      * @param file          A file in the queue of pending synchronizations 
 152     public void cancel(Account account
, OCFile file
){ 
 153         if (account 
== null 
|| file 
== null
) { 
 154             Log_OC
.e(TAG
, "Cannot cancel with NULL parameters"); 
 157         Pair
<SynchronizeFolderOperation
, String
> removeResult 
= 
 158                 mPendingOperations
.remove(account
, file
.getRemotePath()); 
 159         SynchronizeFolderOperation synchronization 
= removeResult
.first
; 
 160         if (synchronization 
!= null
) { 
 161             synchronization
.cancel(); 
 164             if (mCurrentSyncOperation 
!= null 
&& mCurrentAccount 
!= null 
&& 
 165                     mCurrentSyncOperation
.getRemotePath().startsWith(file
.getRemotePath()) && 
 166                     account
.name
.equals(mCurrentAccount
.name
)) { 
 167                 mCurrentSyncOperation
.cancel(); 
 171         //sendBroadcastFinishedSyncFolder(account, file.getRemotePath()); 
 175      * TODO review this method when "folder synchronization" replaces "folder download"; 
 176      * this is a fast and ugly patch. 
 178     private void sendBroadcastNewSyncFolder(Account account
, String remotePath
) { 
 179         Intent added 
= new Intent(FileDownloader
.getDownloadAddedMessage()); 
 180         added
.putExtra(FileDownloader
.ACCOUNT_NAME
, account
.name
); 
 181         added
.putExtra(FileDownloader
.EXTRA_REMOTE_PATH
, remotePath
); 
 182         added
.putExtra(FileDownloader
.EXTRA_FILE_PATH
, FileStorageUtils
.getSavePath(account
.name
) 
 184         mService
.sendStickyBroadcast(added
); 
 188      * TODO review this method when "folder synchronization" replaces "folder download"; 
 189      * this is a fast and ugly patch. 
 191     private void sendBroadcastFinishedSyncFolder(Account account
, String remotePath
, 
 193         Intent finished 
= new Intent(FileDownloader
.getDownloadFinishMessage()); 
 194         finished
.putExtra(FileDownloader
.ACCOUNT_NAME
, account
.name
); 
 195         finished
.putExtra(FileDownloader
.EXTRA_REMOTE_PATH
, remotePath
); 
 196         finished
.putExtra(FileDownloader
.EXTRA_FILE_PATH
, 
 197                 FileStorageUtils
.getSavePath(account
.name
) + remotePath
); 
 198         finished
.putExtra(FileDownloader
.EXTRA_DOWNLOAD_RESULT
, success
); 
 199         mService
.sendStickyBroadcast(finished
);