1 /* ownCloud Android client application
2 * Copyright (C) 2015 ownCloud Inc.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2,
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package com
.owncloud
.android
.services
;
20 import android
.accounts
.Account
;
21 import android
.accounts
.AccountsException
;
22 import android
.content
.Intent
;
23 import android
.os
.Handler
;
24 import android
.os
.Looper
;
25 import android
.os
.Message
;
26 import android
.util
.Pair
;
28 import com
.owncloud
.android
.datamodel
.FileDataStorageManager
;
29 import com
.owncloud
.android
.datamodel
.OCFile
;
30 import com
.owncloud
.android
.files
.services
.FileDownloader
;
31 import com
.owncloud
.android
.files
.services
.IndexedForest
;
32 import com
.owncloud
.android
.lib
.common
.OwnCloudAccount
;
33 import com
.owncloud
.android
.lib
.common
.OwnCloudClient
;
34 import com
.owncloud
.android
.lib
.common
.OwnCloudClientManagerFactory
;
35 import com
.owncloud
.android
.lib
.common
.operations
.RemoteOperationResult
;
36 import com
.owncloud
.android
.lib
.common
.utils
.Log_OC
;
37 import com
.owncloud
.android
.operations
.SynchronizeFolderOperation
;
38 import com
.owncloud
.android
.utils
.FileStorageUtils
;
40 import java
.io
.IOException
;
43 * SyncFolder worker. Performs the pending operations in the order they were requested.
45 * Created with the Looper of a new thread, started in
46 * {@link com.owncloud.android.services.OperationsService#onCreate()}.
48 class SyncFolderHandler
extends Handler
{
50 private static final String TAG
= SyncFolderHandler
.class.getSimpleName();
53 OperationsService mService
;
55 private IndexedForest
<SynchronizeFolderOperation
> mPendingOperations
=
56 new IndexedForest
<SynchronizeFolderOperation
>();
58 private OwnCloudClient mOwnCloudClient
= null
;
59 private Account mCurrentAccount
= null
;
60 private FileDataStorageManager mStorageManager
;
61 private SynchronizeFolderOperation mCurrentSyncOperation
;
64 public SyncFolderHandler(Looper looper
, OperationsService service
) {
66 if (service
== null
) {
67 throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");
74 * Returns True when the folder located in 'remotePath' in the ownCloud account 'account', or any of its
75 * descendants, is being synchronized (or waiting for it).
77 * @param account ownCloud account where the remote folder is stored.
78 * @param remotePath The path to a folder that could be in the queue of synchronizations.
80 public boolean isSynchronizing(Account account
, String remotePath
) {
81 if (account
== null
|| remotePath
== null
) return false
;
82 return (mPendingOperations
.contains(account
, remotePath
));
87 public void handleMessage(Message msg
) {
88 Pair
<Account
, String
> itemSyncKey
= (Pair
<Account
, String
>) msg
.obj
;
89 Log_OC
.v( "NOW " + TAG
+ ", thread " + Thread
.currentThread().getName(),
90 "Handling sync folder " + itemSyncKey
.second
);
91 doOperation(itemSyncKey
.first
, itemSyncKey
.second
);
92 mService
.stopSelf(msg
.arg1
);
97 * Performs the next operation in the queue
99 private void doOperation(Account account
, String remotePath
) {
101 Log_OC
.v( "NOW " + TAG
+ ", thread " + Thread
.currentThread().getName(),
102 "Getting sync folder " + remotePath
);
103 mCurrentSyncOperation
= mPendingOperations
.get(account
, remotePath
);
105 if (mCurrentSyncOperation
!= null
) {
106 RemoteOperationResult result
= null
;
109 if (mOwnCloudClient
== null
|| !account
.equals(mCurrentAccount
)) {
110 /// get client object to send the request to the ownCloud server, if cannot
111 mCurrentAccount
= account
;
112 mStorageManager
= new FileDataStorageManager(
114 mService
.getContentResolver()
116 OwnCloudAccount ocAccount
= new OwnCloudAccount(account
, mService
);
117 mOwnCloudClient
= OwnCloudClientManagerFactory
.getDefaultSingleton().
118 getClientFor(ocAccount
, mService
);
120 } // else, reuse client from previous operation
122 Log_OC
.v( "NOW " + TAG
+ ", thread " + Thread
.currentThread().getName(),
123 "Executing sync folder " + remotePath
);
124 result
= mCurrentSyncOperation
.execute(mOwnCloudClient
, mStorageManager
);
126 } catch (AccountsException e
) {
127 Log_OC
.e(TAG
, "Error while trying to get authorization", e
);
128 } catch (IOException e
) {
129 Log_OC
.e(TAG
, "Error while trying to get authorization", e
);
131 Log_OC
.v( "NOW " + TAG
+ ", thread " + Thread
.currentThread().getName(),
132 "Removing payload " + remotePath
);
134 mPendingOperations
.removePayload(account
, remotePath
);
136 mService
.dispatchResultToOperationListeners(null
, mCurrentSyncOperation
, result
);
138 sendBroadcastFinishedSyncFolder(account
, remotePath
, result
.isSuccess());
143 public void add(Account account
, String remotePath
, SynchronizeFolderOperation syncFolderOperation
){
144 mPendingOperations
.putIfAbsent(account
, remotePath
, syncFolderOperation
);
145 sendBroadcastNewSyncFolder(account
, remotePath
); // TODO upgrade!
150 * Cancels a pending or current sync' operation.
152 * @param account ownCloud account where the remote file is stored.
153 * @param file A file in the queue of pending synchronizations
155 public void cancel(Account account
, OCFile file
){
156 if (account
== null
|| file
== null
) {
157 Log_OC
.e(TAG
, "Cannot cancel with NULL parameters");
160 Log_OC
.v( "NOW " + TAG
+ ", thread " + Thread
.currentThread().getName(),
161 "Removing sync folder " + file
.getRemotePath());
162 Pair
<SynchronizeFolderOperation
, String
> removeResult
=
163 mPendingOperations
.remove(account
, file
.getRemotePath());
164 SynchronizeFolderOperation synchronization
= removeResult
.first
;
165 if (synchronization
!= null
) {
166 Log_OC
.v( "NOW " + TAG
+ ", thread " + Thread
.currentThread().getName(),
167 "Canceling returned sync of " + file
.getRemotePath());
168 synchronization
.cancel();
171 if (mCurrentSyncOperation
!= null
&& mCurrentAccount
!= null
&&
172 mCurrentSyncOperation
.getRemotePath().startsWith(file
.getRemotePath()) &&
173 account
.name
.equals(mCurrentAccount
.name
)) {
174 Log_OC
.v( "NOW " + TAG
+ ", thread " + Thread
.currentThread().getName(),
175 "Canceling current sync as descendant: " + mCurrentSyncOperation
.getRemotePath());
176 mCurrentSyncOperation
.cancel();
178 Log_OC
.v( "NOW " + TAG
+ ", thread " + Thread
.currentThread().getName(),
179 "Nothing else in cancelation of " + file
.getRemotePath());
183 //sendBroadcastFinishedSyncFolder(account, file.getRemotePath());
187 * TODO review this method when "folder synchronization" replaces "folder download"; this is a fast and ugly
190 private void sendBroadcastNewSyncFolder(Account account
, String remotePath
) {
191 Intent added
= new Intent(FileDownloader
.getDownloadAddedMessage());
192 added
.putExtra(FileDownloader
.ACCOUNT_NAME
, account
.name
);
193 added
.putExtra(FileDownloader
.EXTRA_REMOTE_PATH
, remotePath
);
194 added
.putExtra(FileDownloader
.EXTRA_FILE_PATH
, FileStorageUtils
.getSavePath(account
.name
) + remotePath
);
195 mService
.sendStickyBroadcast(added
);
199 * TODO review this method when "folder synchronization" replaces "folder download"; this is a fast and ugly
202 private void sendBroadcastFinishedSyncFolder(Account account
, String remotePath
, boolean success
) {
203 Intent finished
= new Intent(FileDownloader
.getDownloadFinishMessage());
204 finished
.putExtra(FileDownloader
.ACCOUNT_NAME
, account
.name
);
205 finished
.putExtra(FileDownloader
.EXTRA_REMOTE_PATH
, remotePath
);
206 finished
.putExtra(FileDownloader
.EXTRA_FILE_PATH
, FileStorageUtils
.getSavePath(account
.name
) + remotePath
);
207 finished
.putExtra(FileDownloader
.EXTRA_DOWNLOAD_RESULT
, success
);
208 mService
.sendStickyBroadcast(finished
);