FileDataStorageManager.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  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.Collections;
  22. import java.util.Iterator;
  23. import java.util.List;
  24. import java.util.Vector;
  25. import com.owncloud.android.DisplayUtils;
  26. import com.owncloud.android.Log_OC;
  27. import com.owncloud.android.db.ProviderMeta;
  28. import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
  29. import com.owncloud.android.utils.FileStorageUtils;
  30. import android.accounts.Account;
  31. import android.content.ContentProviderClient;
  32. import android.content.ContentProviderOperation;
  33. import android.content.ContentProviderResult;
  34. import android.content.ContentResolver;
  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 implements DataStorageManager {
  41. private ContentResolver mContentResolver;
  42. private ContentProviderClient mContentProvider;
  43. private Account mAccount;
  44. private static String TAG = "FileDataStorageManager";
  45. public FileDataStorageManager(Account account, ContentResolver cr) {
  46. mContentProvider = null;
  47. mContentResolver = cr;
  48. mAccount = account;
  49. }
  50. public FileDataStorageManager(Account account, ContentProviderClient cp) {
  51. mContentProvider = cp;
  52. mContentResolver = null;
  53. mAccount = account;
  54. }
  55. @Override
  56. public OCFile getFileByPath(String path) {
  57. Cursor c = getCursorForValue(ProviderTableMeta.FILE_PATH, path);
  58. OCFile file = null;
  59. if (c.moveToFirst()) {
  60. file = createFileInstance(c);
  61. }
  62. c.close();
  63. if (file == null && OCFile.PATH_SEPARATOR.equals(path)) {
  64. return createRootDir(); // root should always exist
  65. }
  66. return file;
  67. }
  68. private OCFile createRootDir() {
  69. OCFile file = new OCFile(OCFile.PATH_SEPARATOR);
  70. file.setMimetype("DIR");
  71. file.setParentId(DataStorageManager.ROOT_PARENT_ID);
  72. saveFile(file);
  73. return file;
  74. }
  75. @Override
  76. public OCFile getFileById(long id) {
  77. Cursor c = getCursorForValue(ProviderTableMeta._ID, String.valueOf(id));
  78. OCFile file = null;
  79. if (c.moveToFirst()) {
  80. file = createFileInstance(c);
  81. }
  82. c.close();
  83. return file;
  84. }
  85. public OCFile getFileByLocalPath(String path) {
  86. Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
  87. OCFile file = null;
  88. if (c.moveToFirst()) {
  89. file = createFileInstance(c);
  90. }
  91. c.close();
  92. return file;
  93. }
  94. @Override
  95. public boolean fileExists(long id) {
  96. return fileExists(ProviderTableMeta._ID, String.valueOf(id));
  97. }
  98. @Override
  99. public boolean fileExists(String path) {
  100. return fileExists(ProviderTableMeta.FILE_PATH, path);
  101. }
  102. @Override
  103. public boolean saveFile(OCFile file) {
  104. boolean overriden = false;
  105. ContentValues cv = new ContentValues();
  106. cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
  107. cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData());
  108. cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
  109. cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
  110. cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
  111. cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
  112. //if (file.getParentId() != DataStorageManager.ROOT_PARENT_ID)
  113. cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
  114. cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
  115. if (!file.isDirectory())
  116. cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
  117. cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
  118. cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
  119. cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
  120. cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
  121. cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
  122. boolean sameRemotePath = fileExists(file.getRemotePath());
  123. boolean changesSizeOfAncestors = false;
  124. if (sameRemotePath ||
  125. fileExists(file.getFileId()) ) { // for renamed files; no more delete and create
  126. OCFile oldFile = null;
  127. if (sameRemotePath) {
  128. oldFile = getFileByPath(file.getRemotePath());
  129. file.setFileId(oldFile.getFileId());
  130. } else {
  131. oldFile = getFileById(file.getFileId());
  132. }
  133. changesSizeOfAncestors = (oldFile.getFileLength() != file.getFileLength());
  134. overriden = true;
  135. if (getContentResolver() != null) {
  136. getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv,
  137. ProviderTableMeta._ID + "=?",
  138. new String[] { String.valueOf(file.getFileId()) });
  139. } else {
  140. try {
  141. getContentProvider().update(ProviderTableMeta.CONTENT_URI,
  142. cv, ProviderTableMeta._ID + "=?",
  143. new String[] { String.valueOf(file.getFileId()) });
  144. } catch (RemoteException e) {
  145. Log_OC.e(TAG,
  146. "Fail to insert insert file to database "
  147. + e.getMessage());
  148. }
  149. }
  150. } else {
  151. changesSizeOfAncestors = true;
  152. Uri result_uri = null;
  153. if (getContentResolver() != null) {
  154. result_uri = getContentResolver().insert(
  155. ProviderTableMeta.CONTENT_URI_FILE, cv);
  156. } else {
  157. try {
  158. result_uri = getContentProvider().insert(
  159. ProviderTableMeta.CONTENT_URI_FILE, cv);
  160. } catch (RemoteException e) {
  161. Log_OC.e(TAG,
  162. "Fail to insert insert file to database "
  163. + e.getMessage());
  164. }
  165. }
  166. if (result_uri != null) {
  167. long new_id = Long.parseLong(result_uri.getPathSegments()
  168. .get(1));
  169. file.setFileId(new_id);
  170. }
  171. }
  172. if (file.isDirectory()) {
  173. calculateFolderSize(file.getFileId());
  174. if (file.needsUpdatingWhileSaving()) {
  175. for (OCFile f : getDirectoryContent(file))
  176. saveFile(f);
  177. }
  178. }
  179. if (changesSizeOfAncestors || file.isDirectory()) {
  180. updateSizesToTheRoot(file.getParentId());
  181. }
  182. return overriden;
  183. }
  184. @Override
  185. public void saveFiles(List<OCFile> files) {
  186. Iterator<OCFile> filesIt = files.iterator();
  187. ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(files.size());
  188. OCFile file = null;
  189. // prepare operations to perform
  190. while (filesIt.hasNext()) {
  191. file = filesIt.next();
  192. ContentValues cv = new ContentValues();
  193. cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
  194. cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData());
  195. cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
  196. cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
  197. cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
  198. cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
  199. if (file.getParentId() != DataStorageManager.ROOT_PARENT_ID)
  200. cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
  201. cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
  202. if (!file.isDirectory())
  203. cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
  204. cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
  205. cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
  206. cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
  207. cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
  208. cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
  209. if (fileExists(file.getRemotePath())) {
  210. OCFile oldFile = getFileByPath(file.getRemotePath());
  211. file.setFileId(oldFile.getFileId());
  212. if (file.isDirectory()) {
  213. cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, oldFile.getFileLength());
  214. file.setFileLength(oldFile.getFileLength());
  215. }
  216. operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
  217. withValues(cv).
  218. withSelection( ProviderTableMeta._ID + "=?",
  219. new String[] { String.valueOf(file.getFileId()) })
  220. .build());
  221. } else if (fileExists(file.getFileId())) {
  222. OCFile oldFile = getFileById(file.getFileId());
  223. if (file.getStoragePath() == null && oldFile.getStoragePath() != null)
  224. file.setStoragePath(oldFile.getStoragePath());
  225. if (!file.isDirectory())
  226. cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
  227. else {
  228. cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, oldFile.getFileLength());
  229. file.setFileLength(oldFile.getFileLength());
  230. }
  231. operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
  232. withValues(cv).
  233. withSelection( ProviderTableMeta._ID + "=?",
  234. new String[] { String.valueOf(file.getFileId()) })
  235. .build());
  236. } else {
  237. operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build());
  238. }
  239. }
  240. // apply operations in batch
  241. ContentProviderResult[] results = null;
  242. try {
  243. if (getContentResolver() != null) {
  244. results = getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations);
  245. } else {
  246. results = getContentProvider().applyBatch(operations);
  247. }
  248. } catch (OperationApplicationException e) {
  249. Log_OC.e(TAG, "Fail to update/insert list of files to database " + e.getMessage());
  250. } catch (RemoteException e) {
  251. Log_OC.e(TAG, "Fail to update/insert list of files to database " + e.getMessage());
  252. }
  253. // update new id in file objects for insertions
  254. if (results != null) {
  255. long newId;
  256. for (int i=0; i<results.length; i++) {
  257. if (results[i].uri != null) {
  258. newId = Long.parseLong(results[i].uri.getPathSegments().get(1));
  259. files.get(i).setFileId(newId);
  260. //Log_OC.v(TAG, "Found and added id in insertion for " + files.get(i).getRemotePath());
  261. }
  262. }
  263. }
  264. for (OCFile aFile : files) {
  265. if (aFile.isDirectory() && aFile.needsUpdatingWhileSaving())
  266. saveFiles(getDirectoryContent(aFile));
  267. }
  268. }
  269. public void setAccount(Account account) {
  270. mAccount = account;
  271. }
  272. public Account getAccount() {
  273. return mAccount;
  274. }
  275. public void setContentResolver(ContentResolver cr) {
  276. mContentResolver = cr;
  277. }
  278. public ContentResolver getContentResolver() {
  279. return mContentResolver;
  280. }
  281. public void setContentProvider(ContentProviderClient cp) {
  282. mContentProvider = cp;
  283. }
  284. public ContentProviderClient getContentProvider() {
  285. return mContentProvider;
  286. }
  287. @Override
  288. public Vector<OCFile> getDirectoryContent(OCFile f) {
  289. if (f != null && f.isDirectory() && f.getFileId() != -1) {
  290. return getDirectoryContent(f.getFileId());
  291. } else {
  292. return new Vector<OCFile>();
  293. }
  294. }
  295. private Vector<OCFile> getDirectoryContent(long parentId) {
  296. Vector<OCFile> ret = new Vector<OCFile>();
  297. Uri req_uri = Uri.withAppendedPath(
  298. ProviderTableMeta.CONTENT_URI_DIR,
  299. String.valueOf(parentId));
  300. Cursor c = null;
  301. if (getContentProvider() != null) {
  302. try {
  303. c = getContentProvider().query(req_uri, null,
  304. ProviderTableMeta.FILE_PARENT + "=?" ,
  305. new String[] { String.valueOf(parentId)}, null);
  306. } catch (RemoteException e) {
  307. Log_OC.e(TAG, e.getMessage());
  308. return ret;
  309. }
  310. } else {
  311. c = getContentResolver().query(req_uri, null,
  312. ProviderTableMeta.FILE_PARENT + "=?" ,
  313. new String[] { String.valueOf(parentId)}, null);
  314. }
  315. if (c.moveToFirst()) {
  316. do {
  317. OCFile child = createFileInstance(c);
  318. ret.add(child);
  319. } while (c.moveToNext());
  320. }
  321. c.close();
  322. Collections.sort(ret);
  323. return ret;
  324. }
  325. private boolean fileExists(String cmp_key, String value) {
  326. Cursor c;
  327. if (getContentResolver() != null) {
  328. c = getContentResolver()
  329. .query(ProviderTableMeta.CONTENT_URI,
  330. null,
  331. cmp_key + "=? AND "
  332. + ProviderTableMeta.FILE_ACCOUNT_OWNER
  333. + "=?",
  334. new String[] { value, mAccount.name }, null);
  335. } else {
  336. try {
  337. c = getContentProvider().query(
  338. ProviderTableMeta.CONTENT_URI,
  339. null,
  340. cmp_key + "=? AND "
  341. + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
  342. new String[] { value, mAccount.name }, null);
  343. } catch (RemoteException e) {
  344. Log_OC.e(TAG,
  345. "Couldn't determine file existance, assuming non existance: "
  346. + e.getMessage());
  347. return false;
  348. }
  349. }
  350. boolean retval = c.moveToFirst();
  351. c.close();
  352. return retval;
  353. }
  354. private Cursor getCursorForValue(String key, String value) {
  355. Cursor c = null;
  356. if (getContentResolver() != null) {
  357. c = getContentResolver()
  358. .query(ProviderTableMeta.CONTENT_URI,
  359. null,
  360. key + "=? AND "
  361. + ProviderTableMeta.FILE_ACCOUNT_OWNER
  362. + "=?",
  363. new String[] { value, mAccount.name }, null);
  364. } else {
  365. try {
  366. c = getContentProvider().query(
  367. ProviderTableMeta.CONTENT_URI,
  368. null,
  369. key + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER
  370. + "=?", new String[] { value, mAccount.name },
  371. null);
  372. } catch (RemoteException e) {
  373. Log_OC.e(TAG, "Could not get file details: " + e.getMessage());
  374. c = null;
  375. }
  376. }
  377. return c;
  378. }
  379. private OCFile createFileInstance(Cursor c) {
  380. OCFile file = null;
  381. if (c != null) {
  382. file = new OCFile(c.getString(c
  383. .getColumnIndex(ProviderTableMeta.FILE_PATH)));
  384. file.setFileId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
  385. file.setParentId(c.getLong(c
  386. .getColumnIndex(ProviderTableMeta.FILE_PARENT)));
  387. file.setMimetype(c.getString(c
  388. .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
  389. if (!file.isDirectory()) {
  390. file.setStoragePath(c.getString(c
  391. .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)));
  392. if (file.getStoragePath() == null) {
  393. // 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
  394. File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
  395. if (f.exists()) {
  396. file.setStoragePath(f.getAbsolutePath());
  397. file.setLastSyncDateForData(f.lastModified());
  398. }
  399. }
  400. }
  401. file.setFileLength(c.getLong(c
  402. .getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH)));
  403. file.setCreationTimestamp(c.getLong(c
  404. .getColumnIndex(ProviderTableMeta.FILE_CREATION)));
  405. file.setModificationTimestamp(c.getLong(c
  406. .getColumnIndex(ProviderTableMeta.FILE_MODIFIED)));
  407. file.setModificationTimestampAtLastSyncForData(c.getLong(c
  408. .getColumnIndex(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA)));
  409. file.setLastSyncDateForProperties(c.getLong(c
  410. .getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE)));
  411. file.setLastSyncDateForData(c.getLong(c.
  412. getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA)));
  413. file.setKeepInSync(c.getInt(
  414. c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false);
  415. file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG)));
  416. }
  417. return file;
  418. }
  419. @Override
  420. public void removeFile(OCFile file, boolean removeLocalCopy) {
  421. Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, ""+file.getFileId());
  422. if (getContentProvider() != null) {
  423. try {
  424. getContentProvider().delete(file_uri,
  425. ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?",
  426. new String[]{mAccount.name});
  427. } catch (RemoteException e) {
  428. e.printStackTrace();
  429. }
  430. } else {
  431. getContentResolver().delete(file_uri,
  432. ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?",
  433. new String[]{mAccount.name});
  434. }
  435. if (file.isDown() && removeLocalCopy) {
  436. new File(file.getStoragePath()).delete();
  437. }
  438. if (file.isDirectory() && removeLocalCopy) {
  439. File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
  440. if (f.exists() && f.isDirectory() && (f.list() == null || f.list().length == 0)) {
  441. f.delete();
  442. }
  443. }
  444. if (file.getFileLength() > 0) {
  445. updateSizesToTheRoot(file.getParentId());
  446. }
  447. }
  448. @Override
  449. public void removeDirectory(OCFile dir, boolean removeDBData, boolean removeLocalContent) {
  450. // TODO consider possible failures
  451. if (dir != null && dir.isDirectory() && dir.getFileId() != -1) {
  452. Vector<OCFile> children = getDirectoryContent(dir);
  453. if (children.size() > 0) {
  454. OCFile child = null;
  455. for (int i=0; i<children.size(); i++) {
  456. child = children.get(i);
  457. if (child.isDirectory()) {
  458. removeDirectory(child, removeDBData, removeLocalContent);
  459. } else {
  460. if (removeDBData) {
  461. removeFile(child, removeLocalContent);
  462. } else if (removeLocalContent) {
  463. if (child.isDown()) {
  464. new File(child.getStoragePath()).delete();
  465. }
  466. }
  467. }
  468. }
  469. }
  470. if (removeDBData) {
  471. removeFile(dir, true);
  472. }
  473. if (dir.getFileLength() > 0) {
  474. updateSizesToTheRoot(dir.getParentId());
  475. }
  476. }
  477. }
  478. /**
  479. * Updates database for a folder that was moved to a different location.
  480. *
  481. * TODO explore better (faster) implementations
  482. * TODO throw exceptions up !
  483. */
  484. @Override
  485. public void moveDirectory(OCFile dir, String newPath) {
  486. // TODO check newPath
  487. if (dir != null && dir.isDirectory() && dir.fileExists() && !dir.getFileName().equals(OCFile.PATH_SEPARATOR)) {
  488. /// 1. get all the descendants of 'dir' in a single QUERY (including 'dir')
  489. Cursor c = null;
  490. if (getContentProvider() != null) {
  491. try {
  492. c = getContentProvider().query(ProviderTableMeta.CONTENT_URI,
  493. null,
  494. ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ? ",
  495. new String[] { mAccount.name, dir.getRemotePath() + "%" }, ProviderTableMeta.FILE_PATH + " ASC ");
  496. } catch (RemoteException e) {
  497. Log_OC.e(TAG, e.getMessage());
  498. }
  499. } else {
  500. c = getContentResolver().query(ProviderTableMeta.CONTENT_URI,
  501. null,
  502. ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ? ",
  503. new String[] { mAccount.name, dir.getRemotePath() + "%" }, ProviderTableMeta.FILE_PATH + " ASC ");
  504. }
  505. /// 2. prepare a batch of update operations to change all the descendants
  506. ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(c.getCount());
  507. int lengthOfOldPath = dir.getRemotePath().length();
  508. String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
  509. int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
  510. if (c.moveToFirst()) {
  511. do {
  512. ContentValues cv = new ContentValues(); // don't take the constructor out of the loop and clear the object
  513. OCFile child = createFileInstance(c);
  514. cv.put(ProviderTableMeta.FILE_PATH, newPath + child.getRemotePath().substring(lengthOfOldPath));
  515. if (child.getStoragePath() != null && child.getStoragePath().startsWith(defaultSavePath)) {
  516. cv.put(ProviderTableMeta.FILE_STORAGE_PATH, defaultSavePath + newPath + child.getStoragePath().substring(lengthOfOldStoragePath));
  517. }
  518. operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
  519. withValues(cv).
  520. withSelection( ProviderTableMeta._ID + "=?",
  521. new String[] { String.valueOf(child.getFileId()) })
  522. .build());
  523. } while (c.moveToNext());
  524. }
  525. c.close();
  526. /// 3. apply updates in batch
  527. try {
  528. if (getContentResolver() != null) {
  529. getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations);
  530. } else {
  531. getContentProvider().applyBatch(operations);
  532. }
  533. } catch (OperationApplicationException e) {
  534. Log_OC.e(TAG, "Fail to update descendants of " + dir.getFileId() + " in database", e);
  535. } catch (RemoteException e) {
  536. Log_OC.e(TAG, "Fail to update desendants of " + dir.getFileId() + " in database", e);
  537. }
  538. }
  539. }
  540. @Override
  541. public Vector<OCFile> getDirectoryImages(OCFile directory) {
  542. Vector<OCFile> ret = new Vector<OCFile>();
  543. if (directory != null) {
  544. // TODO better implementation, filtering in the access to database (if possible) instead of here
  545. Vector<OCFile> tmp = getDirectoryContent(directory);
  546. OCFile current = null;
  547. for (int i=0; i<tmp.size(); i++) {
  548. current = tmp.get(i);
  549. if (current.isImage()) {
  550. ret.add(current);
  551. }
  552. }
  553. }
  554. return ret;
  555. }
  556. /**
  557. * Calculate and save the folderSize on DB
  558. * @param id
  559. */
  560. @Override
  561. public void calculateFolderSize(long id) {
  562. long folderSize = 0;
  563. Vector<OCFile> files = getDirectoryContent(id);
  564. for (OCFile f: files)
  565. {
  566. folderSize = folderSize + f.getFileLength();
  567. }
  568. updateSize(id, folderSize);
  569. }
  570. /**
  571. * Update the size value of an OCFile in DB
  572. */
  573. private int updateSize(long id, long size) {
  574. ContentValues cv = new ContentValues();
  575. cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, size);
  576. int result = -1;
  577. if (getContentResolver() != null) {
  578. result = getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, ProviderTableMeta._ID + "=?",
  579. new String[] { String.valueOf(id) });
  580. } else {
  581. try {
  582. result = getContentProvider().update(ProviderTableMeta.CONTENT_URI, cv, ProviderTableMeta._ID + "=?",
  583. new String[] { String.valueOf(id) });
  584. } catch (RemoteException e) {
  585. Log_OC.e(TAG,"Fail to update size column into database " + e.getMessage());
  586. }
  587. }
  588. return result;
  589. }
  590. /**
  591. * Update the size of a subtree of folder from a file to the root
  592. * @param parentId: parent of the file
  593. */
  594. private void updateSizesToTheRoot(long parentId) {
  595. OCFile file;
  596. while (parentId != DataStorageManager.ROOT_PARENT_ID) {
  597. // Update the size of the parent
  598. calculateFolderSize(parentId);
  599. // search the next parent
  600. file = getFileById(parentId);
  601. parentId = file.getParentId();
  602. }
  603. }
  604. }