FileDataStorageManager.java 32 KB

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