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