Merge pull request #1048 from owncloud/shareWithYou_icon_in_fileList
[pub/Android/ownCloud.git] / src / com / owncloud / android / services / SyncFolderHandler.java
1 /**
2 * ownCloud Android client application
3 *
4 * Copyright (C) 2015 ownCloud Inc.
5 *
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.
9 *
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.
14 *
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/>.
17 *
18 */
19
20 package com.owncloud.android.services;
21
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;
29
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;
42
43 import java.io.IOException;
44
45 /**
46 * SyncFolder worker. Performs the pending operations in the order they were requested.
47 *
48 * Created with the Looper of a new thread, started in
49 * {@link com.owncloud.android.services.OperationsService#onCreate()}.
50 */
51 class SyncFolderHandler extends Handler {
52
53 private static final String TAG = SyncFolderHandler.class.getSimpleName();
54
55
56 OperationsService mService;
57
58 private IndexedForest<SynchronizeFolderOperation> mPendingOperations =
59 new IndexedForest<SynchronizeFolderOperation>();
60
61 private OwnCloudClient mOwnCloudClient = null;
62 private Account mCurrentAccount = null;
63 private FileDataStorageManager mStorageManager;
64 private SynchronizeFolderOperation mCurrentSyncOperation;
65
66
67 public SyncFolderHandler(Looper looper, OperationsService service) {
68 super(looper);
69 if (service == null) {
70 throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");
71 }
72 mService = service;
73 }
74
75
76 /**
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).
79 *
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.
82 */
83 public boolean isSynchronizing(Account account, String remotePath) {
84 if (account == null || remotePath == null) return false;
85 return (mPendingOperations.contains(account, remotePath));
86 }
87
88
89 @Override
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);
95 }
96
97
98 /**
99 * Performs the next operation in the queue
100 */
101 private void doOperation(Account account, String remotePath) {
102
103 mCurrentSyncOperation = mPendingOperations.get(account, remotePath);
104
105 if (mCurrentSyncOperation != null) {
106 RemoteOperationResult result = null;
107
108 try {
109
110 if (mCurrentAccount == null || !mCurrentAccount.equals(account)) {
111 mCurrentAccount = account;
112 mStorageManager = new FileDataStorageManager(
113 account,
114 mService.getContentResolver()
115 );
116 } // else, reuse storage manager from previous operation
117
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);
122
123 result = mCurrentSyncOperation.execute(mOwnCloudClient, mStorageManager);
124
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);
129 } finally {
130 mPendingOperations.removePayload(account, remotePath);
131
132 mService.dispatchResultToOperationListeners(mCurrentSyncOperation, result);
133
134 sendBroadcastFinishedSyncFolder(account, remotePath, result.isSuccess());
135 }
136 }
137 }
138
139 public void add(Account account, String remotePath,
140 SynchronizeFolderOperation syncFolderOperation){
141 mPendingOperations.putIfAbsent(account, remotePath, syncFolderOperation);
142 sendBroadcastNewSyncFolder(account, remotePath); // TODO upgrade!
143 }
144
145
146 /**
147 * Cancels a pending or current sync' operation.
148 *
149 * @param account ownCloud account where the remote file is stored.
150 * @param file A file in the queue of pending synchronizations
151 */
152 public void cancel(Account account, OCFile file){
153 if (account == null || file == null) {
154 Log_OC.e(TAG, "Cannot cancel with NULL parameters");
155 return;
156 }
157 Pair<SynchronizeFolderOperation, String> removeResult =
158 mPendingOperations.remove(account, file.getRemotePath());
159 SynchronizeFolderOperation synchronization = removeResult.first;
160 if (synchronization != null) {
161 synchronization.cancel();
162 } else {
163 // TODO synchronize?
164 if (mCurrentSyncOperation != null && mCurrentAccount != null &&
165 mCurrentSyncOperation.getRemotePath().startsWith(file.getRemotePath()) &&
166 account.name.equals(mCurrentAccount.name)) {
167 mCurrentSyncOperation.cancel();
168 }
169 }
170
171 //sendBroadcastFinishedSyncFolder(account, file.getRemotePath());
172 }
173
174 /**
175 * TODO review this method when "folder synchronization" replaces "folder download";
176 * this is a fast and ugly patch.
177 */
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)
183 + remotePath);
184 mService.sendStickyBroadcast(added);
185 }
186
187 /**
188 * TODO review this method when "folder synchronization" replaces "folder download";
189 * this is a fast and ugly patch.
190 */
191 private void sendBroadcastFinishedSyncFolder(Account account, String remotePath,
192 boolean success) {
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);
200 }
201
202
203 }