2 * ownCloud Android client application
4 * Copyright (C) 2012 Bartek Przybylski
5 * Copyright (C) 2015 ownCloud Inc.
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.
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.
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/>.
21 package com
.owncloud
.android
.datamodel
;
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
;
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
;
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
;
53 public class FileDataStorageManager
{
55 public static final int ROOT_PARENT_ID
= 0;
57 private ContentResolver mContentResolver
;
58 private ContentProviderClient mContentProviderClient
;
59 private Account mAccount
;
61 private static String TAG
= FileDataStorageManager
.class.getSimpleName();
64 public FileDataStorageManager(Account account
, ContentResolver cr
) {
65 mContentProviderClient
= null
;
66 mContentResolver
= cr
;
70 public FileDataStorageManager(Account account
, ContentProviderClient cp
) {
71 mContentProviderClient
= cp
;
72 mContentResolver
= null
;
77 public void setAccount(Account account
) {
81 public Account
getAccount() {
85 public void setContentResolver(ContentResolver cr
) {
86 mContentResolver
= cr
;
89 public ContentResolver
getContentResolver() {
90 return mContentResolver
;
93 public void setContentProviderClient(ContentProviderClient cp
) {
94 mContentProviderClient
= cp
;
97 public ContentProviderClient
getContentProviderClient() {
98 return mContentProviderClient
;
102 public OCFile
getFileByPath(String path
) {
103 Cursor c
= getCursorForValue(ProviderTableMeta
.FILE_PATH
, path
);
105 if (c
.moveToFirst()) {
106 file
= createFileInstance(c
);
109 if (file
== null
&& OCFile
.ROOT_PATH
.equals(path
)) {
110 return createRootDir(); // root should always exist
116 public OCFile
getFileById(long id
) {
117 Cursor c
= getCursorForValue(ProviderTableMeta
._ID
, String
.valueOf(id
));
119 if (c
.moveToFirst()) {
120 file
= createFileInstance(c
);
126 public OCFile
getFileByLocalPath(String path
) {
127 Cursor c
= getCursorForValue(ProviderTableMeta
.FILE_STORAGE_PATH
, path
);
129 if (c
.moveToFirst()) {
130 file
= createFileInstance(c
);
136 public boolean fileExists(long id
) {
137 return fileExists(ProviderTableMeta
._ID
, String
.valueOf(id
));
140 public boolean fileExists(String path
) {
141 return fileExists(ProviderTableMeta
.FILE_PATH
, path
);
145 public Vector
<OCFile
> getFolderContent(OCFile f
) {
146 if (f
!= null
&& f
.isFolder() && f
.getFileId() != -1) {
147 return getFolderContent(f
.getFileId());
150 return new Vector
<OCFile
>();
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()) {
172 public boolean saveFile(OCFile file
) {
173 boolean overriden
= false
;
174 ContentValues cv
= new ContentValues();
175 cv
.put(ProviderTableMeta
.FILE_MODIFIED
, file
.getModificationTimestamp());
177 ProviderTableMeta
.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA
,
178 file
.getModificationTimestampAtLastSyncForData()
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());
201 boolean sameRemotePath
= fileExists(file
.getRemotePath());
202 if (sameRemotePath
||
203 fileExists(file
.getFileId()) ) { // for renamed files
205 OCFile oldFile
= null
;
206 if (sameRemotePath
) {
207 oldFile
= getFileByPath(file
.getRemotePath());
208 file
.setFileId(oldFile
.getFileId());
210 oldFile
= getFileById(file
.getFileId());
214 if (getContentResolver() != null
) {
215 getContentResolver().update(ProviderTableMeta
.CONTENT_URI
, cv
,
216 ProviderTableMeta
._ID
+ "=?",
217 new String
[] { String
.valueOf(file
.getFileId()) });
220 getContentProviderClient().update(ProviderTableMeta
.CONTENT_URI
,
221 cv
, ProviderTableMeta
._ID
+ "=?",
222 new String
[] { String
.valueOf(file
.getFileId()) });
223 } catch (RemoteException e
) {
225 "Fail to insert insert file to database "
230 Uri result_uri
= null
;
231 if (getContentResolver() != null
) {
232 result_uri
= getContentResolver().insert(
233 ProviderTableMeta
.CONTENT_URI_FILE
, cv
);
236 result_uri
= getContentProviderClient().insert(
237 ProviderTableMeta
.CONTENT_URI_FILE
, cv
);
238 } catch (RemoteException e
) {
240 "Fail to insert insert file to database "
244 if (result_uri
!= null
) {
245 long new_id
= Long
.parseLong(result_uri
.getPathSegments()
247 file
.setFileId(new_id
);
251 // if (file.isFolder()) {
252 // updateFolderSize(file.getFileId());
254 // updateFolderSize(file.getParentId());
262 * Inserts or updates the list of files contained in a given folder.
264 * CALLER IS THE RESPONSIBLE FOR GRANTING RIGHT UPDATE OF INFORMATION, NOT THIS METHOD.
265 * HERE ONLY DATA CONSISTENCY SHOULD BE GRANTED
268 * @param updatedFiles
269 * @param filesToRemove
271 public void saveFolder(
272 OCFile folder
, Collection
<OCFile
> updatedFiles
, Collection
<OCFile
> filesToRemove
275 Log_OC
.d(TAG
, "Saving folder " + folder
.getRemotePath() + " with " + updatedFiles
.size()
276 + " children and " + filesToRemove
.size() + " files to remove");
278 ArrayList
<ContentProviderOperation
> operations
=
279 new ArrayList
<ContentProviderOperation
>(updatedFiles
.size());
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());
286 ProviderTableMeta
.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA
,
287 file
.getModificationTimestampAtLastSyncForData()
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());
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());
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
).
316 withSelection( ProviderTableMeta
._ID
+ "=?",
317 new String
[] { String
.valueOf(file
.getFileId()) })
322 operations
.add(ContentProviderOperation
.newInsert(ProviderTableMeta
.CONTENT_URI
).
323 withValues(cv
).build());
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()
340 ).withSelection(where
, whereArgs
).build());
343 new File(FileStorageUtils
.getDefaultSavePathFor(mAccount
.name
, file
));
344 if (localFolder
.exists()) {
345 removeLocalFolder(localFolder
);
348 operations
.add(ContentProviderOperation
.newDelete(
349 ContentUris
.withAppendedId(
350 ProviderTableMeta
.CONTENT_URI_FILE
, file
.getFileId()
352 ).withSelection(where
, whereArgs
).build());
355 String path
= file
.getStoragePath();
356 new File(path
).delete();
357 triggerMediaScan(path
); // notify MediaScanner about removed file
363 // update metadata of folder
364 ContentValues cv
= new ContentValues();
365 cv
.put(ProviderTableMeta
.FILE_MODIFIED
, folder
.getModificationTimestamp());
367 ProviderTableMeta
.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA
,
368 folder
.getModificationTimestampAtLastSyncForData()
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());
386 operations
.add(ContentProviderOperation
.newUpdate(ProviderTableMeta
.CONTENT_URI
).
388 withSelection( ProviderTableMeta
._ID
+ "=?",
389 new String
[] { String
.valueOf(folder
.getFileId()) })
392 // apply operations in batch
393 ContentProviderResult
[] results
= null
;
394 Log_OC
.d(TAG
, "Sending " + operations
.size() + " operations to FileContentProvider");
396 if (getContentResolver() != null
) {
397 results
= getContentResolver().applyBatch(MainApp
.getAuthority(), operations
);
400 results
= getContentProviderClient().applyBatch(operations
);
403 } catch (OperationApplicationException e
) {
404 Log_OC
.e(TAG
, "Exception in batch of operations " + e
.getMessage());
406 } catch (RemoteException e
) {
407 Log_OC
.e(TAG
, "Exception in batch of operations " + e
.getMessage());
410 // update new id in file objects for insertions
411 if (results
!= null
) {
413 Iterator
<OCFile
> filesIt
= updatedFiles
.iterator();
415 for (int i
=0; i
<results
.length
; i
++) {
416 if (filesIt
.hasNext()) {
417 file
= filesIt
.next();
421 if (results
[i
].uri
!= null
) {
422 newId
= Long
.parseLong(results
[i
].uri
.getPathSegments().get(1));
423 //updatedFiles.get(i).setFileId(newId);
425 file
.setFileId(newId
);
431 //updateFolderSize(folder.getFileId());
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) });
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) });
457 // } catch (RemoteException e) {
459 // TAG, "Exception in update of folder size through compatibility patch " + e.getMessage());
463 // Log_OC.e(TAG, "not updating size for folder " + id);
468 public boolean removeFile(OCFile file
, boolean removeDBData
, boolean removeLocalCopy
) {
469 boolean success
= true
;
471 if (file
.isFolder()) {
472 success
= removeFolder(file
, removeDBData
, removeLocalCopy
);
476 Uri file_uri
= ContentUris
.withAppendedId(
477 ProviderTableMeta
.CONTENT_URI_FILE
,
480 String where
= ProviderTableMeta
.FILE_ACCOUNT_OWNER
+ "=?" + " AND " +
481 ProviderTableMeta
.FILE_PATH
+ "=?";
482 String
[] whereArgs
= new String
[]{mAccount
.name
, file
.getRemotePath()};
484 if (getContentProviderClient() != null
) {
486 deleted
= getContentProviderClient().delete(file_uri
, where
, whereArgs
);
487 } catch (RemoteException e
) {
491 deleted
= getContentResolver().delete(file_uri
, where
, whereArgs
);
493 success
&= (deleted
> 0);
495 String localPath
= file
.getStoragePath();
496 if (removeLocalCopy
&& file
.isDown() && localPath
!= null
&& success
) {
497 success
= new File(localPath
).delete();
499 deleteFileInMediaScan(localPath
);
501 if (!removeDBData
&& success
) {
502 // maybe unnecessary, but should be checked TODO remove if unnecessary
503 file
.setStoragePath(null
);
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
);
519 if (removeLocalContent
&& success
) {
520 success
= removeLocalFolder(folder
);
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()};
533 if (getContentProviderClient() != null
) {
535 deleted
= getContentProviderClient().delete(folder_uri
, where
, whereArgs
);
536 } catch (RemoteException e
) {
540 deleted
= getContentResolver().delete(folder_uri
, where
, whereArgs
);
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());
553 for (OCFile file
: files
) {
554 if (file
.isFolder()) {
555 success
&= removeLocalFolder(file
);
558 File localFile
= new File(file
.getStoragePath());
559 success
&= localFile
.delete();
561 // notify MediaScanner about removed file
562 deleteFileInMediaScan(file
.getStoragePath());
563 file
.setStoragePath(null
);
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
);
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
);
586 String path
= localFile
.getAbsolutePath();
587 success
&= localFile
.delete();
591 success
&= localFolder
.delete();
597 * Updates database and file system for a file or folder that was moved to a different location.
599 * TODO explore better (faster) implementations
600 * TODO throw exceptions up !
602 public void moveLocalFile(OCFile file
, String targetPath
, String targetParentPath
) {
604 if (file
!= null
&& file
.fileExists() && !OCFile
.ROOT_PATH
.equals(file
.getFileName())) {
606 OCFile targetParent
= getFileByPath(targetParentPath
);
607 if (targetParent
== null
) {
608 throw new IllegalStateException("Parent folder of the target path does not exist!!");
611 /// 1. get all the descendants of the moved element in a single QUERY
613 if (getContentProviderClient() != null
) {
615 c
= getContentProviderClient().query(
616 ProviderTableMeta
.CONTENT_URI
,
618 ProviderTableMeta
.FILE_ACCOUNT_OWNER
+ "=? AND " +
619 ProviderTableMeta
.FILE_PATH
+ " LIKE ? ",
622 file
.getRemotePath() + "%"
624 ProviderTableMeta
.FILE_PATH
+ " ASC "
626 } catch (RemoteException e
) {
627 Log_OC
.e(TAG
, e
.getMessage());
631 c
= getContentResolver().query(
632 ProviderTableMeta
.CONTENT_URI
,
634 ProviderTableMeta
.FILE_ACCOUNT_OWNER
+ "=? AND " +
635 ProviderTableMeta
.FILE_PATH
+ " LIKE ? ",
638 file
.getRemotePath() + "%"
640 ProviderTableMeta
.FILE_PATH
+ " ASC "
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
;
654 ContentValues cv
= new ContentValues(); // keep construction in the loop
655 OCFile child
= createFileInstance(c
);
657 ProviderTableMeta
.FILE_PATH
,
658 targetPath
+ child
.getRemotePath().substring(lengthOfOldPath
)
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
);
666 cv
.put(ProviderTableMeta
.FILE_STORAGE_PATH
, targetLocalPath
);
668 originalPathsToTriggerMediaScan
.add(child
.getStoragePath());
669 newPathsToTriggerMediaScan
.add(targetLocalPath
);
672 if (child
.getRemotePath().equals(file
.getRemotePath())) {
674 ProviderTableMeta
.FILE_PARENT
,
675 targetParent
.getFileId()
679 ContentProviderOperation
.newUpdate(ProviderTableMeta
.CONTENT_URI
).
682 ProviderTableMeta
._ID
+ "=?",
683 new String
[] { String
.valueOf(child
.getFileId()) }
687 } while (c
.moveToNext());
691 /// 3. apply updates in batch
693 if (getContentResolver() != null
) {
694 getContentResolver().applyBatch(MainApp
.getAuthority(), operations
);
697 getContentProviderClient().applyBatch(operations
);
700 } catch (Exception e
) {
701 Log_OC
.e(TAG
, "Fail to update " + file
.getFileId() + " and descendants in database", e
);
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();
715 renamed
= localFile
.renameTo(targetFile
);
719 Iterator
<String
> it
= originalPathsToTriggerMediaScan
.iterator();
720 while (it
.hasNext()) {
721 // Notify MediaScanner about removed file
722 deleteFileInMediaScan(it
.next());
724 it
= newPathsToTriggerMediaScan
.iterator();
725 while (it
.hasNext()) {
726 // Notify MediaScanner about new file/folder
727 triggerMediaScan(it
.next());
735 private Vector
<OCFile
> getFolderContent(long parentId
) {
737 Vector
<OCFile
> ret
= new Vector
<OCFile
>();
739 Uri req_uri
= Uri
.withAppendedPath(
740 ProviderTableMeta
.CONTENT_URI_DIR
,
741 String
.valueOf(parentId
));
744 if (getContentProviderClient() != null
) {
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());
754 c
= getContentResolver().query(req_uri
, null
,
755 ProviderTableMeta
.FILE_PARENT
+ "=?" ,
756 new String
[] { String
.valueOf(parentId
)}, null
);
759 if (c
.moveToFirst()) {
761 OCFile child
= createFileInstance(c
);
763 } while (c
.moveToNext());
768 Collections
.sort(ret
);
774 private OCFile
createRootDir() {
775 OCFile file
= new OCFile(OCFile
.ROOT_PATH
);
776 file
.setMimetype("DIR");
777 file
.setParentId(FileDataStorageManager
.ROOT_PARENT_ID
);
782 private boolean fileExists(String cmp_key
, String value
) {
784 if (getContentResolver() != null
) {
785 c
= getContentResolver()
786 .query(ProviderTableMeta
.CONTENT_URI
,
789 + ProviderTableMeta
.FILE_ACCOUNT_OWNER
791 new String
[] { value
, mAccount
.name
}, null
);
794 c
= getContentProviderClient().query(
795 ProviderTableMeta
.CONTENT_URI
,
798 + ProviderTableMeta
.FILE_ACCOUNT_OWNER
+ "=?",
799 new String
[] { value
, mAccount
.name
}, null
);
800 } catch (RemoteException e
) {
802 "Couldn't determine file existance, assuming non existance: "
807 boolean retval
= c
.moveToFirst();
812 private Cursor
getCursorForValue(String key
, String value
) {
814 if (getContentResolver() != null
) {
815 c
= getContentResolver()
816 .query(ProviderTableMeta
.CONTENT_URI
,
819 + ProviderTableMeta
.FILE_ACCOUNT_OWNER
821 new String
[] { value
, mAccount
.name
}, null
);
824 c
= getContentProviderClient().query(
825 ProviderTableMeta
.CONTENT_URI
,
827 key
+ "=? AND " + ProviderTableMeta
.FILE_ACCOUNT_OWNER
828 + "=?", new String
[] { value
, mAccount
.name
},
830 } catch (RemoteException e
) {
831 Log_OC
.e(TAG
, "Could not get file details: " + e
.getMessage());
839 private OCFile
createFileInstance(Cursor c
) {
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
));
858 file
.setStoragePath(f
.getAbsolutePath());
859 file
.setLastSyncDateForData(f
.lastModified());
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
);
893 * Returns if the file/folder is shared by link or not
894 * @param path Path of the file/folder
897 public boolean isShareByLink(String path
) {
898 Cursor c
= getCursorForValue(ProviderTableMeta
.FILE_STORAGE_PATH
, path
);
900 if (c
.moveToFirst()) {
901 file
= createFileInstance(c
);
904 return file
.isShareByLink();
908 * Returns the public link of the file/folder
909 * @param path Path of the file/folder
912 public String
getPublicLink(String path
) {
913 Cursor c
= getCursorForValue(ProviderTableMeta
.FILE_STORAGE_PATH
, path
);
915 if (c
.moveToFirst()) {
916 file
= createFileInstance(c
);
919 return file
.getPublicLink();
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());
937 ProviderTableMeta
.OCSHARES_SHARE_WITH_DISPLAY_NAME
,
938 share
.getSharedWithDisplayName()
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
);
945 if (shareExists(share
.getIdRemoteShared())) { // for renamed files
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()) });
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
) {
959 "Fail to insert insert file to database "
964 Uri result_uri
= null
;
965 if (getContentResolver() != null
) {
966 result_uri
= getContentResolver().insert(
967 ProviderTableMeta
.CONTENT_URI_SHARE
, cv
);
970 result_uri
= getContentProviderClient().insert(
971 ProviderTableMeta
.CONTENT_URI_SHARE
, cv
);
972 } catch (RemoteException e
) {
974 "Fail to insert insert file to database "
978 if (result_uri
!= null
) {
979 long new_id
= Long
.parseLong(result_uri
.getPathSegments()
989 public OCShare
getFirstShareByPathAndType(String path
, ShareType type
) {
991 if (getContentResolver() != null
) {
992 c
= getContentResolver().query(
993 ProviderTableMeta
.CONTENT_URI_SHARE
,
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
},
1002 c
= getContentProviderClient().query(
1003 ProviderTableMeta
.CONTENT_URI_SHARE
,
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
},
1011 } catch (RemoteException e
) {
1012 Log_OC
.e(TAG
, "Could not get file details: " + e
.getMessage());
1016 OCShare share
= null
;
1017 if (c
.moveToFirst()) {
1018 share
= createShareInstance(c
);
1024 private OCShare
createShareInstance(Cursor c
) {
1025 OCShare share
= 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
))
1055 private boolean shareExists(String cmp_key
, String value
) {
1057 if (getContentResolver() != null
) {
1058 c
= getContentResolver()
1059 .query(ProviderTableMeta
.CONTENT_URI_SHARE
,
1062 + ProviderTableMeta
.OCSHARES_ACCOUNT_OWNER
1064 new String
[] { value
, mAccount
.name
}, null
);
1067 c
= getContentProviderClient().query(
1068 ProviderTableMeta
.CONTENT_URI_SHARE
,
1071 + ProviderTableMeta
.OCSHARES_ACCOUNT_OWNER
+ "=?",
1072 new String
[] { value
, mAccount
.name
}, null
);
1073 } catch (RemoteException e
) {
1075 "Couldn't determine file existance, assuming non existance: "
1080 boolean retval
= c
.moveToFirst();
1085 private boolean shareExists(long remoteId
) {
1086 return shareExists(ProviderTableMeta
.OCSHARES_ID_REMOTE_SHARED
, String
.valueOf(remoteId
));
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
};
1096 if (getContentResolver() != null
) {
1097 getContentResolver().update(ProviderTableMeta
.CONTENT_URI
, cv
, where
, whereArgs
);
1101 getContentProviderClient().update(
1102 ProviderTableMeta
.CONTENT_URI
, cv
, where
, whereArgs
1105 } catch (RemoteException e
) {
1106 Log_OC
.e(TAG
, "Exception in cleanSharedFiles" + e
.getMessage());
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()) };
1119 if (getContentResolver() != null
) {
1120 getContentResolver().update(ProviderTableMeta
.CONTENT_URI
, cv
, where
, whereArgs
);
1124 getContentProviderClient().update(
1125 ProviderTableMeta
.CONTENT_URI
, cv
, where
, whereArgs
1128 } catch (RemoteException e
) {
1129 Log_OC
.e(TAG
, "Exception in cleanSharedFilesInFolder " + e
.getMessage());
1134 private void cleanShares() {
1135 String where
= ProviderTableMeta
.OCSHARES_ACCOUNT_OWNER
+ "=?";
1136 String
[] whereArgs
= new String
[]{mAccount
.name
};
1138 if (getContentResolver() != null
) {
1139 getContentResolver().delete(ProviderTableMeta
.CONTENT_URI_SHARE
, where
, whereArgs
);
1143 getContentProviderClient().delete(
1144 ProviderTableMeta
.CONTENT_URI_SHARE
, where
, whereArgs
1147 } catch (RemoteException e
) {
1148 Log_OC
.e(TAG
, "Exception in cleanShares" + e
.getMessage());
1153 public void saveShares(Collection
<OCShare
> shares
) {
1155 if (shares
!= null
) {
1156 ArrayList
<ContentProviderOperation
> operations
=
1157 new ArrayList
<ContentProviderOperation
>(shares
.size());
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());
1172 ProviderTableMeta
.OCSHARES_SHARE_WITH_DISPLAY_NAME
,
1173 share
.getSharedWithDisplayName()
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
);
1180 if (shareExists(share
.getIdRemoteShared())) {
1181 // updating an existing file
1183 ContentProviderOperation
.newUpdate(ProviderTableMeta
.CONTENT_URI_SHARE
).
1186 ProviderTableMeta
.OCSHARES_ID_REMOTE_SHARED
+ "=?",
1187 new String
[] { String
.valueOf(share
.getIdRemoteShared()) }
1193 // adding a new file
1195 ContentProviderOperation
.newInsert(ProviderTableMeta
.CONTENT_URI_SHARE
).
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");
1209 if (getContentResolver() != null
) {
1210 results
= getContentResolver().applyBatch(
1211 MainApp
.getAuthority(), operations
1215 results
= getContentProviderClient().applyBatch(operations
);
1218 } catch (OperationApplicationException e
) {
1219 Log_OC
.e(TAG
, "Exception in batch of operations " + e
.getMessage());
1221 } catch (RemoteException e
) {
1222 Log_OC
.e(TAG
, "Exception in batch of operations " + e
.getMessage());
1229 public void updateSharedFiles(Collection
<OCFile
> sharedFiles
) {
1232 if (sharedFiles
!= null
) {
1233 ArrayList
<ContentProviderOperation
> operations
=
1234 new ArrayList
<ContentProviderOperation
>(sharedFiles
.size());
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());
1241 ProviderTableMeta
.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA
,
1242 file
.getModificationTimestampAtLastSyncForData()
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());
1253 cv
.put(ProviderTableMeta
.FILE_ACCOUNT_OWNER
, mAccount
.name
);
1254 cv
.put(ProviderTableMeta
.FILE_LAST_SYNC_DATE
, file
.getLastSyncDateForProperties());
1256 ProviderTableMeta
.FILE_LAST_SYNC_DATE_FOR_DATA
,
1257 file
.getLastSyncDateForData()
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());
1266 ProviderTableMeta
.FILE_UPDATE_THUMBNAIL
,
1267 file
.needsUpdateThumbnail() ?
1 : 0
1270 ProviderTableMeta
.FILE_IS_DOWNLOADING
,
1271 file
.isDownloading() ?
1 : 0
1274 boolean existsByPath
= fileExists(file
.getRemotePath());
1275 if (existsByPath
|| fileExists(file
.getFileId())) {
1276 // updating an existing file
1278 ContentProviderOperation
.newUpdate(ProviderTableMeta
.CONTENT_URI
).
1281 ProviderTableMeta
._ID
+ "=?",
1282 new String
[] { String
.valueOf(file
.getFileId()) }
1287 // adding a new file
1289 ContentProviderOperation
.newInsert(ProviderTableMeta
.CONTENT_URI
).
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");
1303 if (getContentResolver() != null
) {
1304 results
= getContentResolver().applyBatch(
1305 MainApp
.getAuthority(), operations
1309 results
= getContentProviderClient().applyBatch(operations
);
1312 } catch (OperationApplicationException e
) {
1313 Log_OC
.e(TAG
, "Exception in batch of operations " + e
.getMessage());
1315 } catch (RemoteException e
) {
1316 Log_OC
.e(TAG
, "Exception in batch of operations " + e
.getMessage());
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
) {
1330 getContentProviderClient().delete(share_uri
, where
, whereArgs
);
1331 } catch (RemoteException e
) {
1332 e
.printStackTrace();
1335 getContentResolver().delete(share_uri
, where
, whereArgs
);
1339 public void saveSharesDB(ArrayList
<OCShare
> shares
) {
1342 ArrayList
<OCFile
> sharedFiles
= new ArrayList
<OCFile
>();
1344 for (OCShare share
: shares
) {
1346 String path
= share
.getPath();
1347 if (share
.isFolder()) {
1348 path
= path
+ FileUtils
.PATH_SEPARATOR
;
1351 // Update OCFile with data from share: ShareByLink and publicLink
1352 OCFile file
= getFileByPath(path
);
1354 if (share
.getShareType().equals(ShareType
.PUBLIC_LINK
)) {
1355 file
.setShareByLink(true
);
1356 sharedFiles
.add(file
);
1361 updateSharedFiles(sharedFiles
);
1365 public void saveSharesInFolder(ArrayList
<OCShare
> shares
, OCFile folder
) {
1366 cleanSharedFilesInFolder(folder
);
1367 ArrayList
<ContentProviderOperation
> operations
= new ArrayList
<ContentProviderOperation
>();
1368 operations
= prepareRemoveSharesInFolder(folder
, operations
);
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());
1384 ProviderTableMeta
.OCSHARES_SHARE_WITH_DISPLAY_NAME
,
1385 share
.getSharedWithDisplayName()
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
);
1393 if (shareExists(share.getIdRemoteShared())) {
1394 // updating an existing share resource
1396 ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE).
1398 withSelection( ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
1399 new String[] { String.valueOf(share.getIdRemoteShared()) })
1404 // adding a new share resource
1406 ContentProviderOperation
.newInsert(ProviderTableMeta
.CONTENT_URI_SHARE
).
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");
1420 if (getContentResolver() != null
) {
1421 results
= getContentResolver().applyBatch(MainApp
.getAuthority(), operations
);
1424 results
= getContentProviderClient().applyBatch(operations
);
1427 } catch (OperationApplicationException e
) {
1428 Log_OC
.e(TAG
, "Exception in batch of operations " + e
.getMessage());
1430 } catch (RemoteException e
) {
1431 Log_OC
.e(TAG
, "Exception in batch of operations " + e
.getMessage());
1438 private ArrayList
<ContentProviderOperation
> prepareRemoveSharesInFolder(
1439 OCFile folder
, ArrayList
<ContentProviderOperation
> preparedOperations
1441 if (folder
!= null
) {
1442 String where
= ProviderTableMeta
.OCSHARES_PATH
+ "=?" + " AND "
1443 + ProviderTableMeta
.OCSHARES_ACCOUNT_OWNER
+ "=?";
1444 String
[] whereArgs
= new String
[]{ "", mAccount
.name
};
1446 Vector
<OCFile
> files
= getFolderContent(folder
);
1448 for (OCFile file
: files
) {
1449 whereArgs
[0] = file
.getRemotePath();
1450 preparedOperations
.add(
1451 ContentProviderOperation
.newDelete(ProviderTableMeta
.CONTENT_URI_SHARE
).
1452 withSelection(where
, whereArgs
).
1457 return preparedOperations
;
1460 if (operations.size() > 0) {
1462 if (getContentResolver() != null) {
1463 getContentResolver().applyBatch(MainApp.getAuthority(), operations);
1466 getContentProviderClient().applyBatch(operations);
1469 } catch (OperationApplicationException e) {
1470 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1472 } catch (RemoteException e) {
1473 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1479 if (getContentResolver() != null) {
1481 getContentResolver().delete(ProviderTableMeta.CONTENT_URI_SHARE,
1486 getContentProviderClient().delete( ProviderTableMeta.CONTENT_URI_SHARE,
1490 } catch (RemoteException e) {
1491 Log_OC.e(TAG, "Exception deleting shares in a folder " + e.getMessage());
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
);
1504 public void deleteFileInMediaScan(String path
) {
1506 String mimetypeString
= FileStorageUtils
.getMimeTypeFromName(path
);
1507 ContentResolver contentResolver
= getContentResolver();
1509 if (contentResolver
!= null
) {
1510 if (mimetypeString
.startsWith("image/")) {
1512 contentResolver
.delete(MediaStore
.Images
.Media
.EXTERNAL_CONTENT_URI
,
1513 MediaStore
.Images
.Media
.DATA
+ "=?", new String
[]{path
});
1514 } else if (mimetypeString
.startsWith("audio/")) {
1516 contentResolver
.delete(MediaStore
.Audio
.Media
.EXTERNAL_CONTENT_URI
,
1517 MediaStore
.Audio
.Media
.DATA
+ "=?", new String
[]{path
});
1518 } else if (mimetypeString
.startsWith("video/")) {
1520 contentResolver
.delete(MediaStore
.Video
.Media
.EXTERNAL_CONTENT_URI
,
1521 MediaStore
.Video
.Media
.DATA
+ "=?", new String
[]{path
});
1524 ContentProviderClient contentProviderClient
= getContentProviderClient();
1526 if (mimetypeString
.startsWith("image/")) {
1528 contentProviderClient
.delete(MediaStore
.Images
.Media
.EXTERNAL_CONTENT_URI
,
1529 MediaStore
.Images
.Media
.DATA
+ "=?", new String
[]{path
});
1530 } else if (mimetypeString
.startsWith("audio/")) {
1532 contentProviderClient
.delete(MediaStore
.Audio
.Media
.EXTERNAL_CONTENT_URI
,
1533 MediaStore
.Audio
.Media
.DATA
+ "=?", new String
[]{path
});
1534 } else if (mimetypeString
.startsWith("video/")) {
1536 contentProviderClient
.delete(MediaStore
.Video
.Media
.EXTERNAL_CONTENT_URI
,
1537 MediaStore
.Video
.Media
.DATA
+ "=?", new String
[]{path
});
1539 } catch (RemoteException e
) {
1540 Log_OC
.e(TAG
, "Exception deleting media file in MediaStore " + e
.getMessage());