ConflictsResolveActivity.java 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /**
  2. * ownCloud Android client application
  3. *
  4. * @author Bartek Przybylski
  5. * @author David A. Velasco Copyright (C) 2012 Bartek Przybylski Copyright (C) 2016 ownCloud Inc.
  6. * <p>
  7. * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
  8. * License version 2, as published by the Free Software Foundation.
  9. * <p>
  10. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  11. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  12. * details.
  13. * <p/>
  14. * You should have received a copy of the GNU General Public License along with this program. If not, see
  15. * <http://www.gnu.org/licenses/>.
  16. */
  17. package com.owncloud.android.ui.activity;
  18. import android.content.Intent;
  19. import android.os.Bundle;
  20. import android.widget.Toast;
  21. import com.nextcloud.client.account.User;
  22. import com.nextcloud.java.util.Optional;
  23. import com.owncloud.android.R;
  24. import com.owncloud.android.datamodel.OCFile;
  25. import com.owncloud.android.datamodel.UploadsStorageManager;
  26. import com.owncloud.android.db.OCUpload;
  27. import com.owncloud.android.files.services.FileDownloader;
  28. import com.owncloud.android.files.services.FileUploader;
  29. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  30. import com.owncloud.android.lib.common.utils.Log_OC;
  31. import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation;
  32. import com.owncloud.android.lib.resources.files.model.RemoteFile;
  33. import com.owncloud.android.ui.dialog.ConflictsResolveDialog;
  34. import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision;
  35. import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener;
  36. import com.owncloud.android.utils.FileStorageUtils;
  37. import javax.inject.Inject;
  38. import androidx.annotation.NonNull;
  39. import androidx.fragment.app.Fragment;
  40. import androidx.fragment.app.FragmentTransaction;
  41. /**
  42. * Wrapper activity which will be launched if keep-in-sync file will be modified by external
  43. * application.
  44. */
  45. public class ConflictsResolveActivity extends FileActivity implements OnConflictDecisionMadeListener {
  46. /**
  47. * A nullable upload entry that must be removed when and if the conflict is resolved.
  48. */
  49. public static final String EXTRA_CONFLICT_UPLOAD = "CONFLICT_UPLOAD";
  50. /**
  51. * Specify the upload local behaviour when there is no CONFLICT_UPLOAD.
  52. */
  53. public static final String EXTRA_LOCAL_BEHAVIOUR = "LOCAL_BEHAVIOUR";
  54. public static final String EXTRA_EXISTING_FILE = "EXISTING_FILE";
  55. private static final String TAG = ConflictsResolveActivity.class.getSimpleName();
  56. @Inject UploadsStorageManager uploadsStorageManager;
  57. private OCUpload conflictUpload;
  58. private OCFile existingFile;
  59. private OCFile newFile;
  60. private int localBehaviour = FileUploader.LOCAL_BEHAVIOUR_FORGET;
  61. protected OnConflictDecisionMadeListener listener;
  62. @Override
  63. protected void onCreate(Bundle savedInstanceState) {
  64. super.onCreate(savedInstanceState);
  65. if (savedInstanceState != null) {
  66. conflictUpload = savedInstanceState.getParcelable(EXTRA_CONFLICT_UPLOAD);
  67. existingFile = savedInstanceState.getParcelable(EXTRA_EXISTING_FILE);
  68. localBehaviour = savedInstanceState.getInt(EXTRA_LOCAL_BEHAVIOUR);
  69. } else {
  70. conflictUpload = getIntent().getParcelableExtra(EXTRA_CONFLICT_UPLOAD);
  71. existingFile = getIntent().getParcelableExtra(EXTRA_EXISTING_FILE);
  72. localBehaviour = getIntent().getIntExtra(EXTRA_LOCAL_BEHAVIOUR, localBehaviour);
  73. }
  74. if (conflictUpload != null) {
  75. localBehaviour = conflictUpload.getLocalAction();
  76. }
  77. // new file was modified locally in file system
  78. newFile = getFile();
  79. listener = new OnConflictDecisionMadeListener() {
  80. @Override
  81. public void conflictDecisionMade(Decision decision) {
  82. OCFile file = newFile; // local file got changed, so either upload it or replace it again by server
  83. // version
  84. switch (decision) {
  85. case CANCEL:
  86. // nothing to do
  87. break;
  88. case KEEP_LOCAL: // Upload
  89. FileUploader.uploadUpdateFile(
  90. getBaseContext(),
  91. getAccount(),
  92. file,
  93. localBehaviour,
  94. FileUploader.NameCollisionPolicy.OVERWRITE
  95. );
  96. if (conflictUpload != null) {
  97. uploadsStorageManager.removeUpload(conflictUpload);
  98. }
  99. break;
  100. case KEEP_BOTH: // Upload
  101. FileUploader.uploadUpdateFile(
  102. getBaseContext(),
  103. getAccount(),
  104. file,
  105. localBehaviour,
  106. FileUploader.NameCollisionPolicy.RENAME
  107. );
  108. if (conflictUpload != null) {
  109. uploadsStorageManager.removeUpload(conflictUpload);
  110. }
  111. break;
  112. case KEEP_SERVER: // Download
  113. if (!shouldDeleteLocal()) {
  114. // Overwrite local file
  115. Intent intent = new Intent(getBaseContext(), FileDownloader.class);
  116. intent.putExtra(FileDownloader.EXTRA_ACCOUNT, getAccount());
  117. intent.putExtra(FileDownloader.EXTRA_FILE, file);
  118. if (conflictUpload != null) {
  119. intent.putExtra(FileDownloader.EXTRA_CONFLICT_UPLOAD, conflictUpload);
  120. }
  121. startService(intent);
  122. }
  123. break;
  124. }
  125. finish();
  126. }
  127. };
  128. }
  129. @Override
  130. protected void onSaveInstanceState(@NonNull Bundle outState) {
  131. super.onSaveInstanceState(outState);
  132. outState.putParcelable(EXTRA_CONFLICT_UPLOAD, conflictUpload);
  133. outState.putParcelable(EXTRA_EXISTING_FILE, existingFile);
  134. outState.putInt(EXTRA_LOCAL_BEHAVIOUR, localBehaviour);
  135. }
  136. @Override
  137. public void conflictDecisionMade(Decision decision) {
  138. listener.conflictDecisionMade(decision);
  139. }
  140. @Override
  141. protected void onStart() {
  142. super.onStart();
  143. if (getAccount() == null) {
  144. finish();
  145. }
  146. if (newFile == null) {
  147. Log_OC.e(TAG, "No file received");
  148. finish();
  149. }
  150. if (existingFile == null) {
  151. // fetch info of existing file from server
  152. ReadFileRemoteOperation operation = new ReadFileRemoteOperation(newFile.getRemotePath());
  153. new Thread(() -> {
  154. try {
  155. RemoteOperationResult result = operation.execute(getAccount(), this);
  156. if (result.isSuccess()) {
  157. existingFile = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0));
  158. existingFile.setLastSyncDateForProperties(System.currentTimeMillis());
  159. startDialog();
  160. } else {
  161. showErrorAndFinish();
  162. }
  163. } catch (Exception e) {
  164. showErrorAndFinish();
  165. }
  166. }).start();
  167. } else {
  168. startDialog();
  169. }
  170. }
  171. private void startDialog() {
  172. Optional<User> userOptional = getUser();
  173. if (!userOptional.isPresent()) {
  174. showErrorAndFinish();
  175. }
  176. // Check whether the file is contained in the current Account
  177. Fragment prev = getSupportFragmentManager().findFragmentByTag("conflictDialog");
  178. FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
  179. if (prev != null) {
  180. fragmentTransaction.remove(prev);
  181. }
  182. if (existingFile != null && getStorageManager().fileExists(newFile.getRemotePath())) {
  183. ConflictsResolveDialog dialog = ConflictsResolveDialog.newInstance(existingFile,
  184. newFile,
  185. userOptional.get());
  186. dialog.show(fragmentTransaction, "conflictDialog");
  187. } else {
  188. // Account was changed to a different one - just finish
  189. showErrorAndFinish();
  190. }
  191. }
  192. private void showErrorAndFinish() {
  193. Toast.makeText(this, R.string.conflict_dialog_error, Toast.LENGTH_LONG).show();
  194. finish();
  195. }
  196. /**
  197. * @return whether the local version of the files is to be deleted.
  198. */
  199. private boolean shouldDeleteLocal() {
  200. return localBehaviour == FileUploader.LOCAL_BEHAVIOUR_DELETE;
  201. }
  202. }