5709dc1921fe5d6eb6d6edbddbb57de7a600456d
[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.MainApp;
29 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
30 import com.owncloud.android.lib.operations.common.ShareType;
31 import com.owncloud.android.utils.FileStorageUtils;
32 import com.owncloud.android.utils.Log_OC;
33
34
35 import android.accounts.Account;
36 import android.content.ContentProviderClient;
37 import android.content.ContentProviderOperation;
38 import android.content.ContentProviderResult;
39 import android.content.ContentResolver;
40 import android.content.ContentUris;
41 import android.content.ContentValues;
42 import android.content.OperationApplicationException;
43 import android.database.Cursor;
44 import android.net.Uri;
45 import android.os.RemoteException;
46
47 public class FileDataStorageManager {
48
49 public static final int ROOT_PARENT_ID = 0;
50
51 private ContentResolver mContentResolver;
52 private ContentProviderClient mContentProviderClient;
53 private Account mAccount;
54
55 private static String TAG = FileDataStorageManager.class.getSimpleName();
56
57
58 public FileDataStorageManager(Account account, ContentResolver cr) {
59 mContentProviderClient = null;
60 mContentResolver = cr;
61 mAccount = account;
62 }
63
64 public FileDataStorageManager(Account account, ContentProviderClient cp) {
65 mContentProviderClient = cp;
66 mContentResolver = null;
67 mAccount = account;
68 }
69
70
71 public void setAccount(Account account) {
72 mAccount = account;
73 }
74
75 public Account getAccount() {
76 return mAccount;
77 }
78
79 public void setContentResolver(ContentResolver cr) {
80 mContentResolver = cr;
81 }
82
83 public ContentResolver getContentResolver() {
84 return mContentResolver;
85 }
86
87 public void setContentProviderClient(ContentProviderClient cp) {
88 mContentProviderClient = cp;
89 }
90
91 public ContentProviderClient getContentProviderClient() {
92 return mContentProviderClient;
93 }
94
95
96 public OCFile getFileByPath(String path) {
97 Cursor c = getCursorForValue(ProviderTableMeta.FILE_PATH, path);
98 OCFile file = null;
99 if (c.moveToFirst()) {
100 file = createFileInstance(c);
101 }
102 c.close();
103 if (file == null && OCFile.ROOT_PATH.equals(path)) {
104 return createRootDir(); // root should always exist
105 }
106 return file;
107 }
108
109
110 public OCFile getFileById(long id) {
111 Cursor c = getCursorForValue(ProviderTableMeta._ID, String.valueOf(id));
112 OCFile file = null;
113 if (c.moveToFirst()) {
114 file = createFileInstance(c);
115 }
116 c.close();
117 return file;
118 }
119
120 public OCFile getFileByLocalPath(String path) {
121 Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
122 OCFile file = null;
123 if (c.moveToFirst()) {
124 file = createFileInstance(c);
125 }
126 c.close();
127 return file;
128 }
129
130 public boolean fileExists(long id) {
131 return fileExists(ProviderTableMeta._ID, String.valueOf(id));
132 }
133
134 public boolean fileExists(String path) {
135 return fileExists(ProviderTableMeta.FILE_PATH, path);
136 }
137
138
139 public Vector<OCFile> getFolderContent(OCFile f) {
140 if (f != null && f.isFolder() && f.getFileId() != -1) {
141 return getFolderContent(f.getFileId());
142
143 } else {
144 return new Vector<OCFile>();
145 }
146 }
147
148
149 public Vector<OCFile> getFolderImages(OCFile folder) {
150 Vector<OCFile> ret = new Vector<OCFile>();
151 if (folder != null) {
152 // TODO better implementation, filtering in the access to database (if possible) instead of here
153 Vector<OCFile> tmp = getFolderContent(folder);
154 OCFile current = null;
155 for (int i=0; i<tmp.size(); i++) {
156 current = tmp.get(i);
157 if (current.isImage()) {
158 ret.add(current);
159 }
160 }
161 }
162 return ret;
163 }
164
165
166 public boolean saveFile(OCFile file) {
167 boolean overriden = false;
168 ContentValues cv = new ContentValues();
169 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
170 cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData());
171 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
172 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
173 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
174 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
175 //if (file.getParentId() != DataStorageManager.ROOT_PARENT_ID)
176 cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
177 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
178 if (!file.isFolder())
179 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
180 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
181 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
182 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
183 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
184 cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
185 cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0);
186 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
187
188 boolean sameRemotePath = fileExists(file.getRemotePath());
189 if (sameRemotePath ||
190 fileExists(file.getFileId()) ) { // for renamed files; no more delete and create
191
192 OCFile oldFile = null;
193 if (sameRemotePath) {
194 oldFile = getFileByPath(file.getRemotePath());
195 file.setFileId(oldFile.getFileId());
196 } else {
197 oldFile = getFileById(file.getFileId());
198 }
199
200 overriden = true;
201 if (getContentResolver() != null) {
202 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv,
203 ProviderTableMeta._ID + "=?",
204 new String[] { String.valueOf(file.getFileId()) });
205 } else {
206 try {
207 getContentProviderClient().update(ProviderTableMeta.CONTENT_URI,
208 cv, ProviderTableMeta._ID + "=?",
209 new String[] { String.valueOf(file.getFileId()) });
210 } catch (RemoteException e) {
211 Log_OC.e(TAG,
212 "Fail to insert insert file to database "
213 + e.getMessage());
214 }
215 }
216 } else {
217 Uri result_uri = null;
218 if (getContentResolver() != null) {
219 result_uri = getContentResolver().insert(
220 ProviderTableMeta.CONTENT_URI_FILE, cv);
221 } else {
222 try {
223 result_uri = getContentProviderClient().insert(
224 ProviderTableMeta.CONTENT_URI_FILE, cv);
225 } catch (RemoteException e) {
226 Log_OC.e(TAG,
227 "Fail to insert insert file to database "
228 + e.getMessage());
229 }
230 }
231 if (result_uri != null) {
232 long new_id = Long.parseLong(result_uri.getPathSegments()
233 .get(1));
234 file.setFileId(new_id);
235 }
236 }
237
238 if (file.isFolder()) {
239 updateFolderSize(file.getFileId());
240 } else {
241 updateFolderSize(file.getParentId());
242 }
243
244 return overriden;
245 }
246
247
248 /**
249 * Inserts or updates the list of files contained in a given folder.
250 *
251 * CALLER IS THE RESPONSIBLE FOR GRANTING RIGHT UPDATE OF INFORMATION, NOT THIS METHOD.
252 * HERE ONLY DATA CONSISTENCY SHOULD BE GRANTED
253 *
254 * @param folder
255 * @param files
256 * @param removeNotUpdated
257 */
258 public void saveFolder(OCFile folder, Collection<OCFile> updatedFiles, Collection<OCFile> filesToRemove) {
259
260 Log_OC.d(TAG, "Saving folder " + folder.getRemotePath() + " with " + updatedFiles.size() + " children and " + filesToRemove.size() + " files to remove");
261
262 ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(updatedFiles.size());
263
264 // prepare operations to insert or update files to save in the given folder
265 for (OCFile file : updatedFiles) {
266 ContentValues cv = new ContentValues();
267 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
268 cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData());
269 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
270 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
271 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
272 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
273 //cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
274 cv.put(ProviderTableMeta.FILE_PARENT, folder.getFileId());
275 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
276 if (!file.isFolder()) {
277 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
278 }
279 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
280 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
281 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
282 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
283 cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
284 cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, file.isShareByLink() ? 1 : 0);
285 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
286
287 boolean existsByPath = fileExists(file.getRemotePath());
288 if (existsByPath || fileExists(file.getFileId())) {
289 // updating an existing file
290 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
291 withValues(cv).
292 withSelection( ProviderTableMeta._ID + "=?",
293 new String[] { String.valueOf(file.getFileId()) })
294 .build());
295
296 } else {
297 // adding a new file
298 operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build());
299 }
300 }
301
302 // prepare operations to remove files in the given folder
303 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
304 String [] whereArgs = null;
305 for (OCFile file : filesToRemove) {
306 if (file.getParentId() == folder.getFileId()) {
307 whereArgs = new String[]{mAccount.name, file.getRemotePath()};
308 //Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, "" + file.getFileId());
309 if (file.isFolder()) {
310 operations.add(ContentProviderOperation
311 .newDelete(ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, file.getFileId())).withSelection(where, whereArgs)
312 .build());
313 // TODO remove local folder
314 } else {
315 operations.add(ContentProviderOperation
316 .newDelete(ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId())).withSelection(where, whereArgs)
317 .build());
318 if (file.isDown()) {
319 new File(file.getStoragePath()).delete();
320 // TODO move the deletion of local contents after success of deletions
321 }
322 }
323 }
324 }
325
326 // update metadata of folder
327 ContentValues cv = new ContentValues();
328 cv.put(ProviderTableMeta.FILE_MODIFIED, folder.getModificationTimestamp());
329 cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, folder.getModificationTimestampAtLastSyncForData());
330 cv.put(ProviderTableMeta.FILE_CREATION, folder.getCreationTimestamp());
331 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, 0); // FileContentProvider calculates the right size
332 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, folder.getMimetype());
333 cv.put(ProviderTableMeta.FILE_NAME, folder.getFileName());
334 cv.put(ProviderTableMeta.FILE_PARENT, folder.getParentId());
335 cv.put(ProviderTableMeta.FILE_PATH, folder.getRemotePath());
336 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
337 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, folder.getLastSyncDateForProperties());
338 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, folder.getLastSyncDateForData());
339 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, folder.keepInSync() ? 1 : 0);
340 cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag());
341 cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, folder.isShareByLink() ? 1 : 0);
342 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, folder.getPublicLink());
343
344 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
345 withValues(cv).
346 withSelection( ProviderTableMeta._ID + "=?",
347 new String[] { String.valueOf(folder.getFileId()) })
348 .build());
349
350 // apply operations in batch
351 ContentProviderResult[] results = null;
352 Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
353 try {
354 if (getContentResolver() != null) {
355 results = getContentResolver().applyBatch(MainApp.getAuthority(), operations);
356
357 } else {
358 results = getContentProviderClient().applyBatch(operations);
359 }
360
361 } catch (OperationApplicationException e) {
362 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
363
364 } catch (RemoteException e) {
365 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
366 }
367
368 // update new id in file objects for insertions
369 if (results != null) {
370 long newId;
371 Iterator<OCFile> filesIt = updatedFiles.iterator();
372 OCFile file = null;
373 for (int i=0; i<results.length; i++) {
374 if (filesIt.hasNext()) {
375 file = filesIt.next();
376 } else {
377 file = null;
378 }
379 if (results[i].uri != null) {
380 newId = Long.parseLong(results[i].uri.getPathSegments().get(1));
381 //updatedFiles.get(i).setFileId(newId);
382 if (file != null) {
383 file.setFileId(newId);
384 }
385 }
386 }
387 }
388
389 updateFolderSize(folder.getFileId());
390
391 }
392
393
394 /**
395 *
396 * @param id
397 */
398 private void updateFolderSize(long id) {
399 if (id > FileDataStorageManager.ROOT_PARENT_ID) {
400 Log_OC.d(TAG, "Updating size of " + id);
401 if (getContentResolver() != null) {
402 getContentResolver().update(ProviderTableMeta.CONTENT_URI_DIR,
403 new ContentValues(), // won't be used, but cannot be null; crashes in KLP
404 ProviderTableMeta._ID + "=?",
405 new String[] { String.valueOf(id) });
406 } else {
407 try {
408 getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_DIR,
409 new ContentValues(), // won't be used, but cannot be null; crashes in KLP
410 ProviderTableMeta._ID + "=?",
411 new String[] { String.valueOf(id) });
412
413 } catch (RemoteException e) {
414 Log_OC.e(TAG, "Exception in update of folder size through compatibility patch " + e.getMessage());
415 }
416 }
417 } else {
418 Log_OC.e(TAG, "not updating size for folder " + id);
419 }
420 }
421
422
423 public void removeFile(OCFile file, boolean removeDBData, boolean removeLocalCopy) {
424 if (file != null) {
425 if (file.isFolder()) {
426 removeFolder(file, removeDBData, removeLocalCopy);
427
428 } else {
429 if (removeDBData) {
430 //Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, ""+file.getFileId());
431 Uri file_uri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId());
432 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
433 String [] whereArgs = new String[]{mAccount.name, file.getRemotePath()};
434 if (getContentProviderClient() != null) {
435 try {
436 getContentProviderClient().delete(file_uri, where, whereArgs);
437 } catch (RemoteException e) {
438 e.printStackTrace();
439 }
440 } else {
441 getContentResolver().delete(file_uri, where, whereArgs);
442 }
443 updateFolderSize(file.getParentId());
444 }
445 if (removeLocalCopy && file.isDown() && file.getStoragePath() != null) {
446 boolean success = new File(file.getStoragePath()).delete();
447 if (!removeDBData && success) {
448 // maybe unnecessary, but should be checked TODO remove if unnecessary
449 file.setStoragePath(null);
450 saveFile(file);
451 }
452 }
453 }
454 }
455 }
456
457
458 public void removeFolder(OCFile folder, boolean removeDBData, boolean removeLocalContent) {
459 if (folder != null && folder.isFolder()) {
460 if (removeDBData && folder.getFileId() != -1) {
461 removeFolderInDb(folder);
462 }
463 if (removeLocalContent) {
464 File localFolder = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder));
465 removeLocalFolder(localFolder);
466 }
467 }
468 }
469
470 private void removeFolderInDb(OCFile folder) {
471 Uri folder_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, ""+ folder.getFileId()); // URI for recursive deletion
472 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
473 String [] whereArgs = new String[]{mAccount.name, folder.getRemotePath()};
474 if (getContentProviderClient() != null) {
475 try {
476 getContentProviderClient().delete(folder_uri, where, whereArgs);
477 } catch (RemoteException e) {
478 e.printStackTrace();
479 }
480 } else {
481 getContentResolver().delete(folder_uri, where, whereArgs);
482 }
483 updateFolderSize(folder.getParentId());
484 }
485
486 private void removeLocalFolder(File folder) {
487 if (folder.exists()) {
488 File[] files = folder.listFiles();
489 if (files != null) {
490 for (File file : files) {
491 if (file.isDirectory()) {
492 removeLocalFolder(file);
493 } else {
494 file.delete();
495 }
496 }
497 }
498 folder.delete();
499 }
500 }
501
502 /**
503 * Updates database for a folder that was moved to a different location.
504 *
505 * TODO explore better (faster) implementations
506 * TODO throw exceptions up !
507 */
508 public void moveFolder(OCFile folder, String newPath) {
509 // TODO check newPath
510
511 if (folder != null && folder.isFolder() && folder.fileExists() && !OCFile.ROOT_PATH.equals(folder.getFileName())) {
512 /// 1. get all the descendants of 'dir' in a single QUERY (including 'dir')
513 Cursor c = null;
514 if (getContentProviderClient() != null) {
515 try {
516 c = getContentProviderClient().query(ProviderTableMeta.CONTENT_URI,
517 null,
518 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ? ",
519 new String[] { mAccount.name, folder.getRemotePath() + "%" }, ProviderTableMeta.FILE_PATH + " ASC ");
520 } catch (RemoteException e) {
521 Log_OC.e(TAG, e.getMessage());
522 }
523 } else {
524 c = getContentResolver().query(ProviderTableMeta.CONTENT_URI,
525 null,
526 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ? ",
527 new String[] { mAccount.name, folder.getRemotePath() + "%" }, ProviderTableMeta.FILE_PATH + " ASC ");
528 }
529
530 /// 2. prepare a batch of update operations to change all the descendants
531 ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(c.getCount());
532 int lengthOfOldPath = folder.getRemotePath().length();
533 String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
534 int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
535 if (c.moveToFirst()) {
536 do {
537 ContentValues cv = new ContentValues(); // don't take the constructor out of the loop and clear the object
538 OCFile child = createFileInstance(c);
539 cv.put(ProviderTableMeta.FILE_PATH, newPath + child.getRemotePath().substring(lengthOfOldPath));
540 if (child.getStoragePath() != null && child.getStoragePath().startsWith(defaultSavePath)) {
541 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, defaultSavePath + newPath + child.getStoragePath().substring(lengthOfOldStoragePath));
542 }
543 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
544 withValues(cv).
545 withSelection( ProviderTableMeta._ID + "=?",
546 new String[] { String.valueOf(child.getFileId()) })
547 .build());
548 } while (c.moveToNext());
549 }
550 c.close();
551
552 /// 3. apply updates in batch
553 try {
554 if (getContentResolver() != null) {
555 getContentResolver().applyBatch(MainApp.getAuthority(), operations);
556
557 } else {
558 getContentProviderClient().applyBatch(operations);
559 }
560
561 } catch (OperationApplicationException e) {
562 Log_OC.e(TAG, "Fail to update descendants of " + folder.getFileId() + " in database", e);
563
564 } catch (RemoteException e) {
565 Log_OC.e(TAG, "Fail to update desendants of " + folder.getFileId() + " in database", e);
566 }
567
568 }
569 }
570
571
572 private Vector<OCFile> getFolderContent(long parentId) {
573
574 Vector<OCFile> ret = new Vector<OCFile>();
575
576 Uri req_uri = Uri.withAppendedPath(
577 ProviderTableMeta.CONTENT_URI_DIR,
578 String.valueOf(parentId));
579 Cursor c = null;
580
581 if (getContentProviderClient() != null) {
582 try {
583 c = getContentProviderClient().query(req_uri, null,
584 ProviderTableMeta.FILE_PARENT + "=?" ,
585 new String[] { String.valueOf(parentId)}, null);
586 } catch (RemoteException e) {
587 Log_OC.e(TAG, e.getMessage());
588 return ret;
589 }
590 } else {
591 c = getContentResolver().query(req_uri, null,
592 ProviderTableMeta.FILE_PARENT + "=?" ,
593 new String[] { String.valueOf(parentId)}, null);
594 }
595
596 if (c.moveToFirst()) {
597 do {
598 OCFile child = createFileInstance(c);
599 ret.add(child);
600 } while (c.moveToNext());
601 }
602
603 c.close();
604
605 Collections.sort(ret);
606
607 return ret;
608 }
609
610
611 private OCFile createRootDir() {
612 OCFile file = new OCFile(OCFile.ROOT_PATH);
613 file.setMimetype("DIR");
614 file.setParentId(FileDataStorageManager.ROOT_PARENT_ID);
615 saveFile(file);
616 return file;
617 }
618
619 private boolean fileExists(String cmp_key, String value) {
620 Cursor c;
621 if (getContentResolver() != null) {
622 c = getContentResolver()
623 .query(ProviderTableMeta.CONTENT_URI,
624 null,
625 cmp_key + "=? AND "
626 + ProviderTableMeta.FILE_ACCOUNT_OWNER
627 + "=?",
628 new String[] { value, mAccount.name }, null);
629 } else {
630 try {
631 c = getContentProviderClient().query(
632 ProviderTableMeta.CONTENT_URI,
633 null,
634 cmp_key + "=? AND "
635 + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
636 new String[] { value, mAccount.name }, null);
637 } catch (RemoteException e) {
638 Log_OC.e(TAG,
639 "Couldn't determine file existance, assuming non existance: "
640 + e.getMessage());
641 return false;
642 }
643 }
644 boolean retval = c.moveToFirst();
645 c.close();
646 return retval;
647 }
648
649 private Cursor getCursorForValue(String key, String value) {
650 Cursor c = null;
651 if (getContentResolver() != null) {
652 c = getContentResolver()
653 .query(ProviderTableMeta.CONTENT_URI,
654 null,
655 key + "=? AND "
656 + ProviderTableMeta.FILE_ACCOUNT_OWNER
657 + "=?",
658 new String[] { value, mAccount.name }, null);
659 } else {
660 try {
661 c = getContentProviderClient().query(
662 ProviderTableMeta.CONTENT_URI,
663 null,
664 key + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER
665 + "=?", new String[] { value, mAccount.name },
666 null);
667 } catch (RemoteException e) {
668 Log_OC.e(TAG, "Could not get file details: " + e.getMessage());
669 c = null;
670 }
671 }
672 return c;
673 }
674
675 private Cursor getShareCursorForValue(String key, String value) {
676 Cursor c = null;
677 if (getContentResolver() != null) {
678 c = getContentResolver()
679 .query(ProviderTableMeta.CONTENT_URI_SHARE,
680 null,
681 key + "=? AND "
682 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
683 + "=?",
684 new String[] { value, mAccount.name }, null);
685 } else {
686 try {
687 c = getContentProviderClient().query(
688 ProviderTableMeta.CONTENT_URI_SHARE,
689 null,
690 key + "=? AND " + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
691 + "=?", new String[] { value, mAccount.name },
692 null);
693 } catch (RemoteException e) {
694 Log_OC.e(TAG, "Could not get file details: " + e.getMessage());
695 c = null;
696 }
697 }
698 return c;
699 }
700
701 private OCFile createFileInstance(Cursor c) {
702 OCFile file = null;
703 if (c != null) {
704 file = new OCFile(c.getString(c
705 .getColumnIndex(ProviderTableMeta.FILE_PATH)));
706 file.setFileId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
707 file.setParentId(c.getLong(c
708 .getColumnIndex(ProviderTableMeta.FILE_PARENT)));
709 file.setMimetype(c.getString(c
710 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
711 if (!file.isFolder()) {
712 file.setStoragePath(c.getString(c
713 .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)));
714 if (file.getStoragePath() == null) {
715 // 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
716 File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
717 if (f.exists()) {
718 file.setStoragePath(f.getAbsolutePath());
719 file.setLastSyncDateForData(f.lastModified());
720 }
721 }
722 }
723 file.setFileLength(c.getLong(c
724 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH)));
725 file.setCreationTimestamp(c.getLong(c
726 .getColumnIndex(ProviderTableMeta.FILE_CREATION)));
727 file.setModificationTimestamp(c.getLong(c
728 .getColumnIndex(ProviderTableMeta.FILE_MODIFIED)));
729 file.setModificationTimestampAtLastSyncForData(c.getLong(c
730 .getColumnIndex(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA)));
731 file.setLastSyncDateForProperties(c.getLong(c
732 .getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE)));
733 file.setLastSyncDateForData(c.getLong(c.
734 getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA)));
735 file.setKeepInSync(c.getInt(
736 c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false);
737 file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG)));
738 file.setShareByLink(c.getInt(
739 c.getColumnIndex(ProviderTableMeta.FILE_SHARE_BY_LINK)) == 1 ? true : false);
740 file.setPublicLink(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PUBLIC_LINK)));
741
742 }
743 return file;
744 }
745
746 /**
747 * Returns if the file/folder is shared by link or not
748 * @param path Path of the file/folder
749 * @return
750 */
751 public boolean isFileShareByLink(String path) {
752 Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
753 OCFile file = null;
754 if (c.moveToFirst()) {
755 file = createFileInstance(c);
756 }
757 c.close();
758 return file.isShareByLink();
759 }
760
761 /**
762 * Returns the public link of the file/folder
763 * @param path Path of the file/folder
764 * @return
765 */
766 public String getFilePublicLink(String path) {
767 Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
768 OCFile file = null;
769 if (c.moveToFirst()) {
770 file = createFileInstance(c);
771 }
772 c.close();
773 return file.getPublicLink();
774 }
775
776
777 // Methods for Share Files
778 public boolean saveShareFile(OCShare shareFile) {
779 boolean overriden = false;
780 ContentValues cv = new ContentValues();
781 cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, shareFile.getFileSource());
782 cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, shareFile.getItemSource());
783 cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, shareFile.getShareType().getValue());
784 cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, shareFile.getShareWith());
785 cv.put(ProviderTableMeta.OCSHARES_PATH, shareFile.getPath());
786 cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, shareFile.getPermissions());
787 cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, shareFile.getSharedDate());
788 cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, shareFile.getExpirationDate());
789 cv.put(ProviderTableMeta.OCSHARES_TOKEN, shareFile.getToken());
790 cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, shareFile.getSharedWithDisplayName());
791 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, shareFile.isDirectory() ? 1 : 0);
792 cv.put(ProviderTableMeta.OCSHARES_USER_ID, shareFile.getUserId());
793 cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, shareFile.getIdRemoteShared());
794 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
795
796 boolean samePath = fileShareExists(shareFile.getPath());
797 if (samePath ||
798 fileShareExists(shareFile.getId()) ) { // for renamed files; no more delete and create
799
800 OCShare oldFile = null;
801 if (samePath) {
802 oldFile = getShareFileByPath(shareFile.getPath());
803 shareFile.setId(oldFile.getId());
804 } else {
805 oldFile = getShareFileById(shareFile.getId());
806 }
807
808 overriden = true;
809 if (getContentResolver() != null) {
810 getContentResolver().update(ProviderTableMeta.CONTENT_URI_SHARE, cv,
811 ProviderTableMeta._ID + "=?",
812 new String[] { String.valueOf(shareFile.getId()) });
813 } else {
814 try {
815 getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_SHARE,
816 cv, ProviderTableMeta._ID + "=?",
817 new String[] { String.valueOf(shareFile.getId()) });
818 } catch (RemoteException e) {
819 Log_OC.e(TAG,
820 "Fail to insert insert file to database "
821 + e.getMessage());
822 }
823 }
824 } else {
825 Uri result_uri = null;
826 if (getContentResolver() != null) {
827 result_uri = getContentResolver().insert(
828 ProviderTableMeta.CONTENT_URI_SHARE, cv);
829 } else {
830 try {
831 result_uri = getContentProviderClient().insert(
832 ProviderTableMeta.CONTENT_URI_SHARE, cv);
833 } catch (RemoteException e) {
834 Log_OC.e(TAG,
835 "Fail to insert insert file to database "
836 + e.getMessage());
837 }
838 }
839 if (result_uri != null) {
840 long new_id = Long.parseLong(result_uri.getPathSegments()
841 .get(1));
842 shareFile.setId(new_id);
843 }
844 }
845
846 return overriden;
847 }
848
849 private OCShare getShareFileById(long id) {
850 Cursor c = getShareCursorForValue(ProviderTableMeta._ID, String.valueOf(id));
851 OCShare share = null;
852 if (c.moveToFirst()) {
853 share = createShareInstance(c);
854 }
855 c.close();
856 return share;
857 }
858
859 public OCShare getShareFileByPath(String path) {
860 Cursor c = getShareCursorForValue(ProviderTableMeta.OCSHARES_PATH, path);
861 OCShare share = null;
862 if (c.moveToFirst()) {
863 share = createShareInstance(c);
864 }
865 c.close();
866 return share;
867 }
868
869 private OCShare createShareInstance(Cursor c) {
870 OCShare share = null;
871 if (c != null) {
872 share = new OCShare(c.getString(c
873 .getColumnIndex(ProviderTableMeta.OCSHARES_PATH)));
874 share.setId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
875 share.setFileSource(c.getLong(c
876 .getColumnIndex(ProviderTableMeta.OCSHARES_ITEM_SOURCE)));
877 share.setShareType(ShareType.fromValue(c.getInt(c
878 .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_TYPE))));
879 share.setPermissions(c.getInt(c
880 .getColumnIndex(ProviderTableMeta.OCSHARES_PERMISSIONS)));
881 share.setSharedDate(c.getLong(c
882 .getColumnIndex(ProviderTableMeta.OCSHARES_SHARED_DATE)));
883 share.setExpirationDate(c.getLong(c
884 .getColumnIndex(ProviderTableMeta.OCSHARES_EXPIRATION_DATE)));
885 share.setToken(c.getString(c
886 .getColumnIndex(ProviderTableMeta.OCSHARES_TOKEN)));
887 share.setSharedWithDisplayName(c.getString(c
888 .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME)));
889 share.setIsDirectory(c.getInt(
890 c.getColumnIndex(ProviderTableMeta.OCSHARES_IS_DIRECTORY)) == 1 ? true : false);
891 share.setUserId(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_USER_ID)));
892 share.setIdRemoteShared(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED)));
893
894 }
895 return share;
896 }
897
898 private boolean fileShareExists(String cmp_key, String value) {
899 Cursor c;
900 if (getContentResolver() != null) {
901 c = getContentResolver()
902 .query(ProviderTableMeta.CONTENT_URI_SHARE,
903 null,
904 cmp_key + "=? AND "
905 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
906 + "=?",
907 new String[] { value, mAccount.name }, null);
908 } else {
909 try {
910 c = getContentProviderClient().query(
911 ProviderTableMeta.CONTENT_URI_SHARE,
912 null,
913 cmp_key + "=? AND "
914 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
915 new String[] { value, mAccount.name }, null);
916 } catch (RemoteException e) {
917 Log_OC.e(TAG,
918 "Couldn't determine file existance, assuming non existance: "
919 + e.getMessage());
920 return false;
921 }
922 }
923 boolean retval = c.moveToFirst();
924 c.close();
925 return retval;
926 }
927
928 public boolean fileShareExists(long id) {
929 return fileShareExists(ProviderTableMeta._ID, String.valueOf(id));
930 }
931
932 public boolean fileShareExists(String path) {
933 return fileShareExists(ProviderTableMeta.OCSHARES_PATH, path);
934 }
935
936 public void cleanShareFile() {
937 ContentValues cv = new ContentValues();
938 cv.put(ProviderTableMeta.FILE_SHARE_BY_LINK, false);
939 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
940 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
941 String [] whereArgs = new String[]{mAccount.name};
942
943 if (getContentResolver() != null) {
944 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
945
946 } else {
947 try {
948 getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
949
950 } catch (RemoteException e) {
951 Log_OC.e(TAG, "Exception in cleanShareFile" + e.getMessage());
952 }
953 }
954 }
955 }