wip
[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 public void setPictureAs(OCFile file) {
240 if (file != null) {
241 String storagePath = file.getStoragePath();
242 String encodedStoragePath = WebdavUtils.encodePath(storagePath);
243 Intent sendIntent = new Intent(Intent.ACTION_ATTACH_DATA);
244 // set MimeType
245 sendIntent.setData(Uri.parse(encodedStoragePath));
246 // sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + encodedStoragePath));
247 // sendIntent.putExtra("jpg", "image/*");
248
249 mFileActivity.startActivity(Intent.createChooser(sendIntent,
250 mFileActivity.getString(R.string.set_picture_as)));
251
252 } else {
253 Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
254 }
255 }
256
257 /**
258 * Request the synchronization of a file or folder with the OC server, including its contents.
259 *
260 * @param file The file or folder to synchronize
261 */
262 public void syncFile(OCFile file) {
263 if (!file.isFolder()){
264 Intent intent = new Intent(mFileActivity, OperationsService.class);
265 intent.setAction(OperationsService.ACTION_SYNC_FILE);
266 intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
267 intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
268 intent.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
269 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(intent);
270 mFileActivity.showLoadingDialog();
271
272 } else {
273 Intent intent = new Intent(mFileActivity, OperationsService.class);
274 intent.setAction(OperationsService.ACTION_SYNC_FOLDER);
275 intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
276 intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
277 mFileActivity.startService(intent);
278
279 }
280 }
281
282 public void toggleFavorite(OCFile file, boolean isFavorite) {
283 file.setFavorite(isFavorite);
284 mFileActivity.getStorageManager().saveFile(file);
285
286 /// register the OCFile instance in the observer service to monitor local updates
287 Intent observedFileIntent = FileObserverService.makeObservedFileIntent(
288 mFileActivity,
289 file,
290 mFileActivity.getAccount(),
291 isFavorite);
292 mFileActivity.startService(observedFileIntent);
293
294 /// immediate content synchronization
295 if (file.isFavorite()) {
296 syncFile(file);
297 }
298 }
299
300 public void renameFile(OCFile file, String newFilename) {
301 // RenameFile
302 Intent service = new Intent(mFileActivity, OperationsService.class);
303 service.setAction(OperationsService.ACTION_RENAME);
304 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
305 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
306 service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
307 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
308
309 mFileActivity.showLoadingDialog();
310 }
311
312
313 public void removeFile(OCFile file, boolean onlyLocalCopy) {
314 // RemoveFile
315 Intent service = new Intent(mFileActivity, OperationsService.class);
316 service.setAction(OperationsService.ACTION_REMOVE);
317 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
318 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
319 service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
320 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
321
322 mFileActivity.showLoadingDialog();
323 }
324
325
326 public void createFolder(String remotePath, boolean createFullPath) {
327 // Create Folder
328 Intent service = new Intent(mFileActivity, OperationsService.class);
329 service.setAction(OperationsService.ACTION_CREATE_FOLDER);
330 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
331 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath);
332 service.putExtra(OperationsService.EXTRA_CREATE_FULL_PATH, createFullPath);
333 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
334
335 mFileActivity.showLoadingDialog();
336 }
337
338 /**
339 * Cancel the transference in downloads (files/folders) and file uploads
340 * @param file OCFile
341 */
342 public void cancelTransference(OCFile file) {
343 Account account = mFileActivity.getAccount();
344 if (file.isFolder()) {
345 OperationsService.OperationsServiceBinder opsBinder = mFileActivity.getOperationsServiceBinder();
346 if (opsBinder != null) {
347 opsBinder.cancel(account, file);
348 }
349 }
350
351 // for both files and folders
352 FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
353 if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) {
354 downloaderBinder.cancel(account, file);
355 }
356 FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
357 if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
358 uploaderBinder.cancel(account, file);
359 }
360 }
361
362 /**
363 * Start move 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 moveFile(OCFile newfile, OCFile currentFile) {
369 // Move files
370 Intent service = new Intent(mFileActivity, OperationsService.class);
371 service.setAction(OperationsService.ACTION_MOVE_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 /**
381 * Start copy file operation
382 *
383 * @param newfile File where it is going to be moved
384 * @param currentFile File with the previous info
385 */
386 public void copyFile(OCFile newfile, OCFile currentFile) {
387 // Copy files
388 Intent service = new Intent(mFileActivity, OperationsService.class);
389 service.setAction(OperationsService.ACTION_COPY_FILE);
390 service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
391 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
392 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
393 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
394
395 mFileActivity.showLoadingDialog();
396 }
397
398 public long getOpIdWaitingFor() {
399 return mWaitingForOpId;
400 }
401
402
403 public void setOpIdWaitingFor(long waitingForOpId) {
404 mWaitingForOpId = waitingForOpId;
405 }
406
407 /**
408 * @return 'True' if the server doesn't need to check forbidden characters
409 */
410 public boolean isVersionWithForbiddenCharacters() {
411 if (mFileActivity.getAccount() != null) {
412 OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
413 return (serverVersion != null && serverVersion.isVersionWithForbiddenCharacters());
414 }
415 return false;
416 }
417 }