Fix Select Local Version or Keep Both behaviour when solving file coflict
[pub/Android/ownCloud.git] / src / com / owncloud / android / files / FileOperationsHelper.java
1 /**
2 * ownCloud Android client application
3 *
4 * @author masensio
5 * @author David A. Velasco
6 * Copyright (C) 2015 ownCloud Inc.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2,
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 package com.owncloud.android.files;
23
24 import android.accounts.Account;
25 import android.content.ActivityNotFoundException;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.pm.PackageManager;
29 import android.content.pm.ResolveInfo;
30 import android.net.Uri;
31 import android.support.v4.app.DialogFragment;
32 import android.webkit.MimeTypeMap;
33 import android.widget.Toast;
34
35 import com.owncloud.android.R;
36 import com.owncloud.android.authentication.AccountUtils;
37 import com.owncloud.android.datamodel.OCFile;
38 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
39 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
40 import com.owncloud.android.lib.common.network.WebdavUtils;
41 import com.owncloud.android.lib.common.utils.Log_OC;
42 import com.owncloud.android.lib.resources.status.OwnCloudVersion;
43 import com.owncloud.android.services.OperationsService;
44 import com.owncloud.android.services.observer.FileObserverService;
45 import com.owncloud.android.ui.activity.FileActivity;
46 import com.owncloud.android.ui.dialog.ShareLinkToDialog;
47
48 import org.apache.http.protocol.HTTP;
49
50 import java.util.List;
51
52 /**
53 *
54 */
55 public class FileOperationsHelper {
56
57 private static final String TAG = FileOperationsHelper.class.getName();
58
59 private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG";
60
61 protected FileActivity mFileActivity = null;
62
63 /// Identifier of operation in progress which result shouldn't be lost
64 private long mWaitingForOpId = Long.MAX_VALUE;
65
66 public FileOperationsHelper(FileActivity fileActivity) {
67 mFileActivity = fileActivity;
68 }
69
70
71 public void openFile(OCFile file) {
72 if (file != null) {
73 String storagePath = file.getStoragePath();
74 String encodedStoragePath = WebdavUtils.encodePath(storagePath);
75
76 Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW);
77 intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
78 intentForSavedMimeType.setFlags(
79 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
80 );
81
82 Intent intentForGuessedMimeType = null;
83 if (storagePath.lastIndexOf('.') >= 0) {
84 String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
85 storagePath.substring(storagePath.lastIndexOf('.') + 1)
86 );
87 if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
88 intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
89 intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType);
90 intentForGuessedMimeType.setFlags(
91 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
92 );
93 }
94 }
95
96 Intent openFileWithIntent;
97 if (intentForGuessedMimeType != null) {
98 openFileWithIntent = intentForGuessedMimeType;
99 } else {
100 openFileWithIntent = intentForSavedMimeType;
101 }
102
103 List<ResolveInfo> launchables = mFileActivity.getPackageManager().
104 queryIntentActivities(openFileWithIntent, PackageManager.GET_INTENT_FILTERS);
105
106 if(launchables != null && launchables.size() > 0) {
107 try {
108 mFileActivity.startActivity(
109 Intent.createChooser(
110 openFileWithIntent, mFileActivity.getString(R.string.actionbar_open_with)
111 )
112 );
113 } catch (ActivityNotFoundException anfe) {
114 showNoAppForFileTypeToast(mFileActivity.getApplicationContext());
115 }
116 } else {
117 showNoAppForFileTypeToast(mFileActivity.getApplicationContext());
118 }
119
120 } else {
121 Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
122 }
123 }
124
125 /**
126 * Displays a toast stating that no application could be found to open the file.
127 *
128 * @param context the context to be able to show a toast.
129 */
130 private void showNoAppForFileTypeToast(Context context) {
131 Toast.makeText(context,
132 R.string.file_list_no_app_for_file_type, Toast.LENGTH_SHORT)
133 .show();
134 }
135
136 public void shareFileWithLink(OCFile file) {
137
138 if (isSharedSupported()) {
139 if (file != null) {
140 String link = "https://fake.url";
141 Intent intent = createShareWithLinkIntent(link);
142 String[] packagesToExclude = new String[]{mFileActivity.getPackageName()};
143 DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intent, packagesToExclude, file);
144 chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
145
146 } else {
147 Log_OC.wtf(TAG, "Trying to share a NULL OCFile");
148 }
149
150 } else {
151 // Show a Message
152 Toast t = Toast.makeText(
153 mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG
154 );
155 t.show();
156 }
157 }
158
159
160 public void shareFileWithLinkToApp(OCFile file, String password, Intent sendIntent) {
161
162 if (file != null) {
163 mFileActivity.showLoadingDialog();
164
165 Intent service = new Intent(mFileActivity, OperationsService.class);
166 service.setAction(OperationsService.ACTION_CREATE_SHARE);
167 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
168 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
169 service.putExtra(OperationsService.EXTRA_PASSWORD_SHARE, password);
170 service.putExtra(OperationsService.EXTRA_SEND_INTENT, sendIntent);
171 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
172
173 } else {
174 Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
175 }
176 }
177
178
179 private Intent createShareWithLinkIntent(String link) {
180 Intent intentToShareLink = new Intent(Intent.ACTION_SEND);
181 intentToShareLink.putExtra(Intent.EXTRA_TEXT, link);
182 intentToShareLink.setType(HTTP.PLAIN_TEXT_TYPE);
183 return intentToShareLink;
184 }
185
186
187 /**
188 * @return 'True' if the server supports the Share API
189 */
190 public boolean isSharedSupported() {
191 if (mFileActivity.getAccount() != null) {
192 OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
193 return (serverVersion != null && serverVersion.isSharedSupported());
194 }
195 return false;
196 }
197
198
199 public void unshareFileWithLink(OCFile file) {
200
201 if (isSharedSupported()) {
202 // Unshare the file
203 Intent service = new Intent(mFileActivity, OperationsService.class);
204 service.setAction(OperationsService.ACTION_UNSHARE);
205 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
206 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
207 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
208
209 mFileActivity.showLoadingDialog();
210
211 } else {
212 // Show a Message
213 Toast t = Toast.makeText(mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
214 t.show();
215
216 }
217 }
218
219 public void sendDownloadedFile(OCFile file) {
220 if (file != null) {
221 String storagePath = file.getStoragePath();
222 String encodedStoragePath = WebdavUtils.encodePath(storagePath);
223 Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND);
224 // set MimeType
225 sendIntent.setType(file.getMimetype());
226 sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + encodedStoragePath));
227 sendIntent.putExtra(Intent.ACTION_SEND, true); // Send Action
228
229 // Show dialog, without the own app
230 String[] packagesToExclude = new String[]{mFileActivity.getPackageName()};
231 DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude, file);
232 chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
233
234 } else {
235 Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
236 }
237 }
238
239 /**
240 * Request the synchronization of a file or folder with the OC server, including its contents.
241 *
242 * @param file The file or folder to synchronize
243 */
244 public void syncFile(OCFile file) {
245 if (!file.isFolder()){
246 Intent intent = new Intent(mFileActivity, OperationsService.class);
247 intent.setAction(OperationsService.ACTION_SYNC_FILE);
248 intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
249 intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
250 intent.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
251 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(intent);
252 mFileActivity.showLoadingDialog();
253
254 } else {
255 Intent intent = new Intent(mFileActivity, OperationsService.class);
256 intent.setAction(OperationsService.ACTION_SYNC_FOLDER);
257 intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
258 intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
259 mFileActivity.startService(intent);
260
261 }
262 }
263
264 public void toggleFavorite(OCFile file, boolean isFavorite) {
265 file.setFavorite(isFavorite);
266 mFileActivity.getStorageManager().saveFile(file);
267
268 /// register the OCFile instance in the observer service to monitor local updates
269 Intent observedFileIntent = FileObserverService.makeObservedFileIntent(
270 mFileActivity,
271 file,
272 mFileActivity.getAccount(),
273 isFavorite);
274 mFileActivity.startService(observedFileIntent);
275
276 /// immediate content synchronization
277 if (file.isFavorite()) {
278 syncFile(file);
279 }
280 }
281
282 public void renameFile(OCFile file, String newFilename) {
283 // RenameFile
284 Intent service = new Intent(mFileActivity, OperationsService.class);
285 service.setAction(OperationsService.ACTION_RENAME);
286 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
287 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
288 service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
289 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
290
291 mFileActivity.showLoadingDialog();
292 }
293
294
295 public void removeFile(OCFile file, boolean onlyLocalCopy) {
296 // RemoveFile
297 Intent service = new Intent(mFileActivity, OperationsService.class);
298 service.setAction(OperationsService.ACTION_REMOVE);
299 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
300 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
301 service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
302 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
303
304 mFileActivity.showLoadingDialog();
305 }
306
307
308 public void createFolder(String remotePath, boolean createFullPath) {
309 // Create Folder
310 Intent service = new Intent(mFileActivity, OperationsService.class);
311 service.setAction(OperationsService.ACTION_CREATE_FOLDER);
312 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
313 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath);
314 service.putExtra(OperationsService.EXTRA_CREATE_FULL_PATH, createFullPath);
315 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
316
317 mFileActivity.showLoadingDialog();
318 }
319
320 /**
321 * Cancel the transference in downloads (files/folders) and file uploads
322 * @param file OCFile
323 */
324 public void cancelTransference(OCFile file) {
325 Account account = mFileActivity.getAccount();
326 if (file.isFolder()) {
327 OperationsService.OperationsServiceBinder opsBinder = mFileActivity.getOperationsServiceBinder();
328 if (opsBinder != null) {
329 opsBinder.cancel(account, file);
330 }
331 }
332
333 // for both files and folders
334 FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
335 if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) {
336 downloaderBinder.cancel(account, file);
337 }
338 FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
339 if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
340 uploaderBinder.cancel(account, file);
341 }
342 }
343
344 /**
345 * Start move file operation
346 *
347 * @param newfile File where it is going to be moved
348 * @param currentFile File with the previous info
349 */
350 public void moveFile(OCFile newfile, OCFile currentFile) {
351 // Move files
352 Intent service = new Intent(mFileActivity, OperationsService.class);
353 service.setAction(OperationsService.ACTION_MOVE_FILE);
354 service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
355 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
356 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
357 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
358
359 mFileActivity.showLoadingDialog();
360 }
361
362 /**
363 * Start copy file operation
364 *
365 * @param newfile File where it is going to be moved
366 * @param currentFile File with the previous info
367 */
368 public void copyFile(OCFile newfile, OCFile currentFile) {
369 // Copy files
370 Intent service = new Intent(mFileActivity, OperationsService.class);
371 service.setAction(OperationsService.ACTION_COPY_FILE);
372 service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
373 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
374 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
375 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
376
377 mFileActivity.showLoadingDialog();
378 }
379
380 public long getOpIdWaitingFor() {
381 return mWaitingForOpId;
382 }
383
384
385 public void setOpIdWaitingFor(long waitingForOpId) {
386 mWaitingForOpId = waitingForOpId;
387 }
388
389 /**
390 * @return 'True' if the server doesn't need to check forbidden characters
391 */
392 public boolean isVersionWithForbiddenCharacters() {
393 if (mFileActivity.getAccount() != null) {
394 OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
395 return (serverVersion != null && serverVersion.isVersionWithForbiddenCharacters());
396 }
397 return false;
398 }
399 }