319a15873ac0e42e0ea9428c5c39a83fff27def9
[pub/Android/ownCloud.git] / src / com / owncloud / android / services / SyncFolderHandler.java
1 /* ownCloud Android client application
2 * Copyright (C) 2015 ownCloud Inc.
3 *
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.
7 *
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.
12 *
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/>.
15 *
16 */
17
18 package com.owncloud.android.services;
19
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;
27
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;
39
40 import java.io.IOException;
41
42 /**
43 * SyncFolder worker. Performs the pending operations in the order they were requested.
44 *
45 * Created with the Looper of a new thread, started in
46 * {@link com.owncloud.android.services.OperationsService#onCreate()}.
47 */
48 class SyncFolderHandler extends Handler {
49
50 private static final String TAG = SyncFolderHandler.class.getSimpleName();
51
52
53 OperationsService mService;
54
55 private IndexedForest<SynchronizeFolderOperation> mPendingOperations =
56 new IndexedForest<SynchronizeFolderOperation>();
57
58 private OwnCloudClient mOwnCloudClient = null;
59 private Account mCurrentAccount = null;
60 private FileDataStorageManager mStorageManager;
61 private SynchronizeFolderOperation mCurrentSyncOperation;
62
63
64 public SyncFolderHandler(Looper looper, OperationsService service) {
65 super(looper);
66 if (service == null) {
67 throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");
68 }
69 mService = service;
70 }
71
72
73 /**
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).
76 *
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.
79 */
80 public boolean isSynchronizing(Account account, String remotePath) {
81 if (account == null || remotePath == null) return false;
82 return (mPendingOperations.contains(account, remotePath));
83 }
84
85
86 @Override
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);
93 }
94
95
96 /**
97 * Performs the next operation in the queue
98 */
99 private void doOperation(Account account, String remotePath) {
100
101 Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
102 "Getting sync folder " + remotePath);
103 mCurrentSyncOperation = mPendingOperations.get(account, remotePath);
104
105 if (mCurrentSyncOperation != null) {
106 RemoteOperationResult result = null;
107
108 try {
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(
113 account,
114 mService.getContentResolver()
115 );
116 OwnCloudAccount ocAccount = new OwnCloudAccount(account, mService);
117 mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
118 getClientFor(ocAccount, mService);
119
120 } // else, reuse client from previous operation
121
122 Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
123 "Executing sync folder " + remotePath);
124 result = mCurrentSyncOperation.execute(mOwnCloudClient, mStorageManager);
125
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);
130 } finally {
131 Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
132 "Removing payload " + remotePath);
133
134 mPendingOperations.removePayload(account, remotePath);
135
136 mService.dispatchResultToOperationListeners(null, mCurrentSyncOperation, result);
137
138 sendBroadcastFinishedSyncFolder(account, remotePath, result.isSuccess());
139 }
140 }
141 }
142
143 public void add(Account account, String remotePath, SynchronizeFolderOperation syncFolderOperation){
144 mPendingOperations.putIfAbsent(account, remotePath, syncFolderOperation);
145 sendBroadcastNewSyncFolder(account, remotePath); // TODO upgrade!
146 }
147
148
149 /**
150 * Cancels a pending or current sync' operation.
151 *
152 * @param account ownCloud account where the remote file is stored.
153 * @param file A file in the queue of pending synchronizations
154 */
155 public void cancel(Account account, OCFile file){
156 if (account == null || file == null) {
157 Log_OC.e(TAG, "Cannot cancel with NULL parameters");
158 return;
159 }
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();
169 } else {
170 // TODO synchronize?
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();
177 } else {
178 Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
179 "Nothing else in cancelation of " + file.getRemotePath());
180 }
181 }
182
183 //sendBroadcastFinishedSyncFolder(account, file.getRemotePath());
184 }
185
186 /**
187 * TODO review this method when "folder synchronization" replaces "folder download"; this is a fast and ugly
188 * patch.
189 */
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);
196 }
197
198 /**
199 * TODO review this method when "folder synchronization" replaces "folder download"; this is a fast and ugly
200 * patch.
201 */
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);
209 }
210
211
212 }