SyncFolderHandler.java 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /**
  2. * ownCloud Android client application
  3. *
  4. * Copyright (C) 2016 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. 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;
  27. import com.owncloud.android.datamodel.FileDataStorageManager;
  28. import com.owncloud.android.datamodel.OCFile;
  29. import com.owncloud.android.files.services.FileDownloader;
  30. import com.owncloud.android.files.services.IndexedForest;
  31. import com.owncloud.android.lib.common.OwnCloudAccount;
  32. import com.owncloud.android.lib.common.OwnCloudClient;
  33. import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
  34. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  35. import com.owncloud.android.lib.common.utils.Log_OC;
  36. import com.owncloud.android.operations.SynchronizeFolderOperation;
  37. import com.owncloud.android.utils.FileStorageUtils;
  38. import java.io.IOException;
  39. /**
  40. * SyncFolder worker. Performs the pending operations in the order they were requested.
  41. *
  42. * Created with the Looper of a new thread, started in
  43. * {@link com.owncloud.android.services.OperationsService#onCreate()}.
  44. */
  45. class SyncFolderHandler extends Handler {
  46. private static final String TAG = SyncFolderHandler.class.getSimpleName();
  47. private OperationsService mService;
  48. private IndexedForest<SynchronizeFolderOperation> mPendingOperations = new IndexedForest<>();
  49. private OwnCloudClient mOwnCloudClient = null;
  50. private Account mCurrentAccount = null;
  51. private FileDataStorageManager mStorageManager;
  52. private SynchronizeFolderOperation mCurrentSyncOperation;
  53. public SyncFolderHandler(Looper looper, OperationsService service) {
  54. super(looper);
  55. if (service == null) {
  56. throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");
  57. }
  58. mService = service;
  59. }
  60. /**
  61. * Returns True when the folder located in 'remotePath' in the ownCloud account 'account', or any of its
  62. * descendants, is being synchronized (or waiting for it).
  63. *
  64. * @param account ownCloud account where the remote folder is stored.
  65. * @param remotePath The path to a folder that could be in the queue of synchronizations.
  66. */
  67. private boolean isSynchronizing(Account account, String remotePath) {
  68. if (account == null || remotePath == null) {
  69. return false;
  70. }
  71. return (mPendingOperations.contains(account.name, remotePath));
  72. }
  73. @Override
  74. public void handleMessage(Message msg) {
  75. Pair<Account, String> itemSyncKey = (Pair<Account, String>) msg.obj;
  76. doOperation(itemSyncKey.first, itemSyncKey.second);
  77. Log_OC.d(TAG, "Stopping after command with id " + msg.arg1);
  78. mService.stopSelf(msg.arg1);
  79. }
  80. /**
  81. * Performs the next operation in the queue
  82. */
  83. private void doOperation(Account account, String remotePath) {
  84. mCurrentSyncOperation = mPendingOperations.get(account.name, remotePath);
  85. if (mCurrentSyncOperation != null) {
  86. RemoteOperationResult result = null;
  87. try {
  88. if (mCurrentAccount == null || !mCurrentAccount.equals(account)) {
  89. mCurrentAccount = account;
  90. mStorageManager = new FileDataStorageManager(
  91. account,
  92. mService.getContentResolver()
  93. );
  94. } // else, reuse storage manager from previous operation
  95. // always get client from client manager, to get fresh credentials in case of update
  96. OwnCloudAccount ocAccount = new OwnCloudAccount(account, mService);
  97. mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
  98. getClientFor(ocAccount, mService);
  99. result = mCurrentSyncOperation.execute(mOwnCloudClient, mStorageManager);
  100. } catch (AccountsException | IOException e) {
  101. Log_OC.e(TAG, "Error while trying to get authorization", e);
  102. } finally {
  103. mPendingOperations.removePayload(account.name, remotePath);
  104. mService.dispatchResultToOperationListeners(mCurrentSyncOperation, result);
  105. sendBroadcastFinishedSyncFolder(account, remotePath, result.isSuccess());
  106. }
  107. }
  108. }
  109. public void add(Account account, String remotePath,
  110. SynchronizeFolderOperation syncFolderOperation){
  111. Pair<String, String> putResult =
  112. mPendingOperations.putIfAbsent(account.name, remotePath, syncFolderOperation);
  113. if (putResult != null) {
  114. sendBroadcastNewSyncFolder(account, remotePath); // TODO upgrade!
  115. }
  116. }
  117. /**
  118. * Cancels a pending or current sync' operation.
  119. *
  120. * @param account ownCloud {@link Account} where the remote file is stored.
  121. * @param file A file in the queue of pending synchronizations
  122. */
  123. public void cancel(Account account, OCFile file){
  124. if (account == null || file == null) {
  125. Log_OC.e(TAG, "Cannot cancel with NULL parameters");
  126. return;
  127. }
  128. Pair<SynchronizeFolderOperation, String> removeResult =
  129. mPendingOperations.remove(account.name, file.getRemotePath());
  130. SynchronizeFolderOperation synchronization = removeResult.first;
  131. if (synchronization != null) {
  132. synchronization.cancel();
  133. } else {
  134. // TODO synchronize?
  135. if (mCurrentSyncOperation != null && mCurrentAccount != null &&
  136. mCurrentSyncOperation.getRemotePath().startsWith(file.getRemotePath()) &&
  137. account.name.equals(mCurrentAccount.name)) {
  138. mCurrentSyncOperation.cancel();
  139. }
  140. }
  141. //sendBroadcastFinishedSyncFolder(account, file.getRemotePath());
  142. }
  143. /**
  144. * TODO review this method when "folder synchronization" replaces "folder download";
  145. * this is a fast and ugly patch.
  146. */
  147. private void sendBroadcastNewSyncFolder(Account account, String remotePath) {
  148. Intent added = new Intent(FileDownloader.getDownloadAddedMessage());
  149. added.putExtra(FileDownloader.ACCOUNT_NAME, account.name);
  150. added.putExtra(FileDownloader.EXTRA_REMOTE_PATH, remotePath);
  151. added.putExtra(FileDownloader.EXTRA_FILE_PATH, FileStorageUtils.getSavePath(account.name)
  152. + remotePath);
  153. mService.sendStickyBroadcast(added);
  154. }
  155. /**
  156. * TODO review this method when "folder synchronization" replaces "folder download";
  157. * this is a fast and ugly patch.
  158. */
  159. private void sendBroadcastFinishedSyncFolder(Account account, String remotePath,
  160. boolean success) {
  161. Intent finished = new Intent(FileDownloader.getDownloadFinishMessage());
  162. finished.putExtra(FileDownloader.ACCOUNT_NAME, account.name);
  163. finished.putExtra(FileDownloader.EXTRA_REMOTE_PATH, remotePath);
  164. finished.putExtra(FileDownloader.EXTRA_FILE_PATH,
  165. FileStorageUtils.getSavePath(account.name) + remotePath);
  166. finished.putExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, success);
  167. mService.sendStickyBroadcast(finished);
  168. }
  169. }