4d07b56eeeedb5509c638ec77abb66f807561245
[pub/Android/ownCloud.git] / src / com / owncloud / android / datamodel / FileDataStorageManager.java
1 /**
2 * ownCloud Android client application
3 *
4 * Copyright (C) 2012 Bartek Przybylski
5 * Copyright (C) 2015 ownCloud Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2,
9 * as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 package com.owncloud.android.datamodel;
22
23 import java.io.File;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Set;
31 import java.util.Vector;
32
33 import android.accounts.Account;
34 import android.content.ContentProvider;
35 import android.content.ContentProviderClient;
36 import android.content.ContentProviderOperation;
37 import android.content.ContentProviderResult;
38 import android.content.ContentResolver;
39 import android.content.ContentUris;
40 import android.content.ContentValues;
41 import android.content.Intent;
42 import android.content.OperationApplicationException;
43 import android.database.Cursor;
44 import android.net.Uri;
45 import android.os.RemoteException;
46 import android.provider.MediaStore;
47
48 import com.owncloud.android.MainApp;
49 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
50 import com.owncloud.android.lib.common.utils.Log_OC;
51 import com.owncloud.android.lib.resources.files.FileUtils;
52 import com.owncloud.android.lib.resources.shares.OCShare;
53 import com.owncloud.android.lib.resources.shares.ShareType;
54 import com.owncloud.android.utils.FileStorageUtils;
55
56 import java.io.FileInputStream;
57 import java.io.FileOutputStream;
58 import java.io.IOException;
59 import java.io.InputStream;
60 import java.io.OutputStream;
61
62 public class FileDataStorageManager {
63
64 public static final int ROOT_PARENT_ID = 0;
65
66 private ContentResolver mContentResolver;
67 private ContentProviderClient mContentProviderClient;
68 private Account mAccount;
69
70 private static String TAG = FileDataStorageManager.class.getSimpleName();
71
72
73 public FileDataStorageManager(Account account, ContentResolver cr) {
74 mContentProviderClient = null;
75 mContentResolver = cr;
76 mAccount = account;
77 }
78
79 public FileDataStorageManager(Account account, ContentProviderClient cp) {
80 mContentProviderClient = cp;
81 mContentResolver = null;
82 mAccount = account;
83 }
84
85
86 public void setAccount(Account account) {
87 mAccount = account;
88 }
89
90 public Account getAccount() {
91 return mAccount;
92 }
93
94 public ContentResolver getContentResolver() {
95 return mContentResolver;
96 }
97
98 public ContentProviderClient getContentProviderClient() {
99 return mContentProviderClient;
100 }
101
102
103 public OCFile getFileByPath(String path) {
104 Cursor c = getCursorForValue(ProviderTableMeta.FILE_PATH, path);
105 OCFile file = null;
106 if (c.moveToFirst()) {
107 file = createFileInstance(c);
108 }
109 c.close();
110 if (file == null && OCFile.ROOT_PATH.equals(path)) {
111 return createRootDir(); // root should always exist
112 }
113 return file;
114 }
115
116
117 public OCFile getFileById(long id) {
118 Cursor c = getCursorForValue(ProviderTableMeta._ID, String.valueOf(id));
119 OCFile file = null;
120 if (c.moveToFirst()) {
121 file = createFileInstance(c);
122 }
123 c.close();
124 return file;
125 }
126
127 public OCFile getFileByLocalPath(String path) {
128 Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
129 OCFile file = null;
130 if (c.moveToFirst()) {
131 file = createFileInstance(c);
132 }
133 c.close();
134 return file;
135 }
136
137 public boolean fileExists(long id) {
138 return fileExists(ProviderTableMeta._ID, String.valueOf(id));
139 }
140
141 public boolean fileExists(String path) {
142 return fileExists(ProviderTableMeta.FILE_PATH, path);
143 }
144
145
146 public Vector<OCFile> getFolderContent(OCFile f/*, boolean onlyOnDevice*/) {
147 if (f != null && f.isFolder() && f.getFileId() != -1) {
148 // TODO Enable when "On Device" is recovered ?
149 return getFolderContent(f.getFileId()/*, onlyOnDevice*/);
150
151 } else {
152 return new Vector<OCFile>();
153 }
154 }
155
156
157 public Vector<OCFile> getFolderImages(OCFile folder/*, boolean onlyOnDevice*/) {
158 Vector<OCFile> ret = new Vector<OCFile>();
159 if (folder != null) {
160 // TODO better implementation, filtering in the access to database instead of here
161 // TODO Enable when "On Device" is recovered ?
162 Vector<OCFile> tmp = getFolderContent(folder/*, onlyOnDevice*/);
163 OCFile current = null;
164 for (int i=0; i<tmp.size(); i++) {
165 current = tmp.get(i);
166 if (current.isImage()) {
167 ret.add(current);
168 }
169 }
170 }
171 return ret;
172 }
173
174 public boolean saveFile(OCFile file) {
175 boolean overriden = false;
176 ContentValues cv = new ContentValues();
177 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
178 cv.put(
179 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
180 file.getModificationTimestampAtLastSyncForData()
181 );
182 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
183 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
184 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
185 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
186 cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
187 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
188 if (!file.isFolder())
189 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
190 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
191 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
192 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
193 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isFavorite() ? 1 : 0);
194 cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
195 cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
196 cv.put(ProviderTableMeta.FILE_SHARED_VIA_USERS, file.isSharedViaUsers() ? 1 : 0);
197 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
198 cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
199 cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
200 cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.needsUpdateThumbnail());
201 cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
202 cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
203
204 boolean sameRemotePath = fileExists(file.getRemotePath());
205 if (sameRemotePath ||
206 fileExists(file.getFileId())) { // for renamed files; no more delete and create
207
208 OCFile oldFile;
209 if (sameRemotePath) {
210 oldFile = getFileByPath(file.getRemotePath());
211 file.setFileId(oldFile.getFileId());
212 } else {
213 oldFile = getFileById(file.getFileId());
214 }
215
216 overriden = true;
217 if (getContentResolver() != null) {
218 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv,
219 ProviderTableMeta._ID + "=?",
220 new String[]{String.valueOf(file.getFileId())});
221 } else {
222 try {
223 getContentProviderClient().update(ProviderTableMeta.CONTENT_URI,
224 cv, ProviderTableMeta._ID + "=?",
225 new String[]{String.valueOf(file.getFileId())});
226 } catch (RemoteException e) {
227 Log_OC.e(TAG,
228 "Fail to insert insert file to database "
229 + e.getMessage());
230 }
231 }
232 } else {
233 Uri result_uri = null;
234 if (getContentResolver() != null) {
235 result_uri = getContentResolver().insert(
236 ProviderTableMeta.CONTENT_URI_FILE, cv);
237 } else {
238 try {
239 result_uri = getContentProviderClient().insert(
240 ProviderTableMeta.CONTENT_URI_FILE, cv);
241 } catch (RemoteException e) {
242 Log_OC.e(TAG,
243 "Fail to insert insert file to database "
244 + e.getMessage());
245 }
246 }
247 if (result_uri != null) {
248 long new_id = Long.parseLong(result_uri.getPathSegments()
249 .get(1));
250 file.setFileId(new_id);
251 }
252 }
253
254 return overriden;
255 }
256
257
258 /**
259 * Inserts or updates the list of files contained in a given folder.
260 * <p/>
261 * CALLER IS THE RESPONSIBLE FOR GRANTING RIGHT UPDATE OF INFORMATION, NOT THIS METHOD.
262 * HERE ONLY DATA CONSISTENCY SHOULD BE GRANTED
263 *
264 * @param folder
265 * @param updatedFiles
266 * @param filesToRemove
267 */
268 public void saveFolder(
269 OCFile folder, Collection<OCFile> updatedFiles, Collection<OCFile> filesToRemove
270 ) {
271
272 Log_OC.d(TAG, "Saving folder " + folder.getRemotePath() + " with " + updatedFiles.size()
273 + " children and " + filesToRemove.size() + " files to remove");
274
275 ArrayList<ContentProviderOperation> operations =
276 new ArrayList<ContentProviderOperation>(updatedFiles.size());
277
278 // prepare operations to insert or update files to save in the given folder
279 for (OCFile file : updatedFiles) {
280 ContentValues cv = new ContentValues();
281 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
282 cv.put(
283 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
284 file.getModificationTimestampAtLastSyncForData()
285 );
286 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
287 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
288 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
289 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
290 //cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
291 cv.put(ProviderTableMeta.FILE_PARENT, folder.getFileId());
292 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
293 if (!file.isFolder()) {
294 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
295 }
296 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
297 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
298 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
299 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isFavorite() ? 1 : 0);
300 cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
301 cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
302 cv.put(ProviderTableMeta.FILE_SHARED_VIA_USERS, file.isSharedViaUsers() ? 1 : 0);
303 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
304 cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
305 cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
306 cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.needsUpdateThumbnail());
307 cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
308 cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
309
310 boolean existsByPath = fileExists(file.getRemotePath());
311 if (existsByPath || fileExists(file.getFileId())) {
312 // updating an existing file
313 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
314 withValues(cv).
315 withSelection(ProviderTableMeta._ID + "=?",
316 new String[]{String.valueOf(file.getFileId())})
317 .build());
318
319 } else {
320 // adding a new file
321 operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).
322 withValues(cv).build());
323 }
324 }
325
326 // prepare operations to remove files in the given folder
327 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " +
328 ProviderTableMeta.FILE_PATH + "=?";
329 String [] whereArgs = null;
330 for (OCFile file : filesToRemove) {
331 if (file.getParentId() == folder.getFileId()) {
332 whereArgs = new String[]{mAccount.name, file.getRemotePath()};
333 if (file.isFolder()) {
334 operations.add(ContentProviderOperation.newDelete(
335 ContentUris.withAppendedId(
336 ProviderTableMeta.CONTENT_URI_DIR, file.getFileId()
337 )
338 ).withSelection(where, whereArgs).build());
339
340 File localFolder =
341 new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
342 if (localFolder.exists()) {
343 removeLocalFolder(localFolder);
344 }
345 } else {
346 operations.add(ContentProviderOperation.newDelete(
347 ContentUris.withAppendedId(
348 ProviderTableMeta.CONTENT_URI_FILE, file.getFileId()
349 )
350 ).withSelection(where, whereArgs).build());
351
352 if (file.isDown()) {
353 String path = file.getStoragePath();
354 new File(path).delete();
355 triggerMediaScan(path); // notify MediaScanner about removed file
356 }
357 }
358 }
359 }
360
361 // update metadata of folder
362 ContentValues cv = new ContentValues();
363 cv.put(ProviderTableMeta.FILE_MODIFIED, folder.getModificationTimestamp());
364 cv.put(
365 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
366 folder.getModificationTimestampAtLastSyncForData()
367 );
368 cv.put(ProviderTableMeta.FILE_CREATION, folder.getCreationTimestamp());
369 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, 0);
370 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, folder.getMimetype());
371 cv.put(ProviderTableMeta.FILE_NAME, folder.getFileName());
372 cv.put(ProviderTableMeta.FILE_PARENT, folder.getParentId());
373 cv.put(ProviderTableMeta.FILE_PATH, folder.getRemotePath());
374 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
375 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, folder.getLastSyncDateForProperties());
376 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, folder.getLastSyncDateForData());
377 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, folder.isFavorite() ? 1 : 0);
378 cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag());
379 cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, folder.isSharedViaLink() ? 1 : 0);
380 cv.put(ProviderTableMeta.FILE_SHARED_VIA_USERS, folder.isSharedViaUsers() ? 1 : 0);
381 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, folder.getPublicLink());
382 cv.put(ProviderTableMeta.FILE_PERMISSIONS, folder.getPermissions());
383 cv.put(ProviderTableMeta.FILE_REMOTE_ID, folder.getRemoteId());
384
385 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
386 withValues(cv).
387 withSelection(ProviderTableMeta._ID + "=?",
388 new String[]{String.valueOf(folder.getFileId())})
389 .build());
390
391 // apply operations in batch
392 ContentProviderResult[] results = null;
393 Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
394 try {
395 if (getContentResolver() != null) {
396 results = getContentResolver().applyBatch(MainApp.getAuthority(), operations);
397
398 } else {
399 results = getContentProviderClient().applyBatch(operations);
400 }
401
402 } catch (OperationApplicationException e) {
403 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
404
405 } catch (RemoteException e) {
406 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
407 }
408
409 // update new id in file objects for insertions
410 if (results != null) {
411 long newId;
412 Iterator<OCFile> filesIt = updatedFiles.iterator();
413 OCFile file = null;
414 for (int i = 0; i < results.length; i++) {
415 if (filesIt.hasNext()) {
416 file = filesIt.next();
417 } else {
418 file = null;
419 }
420 if (results[i].uri != null) {
421 newId = Long.parseLong(results[i].uri.getPathSegments().get(1));
422 //updatedFiles.get(i).setFileId(newId);
423 if (file != null) {
424 file.setFileId(newId);
425 }
426 }
427 }
428 }
429
430 }
431
432
433 public boolean removeFile(OCFile file, boolean removeDBData, boolean removeLocalCopy) {
434 boolean success = true;
435 if (file != null) {
436 if (file.isFolder()) {
437 success = removeFolder(file, removeDBData, removeLocalCopy);
438
439 } else {
440 if (removeDBData) {
441 //Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE,
442 // ""+file.getFileId());
443 Uri file_uri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE,
444 file.getFileId());
445 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " +
446 ProviderTableMeta.FILE_PATH + "=?";
447 String[] whereArgs = new String[]{mAccount.name, file.getRemotePath()};
448 int deleted = 0;
449 if (getContentProviderClient() != null) {
450 try {
451 deleted = getContentProviderClient().delete(file_uri, where, whereArgs);
452 } catch (RemoteException e) {
453 e.printStackTrace();
454 }
455 } else {
456 deleted = getContentResolver().delete(file_uri, where, whereArgs);
457 }
458 success &= (deleted > 0);
459 }
460 String localPath = file.getStoragePath();
461 if (removeLocalCopy && file.isDown() && localPath != null && success) {
462 success = new File(localPath).delete();
463 if (success) {
464 deleteFileInMediaScan(localPath);
465 }
466 if (!removeDBData && success) {
467 // maybe unnecessary, but should be checked TODO remove if unnecessary
468 file.setStoragePath(null);
469 saveFile(file);
470 saveConflict(file, null);
471 }
472 }
473 }
474 }
475 return success;
476 }
477
478
479 public boolean removeFolder(OCFile folder, boolean removeDBData, boolean removeLocalContent) {
480 boolean success = true;
481 if (folder != null && folder.isFolder()) {
482 if (removeDBData && folder.getFileId() != -1) {
483 success = removeFolderInDb(folder);
484 }
485 if (removeLocalContent && success) {
486 success = removeLocalFolder(folder);
487 }
488 }
489 return success;
490 }
491
492 private boolean removeFolderInDb(OCFile folder) {
493 Uri folder_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, "" +
494 folder.getFileId()); // URI for recursive deletion
495 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " +
496 ProviderTableMeta.FILE_PATH + "=?";
497 String [] whereArgs = new String[]{mAccount.name, folder.getRemotePath()};
498 int deleted = 0;
499 if (getContentProviderClient() != null) {
500 try {
501 deleted = getContentProviderClient().delete(folder_uri, where, whereArgs);
502 } catch (RemoteException e) {
503 e.printStackTrace();
504 }
505 } else {
506 deleted = getContentResolver().delete(folder_uri, where, whereArgs);
507 }
508 return deleted > 0;
509 }
510
511 private boolean removeLocalFolder(OCFile folder) {
512 boolean success = true;
513 String localFolderPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder);
514 File localFolder = new File(localFolderPath);
515 if (localFolder.exists()) {
516 // stage 1: remove the local files already registered in the files database
517 // TODO Enable when "On Device" is recovered ?
518 Vector<OCFile> files = getFolderContent(folder.getFileId()/*, false*/);
519 if (files != null) {
520 for (OCFile file : files) {
521 if (file.isFolder()) {
522 success &= removeLocalFolder(file);
523 } else {
524 if (file.isDown()) {
525 File localFile = new File(file.getStoragePath());
526 success &= localFile.delete();
527 if (success) {
528 // notify MediaScanner about removed file
529 deleteFileInMediaScan(file.getStoragePath());
530 file.setStoragePath(null);
531 saveFile(file);
532 }
533 }
534 }
535 }
536 }
537
538 // stage 2: remove the folder itself and any local file inside out of sync;
539 // for instance, after clearing the app cache or reinstalling
540 success &= removeLocalFolder(localFolder);
541 }
542 return success;
543 }
544
545 private boolean removeLocalFolder(File localFolder) {
546 boolean success = true;
547 File[] localFiles = localFolder.listFiles();
548 if (localFiles != null) {
549 for (File localFile : localFiles) {
550 if (localFile.isDirectory()) {
551 success &= removeLocalFolder(localFile);
552 } else {
553 String path = localFile.getAbsolutePath();
554 success &= localFile.delete();
555 }
556 }
557 }
558 success &= localFolder.delete();
559 return success;
560 }
561
562
563 /**
564 * Updates database and file system for a file or folder that was moved to a different location.
565 *
566 * TODO explore better (faster) implementations
567 * TODO throw exceptions up !
568 */
569 public void moveLocalFile(OCFile file, String targetPath, String targetParentPath) {
570
571 if (file != null && file.fileExists() && !OCFile.ROOT_PATH.equals(file.getFileName())) {
572
573 OCFile targetParent = getFileByPath(targetParentPath);
574 if (targetParent == null) {
575 throw new IllegalStateException(
576 "Parent folder of the target path does not exist!!");
577 }
578
579 /// 1. get all the descendants of the moved element in a single QUERY
580 Cursor c = null;
581 if (getContentProviderClient() != null) {
582 try {
583 c = getContentProviderClient().query(
584 ProviderTableMeta.CONTENT_URI,
585 null,
586 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
587 ProviderTableMeta.FILE_PATH + " LIKE ? ",
588 new String[]{
589 mAccount.name,
590 file.getRemotePath() + "%"
591 },
592 ProviderTableMeta.FILE_PATH + " ASC "
593 );
594 } catch (RemoteException e) {
595 Log_OC.e(TAG, e.getMessage());
596 }
597
598 } else {
599 c = getContentResolver().query(
600 ProviderTableMeta.CONTENT_URI,
601 null,
602 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
603 ProviderTableMeta.FILE_PATH + " LIKE ? ",
604 new String[]{
605 mAccount.name,
606 file.getRemotePath() + "%"
607 },
608 ProviderTableMeta.FILE_PATH + " ASC "
609 );
610 }
611
612 /// 2. prepare a batch of update operations to change all the descendants
613 ArrayList<ContentProviderOperation> operations =
614 new ArrayList<ContentProviderOperation>(c.getCount());
615 String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
616 List<String> originalPathsToTriggerMediaScan = new ArrayList<String>();
617 List<String> newPathsToTriggerMediaScan = new ArrayList<String>();
618 if (c.moveToFirst()) {
619 int lengthOfOldPath = file.getRemotePath().length();
620 int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
621 do {
622 ContentValues cv = new ContentValues(); // keep construction in the loop
623 OCFile child = createFileInstance(c);
624 cv.put(
625 ProviderTableMeta.FILE_PATH,
626 targetPath + child.getRemotePath().substring(lengthOfOldPath)
627 );
628 if (child.getStoragePath() != null &&
629 child.getStoragePath().startsWith(defaultSavePath)) {
630 // update link to downloaded content - but local move is not done here!
631 String targetLocalPath = defaultSavePath + targetPath +
632 child.getStoragePath().substring(lengthOfOldStoragePath);
633
634 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, targetLocalPath);
635
636 originalPathsToTriggerMediaScan.add(child.getStoragePath());
637 newPathsToTriggerMediaScan.add(targetLocalPath);
638
639 }
640 if (child.getRemotePath().equals(file.getRemotePath())) {
641 cv.put(
642 ProviderTableMeta.FILE_PARENT,
643 targetParent.getFileId()
644 );
645 }
646 operations.add(
647 ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
648 withValues(cv).
649 withSelection(
650 ProviderTableMeta._ID + "=?",
651 new String[]{String.valueOf(child.getFileId())}
652 )
653 .build());
654
655 } while (c.moveToNext());
656 }
657 c.close();
658
659 /// 3. apply updates in batch
660 try {
661 if (getContentResolver() != null) {
662 getContentResolver().applyBatch(MainApp.getAuthority(), operations);
663
664 } else {
665 getContentProviderClient().applyBatch(operations);
666 }
667
668 } catch (Exception e) {
669 Log_OC.e(TAG, "Fail to update " + file.getFileId() + " and descendants in database",
670 e);
671 }
672
673 /// 4. move in local file system
674 String originalLocalPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, file);
675 String targetLocalPath = defaultSavePath + targetPath;
676 File localFile = new File(originalLocalPath);
677 boolean renamed = false;
678 if (localFile.exists()) {
679 File targetFile = new File(targetLocalPath);
680 File targetFolder = targetFile.getParentFile();
681 if (!targetFolder.exists()) {
682 targetFolder.mkdirs();
683 }
684 renamed = localFile.renameTo(targetFile);
685 }
686
687 if (renamed) {
688 Iterator<String> it = originalPathsToTriggerMediaScan.iterator();
689 while (it.hasNext()) {
690 // Notify MediaScanner about removed file
691 deleteFileInMediaScan(it.next());
692 }
693 it = newPathsToTriggerMediaScan.iterator();
694 while (it.hasNext()) {
695 // Notify MediaScanner about new file/folder
696 triggerMediaScan(it.next());
697 }
698 }
699 }
700
701 }
702
703 public void copyLocalFile(OCFile file, String targetPath) {
704
705 if (file != null && file.fileExists() && !OCFile.ROOT_PATH.equals(file.getFileName())) {
706 String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, file);
707 File localFile = new File(localPath);
708 boolean copied = false;
709 String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
710 if (localFile.exists()) {
711 File targetFile = new File(defaultSavePath + targetPath);
712 File targetFolder = targetFile.getParentFile();
713 if (!targetFolder.exists()) {
714 targetFolder.mkdirs();
715 }
716 copied = copyFile(localFile, targetFile);
717 }
718 Log_OC.d(TAG, "Local file COPIED : " + copied);
719 }
720 }
721
722 private boolean copyFile(File src, File target) {
723 boolean ret = true;
724
725 InputStream in = null;
726 OutputStream out = null;
727
728 try {
729 in = new FileInputStream(src);
730 out = new FileOutputStream(target);
731 byte[] buf = new byte[1024];
732 int len;
733 while ((len = in.read(buf)) > 0) {
734 out.write(buf, 0, len);
735 }
736 } catch (IOException ex) {
737 ret = false;
738 } finally {
739 if (in != null) try {
740 in.close();
741 } catch (IOException e) {
742 e.printStackTrace(System.err);
743 }
744 if (out != null) try {
745 out.close();
746 } catch (IOException e) {
747 e.printStackTrace(System.err);
748 }
749 }
750
751 return ret;
752 }
753
754
755 private Vector<OCFile> getFolderContent(long parentId/*, boolean onlyOnDevice*/) {
756
757 Vector<OCFile> ret = new Vector<OCFile>();
758
759 Uri req_uri = Uri.withAppendedPath(
760 ProviderTableMeta.CONTENT_URI_DIR,
761 String.valueOf(parentId));
762 Cursor c = null;
763
764 if (getContentProviderClient() != null) {
765 try {
766 c = getContentProviderClient().query(req_uri, null,
767 ProviderTableMeta.FILE_PARENT + "=?",
768 new String[]{String.valueOf(parentId)}, null);
769 } catch (RemoteException e) {
770 Log_OC.e(TAG, e.getMessage());
771 return ret;
772 }
773 } else {
774 c = getContentResolver().query(req_uri, null,
775 ProviderTableMeta.FILE_PARENT + "=?",
776 new String[]{String.valueOf(parentId)}, null);
777 }
778
779 if (c.moveToFirst()) {
780 do {
781 OCFile child = createFileInstance(c);
782 // TODO Enable when "On Device" is recovered ?
783 // if (child.isFolder() || !onlyOnDevice || onlyOnDevice && child.isDown()){
784 ret.add(child);
785 // }
786 } while (c.moveToNext());
787 }
788
789 c.close();
790
791 Collections.sort(ret);
792
793 return ret;
794 }
795
796
797 private OCFile createRootDir() {
798 OCFile file = new OCFile(OCFile.ROOT_PATH);
799 file.setMimetype("DIR");
800 file.setParentId(FileDataStorageManager.ROOT_PARENT_ID);
801 saveFile(file);
802 return file;
803 }
804
805 private boolean fileExists(String cmp_key, String value) {
806 Cursor c;
807 if (getContentResolver() != null) {
808 c = getContentResolver()
809 .query(ProviderTableMeta.CONTENT_URI,
810 null,
811 cmp_key + "=? AND "
812 + ProviderTableMeta.FILE_ACCOUNT_OWNER
813 + "=?",
814 new String[]{value, mAccount.name}, null);
815 } else {
816 try {
817 c = getContentProviderClient().query(
818 ProviderTableMeta.CONTENT_URI,
819 null,
820 cmp_key + "=? AND "
821 + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
822 new String[]{value, mAccount.name}, null);
823 } catch (RemoteException e) {
824 Log_OC.e(TAG,
825 "Couldn't determine file existance, assuming non existance: "
826 + e.getMessage());
827 return false;
828 }
829 }
830 boolean retval = c.moveToFirst();
831 c.close();
832 return retval;
833 }
834
835 private Cursor getCursorForValue(String key, String value) {
836 Cursor c = null;
837 if (getContentResolver() != null) {
838 c = getContentResolver()
839 .query(ProviderTableMeta.CONTENT_URI,
840 null,
841 key + "=? AND "
842 + ProviderTableMeta.FILE_ACCOUNT_OWNER
843 + "=?",
844 new String[]{value, mAccount.name}, null);
845 } else {
846 try {
847 c = getContentProviderClient().query(
848 ProviderTableMeta.CONTENT_URI,
849 null,
850 key + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER
851 + "=?", new String[]{value, mAccount.name},
852 null);
853 } catch (RemoteException e) {
854 Log_OC.e(TAG, "Could not get file details: " + e.getMessage());
855 c = null;
856 }
857 }
858 return c;
859 }
860
861
862 private OCFile createFileInstance(Cursor c) {
863 OCFile file = null;
864 if (c != null) {
865 file = new OCFile(c.getString(c
866 .getColumnIndex(ProviderTableMeta.FILE_PATH)));
867 file.setFileId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
868 file.setParentId(c.getLong(c
869 .getColumnIndex(ProviderTableMeta.FILE_PARENT)));
870 file.setMimetype(c.getString(c
871 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
872 if (!file.isFolder()) {
873 file.setStoragePath(c.getString(c
874 .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)));
875 if (file.getStoragePath() == null) {
876 // try to find existing file and bind it with current account;
877 // with the current update of SynchronizeFolderOperation, this won't be
878 // necessary anymore after a full synchronization of the account
879 File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
880 if (f.exists()) {
881 file.setStoragePath(f.getAbsolutePath());
882 file.setLastSyncDateForData(f.lastModified());
883 }
884 }
885 }
886 file.setFileLength(c.getLong(c
887 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH)));
888 file.setCreationTimestamp(c.getLong(c
889 .getColumnIndex(ProviderTableMeta.FILE_CREATION)));
890 file.setModificationTimestamp(c.getLong(c
891 .getColumnIndex(ProviderTableMeta.FILE_MODIFIED)));
892 file.setModificationTimestampAtLastSyncForData(c.getLong(c
893 .getColumnIndex(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA)));
894 file.setLastSyncDateForProperties(c.getLong(c
895 .getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE)));
896 file.setLastSyncDateForData(c.getLong(c.
897 getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA)));
898 file.setFavorite(c.getInt(
899 c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false);
900 file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG)));
901 file.setShareViaLink(c.getInt(
902 c.getColumnIndex(ProviderTableMeta.FILE_SHARED_VIA_LINK)) == 1 ? true : false);
903 file.setShareViaUsers(c.getInt(
904 c.getColumnIndex(ProviderTableMeta.FILE_SHARED_VIA_USERS)) == 1 ? true : false);
905 file.setPublicLink(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PUBLIC_LINK)));
906 file.setPermissions(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PERMISSIONS)));
907 file.setRemoteId(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID)));
908 file.setNeedsUpdateThumbnail(c.getInt(
909 c.getColumnIndex(ProviderTableMeta.FILE_UPDATE_THUMBNAIL)) == 1 ? true : false);
910 file.setDownloading(c.getInt(
911 c.getColumnIndex(ProviderTableMeta.FILE_IS_DOWNLOADING)) == 1 ? true : false);
912 file.setEtagInConflict(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG_IN_CONFLICT)));
913
914 }
915 return file;
916 }
917
918 // Methods for Shares
919 public boolean saveShare(OCShare share) {
920 boolean overriden = false;
921 ContentValues cv = new ContentValues();
922 cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
923 cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
924 cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
925 cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
926 cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
927 cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
928 cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
929 cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
930 cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
931 cv.put(
932 ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
933 share.getSharedWithDisplayName()
934 );
935 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
936 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
937 cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
938 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
939
940 if (shareExists(share.getIdRemoteShared())) {// for renamed files; no more delete and create
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, String shareWith) {
984 Cursor c = null;
985
986 String selection = ProviderTableMeta.OCSHARES_PATH + "=? AND "
987 + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? AND "
988 + ProviderTableMeta.OCSHARES_SHARE_WITH + "=? AND "
989 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?" ;
990
991 String [] selectionArgs = new String[]{path, Integer.toString(type.getValue()),
992 shareWith, mAccount.name};
993
994 if (getContentResolver() != null) {
995 c = getContentResolver().query(
996 ProviderTableMeta.CONTENT_URI_SHARE,
997 null,
998 selection, selectionArgs,
999 null);
1000 } else {
1001 try {
1002 c = getContentProviderClient().query(
1003 ProviderTableMeta.CONTENT_URI_SHARE,
1004 null,
1005 selection, selectionArgs,
1006 null);
1007
1008 } catch (RemoteException e) {
1009 Log_OC.e(TAG, "Could not get file details: " + e.getMessage());
1010 c = null;
1011 }
1012 }
1013 OCShare share = null;
1014 if (c.moveToFirst()) {
1015 share = createShareInstance(c);
1016 }
1017 c.close();
1018 return share;
1019 }
1020
1021 private OCShare createShareInstance(Cursor c) {
1022 OCShare share = null;
1023 if (c != null) {
1024 share = new OCShare(c.getString(c
1025 .getColumnIndex(ProviderTableMeta.OCSHARES_PATH)));
1026 share.setId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
1027 share.setFileSource(c.getLong(c
1028 .getColumnIndex(ProviderTableMeta.OCSHARES_ITEM_SOURCE)));
1029 share.setShareType(ShareType.fromValue(c.getInt(c
1030 .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_TYPE))));
1031 share.setShareWith(c.getString(c
1032 .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_WITH)));
1033 share.setPermissions(c.getInt(c
1034 .getColumnIndex(ProviderTableMeta.OCSHARES_PERMISSIONS)));
1035 share.setSharedDate(c.getLong(c
1036 .getColumnIndex(ProviderTableMeta.OCSHARES_SHARED_DATE)));
1037 share.setExpirationDate(c.getLong(c
1038 .getColumnIndex(ProviderTableMeta.OCSHARES_EXPIRATION_DATE)));
1039 share.setToken(c.getString(c
1040 .getColumnIndex(ProviderTableMeta.OCSHARES_TOKEN)));
1041 share.setSharedWithDisplayName(c.getString(c
1042 .getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME)));
1043 share.setIsFolder(c.getInt(
1044 c.getColumnIndex(ProviderTableMeta.OCSHARES_IS_DIRECTORY)) == 1);
1045 share.setUserId(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_USER_ID)));
1046 share.setIdRemoteShared(c.getLong(
1047 c.getColumnIndex(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED)));
1048 }
1049 return share;
1050 }
1051
1052 private boolean shareExists(String cmp_key, String value) {
1053 Cursor c;
1054 if (getContentResolver() != null) {
1055 c = getContentResolver()
1056 .query(ProviderTableMeta.CONTENT_URI_SHARE,
1057 null,
1058 cmp_key + "=? AND "
1059 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
1060 + "=?",
1061 new String[]{value, mAccount.name}, null);
1062 } else {
1063 try {
1064 c = getContentProviderClient().query(
1065 ProviderTableMeta.CONTENT_URI_SHARE,
1066 null,
1067 cmp_key + "=? AND "
1068 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
1069 new String[]{value, mAccount.name}, null);
1070 } catch (RemoteException e) {
1071 Log_OC.e(TAG,
1072 "Couldn't determine file existance, assuming non existance: "
1073 + e.getMessage());
1074 return false;
1075 }
1076 }
1077 boolean retval = c.moveToFirst();
1078 c.close();
1079 return retval;
1080 }
1081
1082 private boolean shareExists(long remoteId) {
1083 return shareExists(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, String.valueOf(remoteId));
1084 }
1085
1086 private void resetShareFlagsInAllFiles() {
1087 ContentValues cv = new ContentValues();
1088 cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, false);
1089 cv.put(ProviderTableMeta.FILE_SHARED_VIA_USERS, false);
1090 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
1091 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
1092 String[] whereArgs = new String[]{mAccount.name};
1093
1094 if (getContentResolver() != null) {
1095 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
1096
1097 } else {
1098 try {
1099 getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where,
1100 whereArgs);
1101 } catch (RemoteException e) {
1102 Log_OC.e(TAG, "Exception in resetShareFlagsInAllFiles" + e.getMessage());
1103 }
1104 }
1105 }
1106
1107 private void resetShareFlagsInFolder(OCFile folder) {
1108 ContentValues cv = new ContentValues();
1109 cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, false);
1110 cv.put(ProviderTableMeta.FILE_SHARED_VIA_USERS, false);
1111 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
1112 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
1113 ProviderTableMeta.FILE_PARENT + "=?";
1114 String [] whereArgs = new String[] { mAccount.name , String.valueOf(folder.getFileId()) };
1115
1116 if (getContentResolver() != null) {
1117 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
1118
1119 } else {
1120 try {
1121 getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where,
1122 whereArgs);
1123 } catch (RemoteException e) {
1124 Log_OC.e(TAG, "Exception in resetShareFlagsInFolder " + e.getMessage());
1125 }
1126 }
1127 }
1128
1129 private void resetShareFlagInAFile(String filePath){
1130 ContentValues cv = new ContentValues();
1131 cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, false);
1132 cv.put(ProviderTableMeta.FILE_SHARED_VIA_USERS, false);
1133 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
1134 String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
1135 ProviderTableMeta.FILE_PATH+ "=?";
1136 String [] whereArgs = new String[] { mAccount.name , filePath };
1137
1138 if (getContentResolver() != null) {
1139 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
1140
1141 } else {
1142 try {
1143 getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where,
1144 whereArgs);
1145 } catch (RemoteException e) {
1146 Log_OC.e(TAG, "Exception in resetShareFlagsInFolder " + e.getMessage());
1147 }
1148 }
1149 }
1150
1151 private void cleanShares() {
1152 String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
1153 String[] whereArgs = new String[]{mAccount.name};
1154
1155 if (getContentResolver() != null) {
1156 getContentResolver().delete(ProviderTableMeta.CONTENT_URI_SHARE, where, whereArgs);
1157
1158 } else {
1159 try {
1160 getContentProviderClient().delete(ProviderTableMeta.CONTENT_URI_SHARE, where,
1161 whereArgs);
1162 } catch (RemoteException e) {
1163 Log_OC.e(TAG, "Exception in cleanShares" + e.getMessage());
1164 }
1165 }
1166 }
1167
1168 public void saveShares(Collection<OCShare> shares) {
1169 cleanShares();
1170 if (shares != null) {
1171 ArrayList<ContentProviderOperation> operations =
1172 new ArrayList<ContentProviderOperation>(shares.size());
1173
1174 // prepare operations to insert or update files to save in the given folder
1175 for (OCShare share : shares) {
1176 ContentValues cv = new ContentValues();
1177 cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
1178 cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
1179 cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
1180 cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
1181 cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
1182 cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
1183 cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
1184 cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
1185 cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
1186 cv.put(
1187 ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
1188 share.getSharedWithDisplayName()
1189 );
1190 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
1191 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
1192 cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
1193 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
1194
1195 if (shareExists(share.getIdRemoteShared())) {
1196 // updating an existing file
1197 operations.add(
1198 ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE).
1199 withValues(cv).
1200 withSelection(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
1201 new String[]{String.valueOf(share.getIdRemoteShared())})
1202 .build());
1203 } else {
1204 // adding a new file
1205 operations.add(
1206 ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).
1207 withValues(cv).
1208 build()
1209 );
1210 }
1211 }
1212
1213 // apply operations in batch
1214 if (operations.size() > 0) {
1215 @SuppressWarnings("unused")
1216 ContentProviderResult[] results = null;
1217 Log_OC.d(TAG, "Sending " + operations.size() +
1218 " operations to FileContentProvider");
1219 try {
1220 if (getContentResolver() != null) {
1221 results = getContentResolver().applyBatch(MainApp.getAuthority(),
1222 operations);
1223 } else {
1224 results = getContentProviderClient().applyBatch(operations);
1225 }
1226
1227 } catch (OperationApplicationException e) {
1228 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1229
1230 } catch (RemoteException e) {
1231 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1232 }
1233 }
1234 }
1235
1236 }
1237
1238 public void updateSharedFiles(Collection<OCFile> sharedFiles) {
1239 resetShareFlagsInAllFiles();
1240
1241 if (sharedFiles != null) {
1242 ArrayList<ContentProviderOperation> operations =
1243 new ArrayList<ContentProviderOperation>(sharedFiles.size());
1244
1245 // prepare operations to insert or update files to save in the given folder
1246 for (OCFile file : sharedFiles) {
1247 ContentValues cv = new ContentValues();
1248 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
1249 cv.put(
1250 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
1251 file.getModificationTimestampAtLastSyncForData()
1252 );
1253 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
1254 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
1255 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
1256 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
1257 cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
1258 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
1259 if (!file.isFolder()) {
1260 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
1261 }
1262 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
1263 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
1264 cv.put(
1265 ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,
1266 file.getLastSyncDateForData()
1267 );
1268 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isFavorite() ? 1 : 0);
1269 cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
1270 cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
1271 cv.put(ProviderTableMeta.FILE_SHARED_VIA_USERS, file.isSharedViaUsers() ? 1 : 0);
1272 cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
1273 cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
1274 cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
1275 cv.put(
1276 ProviderTableMeta.FILE_UPDATE_THUMBNAIL,
1277 file.needsUpdateThumbnail() ? 1 : 0
1278 );
1279 cv.put(
1280 ProviderTableMeta.FILE_IS_DOWNLOADING,
1281 file.isDownloading() ? 1 : 0
1282 );
1283 cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
1284
1285 boolean existsByPath = fileExists(file.getRemotePath());
1286 if (existsByPath || fileExists(file.getFileId())) {
1287 // updating an existing file
1288 operations.add(
1289 ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
1290 withValues(cv).
1291 withSelection(ProviderTableMeta._ID + "=?",
1292 new String[]{String.valueOf(file.getFileId())})
1293 .build());
1294
1295 } else {
1296 // adding a new file
1297 operations.add(
1298 ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).
1299 withValues(cv).
1300 build()
1301 );
1302 }
1303 }
1304
1305 // apply operations in batch
1306 if (operations.size() > 0) {
1307 @SuppressWarnings("unused")
1308 ContentProviderResult[] results = null;
1309 Log_OC.d(TAG, "Sending " + operations.size() +
1310 " operations to FileContentProvider");
1311 try {
1312 if (getContentResolver() != null) {
1313 results = getContentResolver().applyBatch(MainApp.getAuthority(), operations);
1314 } else {
1315 results = getContentProviderClient().applyBatch(operations);
1316 }
1317
1318 } catch (OperationApplicationException e) {
1319 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1320
1321 } catch (RemoteException e) {
1322 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1323 }
1324 }
1325 }
1326
1327 }
1328
1329 public void removeShare(OCShare share) {
1330 Uri share_uri = ProviderTableMeta.CONTENT_URI_SHARE;
1331 String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?" + " AND " +
1332 ProviderTableMeta._ID + "=?";
1333 String [] whereArgs = new String[]{mAccount.name, Long.toString(share.getId())};
1334 if (getContentProviderClient() != null) {
1335 try {
1336 getContentProviderClient().delete(share_uri, where, whereArgs);
1337 } catch (RemoteException e) {
1338 e.printStackTrace();
1339 }
1340 } else {
1341 getContentResolver().delete(share_uri, where, whereArgs);
1342 }
1343 }
1344
1345 public void saveSharesDB(ArrayList<OCShare> shares) {
1346 ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
1347
1348 // Reset flags & Remove shares for this files
1349 String filePath = "";
1350 for (OCShare share: shares) {
1351 if (filePath != share.getPath()){
1352 resetShareFlagInAFile(filePath);
1353 operations = prepareRemoveSharesInFile(filePath, operations);
1354 filePath = share.getPath();
1355 }
1356 }
1357
1358 // Add operations to insert shares
1359 operations = prepareInsertShares(shares, operations);
1360
1361 // apply operations in batch
1362 if (operations.size() > 0) {
1363 Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
1364 try {
1365 if (getContentResolver() != null) {
1366 getContentResolver().applyBatch(MainApp.getAuthority(), operations);
1367
1368 } else {
1369 getContentProviderClient().applyBatch(operations);
1370 }
1371
1372 } catch (OperationApplicationException e) {
1373 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1374
1375 } catch (RemoteException e) {
1376 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1377 }
1378 }
1379
1380 // // TODO: review if it is needed
1381 // // Update shared files
1382 // ArrayList<OCFile> sharedFiles = new ArrayList<OCFile>();
1383 //
1384 // for (OCShare share : shares) {
1385 // // Get the path
1386 // String path = share.getPath();
1387 // if (share.isFolder()) {
1388 // path = path + FileUtils.PATH_SEPARATOR;
1389 // }
1390 //
1391 // // Update OCFile with data from share: ShareByLink, publicLink and
1392 // OCFile file = getFileByPath(path);
1393 // if (file != null) {
1394 // if (share.getShareType().equals(ShareType.PUBLIC_LINK)) {
1395 // file.setShareViaLink(true);
1396 // sharedFiles.add(file);
1397 // }
1398 // }
1399 // }
1400 //
1401 // // TODO: Review
1402 // updateSharedFiles(sharedFiles);
1403 }
1404
1405
1406 public void saveSharesInFolder(ArrayList<OCShare> shares, OCFile folder) {
1407 resetShareFlagsInFolder(folder);
1408 ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
1409 operations = prepareRemoveSharesInFolder(folder, operations);
1410
1411 if (shares != null) {
1412 // prepare operations to insert or update files to save in the given folder
1413 for (OCShare share : shares) {
1414 ContentValues cv = new ContentValues();
1415 cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
1416 cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
1417 cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
1418 cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
1419 cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
1420 cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
1421 cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
1422 cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
1423 cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
1424 cv.put(
1425 ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
1426 share.getSharedWithDisplayName()
1427 );
1428 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
1429 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
1430 cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
1431 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
1432
1433 // adding a new share resource
1434 operations.add(
1435 ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).
1436 withValues(cv).
1437 build()
1438 );
1439 }
1440 }
1441
1442 // apply operations in batch
1443 if (operations.size() > 0) {
1444 Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
1445 try {
1446 if (getContentResolver() != null) {
1447 getContentResolver().applyBatch(MainApp.getAuthority(), operations);
1448
1449 } else {
1450 getContentProviderClient().applyBatch(operations);
1451 }
1452
1453 } catch (OperationApplicationException e) {
1454 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1455
1456 } catch (RemoteException e) {
1457 Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
1458 }
1459 }
1460
1461 }
1462
1463 /**
1464 * Prepare operations to insert or update files to save in the given folder
1465 * @param shares List of shares to insert
1466 * @param operations List of operations
1467 * @return
1468 */
1469 private ArrayList<ContentProviderOperation> prepareInsertShares(
1470 ArrayList<OCShare> shares, ArrayList<ContentProviderOperation> operations) {
1471
1472 if (shares != null) {
1473 // prepare operations to insert or update files to save in the given folder
1474 for (OCShare share : shares) {
1475 ContentValues cv = new ContentValues();
1476 cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
1477 cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
1478 cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
1479 cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
1480 cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
1481 cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
1482 cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
1483 cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
1484 cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
1485 cv.put(
1486 ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
1487 share.getSharedWithDisplayName()
1488 );
1489 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
1490 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
1491 cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
1492 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
1493
1494 // adding a new share resource
1495 operations.add(
1496 ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).
1497 withValues(cv).
1498 build()
1499 );
1500 }
1501 }
1502 return operations;
1503 }
1504
1505 private ArrayList<ContentProviderOperation> prepareRemoveSharesInFolder(
1506 OCFile folder, ArrayList<ContentProviderOperation> preparedOperations) {
1507 if (folder != null) {
1508 String where = ProviderTableMeta.OCSHARES_PATH + "=?" + " AND "
1509 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
1510 String [] whereArgs = new String[]{ "", mAccount.name };
1511
1512 // TODO Enable when "On Device" is recovered ?
1513 Vector<OCFile> files = getFolderContent(folder /*, false*/);
1514
1515 for (OCFile file : files) {
1516 whereArgs[0] = file.getRemotePath();
1517 preparedOperations.add(
1518 ContentProviderOperation.newDelete(ProviderTableMeta.CONTENT_URI_SHARE).
1519 withSelection(where, whereArgs).
1520 build()
1521 );
1522 }
1523 }
1524 return preparedOperations;
1525
1526 }
1527
1528 private ArrayList<ContentProviderOperation> prepareRemoveSharesInFile(
1529 String filePath, ArrayList<ContentProviderOperation> preparedOperations) {
1530
1531 String where = ProviderTableMeta.OCSHARES_PATH + "=?" + " AND "
1532 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
1533 String[] whereArgs = new String[]{filePath, mAccount.name};
1534
1535 preparedOperations.add(
1536 ContentProviderOperation.newDelete(ProviderTableMeta.CONTENT_URI_SHARE).
1537 withSelection(where, whereArgs).
1538 build()
1539 );
1540
1541 return preparedOperations;
1542
1543 }
1544
1545 public ArrayList<OCShare> getSharesWithForAFile(String filePath, String accountName){
1546 // Condition
1547 String where = ProviderTableMeta.OCSHARES_PATH + "=?" + " AND "
1548 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?"+ "AND"
1549 + " (" + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? OR "
1550 + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? ) ";
1551 String [] whereArgs = new String[]{ filePath, accountName ,
1552 Integer.toString(ShareType.USER.getValue()),
1553 Integer.toString(ShareType.GROUP.getValue()) };
1554
1555 Cursor c = null;
1556 if (getContentResolver() != null) {
1557 c = getContentResolver().query(
1558 ProviderTableMeta.CONTENT_URI_SHARE,
1559 null, where, whereArgs, null);
1560 } else {
1561 try {
1562 c = getContentProviderClient().query(
1563 ProviderTableMeta.CONTENT_URI_SHARE,
1564 null, where, whereArgs, null);
1565
1566 } catch (RemoteException e) {
1567 Log_OC.e(TAG, "Could not get list of shares with: " + e.getMessage());
1568 c = null;
1569 }
1570 }
1571 ArrayList<OCShare> shares = new ArrayList<OCShare>();
1572 OCShare share = null;
1573 if (c.moveToFirst()) {
1574 do {
1575 share = createShareInstance(c);
1576 shares.add(share);
1577 // }
1578 } while (c.moveToNext());
1579 }
1580 c.close();
1581
1582 return shares;
1583 }
1584
1585 public void triggerMediaScan(String path) {
1586 Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
1587 intent.setData(Uri.fromFile(new File(path)));
1588 MainApp.getAppContext().sendBroadcast(intent);
1589 }
1590
1591 public void deleteFileInMediaScan(String path) {
1592
1593 String mimetypeString = FileStorageUtils.getMimeTypeFromName(path);
1594 ContentResolver contentResolver = getContentResolver();
1595
1596 if (contentResolver != null) {
1597 if (mimetypeString.startsWith("image/")) {
1598 // Images
1599 contentResolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
1600 MediaStore.Images.Media.DATA + "=?", new String[]{path});
1601 } else if (mimetypeString.startsWith("audio/")) {
1602 // Audio
1603 contentResolver.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1604 MediaStore.Audio.Media.DATA + "=?", new String[]{path});
1605 } else if (mimetypeString.startsWith("video/")) {
1606 // Video
1607 contentResolver.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
1608 MediaStore.Video.Media.DATA + "=?", new String[]{path});
1609 }
1610 } else {
1611 ContentProviderClient contentProviderClient = getContentProviderClient();
1612 try {
1613 if (mimetypeString.startsWith("image/")) {
1614 // Images
1615 contentProviderClient.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
1616 MediaStore.Images.Media.DATA + "=?", new String[]{path});
1617 } else if (mimetypeString.startsWith("audio/")) {
1618 // Audio
1619 contentProviderClient.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1620 MediaStore.Audio.Media.DATA + "=?", new String[]{path});
1621 } else if (mimetypeString.startsWith("video/")) {
1622 // Video
1623 contentProviderClient.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
1624 MediaStore.Video.Media.DATA + "=?", new String[]{path});
1625 }
1626 } catch (RemoteException e) {
1627 Log_OC.e(TAG, "Exception deleting media file in MediaStore " + e.getMessage());
1628 }
1629 }
1630
1631 }
1632
1633 public void saveConflict(OCFile file, String etagInConflict) {
1634 if (!file.isDown()) {
1635 etagInConflict = null;
1636 }
1637 ContentValues cv = new ContentValues();
1638 cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, etagInConflict);
1639 int updated = 0;
1640 if (getContentResolver() != null) {
1641 updated = getContentResolver().update(
1642 ProviderTableMeta.CONTENT_URI_FILE,
1643 cv,
1644 ProviderTableMeta._ID + "=?",
1645 new String[] { String.valueOf(file.getFileId())}
1646 );
1647 } else {
1648 try {
1649 updated = getContentProviderClient().update(
1650 ProviderTableMeta.CONTENT_URI_FILE,
1651 cv,
1652 ProviderTableMeta._ID + "=?",
1653 new String[]{String.valueOf(file.getFileId())}
1654 );
1655 } catch (RemoteException e) {
1656 Log_OC.e(TAG, "Failed saving conflict in database " + e.getMessage());
1657 }
1658 }
1659
1660 Log_OC.d(TAG, "Number of files updated with CONFLICT: " + updated);
1661
1662 if (updated > 0) {
1663 if (etagInConflict != null) {
1664 /// set conflict in all ancestor folders
1665
1666 long parentId = file.getParentId();
1667 Set<String> ancestorIds = new HashSet<String>();
1668 while (parentId != FileDataStorageManager.ROOT_PARENT_ID) {
1669 ancestorIds.add(Long.toString(parentId));
1670 parentId = getFileById(parentId).getParentId();
1671 }
1672
1673 if (ancestorIds.size() > 0) {
1674 StringBuffer whereBuffer = new StringBuffer();
1675 whereBuffer.append(ProviderTableMeta._ID).append(" IN (");
1676 for (int i = 0; i < ancestorIds.size() - 1; i++) {
1677 whereBuffer.append("?,");
1678 }
1679 whereBuffer.append("?");
1680 whereBuffer.append(")");
1681
1682 if (getContentResolver() != null) {
1683 updated = getContentResolver().update(
1684 ProviderTableMeta.CONTENT_URI_FILE,
1685 cv,
1686 whereBuffer.toString(),
1687 ancestorIds.toArray(new String[]{})
1688 );
1689 } else {
1690 try {
1691 updated = getContentProviderClient().update(
1692 ProviderTableMeta.CONTENT_URI_FILE,
1693 cv,
1694 whereBuffer.toString(),
1695 ancestorIds.toArray(new String[]{})
1696 );
1697 } catch (RemoteException e) {
1698 Log_OC.e(TAG, "Failed saving conflict in database " + e.getMessage());
1699 }
1700 }
1701 } // else file is ROOT folder, no parent to set in conflict
1702
1703 } else {
1704 /// update conflict in ancestor folders
1705 // (not directly unset; maybe there are more conflicts below them)
1706 String parentPath = file.getRemotePath();
1707 if (parentPath.endsWith(OCFile.PATH_SEPARATOR)) {
1708 parentPath = parentPath.substring(0, parentPath.length() - 1);
1709 }
1710 parentPath = parentPath.substring(0, parentPath.lastIndexOf(OCFile.PATH_SEPARATOR) + 1);
1711
1712 Log_OC.d(TAG, "checking parents to remove conflict; STARTING with " + parentPath);
1713 while (parentPath.length() > 0) {
1714
1715 String where =
1716 ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " IS NOT NULL AND " +
1717 ProviderTableMeta.FILE_CONTENT_TYPE + " != 'DIR' AND " +
1718 ProviderTableMeta.FILE_ACCOUNT_OWNER + " = ? AND " +
1719 ProviderTableMeta.FILE_PATH + " LIKE ?";
1720 Cursor descendentsInConflict = getContentResolver().query(
1721 ProviderTableMeta.CONTENT_URI_FILE,
1722 new String[]{ProviderTableMeta._ID},
1723 where,
1724 new String[]{mAccount.name, parentPath + "%"},
1725 null
1726 );
1727 if (descendentsInConflict == null || descendentsInConflict.getCount() == 0) {
1728 Log_OC.d(TAG, "NO MORE conflicts in " + parentPath);
1729 if (getContentResolver() != null) {
1730 updated = getContentResolver().update(
1731 ProviderTableMeta.CONTENT_URI_FILE,
1732 cv,
1733 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
1734 ProviderTableMeta.FILE_PATH + "=?",
1735 new String[]{mAccount.name, parentPath}
1736 );
1737 } else {
1738 try {
1739 updated = getContentProviderClient().update(
1740 ProviderTableMeta.CONTENT_URI_FILE,
1741 cv,
1742 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
1743 ProviderTableMeta.FILE_PATH + "=?"
1744 , new String[]{mAccount.name, parentPath}
1745 );
1746 } catch (RemoteException e) {
1747 Log_OC.e(TAG, "Failed saving conflict in database " + e.getMessage());
1748 }
1749 }
1750
1751 } else {
1752 Log_OC.d(TAG, "STILL " + descendentsInConflict.getCount() + " in " + parentPath);
1753 }
1754
1755 if (descendentsInConflict != null) {
1756 descendentsInConflict.close();
1757 }
1758
1759 parentPath = parentPath.substring(0, parentPath.length() - 1); // trim last /
1760 parentPath = parentPath.substring(0, parentPath.lastIndexOf(OCFile.PATH_SEPARATOR) + 1);
1761 Log_OC.d(TAG, "checking parents to remove conflict; NEXT " + parentPath);
1762 }
1763 }
1764 }
1765
1766 }
1767 }