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