fixed #1244
[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 org.apache.http.protocol.HTTP;
25
26 import android.accounts.Account;
27 import android.content.Intent;
28 import android.graphics.Bitmap;
29 import android.net.Uri;
30 import android.support.v4.app.DialogFragment;
31 import android.webkit.MimeTypeMap;
32 import android.widget.Toast;
33
34 import com.owncloud.android.MainApp;
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.datamodel.ThumbnailsCacheManager;
39 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
40 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
41
42 import com.owncloud.android.lib.common.network.WebdavUtils;
43 import com.owncloud.android.lib.common.utils.Log_OC;
44 import com.owncloud.android.lib.resources.status.OwnCloudVersion;
45 import com.owncloud.android.services.OperationsService;
46 import com.owncloud.android.ui.activity.FileActivity;
47 import com.owncloud.android.ui.adapter.DiskLruImageCacheFileProvider;
48 import com.owncloud.android.ui.dialog.ShareLinkToDialog;
49
50 import java.io.ByteArrayOutputStream;
51 import java.io.File;
52 import java.io.FileNotFoundException;
53 import java.io.FileOutputStream;
54 import java.io.IOException;
55
56 /**
57 *
58 */
59 public class FileOperationsHelper {
60
61 private static final String TAG = FileOperationsHelper.class.getName();
62
63 private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG";
64
65 protected FileActivity mFileActivity = null;
66
67 /// Identifier of operation in progress which result shouldn't be lost
68 private long mWaitingForOpId = Long.MAX_VALUE;
69
70 public FileOperationsHelper(FileActivity fileActivity) {
71 mFileActivity = fileActivity;
72 }
73
74
75 public void openFile(OCFile file) {
76 if (file != null) {
77 String storagePath = file.getStoragePath();
78 String encodedStoragePath = WebdavUtils.encodePath(storagePath);
79
80 Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW);
81 intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
82 intentForSavedMimeType.setFlags(
83 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
84 );
85
86 Intent intentForGuessedMimeType = null;
87 if (storagePath.lastIndexOf('.') >= 0) {
88 String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
89 storagePath.substring(storagePath.lastIndexOf('.') + 1)
90 );
91 if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
92 intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
93 intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType);
94 intentForGuessedMimeType.setFlags(
95 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
96 );
97 }
98 }
99
100 Intent chooserIntent;
101 if (intentForGuessedMimeType != null) {
102 chooserIntent = Intent.createChooser(intentForGuessedMimeType, mFileActivity.getString(R.string.actionbar_open_with));
103 } else {
104 chooserIntent = Intent.createChooser(intentForSavedMimeType, mFileActivity.getString(R.string.actionbar_open_with));
105 }
106
107 mFileActivity.startActivity(chooserIntent);
108
109 } else {
110 Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
111 }
112 }
113
114
115 public void shareFileWithLink(OCFile file) {
116
117 if (isSharedSupported()) {
118 if (file != null) {
119 String link = "https://fake.url";
120 Intent intent = createShareWithLinkIntent(link);
121 String[] packagesToExclude = new String[] { mFileActivity.getPackageName() };
122 DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intent, packagesToExclude, file);
123 chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
124
125 } else {
126 Log_OC.wtf(TAG, "Trying to share a NULL OCFile");
127 }
128
129 } else {
130 // Show a Message
131 Toast t = Toast.makeText(
132 mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG
133 );
134 t.show();
135 }
136 }
137
138
139 public void shareFileWithLinkToApp(OCFile file, String password, Intent sendIntent) {
140
141 if (file != null) {
142 mFileActivity.showLoadingDialog();
143
144 Intent service = new Intent(mFileActivity, OperationsService.class);
145 service.setAction(OperationsService.ACTION_CREATE_SHARE);
146 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
147 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
148 service.putExtra(OperationsService.EXTRA_PASSWORD_SHARE, password);
149 service.putExtra(OperationsService.EXTRA_SEND_INTENT, sendIntent);
150 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
151
152 } else {
153 Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
154 }
155 }
156
157
158 private Intent createShareWithLinkIntent(String link) {
159 Intent intentToShareLink = new Intent(Intent.ACTION_SEND);
160 intentToShareLink.putExtra(Intent.EXTRA_TEXT, link);
161 intentToShareLink.setType(HTTP.PLAIN_TEXT_TYPE);
162 return intentToShareLink;
163 }
164
165
166 /**
167 * @return 'True' if the server supports the Share API
168 */
169 public boolean isSharedSupported() {
170 if (mFileActivity.getAccount() != null) {
171 OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
172 return (serverVersion != null && serverVersion.isSharedSupported());
173 }
174 return false;
175 }
176
177
178 public void unshareFileWithLink(OCFile file) {
179
180 if (isSharedSupported()) {
181 // Unshare the file
182 Intent service = new Intent(mFileActivity, OperationsService.class);
183 service.setAction(OperationsService.ACTION_UNSHARE);
184 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
185 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
186 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
187
188 mFileActivity.showLoadingDialog();
189
190 } else {
191 // Show a Message
192 Toast t = Toast.makeText(mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
193 t.show();
194
195 }
196 }
197
198 public void sendDownloadedFile(OCFile file) {
199 if (file != null) {
200 Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND);
201 // set MimeType
202 sendIntent.setType(file.getMimetype());
203 sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + file.getStoragePath()));
204 sendIntent.putExtra(Intent.ACTION_SEND, true); // Send Action
205
206 // Show dialog, without the own app
207 String[] packagesToExclude = new String[] { mFileActivity.getPackageName() };
208 DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude, file);
209 chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
210
211 } else {
212 Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
213 }
214 }
215
216 public void sendCachedImage(OCFile file) {
217 if (file != null) {
218 Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND);
219 // set MimeType
220 sendIntent.setType(file.getMimetype());
221 // sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + DiskLruImageCacheFileProvider.AUTHORITY + "/#" + file.getRemoteId() + "#" + file.getFileName()));
222 sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + DiskLruImageCacheFileProvider.AUTHORITY + file.getRemotePath()));
223 sendIntent.putExtra(Intent.ACTION_SEND, true); // Send Action
224
225 // Show dialog, without the own app
226 String[] packagesToExclude = new String[] { mFileActivity.getPackageName() };
227 DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude, file);
228 chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
229 } else {
230 Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
231 }
232 }
233
234
235 public void syncFile(OCFile file) {
236
237 if (!file.isFolder()){
238 Intent intent = new Intent(mFileActivity, OperationsService.class);
239 intent.setAction(OperationsService.ACTION_SYNC_FILE);
240 intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
241 intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
242 intent.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
243 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(intent);
244 // mFileActivity.showLoadingDialog();
245
246 } else {
247 Intent intent = new Intent(mFileActivity, OperationsService.class);
248 intent.setAction(OperationsService.ACTION_SYNC_FOLDER);
249 intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
250 intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
251 mFileActivity.startService(intent);
252 }
253 }
254
255 public void renameFile(OCFile file, String newFilename) {
256 // RenameFile
257 Intent service = new Intent(mFileActivity, OperationsService.class);
258 service.setAction(OperationsService.ACTION_RENAME);
259 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
260 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
261 service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
262 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
263
264 mFileActivity.showLoadingDialog();
265 }
266
267
268 public void removeFile(OCFile file, boolean onlyLocalCopy) {
269 // RemoveFile
270 Intent service = new Intent(mFileActivity, OperationsService.class);
271 service.setAction(OperationsService.ACTION_REMOVE);
272 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
273 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
274 service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
275 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
276
277 mFileActivity.showLoadingDialog();
278 }
279
280
281 public void createFolder(String remotePath, boolean createFullPath) {
282 // Create Folder
283 Intent service = new Intent(mFileActivity, OperationsService.class);
284 service.setAction(OperationsService.ACTION_CREATE_FOLDER);
285 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
286 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath);
287 service.putExtra(OperationsService.EXTRA_CREATE_FULL_PATH, createFullPath);
288 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
289
290 mFileActivity.showLoadingDialog();
291 }
292
293 /**
294 * Cancel the transference in downloads (files/folders) and file uploads
295 * @param file OCFile
296 */
297 public void cancelTransference(OCFile file) {
298 Account account = mFileActivity.getAccount();
299 if (file.isFolder()) {
300 OperationsService.OperationsServiceBinder opsBinder = mFileActivity.getOperationsServiceBinder();
301 if (opsBinder != null) {
302 opsBinder.cancel(account, file);
303 }
304 }
305
306 // for both files and folders
307 FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
308 FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
309 if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) {
310 downloaderBinder.cancel(account, file);
311
312 // TODO - review why is this here, and solve in a better way
313 // Remove etag for parent, if file is a keep_in_sync
314 if (file.keepInSync()) {
315 OCFile parent = mFileActivity.getStorageManager().getFileById(file.getParentId());
316 parent.setEtag("");
317 mFileActivity.getStorageManager().saveFile(parent);
318 }
319
320 } else if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
321 uploaderBinder.cancel(account, file);
322 }
323 }
324
325 /**
326 * Start move file operation
327 * @param newfile File where it is going to be moved
328 * @param currentFile File with the previous info
329 */
330 public void moveFile(OCFile newfile, OCFile currentFile) {
331 // Move files
332 Intent service = new Intent(mFileActivity, OperationsService.class);
333 service.setAction(OperationsService.ACTION_MOVE_FILE);
334 service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
335 service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
336 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
337 mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
338
339 mFileActivity.showLoadingDialog();
340 }
341
342
343 public long getOpIdWaitingFor() {
344 return mWaitingForOpId;
345 }
346
347
348 public void setOpIdWaitingFor(long waitingForOpId) {
349 mWaitingForOpId = waitingForOpId;
350 }
351
352 /**
353 * @return 'True' if the server doesn't need to check forbidden characters
354 */
355 public boolean isVersionWithForbiddenCharacters() {
356 if (mFileActivity.getAccount() != null) {
357 OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
358 return (serverVersion != null && serverVersion.isVersionWithForbiddenCharacters());
359 }
360 return false;
361 }
362 }