Merge commit 'refs/pr/707' into text_file_preview_pr_707_with
[pub/Android/ownCloud.git] / src / com / owncloud / android / datamodel / FileDataStorageManager.java
1 /**
2 * ownCloud Android client application
3 *
4 * Copyright (C) 2012 Bartek Przybylski
5 * Copyright (C) 2015 ownCloud Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2,
9 * as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 package com.owncloud.android.datamodel;
22
23 import java.io.File;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Vector;
30
31 import android.accounts.Account;
32 import android.content.ContentProviderClient;
33 import android.content.ContentProviderOperation;
34 import android.content.ContentProviderResult;
35 import android.content.ContentResolver;
36 import android.content.ContentUris;
37 import android.content.ContentValues;
38 import android.content.Intent;
39 import android.content.OperationApplicationException;
40 import android.database.Cursor;
41 import android.net.Uri;
42 import android.os.RemoteException;
43 import android.provider.MediaStore;
44
45 import com.owncloud.android.MainApp;
46 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
47 import com.owncloud.android.lib.common.utils.Log_OC;
48 import com.owncloud.android.lib.resources.files.FileUtils;
49 import com.owncloud.android.lib.resources.shares.OCShare;
50 import com.owncloud.android.lib.resources.shares.ShareType;
51 import com.owncloud.android.utils.FileStorageUtils;
52
53 public class FileDataStorageManager {
54
55 public static final int ROOT_PARENT_ID = 0;
56
57 private ContentResolver mContentResolver;
58 private ContentProviderClient mContentProviderClient;
59 private Account mAccount;
60
61 private static String TAG = FileDataStorageManager.class.getSimpleName();
62
63
64 public FileDataStorageManager(Account account, ContentResolver cr) {
65 mContentProviderClient = null;
66 mContentResolver = cr;
67 mAccount = account;
68 }
69
70 public FileDataStorageManager(Account account, ContentProviderClient cp) {
71 mContentProviderClient = cp;
72 mContentResolver = null;
73 mAccount = account;
74 }
75
76
77 public void setAccount(Account account) {
78 mAccount = account;
79 }
80
81 public Account getAccount() {
82 return mAccount;
83 }
84
85 public void setContentResolver(ContentResolver cr) {
86 mContentResolver = cr;
87 }
88
89 public ContentResolver getContentResolver() {
90 return mContentResolver;
91 }
92
93 public void setContentProviderClient(ContentProviderClient cp) {
94 mContentProviderClient = cp;
95 }
96
97 public ContentProviderClient getContentProviderClient() {
98 return mContentProviderClient;
99 }
100
101
102 public OCFile getFileByPath(String path) {
103 Cursor c = getCursorForValue(ProviderTableMeta.FILE_PATH, path);
104 OCFile file = null;
105 if (c.moveToFirst()) {
106 file = createFileInstance(c);
107 }
108 c.close();
109 if (file == null && OCFile.ROOT_PATH.equals(path)) {
110 return createRootDir(); // root should always exist
111 }
112 return file;
113 }
114
115
116 public OCFile getFileById(long id) {
117 Cursor c = getCursorForValue(ProviderTableMeta._ID, String.valueOf(id));
118 OCFile file = null;
119 if (c.moveToFirst()) {
120 file = createFileInstance(c);
121 }
122 c.close();
123 return file;
124 }
125
126 public OCFile getFileByLocalPath(String path) {
127 Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
128 OCFile file = null;
129 if (c.moveToFirst()) {
130 file = createFileInstance(c);
131 }
132 c.close();
133 return file;
134 }
135
136 public boolean fileExists(long id) {
137 return fileExists(ProviderTableMeta._ID, String.valueOf(id));
138 }
139
140 public boolean fileExists(String path) {
141 return fileExists(ProviderTableMeta.FILE_PATH, path);
142 }
143
144
145 public Vector<OCFile> getFolderContent(OCFile f/*, boolean onlyOnDevice*/) {
146 if (f != null && f.isFolder() && f.getFileId() != -1) {
147 // TODO Enable when "On Device" is recovered ?
148 return getFolderContent(f.getFileId()/*, onlyOnDevice*/);
149
150 } else {
151 return new Vector<OCFile>();
152 }
153 }
154
155
156 public Vector<OCFile> getFolderImages(OCFile folder/*, boolean onlyOnDevice*/) {
157 Vector<OCFile> ret = new Vector<OCFile>();
158 if (folder != null) {
159 // TODO better implementation, filtering in the access to database instead of here
160 // TODO Enable when "On Device" is recovered ?
161 Vector<OCFile> tmp = getFolderContent(folder/*, onlyOnDevice*/);
162 OCFile current = null;
163 for (int i=0; i<tmp.size(); i++) {
164 current = tmp.get(i);
165 if (current.isImage()) {
166 ret.add(current);
167 }
168 }
169 }
170 return ret;
171 }
172
173 public boolean saveFile(OCFile file) {
174 boolean overriden = false;
175 ContentValues cv = new ContentValues();
176 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
177 cv.put(
178 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
179 file.getModificationTimestampAtLastSyncForData()
180 );
181 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
182 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
183 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
184 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
185 //if (file.getParentId() != DataStorageManager.ROOT_PARENT_ID)
186 cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
187 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
188 if (!file.isFolder())
189 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
190 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
191 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
192 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
193 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isFavorite() ? 1 : 0);
194 cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
195 cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0);
196 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
197 cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
198 cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
199 cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.needsUpdateThumbnail());
200 cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
201
202 boolean sameRemotePath = fileExists(file.getRemotePath());
203 if (sameRemotePath ||
204 fileExists(file.getFileId()) ) { // for renamed files
205
206 OCFile oldFile = null;
207 if (sameRemotePath) {
208 oldFile = getFileByPath(file.getRemotePath());
209 file.setFileId(oldFile.getFileId());
210 } else {
211 oldFile = getFileById(file.getFileId());
212 }
213
214 overriden = true;
215 if (getContentResolver() != null) {
216 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv,
217 ProviderTableMeta._ID + "=?",
218 new String[] { String.valueOf(file.getFileId()) });
219 } else {
220 try {
221 getContentProviderClient().update(ProviderTableMeta.CONTENT_URI,
222 cv, ProviderTableMeta._ID + "=?",
223 new String[] { String.valueOf(file.getFileId()) });
224 } catch (RemoteException e) {
225 Log_OC.e(TAG,
226 "Fail to insert insert file to database "
227 + e.getMessage());
228 }
229 }
230 } else {
231 Uri result_uri = null;
232 if (getContentResolver() != null) {
233 result_uri = getContentResolver().insert(
234 ProviderTableMeta.CONTENT_URI_FILE, cv);
235 } else {
236 try {
237 result_uri = getContentProviderClient().insert(
238 ProviderTableMeta.CONTENT_URI_FILE, cv);
239 } catch (RemoteException e) {
240 Log_OC.e(TAG,
241 "Fail to insert insert file to database "
242 + e.getMessage());
243 }
244 }
245 if (result_uri != null) {
246 long new_id = Long.parseLong(result_uri.getPathSegments()
247 .get(1));
248 file.setFileId(new_id);
249 }
250 }
251
252 // if (file.isFolder()) {
253 // updateFolderSize(file.getFileId());
254 // } else {
255 // updateFolderSize(file.getParentId());
256 // }
257
258 return overriden;
259 }
260
261
262 /**
263 * Inserts or updates the list of files contained in a given folder.
264 *
265 * CALLER IS THE RESPONSIBLE FOR GRANTING RIGHT UPDATE OF INFORMATION, NOT THIS METHOD.
266 * HERE ONLY DATA CONSISTENCY SHOULD BE GRANTED
267 *
268 * @param folder
269 * @param updatedFiles
270 * @param filesToRemove
271 */
272 public void saveFolder(
273 OCFile folder, Collection<OCFile> updatedFiles, Collection<OCFile> filesToRemove
274 ) {
275
276 Log_OC.d(TAG, "Saving folder " + folder.getRemotePath() + " with " + updatedFiles.size()
277 + " children and " + filesToRemove.size() + " files to remove");
278
279 ArrayList<ContentProviderOperation> operations =
280 new ArrayList<ContentProviderOperation>(updatedFiles.size());
281
282 // prepare operations to insert or update files to save in the given folder
283 for (OCFile file : updatedFiles) {
284 ContentValues cv = new ContentValues();
285 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
286 cv.put(
287 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
288 file.getModificationTimestampAtLastSyncForData()
289 );
290 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
291 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
292 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
293 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
294 //cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
295 cv.put(ProviderTableMeta.FILE_PARENT, folder.getFileId());
296 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
297 if (!file.isFolder()) {
298 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
299 }
300 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
301 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
302 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
303 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isFavorite() ? 1 : 0);
304 cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
305 cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0);
306 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
307 cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
308 cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
309 cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.needsUpdateThumbnail());
310 cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
311
312 boolean existsByPath = fileExists(file.getRemotePath());
313 if (existsByPath || fileExists(file.getFileId())) {
314 // updating an existing file
315 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
316 withValues(cv).
317 withSelection( ProviderTableMeta._ID + "=?",
318 new String[] { String.valueOf(file.getFileId()) })
319 .build());
320
321 } else {
322 // adding a new file
323 operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).
324 withValues(cv).build());
325 }
326 }
327
328 // prepare operations to remove files in the given folder
329 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " +
330 ProviderTableMeta.FILE_PATH + "=?";
331 String [] whereArgs = null;
332 for (OCFile file : filesToRemove) {
333 if (file.getParentId() == folder.getFileId()) {
334 whereArgs = new String[]{mAccount.name, file.getRemotePath()};
335 //Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, "" + file.getFileId());
336 if (file.isFolder()) {
337 operations.add(ContentProviderOperation.newDelete(
338 ContentUris.withAppendedId(
339 ProviderTableMeta.CONTENT_URI_DIR, file.getFileId()
340 )
341 ).withSelection(where, whereArgs).build());
342
343 File localFolder =
344 new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
345 if (localFolder.exists()) {
346 removeLocalFolder(localFolder);
347 }
348 } else {
349 operations.add(ContentProviderOperation.newDelete(
350 ContentUris.withAppendedId(
351 ProviderTableMeta.CONTENT_URI_FILE, file.getFileId()
352 )
353 ).withSelection(where, whereArgs).build());
354
355 if (file.isDown()) {
356 String path = file.getStoragePath();
357 new File(path).delete();
358 triggerMediaScan(path); // notify MediaScanner about removed file
359 }
360 }
361 }
362 }
363
364 // update metadata of folder
365 ContentValues cv = new ContentValues();
366 cv.put(ProviderTableMeta.FILE_MODIFIED, folder.getModificationTimestamp());
367 cv.put(
368 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
369 folder.getModificationTimestampAtLastSyncForData()
370 );
371 cv.put(ProviderTableMeta.FILE_CREATION, folder.getCreationTimestamp());
372 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, 0);
373 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, folder.getMimetype());
374 cv.put(ProviderTableMeta.FILE_NAME, folder.getFileName());
375 cv.put(ProviderTableMeta.FILE_PARENT, folder.getParentId());
376 cv.put(ProviderTableMeta.FILE_PATH, folder.getRemotePath());
377 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
378 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, folder.getLastSyncDateForProperties());
379 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, folder.getLastSyncDateForData());
380 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, folder.isFavorite() ? 1 : 0);
381 cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag());
382 cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, folder.isShareByLink() ? 1 : 0);
383 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, folder.getPublicLink());
384 cv.put(ProviderTableMeta.FILE_PERMISSIONS, folder.getPermissions());
385 cv.put(ProviderTableMeta.FILE_REMOTE_ID, folder.getRemoteId());
386
387 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
388 withValues(cv).
389 withSelection( ProviderTableMeta._ID + "=?",
390 new String[] { String.valueOf(folder.getFileId()) })
391 .build());
392
393 // apply operations in batch
394 ContentProviderResult[] results = null;
395 Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
396 try {
397 if (getContentResolver() != null) {
398 results = getContentResolver().applyBatch(MainApp.getAuthority(), operations);
399
400 } else {
401 results = getContentProviderClient().applyBatch(operations);
402 }
403
404 } catch (OperationApplicationException e) {
405 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
406
407 } catch (RemoteException e) {
408 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
409 }
410
411 // update new id in file objects for insertions
412 if (results != null) {
413 long newId;
414 Iterator<OCFile> filesIt = updatedFiles.iterator();
415 OCFile file = null;
416 for (int i=0; i<results.length; i++) {
417 if (filesIt.hasNext()) {
418 file = filesIt.next();
419 } else {
420 file = null;
421 }
422 if (results[i].uri != null) {
423 newId = Long.parseLong(results[i].uri.getPathSegments().get(1));
424 //updatedFiles.get(i).setFileId(newId);
425 if (file != null) {
426 file.setFileId(newId);
427 }
428 }
429 }
430 }
431
432 //updateFolderSize(folder.getFileId());
433
434 }
435
436
437 // /**
438 // *
439 // * @param id
440 // */
441 // private void updateFolderSize(long id) {
442 // if (id > FileDataStorageManager.ROOT_PARENT_ID) {
443 // Log_OC.d(TAG, "Updating size of " + id);
444 // if (getContentResolver() != null) {
445 // getContentResolver().update(ProviderTableMeta.CONTENT_URI_DIR,
446 // new ContentValues(),
447 // won't be used, but cannot be null; crashes in KLP
448 // ProviderTableMeta._ID + "=?",
449 // new String[] { String.valueOf(id) });
450 // } else {
451 // try {
452 // getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_DIR,
453 // new ContentValues(),
454 // won't be used, but cannot be null; crashes in KLP
455 // ProviderTableMeta._ID + "=?",
456 // new String[] { String.valueOf(id) });
457 //
458 // } catch (RemoteException e) {
459 // Log_OC.e(
460 // TAG, "Exception in update of folder size through compatibility patch " + e.getMessage());
461 // }
462 // }
463 // } else {
464 // Log_OC.e(TAG, "not updating size for folder " + id);
465 // }
466 // }
467
468
469 public boolean removeFile(OCFile file, boolean removeDBData, boolean removeLocalCopy) {
470 boolean success = true;
471 if (file != null) {
472 if (file.isFolder()) {
473 success = removeFolder(file, removeDBData, removeLocalCopy);
474
475 } else {
476 if (removeDBData) {
477 Uri file_uri = ContentUris.withAppendedId(
478 ProviderTableMeta.CONTENT_URI_FILE,
479 file.getFileId()
480 );
481 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " +
482 ProviderTableMeta.FILE_PATH + "=?";
483 String [] whereArgs = new String[]{mAccount.name, file.getRemotePath()};
484 int deleted = 0;
485 if (getContentProviderClient() != null) {
486 try {
487 deleted = getContentProviderClient().delete(file_uri, where, whereArgs);
488 } catch (RemoteException e) {
489 e.printStackTrace();
490 }
491 } else {
492 deleted = getContentResolver().delete(file_uri, where, whereArgs);
493 }
494 success &= (deleted > 0);
495 }
496 String localPath = file.getStoragePath();
497 if (removeLocalCopy && file.isDown() && localPath != null && success) {
498 success = new File(localPath).delete();
499 if (success) {
500 deleteFileInMediaScan(localPath);
501 }
502 if (!removeDBData && success) {
503 // maybe unnecessary, but should be checked TODO remove if unnecessary
504 file.setStoragePath(null);
505 saveFile(file);
506 }
507 }
508 }
509 }
510 return success;
511 }
512
513
514 public boolean removeFolder(OCFile folder, boolean removeDBData, boolean removeLocalContent) {
515 boolean success = true;
516 if (folder != null && folder.isFolder()) {
517 if (removeDBData && folder.getFileId() != -1) {
518 success = removeFolderInDb(folder);
519 }
520 if (removeLocalContent && success) {
521 success = removeLocalFolder(folder);
522 }
523 }
524 return success;
525 }
526
527 private boolean removeFolderInDb(OCFile folder) {
528 Uri folder_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, "" +
529 folder.getFileId()); // URI for recursive deletion
530 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " +
531 ProviderTableMeta.FILE_PATH + "=?";
532 String [] whereArgs = new String[]{mAccount.name, folder.getRemotePath()};
533 int deleted = 0;
534 if (getContentProviderClient() != null) {
535 try {
536 deleted = getContentProviderClient().delete(folder_uri, where, whereArgs);
537 } catch (RemoteException e) {
538 e.printStackTrace();
539 }
540 } else {
541 deleted = getContentResolver().delete(folder_uri, where, whereArgs);
542 }
543 return deleted > 0;
544 }
545
546 private boolean removeLocalFolder(OCFile folder) {
547 boolean success = true;
548 String localFolderPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder);
549 File localFolder = new File(localFolderPath);
550 if (localFolder.exists()) {
551 // stage 1: remove the local files already registered in the files database
552 // TODO Enable when "On Device" is recovered ?
553 Vector<OCFile> files = getFolderContent(folder.getFileId()/*, false*/);
554 if (files != null) {
555 for (OCFile file : files) {
556 if (file.isFolder()) {
557 success &= removeLocalFolder(file);
558 } else {
559 if (file.isDown()) {
560 File localFile = new File(file.getStoragePath());
561 success &= localFile.delete();
562 if (success) {
563 // notify MediaScanner about removed file
564 deleteFileInMediaScan(file.getStoragePath());
565 file.setStoragePath(null);
566 saveFile(file);
567 }
568 }
569 }
570 }
571 }
572
573 // stage 2: remove the folder itself and any local file inside out of sync;
574 // for instance, after clearing the app cache or reinstalling
575 success &= removeLocalFolder(localFolder);
576 }
577 return success;
578 }
579
580 private boolean removeLocalFolder(File localFolder) {
581 boolean success = true;
582 File[] localFiles = localFolder.listFiles();
583 if (localFiles != null) {
584 for (File localFile : localFiles) {
585 if (localFile.isDirectory()) {
586 success &= removeLocalFolder(localFile);
587 } else {
588 String path = localFile.getAbsolutePath();
589 success &= localFile.delete();
590 }
591 }
592 }
593 success &= localFolder.delete();
594 return success;
595 }
596
597
598 /**
599 * Updates database and file system for a file or folder that was moved to a different location.
600 *
601 * TODO explore better (faster) implementations
602 * TODO throw exceptions up !
603 */
604 public void moveLocalFile(OCFile file, String targetPath, String targetParentPath) {
605
606 if (file != null && file.fileExists() && !OCFile.ROOT_PATH.equals(file.getFileName())) {
607
608 OCFile targetParent = getFileByPath(targetParentPath);
609 if (targetParent == null) {
610 throw new IllegalStateException("Parent folder of the target path does not exist!!");
611 }
612
613 /// 1. get all the descendants of the moved element in a single QUERY
614 Cursor c = null;
615 if (getContentProviderClient() != null) {
616 try {
617 c = getContentProviderClient().query(
618 ProviderTableMeta.CONTENT_URI,
619 null,
620 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
621 ProviderTableMeta.FILE_PATH + " LIKE ? ",
622 new String[] {
623 mAccount.name,
624 file.getRemotePath() + "%"
625 },
626 ProviderTableMeta.FILE_PATH + " ASC "
627 );
628 } catch (RemoteException e) {
629 Log_OC.e(TAG, e.getMessage());
630 }
631
632 } else {
633 c = getContentResolver().query(
634 ProviderTableMeta.CONTENT_URI,
635 null,
636 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
637 ProviderTableMeta.FILE_PATH + " LIKE ? ",
638 new String[] {
639 mAccount.name,
640 file.getRemotePath() + "%"
641 },
642 ProviderTableMeta.FILE_PATH + " ASC "
643 );
644 }
645
646 /// 2. prepare a batch of update operations to change all the descendants
647 ArrayList<ContentProviderOperation> operations =
648 new ArrayList<ContentProviderOperation>(c.getCount());
649 String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
650 List<String> originalPathsToTriggerMediaScan = new ArrayList<String>();
651 List<String> newPathsToTriggerMediaScan = new ArrayList<String>();
652 if (c.moveToFirst()) {
653 int lengthOfOldPath = file.getRemotePath().length();
654 int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
655 do {
656 ContentValues cv = new ContentValues(); // keep construction in the loop
657 OCFile child = createFileInstance(c);
658 cv.put(
659 ProviderTableMeta.FILE_PATH,
660 targetPath + child.getRemotePath().substring(lengthOfOldPath)
661 );
662 if (child.getStoragePath() != null &&
663 child.getStoragePath().startsWith(defaultSavePath)) {
664 // update link to downloaded content - but local move is not done here!
665 String targetLocalPath = defaultSavePath + targetPath +
666 child.getStoragePath().substring(lengthOfOldStoragePath);
667
668 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, targetLocalPath);
669
670 originalPathsToTriggerMediaScan.add(child.getStoragePath());
671 newPathsToTriggerMediaScan.add(targetLocalPath);
672
673 }
674 if (child.getRemotePath().equals(file.getRemotePath())) {
675 cv.put(
676 ProviderTableMeta.FILE_PARENT,
677 targetParent.getFileId()
678 );
679 }
680 operations.add(
681 ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
682 withValues(cv).
683 withSelection(
684 ProviderTableMeta._ID + "=?",
685 new String[] { String.valueOf(child.getFileId()) }
686 )
687 .build());
688
689 } while (c.moveToNext());
690 }
691 c.close();
692
693 /// 3. apply updates in batch
694 try {
695 if (getContentResolver() != null) {
696 getContentResolver().applyBatch(MainApp.getAuthority(), operations);
697
698 } else {
699 getContentProviderClient().applyBatch(operations);
700 }
701
702 } catch (Exception e) {
703 Log_OC.e(TAG, "Fail to update " + file.getFileId() + " and descendants in database", e);
704 }
705
706 /// 4. move in local file system
707 String originalLocalPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, file);
708 String targetLocalPath = defaultSavePath + targetPath;
709 File localFile = new File(originalLocalPath);
710 boolean renamed = false;
711 if (localFile.exists()) {
712 File targetFile = new File(targetLocalPath);
713 File targetFolder = targetFile.getParentFile();
714 if (!targetFolder.exists()) {
715 targetFolder.mkdirs();
716 }
717 renamed = localFile.renameTo(targetFile);
718 }
719
720 if (renamed) {
721 Iterator<String> it = originalPathsToTriggerMediaScan.iterator();
722 while (it.hasNext()) {
723 // Notify MediaScanner about removed file
724 deleteFileInMediaScan(it.next());
725 }
726 it = newPathsToTriggerMediaScan.iterator();
727 while (it.hasNext()) {
728 // Notify MediaScanner about new file/folder
729 triggerMediaScan(it.next());
730 }
731 }
732 }
733
734 }
735
736
737 private Vector<OCFile> getFolderContent(long parentId/*, boolean onlyOnDevice*/) {
738
739 Vector<OCFile> ret = new Vector<OCFile>();
740
741 Uri req_uri = Uri.withAppendedPath(
742 ProviderTableMeta.CONTENT_URI_DIR,
743 String.valueOf(parentId));
744 Cursor c = null;
745
746 if (getContentProviderClient() != null) {
747 try {
748 c = getContentProviderClient().query(req_uri, null,
749 ProviderTableMeta.FILE_PARENT + "=?" ,
750 new String[] { String.valueOf(parentId)}, null);
751 } catch (RemoteException e) {
752 Log_OC.e(TAG, e.getMessage());
753 return ret;
754 }
755 } else {
756 c = getContentResolver().query(req_uri, null,
757 ProviderTableMeta.FILE_PARENT + "=?" ,
758 new String[] { String.valueOf(parentId)}, null);
759 }
760
761 if (c.moveToFirst()) {
762 do {
763 OCFile child = createFileInstance(c);
764 // TODO Enable when "On Device" is recovered ?
765 // if (child.isFolder() || !onlyOnDevice || onlyOnDevice && child.isDown()){
766 ret.add(child);
767 // }
768 } while (c.moveToNext());
769 }
770
771 c.close();
772
773 Collections.sort(ret);
774
775 return ret;
776 }
777
778
779 private OCFile createRootDir() {
780 OCFile file = new OCFile(OCFile.ROOT_PATH);
781 file.setMimetype("DIR");
782 file.setParentId(FileDataStorageManager.ROOT_PARENT_ID);
783 saveFile(file);
784 return file;
785 }
786
787 private boolean fileExists(String cmp_key, String value) {
788 Cursor c;
789 if (getContentResolver() != null) {
790 c = getContentResolver()
791 .query(ProviderTableMeta.CONTENT_URI,
792 null,
793 cmp_key + "=? AND "
794 + ProviderTableMeta.FILE_ACCOUNT_OWNER
795 + "=?",
796 new String[] { value, mAccount.name }, null);
797 } else {
798 try {
799 c = getContentProviderClient().query(
800 ProviderTableMeta.CONTENT_URI,
801 null,
802 cmp_key + "=? AND "
803 + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
804 new String[] { value, mAccount.name }, null);
805 } catch (RemoteException e) {
806 Log_OC.e(TAG,
807 "Couldn't determine file existance, assuming non existance: "
808 + e.getMessage());
809 return false;
810 }
811 }
812 boolean retval = c.moveToFirst();
813 c.close();
814 return retval;
815 }
816
817 private Cursor getCursorForValue(String key, String value) {
818 Cursor c = null;
819 if (getContentResolver() != null) {
820 c = getContentResolver()
821 .query(ProviderTableMeta.CONTENT_URI,
822 null,
823 key + "=? AND "
824 + ProviderTableMeta.FILE_ACCOUNT_OWNER
825 + "=?",
826 new String[] { value, mAccount.name }, null);
827 } else {
828 try {
829 c = getContentProviderClient().query(
830 ProviderTableMeta.CONTENT_URI,
831 null,
832 key + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER
833 + "=?", new String[] { value, mAccount.name },
834 null);
835 } catch (RemoteException e) {
836 Log_OC.e(TAG, "Could not get file details: " + e.getMessage());
837 c = null;
838 }
839 }
840 return c;
841 }
842
843
844 private OCFile createFileInstance(Cursor c) {
845 OCFile file = null;
846 if (c != null) {
847 file = new OCFile(c.getString(c
848 .getColumnIndex(ProviderTableMeta.FILE_PATH)));
849 file.setFileId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
850 file.setParentId(c.getLong(c
851 .getColumnIndex(ProviderTableMeta.FILE_PARENT)));
852 file.setMimetype(c.getString(c
853 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
854 if (!file.isFolder()) {
855 file.setStoragePath(c.getString(c
856 .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)));
857 if (file.getStoragePath() == null) {
858 // try to find existing file and bind it with current account;
859 // with the current update of SynchronizeFolderOperation, this won't be
860 // necessary anymore after a full synchronization of the account
861 File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
862 if (f.exists()) {
863 file.setStoragePath(f.getAbsolutePath());
864 file.setLastSyncDateForData(f.lastModified());
865 }
866 }
867 }
868 file.setFileLength(c.getLong(c
869 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH)));
870 file.setCreationTimestamp(c.getLong(c
871 .getColumnIndex(ProviderTableMeta.FILE_CREATION)));
872 file.setModificationTimestamp(c.getLong(c
873 .getColumnIndex(ProviderTableMeta.FILE_MODIFIED)));
874 file.setModificationTimestampAtLastSyncForData(c.getLong(c
875 .getColumnIndex(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA)));
876 file.setLastSyncDateForProperties(c.getLong(c
877 .getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE)));
878 file.setLastSyncDateForData(c.getLong(c.
879 getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA)));
880 file.setFavorite(c.getInt(
881 c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false);
882 file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG)));
883 file.setShareByLink(c.getInt(
884 c.getColumnIndex(ProviderTableMeta.FILE_SHARE_BY_LINK)) == 1 ? true : false);
885 file.setPublicLink(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PUBLIC_LINK)));
886 file.setPermissions(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PERMISSIONS)));
887 file.setRemoteId(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID)));
888 file.setNeedsUpdateThumbnail(c.getInt(
889 c.getColumnIndex(ProviderTableMeta.FILE_UPDATE_THUMBNAIL)) == 1 ? true : false);
890 file.setDownloading(c.getInt(
891 c.getColumnIndex(ProviderTableMeta.FILE_IS_DOWNLOADING)) == 1 ? true : false);
892
893 }
894 return file;
895 }
896
897 /**
898 * Returns if the file/folder is shared by link or not
899 * @param path Path of the file/folder
900 * @return
901 */
902 public boolean isShareByLink(String path) {
903 Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
904 OCFile file = null;
905 if (c.moveToFirst()) {
906 file = createFileInstance(c);
907 }
908 c.close();
909 return file.isShareByLink();
910 }
911
912 /**
913 * Returns the public link of the file/folder
914 * @param path Path of the file/folder
915 * @return
916 */
917 public String getPublicLink(String path) {
918 Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
919 OCFile file = null;
920 if (c.moveToFirst()) {
921 file = createFileInstance(c);
922 }
923 c.close();
924 return file.getPublicLink();
925 }
926
927
928 // Methods for Shares
929 public boolean saveShare(OCShare share) {
930 boolean overriden = false;
931 ContentValues cv = new ContentValues();
932 cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
933 cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
934 cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
935 cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
936 cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
937 cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
938 cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
939 cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
940 cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
941 cv.put(
942 ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
943 share.getSharedWithDisplayName()
944 );
945 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
946 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
947 cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
948 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
949
950 if (shareExists(share.getIdRemoteShared())) { // for renamed files
951
952 overriden = true;
953 if (getContentResolver() != null) {
954 getContentResolver().update(ProviderTableMeta.CONTENT_URI_SHARE, cv,
955 ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
956 new String[] { String.valueOf(share.getIdRemoteShared()) });
957 } else {
958 try {
959 getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_SHARE,
960 cv, ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
961 new String[] { String.valueOf(share.getIdRemoteShared()) });
962 } catch (RemoteException e) {
963 Log_OC.e(TAG,
964 "Fail to insert insert file to database "
965 + e.getMessage());
966 }
967 }
968 } else {
969 Uri result_uri = null;
970 if (getContentResolver() != null) {
971 result_uri = getContentResolver().insert(
972 ProviderTableMeta.CONTENT_URI_SHARE, cv);
973 } else {
974 try {
975 result_uri = getContentProviderClient().insert(
976 ProviderTableMeta.CONTENT_URI_SHARE, cv);
977 } catch (RemoteException e) {
978 Log_OC.e(TAG,
979 "Fail to insert insert file to database "
980 + e.getMessage());
981 }
982 }
983 if (result_uri != null) {
984 long new_id = Long.parseLong(result_uri.getPathSegments()
985 .get(1));
986 share.setId(new_id);
987 }
988 }
989
990 return overriden;
991 }
992
993
994 public OCShare getFirstShareByPathAndType(String path, ShareType type) {
995 Cursor c = null;
996 if (getContentResolver() != null) {
997 c = getContentResolver().query(
998 ProviderTableMeta.CONTENT_URI_SHARE,
999 null,
1000 ProviderTableMeta.OCSHARES_PATH + "=? AND "
1001 + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? AND "
1002 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
1003 new String[] { path, Integer.toString(type.getValue()), mAccount.name },
1004 null);
1005 } else {
1006 try {
1007 c = getContentProviderClient().query(
1008 ProviderTableMeta.CONTENT_URI_SHARE,
1009 null,
1010 ProviderTableMeta.OCSHARES_PATH + "=? AND "
1011 + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? AND "
1012 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
1013 new String[] { path, Integer.toString(type.getValue()), mAccount.name },
1014 null);
1015
1016 } catch (RemoteException e) {
1017 Log_OC.e(TAG, "Could not get file details: " + e.getMessage());
1018 c = null;
1019 }
1020 }
1021 OCShare share = null;
1022 if (c.moveToFirst()) {
1023 share = createShareInstance(c);
1024 }
1025 c.close();
1026 return share;
1027 }
1028
1029 private OCShare createShareInstance(Cursor c) {
1030 OCShare share = null;
1031 if (c != null) {
1032 share = new OCShare(c.getString(c
1033 .getColumnIndex(ProviderTableMeta.OCSHARES_PATH)));
1034 share.setId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
1035 share.setFileSource(c.getLong(c
1036 .getColumnIndex(ProviderTableMeta.OCSHARES_ITEM_SOURCE)));
1037 share.setShareType(ShareType.fromValue(c.getInt(c
1038 .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_TYPE))));
1039 share.setPermissions(c.getInt(c
1040 .getColumnIndex(ProviderTableMeta.OCSHARES_PERMISSIONS)));
1041 share.setSharedDate(c.getLong(c
1042 .getColumnIndex(ProviderTableMeta.OCSHARES_SHARED_DATE)));
1043 share.setExpirationDate(c.getLong(c
1044 .getColumnIndex(ProviderTableMeta.OCSHARES_EXPIRATION_DATE)));
1045 share.setToken(c.getString(c
1046 .getColumnIndex(ProviderTableMeta.OCSHARES_TOKEN)));
1047 share.setSharedWithDisplayName(c.getString(c
1048 .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME)));
1049 share.setIsFolder(c.getInt(
1050 c.getColumnIndex(ProviderTableMeta.OCSHARES_IS_DIRECTORY)) == 1 ? true : false);
1051 share.setUserId(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_USER_ID)));
1052 share.setIdRemoteShared(
1053 c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED))
1054 );
1055
1056 }
1057 return share;
1058 }
1059
1060 private boolean shareExists(String cmp_key, String value) {
1061 Cursor c;
1062 if (getContentResolver() != null) {
1063 c = getContentResolver()
1064 .query(ProviderTableMeta.CONTENT_URI_SHARE,
1065 null,
1066 cmp_key + "=? AND "
1067 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
1068 + "=?",
1069 new String[] { value, mAccount.name }, null);
1070 } else {
1071 try {
1072 c = getContentProviderClient().query(
1073 ProviderTableMeta.CONTENT_URI_SHARE,
1074 null,
1075 cmp_key + "=? AND "
1076 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
1077 new String[] { value, mAccount.name }, null);
1078 } catch (RemoteException e) {
1079 Log_OC.e(TAG,
1080 "Couldn't determine file existance, assuming non existance: "
1081 + e.getMessage());
1082 return false;
1083 }
1084 }
1085 boolean retval = c.moveToFirst();
1086 c.close();
1087 return retval;
1088 }
1089
1090 private boolean shareExists(long remoteId) {
1091 return shareExists(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, String.valueOf(remoteId));
1092 }
1093
1094 private void cleanSharedFiles() {
1095 ContentValues cv = new ContentValues();
1096 cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, false);
1097 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
1098 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
1099 String [] whereArgs = new String[]{mAccount.name};
1100
1101 if (getContentResolver() != null) {
1102 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
1103
1104 } else {
1105 try {
1106 getContentProviderClient().update(
1107 ProviderTableMeta.CONTENT_URI, cv, where, whereArgs
1108 );
1109
1110 } catch (RemoteException e) {
1111 Log_OC.e(TAG, "Exception in cleanSharedFiles" + e.getMessage());
1112 }
1113 }
1114 }
1115
1116 private void cleanSharedFilesInFolder(OCFile folder) {
1117 ContentValues cv = new ContentValues();
1118 cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, false);
1119 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
1120 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
1121 ProviderTableMeta.FILE_PARENT + "=?";
1122 String [] whereArgs = new String[] { mAccount.name , String.valueOf(folder.getFileId()) };
1123
1124 if (getContentResolver() != null) {
1125 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
1126
1127 } else {
1128 try {
1129 getContentProviderClient().update(
1130 ProviderTableMeta.CONTENT_URI, cv, where, whereArgs
1131 );
1132
1133 } catch (RemoteException e) {
1134 Log_OC.e(TAG, "Exception in cleanSharedFilesInFolder " + e.getMessage());
1135 }
1136 }
1137 }
1138
1139 private void cleanShares() {
1140 String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
1141 String [] whereArgs = new String[]{mAccount.name};
1142
1143 if (getContentResolver() != null) {
1144 getContentResolver().delete(ProviderTableMeta.CONTENT_URI_SHARE, where, whereArgs);
1145
1146 } else {
1147 try {
1148 getContentProviderClient().delete(
1149 ProviderTableMeta.CONTENT_URI_SHARE, where, whereArgs
1150 );
1151
1152 } catch (RemoteException e) {
1153 Log_OC.e(TAG, "Exception in cleanShares" + e.getMessage());
1154 }
1155 }
1156 }
1157
1158 public void saveShares(Collection<OCShare> shares) {
1159 cleanShares();
1160 if (shares != null) {
1161 ArrayList<ContentProviderOperation> operations =
1162 new ArrayList<ContentProviderOperation>(shares.size());
1163
1164 // prepare operations to insert or update files to save in the given folder
1165 for (OCShare share : shares) {
1166 ContentValues cv = new ContentValues();
1167 cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
1168 cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
1169 cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
1170 cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
1171 cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
1172 cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
1173 cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
1174 cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
1175 cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
1176 cv.put(
1177 ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
1178 share.getSharedWithDisplayName()
1179 );
1180 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
1181 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
1182 cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
1183 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
1184
1185 if (shareExists(share.getIdRemoteShared())) {
1186 // updating an existing file
1187 operations.add(
1188 ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE).
1189 withValues(cv).
1190 withSelection(
1191 ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
1192 new String[] { String.valueOf(share.getIdRemoteShared()) }
1193 ).
1194 build()
1195 );
1196
1197 } else {
1198 // adding a new file
1199 operations.add(
1200 ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).
1201 withValues(cv).
1202 build()
1203 );
1204 }
1205 }
1206
1207 // apply operations in batch
1208 if (operations.size() > 0) {
1209 @SuppressWarnings("unused")
1210 ContentProviderResult[] results = null;
1211 Log_OC.d(TAG, "Sending " + operations.size() +
1212 " operations to FileContentProvider");
1213 try {
1214 if (getContentResolver() != null) {
1215 results = getContentResolver().applyBatch(
1216 MainApp.getAuthority(), operations
1217 );
1218
1219 } else {
1220 results = getContentProviderClient().applyBatch(operations);
1221 }
1222
1223 } catch (OperationApplicationException e) {
1224 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1225
1226 } catch (RemoteException e) {
1227 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1228 }
1229 }
1230 }
1231
1232 }
1233
1234 public void updateSharedFiles(Collection<OCFile> sharedFiles) {
1235 cleanSharedFiles();
1236
1237 if (sharedFiles != null) {
1238 ArrayList<ContentProviderOperation> operations =
1239 new ArrayList<ContentProviderOperation>(sharedFiles.size());
1240
1241 // prepare operations to insert or update files to save in the given folder
1242 for (OCFile file : sharedFiles) {
1243 ContentValues cv = new ContentValues();
1244 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
1245 cv.put(
1246 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
1247 file.getModificationTimestampAtLastSyncForData()
1248 );
1249 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
1250 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
1251 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
1252 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
1253 cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
1254 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
1255 if (!file.isFolder()) {
1256 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
1257 }
1258 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
1259 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
1260 cv.put(
1261 ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,
1262 file.getLastSyncDateForData()
1263 );
1264 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isFavorite() ? 1 : 0);
1265 cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
1266 cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0);
1267 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
1268 cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
1269 cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
1270 cv.put(
1271 ProviderTableMeta.FILE_UPDATE_THUMBNAIL,
1272 file.needsUpdateThumbnail() ? 1 : 0
1273 );
1274 cv.put(
1275 ProviderTableMeta.FILE_IS_DOWNLOADING,
1276 file.isDownloading() ? 1 : 0
1277 );
1278
1279 boolean existsByPath = fileExists(file.getRemotePath());
1280 if (existsByPath || fileExists(file.getFileId())) {
1281 // updating an existing file
1282 operations.add(
1283 ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
1284 withValues(cv).
1285 withSelection(
1286 ProviderTableMeta._ID + "=?",
1287 new String[] { String.valueOf(file.getFileId()) }
1288 ).build()
1289 );
1290
1291 } else {
1292 // adding a new file
1293 operations.add(
1294 ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).
1295 withValues(cv).
1296 build()
1297 );
1298 }
1299 }
1300
1301 // apply operations in batch
1302 if (operations.size() > 0) {
1303 @SuppressWarnings("unused")
1304 ContentProviderResult[] results = null;
1305 Log_OC.d(TAG, "Sending " + operations.size() +
1306 " operations to FileContentProvider");
1307 try {
1308 if (getContentResolver() != null) {
1309 results = getContentResolver().applyBatch(
1310 MainApp.getAuthority(), operations
1311 );
1312
1313 } else {
1314 results = getContentProviderClient().applyBatch(operations);
1315 }
1316
1317 } catch (OperationApplicationException e) {
1318 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1319
1320 } catch (RemoteException e) {
1321 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1322 }
1323 }
1324 }
1325
1326 }
1327
1328 public void removeShare(OCShare share){
1329 Uri share_uri = ProviderTableMeta.CONTENT_URI_SHARE;
1330 String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?" + " AND " +
1331 ProviderTableMeta.FILE_PATH + "=?";
1332 String [] whereArgs = new String[]{mAccount.name, share.getPath()};
1333 if (getContentProviderClient() != null) {
1334 try {
1335 getContentProviderClient().delete(share_uri, where, whereArgs);
1336 } catch (RemoteException e) {
1337 e.printStackTrace();
1338 }
1339 } else {
1340 getContentResolver().delete(share_uri, where, whereArgs);
1341 }
1342 }
1343
1344 public void saveSharesDB(ArrayList<OCShare> shares) {
1345 saveShares(shares);
1346
1347 ArrayList<OCFile> sharedFiles = new ArrayList<OCFile>();
1348
1349 for (OCShare share : shares) {
1350 // Get the path
1351 String path = share.getPath();
1352 if (share.isFolder()) {
1353 path = path + FileUtils.PATH_SEPARATOR;
1354 }
1355
1356 // Update OCFile with data from share: ShareByLink and publicLink
1357 OCFile file = getFileByPath(path);
1358 if (file != null) {
1359 if (share.getShareType().equals(ShareType.PUBLIC_LINK)) {
1360 file.setShareByLink(true);
1361 sharedFiles.add(file);
1362 }
1363 }
1364 }
1365
1366 updateSharedFiles(sharedFiles);
1367 }
1368
1369
1370 public void saveSharesInFolder(ArrayList<OCShare> shares, OCFile folder) {
1371 cleanSharedFilesInFolder(folder);
1372 ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
1373 operations = prepareRemoveSharesInFolder(folder, operations);
1374
1375 if (shares != null) {
1376 // prepare operations to insert or update files to save in the given folder
1377 for (OCShare share : shares) {
1378 ContentValues cv = new ContentValues();
1379 cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
1380 cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
1381 cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
1382 cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
1383 cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
1384 cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
1385 cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
1386 cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
1387 cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
1388 cv.put(
1389 ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
1390 share.getSharedWithDisplayName()
1391 );
1392 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
1393 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
1394 cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
1395 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
1396
1397 /*
1398 if (shareExists(share.getIdRemoteShared())) {
1399 // updating an existing share resource
1400 operations.add(
1401 ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE).
1402 withValues(cv).
1403 withSelection( ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
1404 new String[] { String.valueOf(share.getIdRemoteShared()) })
1405 .build());
1406
1407 } else {
1408 */
1409 // adding a new share resource
1410 operations.add(
1411 ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).
1412 withValues(cv).
1413 build()
1414 );
1415 //}
1416 }
1417 }
1418
1419 // apply operations in batch
1420 if (operations.size() > 0) {
1421 @SuppressWarnings("unused")
1422 ContentProviderResult[] results = null;
1423 Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
1424 try {
1425 if (getContentResolver() != null) {
1426 results = getContentResolver().applyBatch(MainApp.getAuthority(), operations);
1427
1428 } else {
1429 results = getContentProviderClient().applyBatch(operations);
1430 }
1431
1432 } catch (OperationApplicationException e) {
1433 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1434
1435 } catch (RemoteException e) {
1436 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1437 }
1438 }
1439 //}
1440
1441 }
1442
1443 private ArrayList<ContentProviderOperation> prepareRemoveSharesInFolder(
1444 OCFile folder, ArrayList<ContentProviderOperation> preparedOperations) {
1445 if (folder != null) {
1446 String where = ProviderTableMeta.OCSHARES_PATH + "=?" + " AND "
1447 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
1448 String [] whereArgs = new String[]{ "", mAccount.name };
1449
1450 // TODO Enable when "On Device" is recovered ?
1451 Vector<OCFile> files = getFolderContent(folder /*, false*/);
1452
1453 for (OCFile file : files) {
1454 whereArgs[0] = file.getRemotePath();
1455 preparedOperations.add(
1456 ContentProviderOperation.newDelete(ProviderTableMeta.CONTENT_URI_SHARE).
1457 withSelection(where, whereArgs).
1458 build()
1459 );
1460 }
1461 }
1462 return preparedOperations;
1463
1464 /*
1465 if (operations.size() > 0) {
1466 try {
1467 if (getContentResolver() != null) {
1468 getContentResolver().applyBatch(MainApp.getAuthority(), operations);
1469
1470 } else {
1471 getContentProviderClient().applyBatch(operations);
1472 }
1473
1474 } catch (OperationApplicationException e) {
1475 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1476
1477 } catch (RemoteException e) {
1478 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1479 }
1480 }
1481 */
1482
1483 /*
1484 if (getContentResolver() != null) {
1485
1486 getContentResolver().delete(ProviderTableMeta.CONTENT_URI_SHARE,
1487 where,
1488 whereArgs);
1489 } else {
1490 try {
1491 getContentProviderClient().delete( ProviderTableMeta.CONTENT_URI_SHARE,
1492 where,
1493 whereArgs);
1494
1495 } catch (RemoteException e) {
1496 Log_OC.e(TAG, "Exception deleting shares in a folder " + e.getMessage());
1497 }
1498 }
1499 */
1500 //}
1501 }
1502
1503 public void triggerMediaScan(String path) {
1504 Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
1505 intent.setData(Uri.fromFile(new File(path)));
1506 MainApp.getAppContext().sendBroadcast(intent);
1507 }
1508
1509 public void deleteFileInMediaScan(String path) {
1510
1511 String mimetypeString = FileStorageUtils.getMimeTypeFromName(path);
1512 ContentResolver contentResolver = getContentResolver();
1513
1514 if (contentResolver != null) {
1515 if (mimetypeString.startsWith("image/")) {
1516 // Images
1517 contentResolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
1518 MediaStore.Images.Media.DATA + "=?", new String[]{path});
1519 } else if (mimetypeString.startsWith("audio/")) {
1520 // Audio
1521 contentResolver.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1522 MediaStore.Audio.Media.DATA + "=?", new String[]{path});
1523 } else if (mimetypeString.startsWith("video/")) {
1524 // Video
1525 contentResolver.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
1526 MediaStore.Video.Media.DATA + "=?", new String[]{path});
1527 }
1528 } else {
1529 ContentProviderClient contentProviderClient = getContentProviderClient();
1530 try {
1531 if (mimetypeString.startsWith("image/")) {
1532 // Images
1533 contentProviderClient.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
1534 MediaStore.Images.Media.DATA + "=?", new String[]{path});
1535 } else if (mimetypeString.startsWith("audio/")) {
1536 // Audio
1537 contentProviderClient.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1538 MediaStore.Audio.Media.DATA + "=?", new String[]{path});
1539 } else if (mimetypeString.startsWith("video/")) {
1540 // Video
1541 contentProviderClient.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
1542 MediaStore.Video.Media.DATA + "=?", new String[]{path});
1543 }
1544 } catch (RemoteException e) {
1545 Log_OC.e(TAG, "Exception deleting media file in MediaStore " + e.getMessage());
1546 }
1547 }
1548
1549 }
1550
1551 }