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