e0e59dd1e037684f98b1e3a01b9fb5f9bf78bd48
[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.providers.FileContentProvider;
44 import com.owncloud.android.services.OperationsService;
45 import com.owncloud.android.services.observer.FileObserverService;
46 import com.owncloud.android.ui.activity.FileActivity;
47 import com.owncloud.android.ui.dialog.ShareLinkToDialog;
48
49 import org.apache.http.protocol.HTTP;
50
51 import java.io.File;
52 import java.util.List;
53
54 /**
55 *
56 */
57 public class FileOperationsHelper {
58
59 private static final String TAG = FileOperationsHelper.class.getName();
60
61 private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG";
62
63 protected FileActivity mFileActivity = null;
64
65 /// Identifier of operation in progress which result shouldn't be lost
66 private long mWaitingForOpId = Long.MAX_VALUE;
67
68 public FileOperationsHelper(FileActivity fileActivity) {
69 mFileActivity = fileActivity;
70 }
71
72
73 public void openFile(OCFile file) {
74 if (file != null) {
75 String storagePath = file.getStoragePath();
76 String encodedStoragePath = WebdavUtils.encodePath(storagePath);
77
78 Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW);
79 intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
80 intentForSavedMimeType.setFlags(
81 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
82 );
83
84 Intent intentForGuessedMimeType = null;
85 if (storagePath.lastIndexOf('.') >= 0) {
86 String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
87 storagePath.substring(storagePath.lastIndexOf('.') + 1)
88 );
89 if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
90 intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
91 intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType);
92 intentForGuessedMimeType.setFlags(
93 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
94 );
95 }
96 }
97
98 Intent openFileWithIntent;
99 if (intentForGuessedMimeType != null) {
100 openFileWithIntent = intentForGuessedMimeType;
101 } else {
102 openFileWithIntent = intentForSavedMimeType;
103 }
104
105 List<ResolveInfo> launchables = mFileActivity.getPackageManager().
106 queryIntentActivities(openFileWithIntent, PackageManager.GET_INTENT_FILTERS);
107
108 if(launchables != null && launchables.size() > 0) {
109 try {
110 mFileActivity.startActivity(
111 Intent.createChooser(
112 openFileWithIntent, mFileActivity.getString(R.string.actionbar_open_with)
113 )
114 );
115 } catch (ActivityNotFoundException anfe) {
116 showNoAppForFileTypeToast(mFileActivity.getApplicationContext());
117 }
118 } else {
119 showNoAppForFileTypeToast(mFileActivity.getApplicationContext());
120 }
121
122 } else {
123 Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
124 }
125 }
126
127 /**
128 * Displays a toast stating that no application could be found to open the file.
129 *
130 * @param context the context to be able to show a toast.
131 */
132 private void showNoAppForFileTypeToast(Context context) {
133 Toast.makeText(context,
134 R.string.file_list_no_app_for_file_type, Toast.LENGTH_SHORT)
135 .show();
136 }
137
138 public void shareFileWithLink(OCFile file) {
139
140 if (isSharedSupported()) {
141 if (file != null) {
142 String link = "https://fake.url";
143 Intent intent = createShareWithLinkIntent(link);
144 String[] packagesToExclude = new String[]{mFileActivity.getPackageName()};
145 DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intent, packagesToExclude, file);
146 chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
147
148 } else {
149 Log_OC.wtf(TAG, "Trying to share a NULL OCFile");
150 }
151
152 } else {
153 // Show a Message
154 Toast t = Toast.makeText(
155 mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG
156 );
157 t.show();
158 }
159 }
160
161
162 public void shareFileWithLinkToApp(OCFile file, String password, Intent sendIntent) {
163
164 if (file != null) {
165 mFileActivity.showLoadingDialog();
166
167 Intent service = new Intent(mFileActivity, OperationsService.class);
168 service.setAction(OperationsService.ACTION_CREATE_SHARE);
169 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
170 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
171 service.putExtra(OperationsService.EXTRA_PASSWORD_SHARE, password);
172 service.putExtra(OperationsService.EXTRA_SEND_INTENT, sendIntent);
173 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
174
175 } else {
176 Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
177 }
178 }
179
180
181 private Intent createShareWithLinkIntent(String link) {
182 Intent intentToShareLink = new Intent(Intent.ACTION_SEND);
183 intentToShareLink.putExtra(Intent.EXTRA_TEXT, link);
184 intentToShareLink.setType(HTTP.PLAIN_TEXT_TYPE);
185 return intentToShareLink;
186 }
187
188
189 /**
190 * @return 'True' if the server supports the Share API
191 */
192 public boolean isSharedSupported() {
193 if (mFileActivity.getAccount() != null) {
194 OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
195 return (serverVersion != null && serverVersion.isSharedSupported());
196 }
197 return false;
198 }
199
200
201 public void unshareFileWithLink(OCFile file) {
202
203 if (isSharedSupported()) {
204 // Unshare the file
205 Intent service = new Intent(mFileActivity, OperationsService.class);
206 service.setAction(OperationsService.ACTION_UNSHARE);
207 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
208 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
209 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
210
211 mFileActivity.showLoadingDialog();
212
213 } else {
214 // Show a Message
215 Toast t = Toast.makeText(mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
216 t.show();
217
218 }
219 }
220
221 public void sendDownloadedFile(OCFile file) {
222 if (file != null) {
223 String storagePath = file.getStoragePath();
224 String encodedStoragePath = WebdavUtils.encodePath(storagePath);
225 Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND);
226 // set MimeType
227 sendIntent.setType(file.getMimetype());
228 sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + encodedStoragePath));
229 sendIntent.putExtra(Intent.ACTION_SEND, true); // Send Action
230
231 // Show dialog, without the own app
232 String[] packagesToExclude = new String[]{mFileActivity.getPackageName()};
233 DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude, file);
234 chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
235
236 } else {
237 Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
238 }
239 }
240
241 public void setPictureAs(OCFile file) {
242 if (file != null) {
243 if (file.isDown()) {
244 File externalFile=new File(file.getStoragePath());
245 Uri sendUri = Uri.fromFile(externalFile);
246 Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
247 intent.setDataAndType(sendUri, file.getMimetype());
248 intent.putExtra("mimeType", file.getMimetype());
249 mFileActivity.startActivityForResult(Intent.createChooser(intent, "Set As"), 200);
250 } else {
251 // TODO re-enable after resized images is available
252 // Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND);
253 // // set MimeType
254 // sendIntent.setType(file.getMimetype());
255 //// sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + DiskLruImageCacheFileProvider.AUTHORITY + "/#" + file.getRemoteId() + "#" + file.getFileName()));
256 // sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + DiskLruImageCacheFileProvider.AUTHORITY + file.getRemotePath()));
257 // sendIntent.putExtra(Intent.ACTION_SEND, true); // Send Action
258 //
259 // // Show dialog, without the own app
260 // String[] packagesToExclude = new String[] { mFileActivity.getPackageName() };
261 // DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude, file);
262 // chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
263 }
264 } else {
265 Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
266 }
267 }
268
269 /**
270 * Request the synchronization of a file or folder with the OC server, including its contents.
271 *
272 * @param file The file or folder to synchronize
273 */
274 public void syncFile(OCFile file) {
275 if (!file.isFolder()){
276 Intent intent = new Intent(mFileActivity, OperationsService.class);
277 intent.setAction(OperationsService.ACTION_SYNC_FILE);
278 intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
279 intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
280 intent.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
281 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(intent);
282 mFileActivity.showLoadingDialog();
283
284 } else {
285 Intent intent = new Intent(mFileActivity, OperationsService.class);
286 intent.setAction(OperationsService.ACTION_SYNC_FOLDER);
287 intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
288 intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
289 mFileActivity.startService(intent);
290
291 }
292 }
293
294 public void toggleFavorite(OCFile file, boolean isFavorite) {
295 file.setFavorite(isFavorite);
296 mFileActivity.getStorageManager().saveFile(file);
297
298 /// register the OCFile instance in the observer service to monitor local updates
299 Intent observedFileIntent = FileObserverService.makeObservedFileIntent(
300 mFileActivity,
301 file,
302 mFileActivity.getAccount(),
303 isFavorite);
304 mFileActivity.startService(observedFileIntent);
305
306 /// immediate content synchronization
307 if (file.isFavorite()) {
308 syncFile(file);
309 }
310 }
311
312 public void renameFile(OCFile file, String newFilename) {
313 // RenameFile
314 Intent service = new Intent(mFileActivity, OperationsService.class);
315 service.setAction(OperationsService.ACTION_RENAME);
316 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
317 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
318 service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
319 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
320
321 mFileActivity.showLoadingDialog();
322 }
323
324
325 public void removeFile(OCFile file, boolean onlyLocalCopy) {
326 // RemoveFile
327 Intent service = new Intent(mFileActivity, OperationsService.class);
328 service.setAction(OperationsService.ACTION_REMOVE);
329 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
330 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
331 service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
332 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
333
334 mFileActivity.showLoadingDialog();
335 }
336
337
338 public void createFolder(String remotePath, boolean createFullPath) {
339 // Create Folder
340 Intent service = new Intent(mFileActivity, OperationsService.class);
341 service.setAction(OperationsService.ACTION_CREATE_FOLDER);
342 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
343 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath);
344 service.putExtra(OperationsService.EXTRA_CREATE_FULL_PATH, createFullPath);
345 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
346
347 mFileActivity.showLoadingDialog();
348 }
349
350 /**
351 * Cancel the transference in downloads (files/folders) and file uploads
352 * @param file OCFile
353 */
354 public void cancelTransference(OCFile file) {
355 Account account = mFileActivity.getAccount();
356 if (file.isFolder()) {
357 OperationsService.OperationsServiceBinder opsBinder = mFileActivity.getOperationsServiceBinder();
358 if (opsBinder != null) {
359 opsBinder.cancel(account, file);
360 }
361 }
362
363 // for both files and folders
364 FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
365 if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) {
366 downloaderBinder.cancel(account, file);
367 }
368 FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
369 if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
370 uploaderBinder.cancel(account, file);
371 }
372 }
373
374 /**
375 * Start move file operation
376 *
377 * @param newfile File where it is going to be moved
378 * @param currentFile File with the previous info
379 */
380 public void moveFile(OCFile newfile, OCFile currentFile) {
381 // Move files
382 Intent service = new Intent(mFileActivity, OperationsService.class);
383 service.setAction(OperationsService.ACTION_MOVE_FILE);
384 service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
385 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
386 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
387 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
388
389 mFileActivity.showLoadingDialog();
390 }
391
392 /**
393 * Start copy file operation
394 *
395 * @param newfile File where it is going to be moved
396 * @param currentFile File with the previous info
397 */
398 public void copyFile(OCFile newfile, OCFile currentFile) {
399 // Copy files
400 Intent service = new Intent(mFileActivity, OperationsService.class);
401 service.setAction(OperationsService.ACTION_COPY_FILE);
402 service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
403 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
404 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
405 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
406
407 mFileActivity.showLoadingDialog();
408 }
409
410 public long getOpIdWaitingFor() {
411 return mWaitingForOpId;
412 }
413
414
415 public void setOpIdWaitingFor(long waitingForOpId) {
416 mWaitingForOpId = waitingForOpId;
417 }
418
419 /**
420 * @return 'True' if the server doesn't need to check forbidden characters
421 */
422 public boolean isVersionWithForbiddenCharacters() {
423 if (mFileActivity.getAccount() != null) {
424 OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
425 return (serverVersion != null && serverVersion.isVersionWithForbiddenCharacters());
426 }
427 return false;
428 }
429 }