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