d43de6a06d9dca5f1734ab636ce09f85aaa53f47
[pub/Android/ownCloud.git] / src / com / owncloud / android / datamodel / FileDataStorageManager.java
1 /* ownCloud Android client application
2 * Copyright (C) 2012 Bartek Przybylski
3 * Copyright (C) 2012-2013 ownCloud Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 package com.owncloud.android.datamodel;
20
21 import java.io.File;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Iterator;
26 import java.util.Vector;
27
28 import com.owncloud.android.Log_OC;
29 import com.owncloud.android.db.ProviderMeta;
30 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
31 import com.owncloud.android.utils.FileStorageUtils;
32
33 import android.accounts.Account;
34 import android.content.ContentProviderClient;
35 import android.content.ContentProviderOperation;
36 import android.content.ContentProviderResult;
37 import android.content.ContentResolver;
38 import android.content.ContentUris;
39 import android.content.ContentValues;
40 import android.content.OperationApplicationException;
41 import android.database.Cursor;
42 import android.net.Uri;
43 import android.os.RemoteException;
44
45 public class FileDataStorageManager {
46
47 public static final int ROOT_PARENT_ID = 0;
48
49 private ContentResolver mContentResolver;
50 private ContentProviderClient mContentProviderClient;
51 private Account mAccount;
52
53 private static String TAG = FileDataStorageManager.class.getSimpleName();
54
55
56 public FileDataStorageManager(Account account, ContentResolver cr) {
57 mContentProviderClient = null;
58 mContentResolver = cr;
59 mAccount = account;
60 }
61
62 public FileDataStorageManager(Account account, ContentProviderClient cp) {
63 mContentProviderClient = cp;
64 mContentResolver = null;
65 mAccount = account;
66 }
67
68
69 public void setAccount(Account account) {
70 mAccount = account;
71 }
72
73 public Account getAccount() {
74 return mAccount;
75 }
76
77 public void setContentResolver(ContentResolver cr) {
78 mContentResolver = cr;
79 }
80
81 public ContentResolver getContentResolver() {
82 return mContentResolver;
83 }
84
85 public void setContentProviderClient(ContentProviderClient cp) {
86 mContentProviderClient = cp;
87 }
88
89 public ContentProviderClient getContentProviderClient() {
90 return mContentProviderClient;
91 }
92
93
94 public OCFile getFileByPath(String path) {
95 Cursor c = getCursorForValue(ProviderTableMeta.FILE_PATH, path);
96 OCFile file = null;
97 if (c.moveToFirst()) {
98 file = createFileInstance(c);
99 }
100 c.close();
101 if (file == null && OCFile.ROOT_PATH.equals(path)) {
102 return createRootDir(); // root should always exist
103 }
104 return file;
105 }
106
107
108 public OCFile getFileById(long id) {
109 Cursor c = getCursorForValue(ProviderTableMeta._ID, String.valueOf(id));
110 OCFile file = null;
111 if (c.moveToFirst()) {
112 file = createFileInstance(c);
113 }
114 c.close();
115 return file;
116 }
117
118 public OCFile getFileByLocalPath(String path) {
119 Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
120 OCFile file = null;
121 if (c.moveToFirst()) {
122 file = createFileInstance(c);
123 }
124 c.close();
125 return file;
126 }
127
128 public boolean fileExists(long id) {
129 return fileExists(ProviderTableMeta._ID, String.valueOf(id));
130 }
131
132 public boolean fileExists(String path) {
133 return fileExists(ProviderTableMeta.FILE_PATH, path);
134 }
135
136
137 public Vector<OCFile> getFolderContent(OCFile f) {
138 if (f != null && f.isFolder() && f.getFileId() != -1) {
139 return getFolderContent(f.getFileId());
140
141 } else {
142 return new Vector<OCFile>();
143 }
144 }
145
146
147 public Vector<OCFile> getFolderImages(OCFile folder) {
148 Vector<OCFile> ret = new Vector<OCFile>();
149 if (folder != null) {
150 // TODO better implementation, filtering in the access to database (if possible) instead of here
151 Vector<OCFile> tmp = getFolderContent(folder);
152 OCFile current = null;
153 for (int i=0; i<tmp.size(); i++) {
154 current = tmp.get(i);
155 if (current.isImage()) {
156 ret.add(current);
157 }
158 }
159 }
160 return ret;
161 }
162
163
164 public boolean saveFile(OCFile file) {
165 boolean overriden = false;
166 ContentValues cv = new ContentValues();
167 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
168 cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData());
169 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
170 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
171 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
172 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
173 //if (file.getParentId() != DataStorageManager.ROOT_PARENT_ID)
174 cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
175 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
176 if (!file.isFolder())
177 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
178 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
179 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
180 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
181 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
182 cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
183
184 boolean sameRemotePath = fileExists(file.getRemotePath());
185 boolean changesSizeOfAncestors = false;
186 if (sameRemotePath ||
187 fileExists(file.getFileId()) ) { // for renamed files; no more delete and create
188
189 OCFile oldFile = null;
190 if (sameRemotePath) {
191 oldFile = getFileByPath(file.getRemotePath());
192 file.setFileId(oldFile.getFileId());
193 } else {
194 oldFile = getFileById(file.getFileId());
195 }
196 changesSizeOfAncestors = (oldFile.getFileLength() != file.getFileLength());
197
198 overriden = true;
199 if (getContentResolver() != null) {
200 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv,
201 ProviderTableMeta._ID + "=?",
202 new String[] { String.valueOf(file.getFileId()) });
203 } else {
204 try {
205 getContentProviderClient().update(ProviderTableMeta.CONTENT_URI,
206 cv, ProviderTableMeta._ID + "=?",
207 new String[] { String.valueOf(file.getFileId()) });
208 } catch (RemoteException e) {
209 Log_OC.e(TAG,
210 "Fail to insert insert file to database "
211 + e.getMessage());
212 }
213 }
214 } else {
215 changesSizeOfAncestors = true;
216 Uri result_uri = null;
217 if (getContentResolver() != null) {
218 result_uri = getContentResolver().insert(
219 ProviderTableMeta.CONTENT_URI_FILE, cv);
220 } else {
221 try {
222 result_uri = getContentProviderClient().insert(
223 ProviderTableMeta.CONTENT_URI_FILE, cv);
224 } catch (RemoteException e) {
225 Log_OC.e(TAG,
226 "Fail to insert insert file to database "
227 + e.getMessage());
228 }
229 }
230 if (result_uri != null) {
231 long new_id = Long.parseLong(result_uri.getPathSegments()
232 .get(1));
233 file.setFileId(new_id);
234 }
235 }
236
237 if (file.isFolder()) {
238 calculateFolderSize(file.getFileId());
239 if (file.needsUpdatingWhileSaving()) {
240 for (OCFile f : getFolderContent(file))
241 saveFile(f);
242 }
243 }
244
245 if (changesSizeOfAncestors || file.isFolder()) {
246 updateSizesToTheRoot(file.getParentId());
247 }
248
249 return overriden;
250 }
251
252
253 /**
254 * Inserts or updates the list of files contained in a given folder.
255 *
256 * @param folder
257 * @param files
258 * @param removeNotUpdated
259 */
260 public void saveFolder(OCFile folder, Collection<OCFile> updatedFiles, Collection<OCFile> filesToRemove) {
261
262 Log_OC.d(TAG, "Saving folder " + folder.getRemotePath() + " with " + updatedFiles.size() + " children and " + filesToRemove.size() + " files to remove");
263
264 ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(updatedFiles.size());
265
266 // prepare operations to insert or update files to save in the given folder
267 for (OCFile file : updatedFiles) {
268 ContentValues cv = new ContentValues();
269 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
270 cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData());
271 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
272 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
273 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
274 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
275 //cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
276 cv.put(ProviderTableMeta.FILE_PARENT, folder.getFileId());
277 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
278 if (!file.isFolder()) {
279 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
280 }
281 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
282 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
283 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
284 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
285 cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
286
287 boolean existsByPath = fileExists(file.getRemotePath());
288 if (existsByPath || fileExists(file.getFileId())) {
289 // updating an existing file
290
291 /* CALLER IS THE RESPONSIBLE FOR GRANTING RIGHT UPDATE OF INFORMATION, NOT THIS METHOD.
292 *
293 * HERE ONLY DATA CONSISTENCY SHOULD BE GRANTED
294 */
295 /*
296 OCFile oldFile = null;
297 if (existsByPath) {
298 // grant same id
299 oldFile = getFileByPath(file.getRemotePath());
300 file.setFileId(oldFile.getFileId());
301 } else {
302 oldFile = getFileById(file.getFileId());
303 }
304
305 if (file.isFolder()) {
306 // folders keep size information, since it's calculated
307 file.setFileLength(oldFile.getFileLength());
308 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, oldFile.getFileLength());
309
310 } else if (file.getStoragePath() == null && oldFile.getStoragePath() != null) {
311 // regular files keep access to local contents, although it's lost in the new OCFile
312 file.setStoragePath(oldFile.getStoragePath());
313 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, oldFile.getStoragePath());
314 }
315 */
316
317 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
318 withValues(cv).
319 withSelection( ProviderTableMeta._ID + "=?",
320 new String[] { String.valueOf(file.getFileId()) })
321 .build());
322
323 } else {
324 // adding a new file
325 operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build());
326 }
327 }
328
329 // prepare operations to remove files in the given folder
330 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
331 String [] whereArgs = null;
332 for (OCFile file : filesToRemove) {
333 if (file.getParentId() == folder.getFileId()) {
334 whereArgs = new String[]{mAccount.name, file.getRemotePath()};
335 //Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, "" + file.getFileId());
336 if (file.isFolder()) {
337 operations.add(ContentProviderOperation
338 .newDelete(ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, file.getFileId())).withSelection(where, whereArgs)
339 .build());
340 // TODO remove local folder
341 } else {
342 operations.add(ContentProviderOperation
343 .newDelete(ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId())).withSelection(where, whereArgs)
344 .build());
345 if (file.isDown()) {
346 new File(file.getStoragePath()).delete();
347 // TODO move the deletion of local contents after success of deletions
348 }
349 }
350 }
351 }
352
353 // update metadata of folder --> TODO MOVE UPDATE OF SIZE TO CONTENTPROVIDER
354 ContentValues cv = new ContentValues();
355 cv.put(ProviderTableMeta.FILE_MODIFIED, folder.getModificationTimestamp());
356 cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, folder.getModificationTimestampAtLastSyncForData());
357 cv.put(ProviderTableMeta.FILE_CREATION, folder.getCreationTimestamp());
358 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, folder.getFileLength());
359 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, folder.getMimetype());
360 cv.put(ProviderTableMeta.FILE_NAME, folder.getFileName());
361 cv.put(ProviderTableMeta.FILE_PARENT, folder.getParentId());
362 cv.put(ProviderTableMeta.FILE_PATH, folder.getRemotePath());
363 if (!folder.isFolder()) {
364 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, folder.getStoragePath());
365 }
366 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
367 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, folder.getLastSyncDateForProperties());
368 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, folder.getLastSyncDateForData());
369 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, folder.keepInSync() ? 1 : 0);
370 cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag());
371 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
372 withValues(cv).
373 withSelection( ProviderTableMeta._ID + "=?",
374 new String[] { String.valueOf(folder.getFileId()) })
375 .build());
376
377 // apply operations in batch
378 ContentProviderResult[] results = null;
379 Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
380 try {
381 if (getContentResolver() != null) {
382 results = getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations);
383
384 } else {
385 results = getContentProviderClient().applyBatch(operations);
386 }
387
388 } catch (OperationApplicationException e) {
389 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
390
391 } catch (RemoteException e) {
392 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
393 }
394
395 // update new id in file objects for insertions
396 if (results != null) {
397 long newId;
398 Iterator<OCFile> filesIt = updatedFiles.iterator();
399 OCFile file = null;
400 for (int i=0; i<results.length; i++) {
401 if (filesIt.hasNext()) {
402 file = filesIt.next();
403 } else {
404 file = null;
405 }
406 if (results[i].uri != null) {
407 newId = Long.parseLong(results[i].uri.getPathSegments().get(1));
408 //updatedFiles.get(i).setFileId(newId);
409 if (file != null) {
410 file.setFileId(newId);
411 }
412 }
413 }
414 }
415
416 }
417
418
419 /**
420 * Calculate and save the folderSize on DB
421 * @param id
422 */
423 public void calculateFolderSize(long id) {
424 long folderSize = 0;
425
426 Vector<OCFile> files = getFolderContent(id);
427
428 for (OCFile f: files)
429 {
430 folderSize = folderSize + f.getFileLength();
431 }
432
433 updateSize(id, folderSize);
434 }
435
436
437 public void removeFile(OCFile file, boolean removeDBData, boolean removeLocalCopy) {
438 if (file != null) {
439 if (file.isFolder()) {
440 removeFolder(file, removeDBData, removeLocalCopy);
441
442 } else {
443 if (removeDBData) {
444 //Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, ""+file.getFileId());
445 Uri file_uri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId());
446 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
447 String [] whereArgs = new String[]{mAccount.name, file.getRemotePath()};
448 if (getContentProviderClient() != null) {
449 try {
450 getContentProviderClient().delete(file_uri, where, whereArgs);
451 } catch (RemoteException e) {
452 e.printStackTrace();
453 }
454 } else {
455 getContentResolver().delete(file_uri, where, whereArgs);
456 }
457 if (file.getFileLength() > 0) {
458 updateSizesToTheRoot(file.getParentId()); // TODO move to content provider
459 }
460 }
461 if (removeLocalCopy && file.isDown()) {
462 boolean success = new File(file.getStoragePath()).delete();
463 if (!removeDBData && success) {
464 // maybe unnecessary, but should be checked TODO remove if unnecessary
465 file.setStoragePath(null);
466 saveFile(file);
467 }
468 }
469 }
470 }
471 }
472
473
474 public void removeFolder(OCFile folder, boolean removeDBData, boolean removeLocalContent) {
475 if (folder != null && folder.isFolder()) {
476 if (removeDBData && folder.getFileId() != -1) {
477 removeFolderInDb(folder);
478 }
479 if (removeLocalContent) {
480 File localFolder = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder));
481 removeLocalFolder(localFolder);
482 }
483 }
484 }
485
486 private void removeFolderInDb(OCFile folder) {
487 Uri folder_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, ""+ folder.getFileId()); // URI for recursive deletion
488 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
489 String [] whereArgs = new String[]{mAccount.name, folder.getRemotePath()};
490 if (getContentProviderClient() != null) {
491 try {
492 getContentProviderClient().delete(folder_uri, where, whereArgs);
493 } catch (RemoteException e) {
494 e.printStackTrace();
495 }
496 } else {
497 getContentResolver().delete(folder_uri, where, whereArgs);
498 }
499 if (folder.getFileLength() > 0) {
500 updateSizesToTheRoot(folder.getParentId()); // TODO move to FileContentProvider
501 }
502 }
503
504 private void removeLocalFolder(File folder) {
505 if (folder.exists()) {
506 File[] files = folder.listFiles();
507 if (files != null) {
508 for (File file : files) {
509 if (file.isDirectory()) {
510 removeLocalFolder(file);
511 } else {
512 file.delete();
513 }
514 }
515 }
516 folder.delete();
517 }
518 }
519
520 /**
521 * Updates database for a folder that was moved to a different location.
522 *
523 * TODO explore better (faster) implementations
524 * TODO throw exceptions up !
525 */
526 public void moveFolder(OCFile folder, String newPath) {
527 // TODO check newPath
528
529 if (folder != null && folder.isFolder() && folder.fileExists() && !OCFile.ROOT_PATH.equals(folder.getFileName())) {
530 /// 1. get all the descendants of 'dir' in a single QUERY (including 'dir')
531 Cursor c = null;
532 if (getContentProviderClient() != null) {
533 try {
534 c = getContentProviderClient().query(ProviderTableMeta.CONTENT_URI,
535 null,
536 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ? ",
537 new String[] { mAccount.name, folder.getRemotePath() + "%" }, ProviderTableMeta.FILE_PATH + " ASC ");
538 } catch (RemoteException e) {
539 Log_OC.e(TAG, e.getMessage());
540 }
541 } else {
542 c = getContentResolver().query(ProviderTableMeta.CONTENT_URI,
543 null,
544 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ? ",
545 new String[] { mAccount.name, folder.getRemotePath() + "%" }, ProviderTableMeta.FILE_PATH + " ASC ");
546 }
547
548 /// 2. prepare a batch of update operations to change all the descendants
549 ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(c.getCount());
550 int lengthOfOldPath = folder.getRemotePath().length();
551 String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
552 int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
553 if (c.moveToFirst()) {
554 do {
555 ContentValues cv = new ContentValues(); // don't take the constructor out of the loop and clear the object
556 OCFile child = createFileInstance(c);
557 cv.put(ProviderTableMeta.FILE_PATH, newPath + child.getRemotePath().substring(lengthOfOldPath));
558 if (child.getStoragePath() != null && child.getStoragePath().startsWith(defaultSavePath)) {
559 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, defaultSavePath + newPath + child.getStoragePath().substring(lengthOfOldStoragePath));
560 }
561 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
562 withValues(cv).
563 withSelection( ProviderTableMeta._ID + "=?",
564 new String[] { String.valueOf(child.getFileId()) })
565 .build());
566 } while (c.moveToNext());
567 }
568 c.close();
569
570 /// 3. apply updates in batch
571 try {
572 if (getContentResolver() != null) {
573 getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations);
574
575 } else {
576 getContentProviderClient().applyBatch(operations);
577 }
578
579 } catch (OperationApplicationException e) {
580 Log_OC.e(TAG, "Fail to update descendants of " + folder.getFileId() + " in database", e);
581
582 } catch (RemoteException e) {
583 Log_OC.e(TAG, "Fail to update desendants of " + folder.getFileId() + " in database", e);
584 }
585
586 }
587 }
588
589
590 private Vector<OCFile> getFolderContent(long parentId) {
591
592 Vector<OCFile> ret = new Vector<OCFile>();
593
594 Uri req_uri = Uri.withAppendedPath(
595 ProviderTableMeta.CONTENT_URI_DIR,
596 String.valueOf(parentId));
597 Cursor c = null;
598
599 if (getContentProviderClient() != null) {
600 try {
601 c = getContentProviderClient().query(req_uri, null,
602 ProviderTableMeta.FILE_PARENT + "=?" ,
603 new String[] { String.valueOf(parentId)}, null);
604 } catch (RemoteException e) {
605 Log_OC.e(TAG, e.getMessage());
606 return ret;
607 }
608 } else {
609 c = getContentResolver().query(req_uri, null,
610 ProviderTableMeta.FILE_PARENT + "=?" ,
611 new String[] { String.valueOf(parentId)}, null);
612 }
613
614 if (c.moveToFirst()) {
615 do {
616 OCFile child = createFileInstance(c);
617 ret.add(child);
618 } while (c.moveToNext());
619 }
620
621 c.close();
622
623 Collections.sort(ret);
624
625 return ret;
626 }
627
628
629 private OCFile createRootDir() {
630 OCFile file = new OCFile(OCFile.ROOT_PATH);
631 file.setMimetype("DIR");
632 file.setParentId(FileDataStorageManager.ROOT_PARENT_ID);
633 saveFile(file);
634 return file;
635 }
636
637 private boolean fileExists(String cmp_key, String value) {
638 Cursor c;
639 if (getContentResolver() != null) {
640 c = getContentResolver()
641 .query(ProviderTableMeta.CONTENT_URI,
642 null,
643 cmp_key + "=? AND "
644 + ProviderTableMeta.FILE_ACCOUNT_OWNER
645 + "=?",
646 new String[] { value, mAccount.name }, null);
647 } else {
648 try {
649 c = getContentProviderClient().query(
650 ProviderTableMeta.CONTENT_URI,
651 null,
652 cmp_key + "=? AND "
653 + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
654 new String[] { value, mAccount.name }, null);
655 } catch (RemoteException e) {
656 Log_OC.e(TAG,
657 "Couldn't determine file existance, assuming non existance: "
658 + e.getMessage());
659 return false;
660 }
661 }
662 boolean retval = c.moveToFirst();
663 c.close();
664 return retval;
665 }
666
667 private Cursor getCursorForValue(String key, String value) {
668 Cursor c = null;
669 if (getContentResolver() != null) {
670 c = getContentResolver()
671 .query(ProviderTableMeta.CONTENT_URI,
672 null,
673 key + "=? AND "
674 + ProviderTableMeta.FILE_ACCOUNT_OWNER
675 + "=?",
676 new String[] { value, mAccount.name }, null);
677 } else {
678 try {
679 c = getContentProviderClient().query(
680 ProviderTableMeta.CONTENT_URI,
681 null,
682 key + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER
683 + "=?", new String[] { value, mAccount.name },
684 null);
685 } catch (RemoteException e) {
686 Log_OC.e(TAG, "Could not get file details: " + e.getMessage());
687 c = null;
688 }
689 }
690 return c;
691 }
692
693 private OCFile createFileInstance(Cursor c) {
694 OCFile file = null;
695 if (c != null) {
696 file = new OCFile(c.getString(c
697 .getColumnIndex(ProviderTableMeta.FILE_PATH)));
698 file.setFileId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
699 file.setParentId(c.getLong(c
700 .getColumnIndex(ProviderTableMeta.FILE_PARENT)));
701 file.setMimetype(c.getString(c
702 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
703 if (!file.isFolder()) {
704 file.setStoragePath(c.getString(c
705 .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)));
706 if (file.getStoragePath() == null) {
707 // try to find existing file and bind it with current account; - with the current update of SynchronizeFolderOperation, this won't be necessary anymore after a full synchronization of the account
708 File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
709 if (f.exists()) {
710 file.setStoragePath(f.getAbsolutePath());
711 file.setLastSyncDateForData(f.lastModified());
712 }
713 }
714 }
715 file.setFileLength(c.getLong(c
716 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH)));
717 file.setCreationTimestamp(c.getLong(c
718 .getColumnIndex(ProviderTableMeta.FILE_CREATION)));
719 file.setModificationTimestamp(c.getLong(c
720 .getColumnIndex(ProviderTableMeta.FILE_MODIFIED)));
721 file.setModificationTimestampAtLastSyncForData(c.getLong(c
722 .getColumnIndex(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA)));
723 file.setLastSyncDateForProperties(c.getLong(c
724 .getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE)));
725 file.setLastSyncDateForData(c.getLong(c.
726 getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA)));
727 file.setKeepInSync(c.getInt(
728 c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false);
729 file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG)));
730
731 }
732 return file;
733 }
734
735 /**
736 * Update the size value of an OCFile in DB
737 */
738 private int updateSize(long id, long size) {
739 ContentValues cv = new ContentValues();
740 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, size);
741 int result = -1;
742 if (getContentResolver() != null) {
743 result = getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, ProviderTableMeta._ID + "=?",
744 new String[] { String.valueOf(id) });
745 } else {
746 try {
747 result = getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, ProviderTableMeta._ID + "=?",
748 new String[] { String.valueOf(id) });
749 } catch (RemoteException e) {
750 Log_OC.e(TAG,"Fail to update size column into database " + e.getMessage());
751 }
752 }
753 return result;
754 }
755
756 /**
757 * Update the size of a subtree of folder from a file to the root
758 * @param parentId: parent of the file
759 */
760 private void updateSizesToTheRoot(long parentId) {
761
762 OCFile file;
763
764 while (parentId != FileDataStorageManager.ROOT_PARENT_ID) {
765
766 // Update the size of the parent
767 calculateFolderSize(parentId);
768
769 // search the next parent
770 file = getFileById(parentId);
771 parentId = file.getParentId();
772
773 }
774
775 }
776
777 }