FileContentProvider.java 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. /* ownCloud Android client application
  2. * Copyright (C) 2011 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.providers;
  19. import java.util.ArrayList;
  20. import java.util.HashMap;
  21. import com.owncloud.android.R;
  22. import com.owncloud.android.datamodel.FileDataStorageManager;
  23. import com.owncloud.android.db.ProviderMeta;
  24. import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
  25. import com.owncloud.android.lib.operations.common.ShareType;
  26. import com.owncloud.android.utils.Log_OC;
  27. import android.content.ContentProvider;
  28. import android.content.ContentProviderOperation;
  29. import android.content.ContentProviderResult;
  30. import android.content.ContentUris;
  31. import android.content.ContentValues;
  32. import android.content.Context;
  33. import android.content.OperationApplicationException;
  34. import android.content.UriMatcher;
  35. import android.database.Cursor;
  36. import android.database.SQLException;
  37. import android.database.sqlite.SQLiteDatabase;
  38. import android.database.sqlite.SQLiteOpenHelper;
  39. import android.database.sqlite.SQLiteQueryBuilder;
  40. import android.net.Uri;
  41. import android.text.TextUtils;
  42. /**
  43. * The ContentProvider for the ownCloud App.
  44. *
  45. * @author Bartek Przybylski
  46. * @author David A. Velasco
  47. *
  48. */
  49. public class FileContentProvider extends ContentProvider {
  50. private DataBaseHelper mDbHelper;
  51. // Projection for filelist table
  52. private static HashMap<String, String> mFileProjectionMap;
  53. static {
  54. mFileProjectionMap = new HashMap<String, String>();
  55. mFileProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);
  56. mFileProjectionMap.put(ProviderTableMeta.FILE_PARENT,
  57. ProviderTableMeta.FILE_PARENT);
  58. mFileProjectionMap.put(ProviderTableMeta.FILE_PATH,
  59. ProviderTableMeta.FILE_PATH);
  60. mFileProjectionMap.put(ProviderTableMeta.FILE_NAME,
  61. ProviderTableMeta.FILE_NAME);
  62. mFileProjectionMap.put(ProviderTableMeta.FILE_CREATION,
  63. ProviderTableMeta.FILE_CREATION);
  64. mFileProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,
  65. ProviderTableMeta.FILE_MODIFIED);
  66. mFileProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
  67. ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA);
  68. mFileProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,
  69. ProviderTableMeta.FILE_CONTENT_LENGTH);
  70. mFileProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,
  71. ProviderTableMeta.FILE_CONTENT_TYPE);
  72. mFileProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,
  73. ProviderTableMeta.FILE_STORAGE_PATH);
  74. mFileProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE,
  75. ProviderTableMeta.FILE_LAST_SYNC_DATE);
  76. mFileProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,
  77. ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA);
  78. mFileProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC,
  79. ProviderTableMeta.FILE_KEEP_IN_SYNC);
  80. mFileProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER,
  81. ProviderTableMeta.FILE_ACCOUNT_OWNER);
  82. mFileProjectionMap.put(ProviderTableMeta.FILE_ETAG,
  83. ProviderTableMeta.FILE_ETAG);
  84. mFileProjectionMap.put(ProviderTableMeta.FILE_SHARE_BY_LINK,
  85. ProviderTableMeta.FILE_SHARE_BY_LINK);
  86. mFileProjectionMap.put(ProviderTableMeta.FILE_PUBLIC_LINK,
  87. ProviderTableMeta.FILE_PUBLIC_LINK);
  88. }
  89. private static final int SINGLE_FILE = 1;
  90. private static final int DIRECTORY = 2;
  91. private static final int ROOT_DIRECTORY = 3;
  92. private static final int SHARES = 4;
  93. // Projection for ocshares table
  94. private static HashMap<String, String> mOCSharesProjectionMap;
  95. static {
  96. mOCSharesProjectionMap = new HashMap<String, String>();
  97. mOCSharesProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);
  98. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_FILE_SOURCE,
  99. ProviderTableMeta.OCSHARES_FILE_SOURCE);
  100. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE,
  101. ProviderTableMeta.OCSHARES_ITEM_SOURCE);
  102. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARE_TYPE,
  103. ProviderTableMeta.OCSHARES_SHARE_TYPE);
  104. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARE_WITH,
  105. ProviderTableMeta.OCSHARES_SHARE_WITH);
  106. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_PATH,
  107. ProviderTableMeta.OCSHARES_PATH);
  108. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_PERMISSIONS,
  109. ProviderTableMeta.OCSHARES_PERMISSIONS);
  110. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARED_DATE,
  111. ProviderTableMeta.OCSHARES_SHARED_DATE);
  112. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE,
  113. ProviderTableMeta.OCSHARES_EXPIRATION_DATE);
  114. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_TOKEN,
  115. ProviderTableMeta.OCSHARES_TOKEN);
  116. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME,
  117. ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME);
  118. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY,
  119. ProviderTableMeta.OCSHARES_IS_DIRECTORY);
  120. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_USER_ID,
  121. ProviderTableMeta.OCSHARES_USER_ID);
  122. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED,
  123. ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED);
  124. mOCSharesProjectionMap.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER,
  125. ProviderTableMeta.OCSHARES_ACCOUNT_OWNER);
  126. }
  127. private UriMatcher mUriMatcher;
  128. @Override
  129. public int delete(Uri uri, String where, String[] whereArgs) {
  130. //Log_OC.d(TAG, "Deleting " + uri + " at provider " + this);
  131. int count = 0;
  132. SQLiteDatabase db = mDbHelper.getWritableDatabase();
  133. db.beginTransaction();
  134. try {
  135. count = delete(db, uri, where, whereArgs);
  136. db.setTransactionSuccessful();
  137. } finally {
  138. db.endTransaction();
  139. }
  140. getContext().getContentResolver().notifyChange(uri, null);
  141. return count;
  142. }
  143. private int delete(SQLiteDatabase db, Uri uri, String where, String[] whereArgs) {
  144. int count = 0;
  145. switch (mUriMatcher.match(uri)) {
  146. case SINGLE_FILE:
  147. /*Cursor c = query(db, uri, null, where, whereArgs, null);
  148. String remotePath = "(unexisting)";
  149. if (c != null && c.moveToFirst()) {
  150. remotePath = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH));
  151. }
  152. Log_OC.d(TAG, "Removing FILE " + remotePath);
  153. */
  154. count = db.delete(ProviderTableMeta.FILE_TABLE_NAME,
  155. ProviderTableMeta._ID
  156. + "="
  157. + uri.getPathSegments().get(1)
  158. + (!TextUtils.isEmpty(where) ? " AND (" + where
  159. + ")" : ""), whereArgs);
  160. /* just for log
  161. if (c!=null) {
  162. c.close();
  163. }
  164. */
  165. break;
  166. case DIRECTORY:
  167. // deletion of folder is recursive
  168. /*
  169. Uri folderUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, Long.parseLong(uri.getPathSegments().get(1)));
  170. Cursor folder = query(db, folderUri, null, null, null, null);
  171. String folderName = "(unknown)";
  172. if (folder != null && folder.moveToFirst()) {
  173. folderName = folder.getString(folder.getColumnIndex(ProviderTableMeta.FILE_PATH));
  174. }
  175. */
  176. Cursor children = query(uri, null, null, null, null);
  177. if (children != null && children.moveToFirst()) {
  178. long childId;
  179. boolean isDir;
  180. //String remotePath;
  181. while (!children.isAfterLast()) {
  182. childId = children.getLong(children.getColumnIndex(ProviderTableMeta._ID));
  183. isDir = "DIR".equals(children.getString(children.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
  184. //remotePath = children.getString(children.getColumnIndex(ProviderTableMeta.FILE_PATH));
  185. if (isDir) {
  186. count += delete(db, ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId), null, null);
  187. } else {
  188. count += delete(db, ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, childId), null, null);
  189. }
  190. children.moveToNext();
  191. }
  192. children.close();
  193. } /*else {
  194. Log_OC.d(TAG, "No child to remove in DIRECTORY " + folderName);
  195. }
  196. Log_OC.d(TAG, "Removing DIRECTORY " + folderName + " (or maybe not) ");
  197. */
  198. count += db.delete(ProviderTableMeta.FILE_TABLE_NAME,
  199. ProviderTableMeta._ID
  200. + "="
  201. + uri.getPathSegments().get(1)
  202. + (!TextUtils.isEmpty(where) ? " AND (" + where
  203. + ")" : ""), whereArgs);
  204. /* Just for log
  205. if (folder != null) {
  206. folder.close();
  207. }*/
  208. break;
  209. case ROOT_DIRECTORY:
  210. //Log_OC.d(TAG, "Removing ROOT!");
  211. count = db.delete(ProviderTableMeta.FILE_TABLE_NAME, where, whereArgs);
  212. break;
  213. case SHARES:
  214. count = db.delete(ProviderTableMeta.OCSHARES_TABLE_NAME, where, whereArgs);
  215. break;
  216. default:
  217. //Log_OC.e(TAG, "Unknown uri " + uri);
  218. throw new IllegalArgumentException("Unknown uri: " + uri.toString());
  219. }
  220. return count;
  221. }
  222. // TODO: switch(uri)
  223. @Override
  224. public String getType(Uri uri) {
  225. switch (mUriMatcher.match(uri)) {
  226. case ROOT_DIRECTORY:
  227. return ProviderTableMeta.CONTENT_TYPE;
  228. case SINGLE_FILE:
  229. return ProviderTableMeta.CONTENT_TYPE_ITEM;
  230. default:
  231. throw new IllegalArgumentException("Unknown Uri id."
  232. + uri.toString());
  233. }
  234. }
  235. @Override
  236. public Uri insert(Uri uri, ContentValues values) {
  237. //Log_OC.d(TAG, "Inserting " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
  238. Uri newUri = null;
  239. SQLiteDatabase db = mDbHelper.getWritableDatabase();
  240. db.beginTransaction();
  241. try {
  242. newUri = insert(db, uri, values);
  243. db.setTransactionSuccessful();
  244. } finally {
  245. db.endTransaction();
  246. }
  247. getContext().getContentResolver().notifyChange(newUri, null);
  248. return newUri;
  249. }
  250. private Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) {
  251. switch (mUriMatcher.match(uri)){
  252. case ROOT_DIRECTORY:
  253. case SINGLE_FILE:
  254. String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH);
  255. String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER);
  256. String[] projection = new String[] {ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH, ProviderTableMeta.FILE_ACCOUNT_OWNER };
  257. String where = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
  258. String[] whereArgs = new String[] {remotePath, accountName};
  259. Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null);
  260. if (doubleCheck == null || !doubleCheck.moveToFirst()) { // ugly patch; serious refactorization is needed to reduce work in FileDataStorageManager and bring it to FileContentProvider
  261. long rowId = db.insert(ProviderTableMeta.FILE_TABLE_NAME, null, values);
  262. if (rowId > 0) {
  263. Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
  264. //Log_OC.d(TAG, "Inserted " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
  265. return insertedFileUri;
  266. } else {
  267. //Log_OC.d(TAG, "Error while inserting " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
  268. throw new SQLException("ERROR " + uri);
  269. }
  270. } else {
  271. // file is already inserted; race condition, let's avoid a duplicated entry
  272. Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID)));
  273. doubleCheck.close();
  274. return insertedFileUri;
  275. }
  276. case SHARES:
  277. String path = values.getAsString(ProviderTableMeta.OCSHARES_PATH);
  278. String accountNameShare= values.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER);
  279. String[] projectionShare = new String[] {ProviderTableMeta._ID, ProviderTableMeta.OCSHARES_PATH, ProviderTableMeta.OCSHARES_ACCOUNT_OWNER };
  280. String whereShare = ProviderTableMeta.OCSHARES_PATH + "=? AND " + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
  281. String[] whereArgsShare = new String[] {path, accountNameShare};
  282. Uri insertedShareUri = null;
  283. Cursor doubleCheckShare = query(db, uri, projectionShare, whereShare, whereArgsShare, null);
  284. if (doubleCheckShare == null || !doubleCheckShare.moveToFirst()) { // ugly patch; serious refactorization is needed to reduce work in FileDataStorageManager and bring it to FileContentProvider
  285. long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values);
  286. if (rowId >0) {
  287. insertedShareUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId);
  288. } else {
  289. throw new SQLException("ERROR " + uri);
  290. }
  291. } else {
  292. // file is already inserted; race condition, let's avoid a duplicated entry
  293. insertedShareUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, doubleCheckShare.getLong(doubleCheckShare.getColumnIndex(ProviderTableMeta._ID)));
  294. doubleCheckShare.close();
  295. }
  296. updateFilesTableAccordingToShareInsertion(db, uri, values);
  297. return insertedShareUri;
  298. default:
  299. throw new IllegalArgumentException("Unknown uri id: " + uri);
  300. }
  301. }
  302. private void updateFilesTableAccordingToShareInsertion(SQLiteDatabase db, Uri uri, ContentValues shareValues) {
  303. ContentValues fileValues = new ContentValues();
  304. fileValues.put(ProviderTableMeta.FILE_SHARE_BY_LINK,
  305. ShareType.PUBLIC_LINK.getValue() == shareValues.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE)? 1 : 0);
  306. String whereShare = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
  307. String[] whereArgsShare = new String[] {
  308. shareValues.getAsString(ProviderTableMeta.OCSHARES_PATH),
  309. shareValues.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER)
  310. };
  311. db.update(ProviderTableMeta.FILE_TABLE_NAME, fileValues, whereShare, whereArgsShare);
  312. }
  313. @Override
  314. public boolean onCreate() {
  315. mDbHelper = new DataBaseHelper(getContext());
  316. String authority = getContext().getResources().getString(R.string.authority);
  317. mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  318. mUriMatcher.addURI(authority, null, ROOT_DIRECTORY);
  319. mUriMatcher.addURI(authority, "file/", SINGLE_FILE);
  320. mUriMatcher.addURI(authority, "file/#", SINGLE_FILE);
  321. mUriMatcher.addURI(authority, "dir/", DIRECTORY);
  322. mUriMatcher.addURI(authority, "dir/#", DIRECTORY);
  323. mUriMatcher.addURI(authority, "shares/", SHARES);
  324. mUriMatcher.addURI(authority, "shares/#", SHARES);
  325. return true;
  326. }
  327. @Override
  328. public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  329. Cursor result = null;
  330. SQLiteDatabase db = mDbHelper.getReadableDatabase();
  331. db.beginTransaction();
  332. try {
  333. result = query(db, uri, projection, selection, selectionArgs, sortOrder);
  334. db.setTransactionSuccessful();
  335. } finally {
  336. db.endTransaction();
  337. }
  338. return result;
  339. }
  340. private Cursor query(SQLiteDatabase db, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  341. SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();
  342. sqlQuery.setTables(ProviderTableMeta.FILE_TABLE_NAME);
  343. sqlQuery.setProjectionMap(mFileProjectionMap);
  344. switch (mUriMatcher.match(uri)) {
  345. case ROOT_DIRECTORY:
  346. break;
  347. case DIRECTORY:
  348. String folderId = uri.getPathSegments().get(1);
  349. sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="
  350. + folderId);
  351. break;
  352. case SINGLE_FILE:
  353. if (uri.getPathSegments().size() > 1) {
  354. sqlQuery.appendWhere(ProviderTableMeta._ID + "="
  355. + uri.getPathSegments().get(1));
  356. }
  357. break;
  358. case SHARES:
  359. sqlQuery.setTables(ProviderTableMeta.OCSHARES_TABLE_NAME);
  360. sqlQuery.setProjectionMap(mOCSharesProjectionMap);
  361. if (uri.getPathSegments().size() > 1) {
  362. sqlQuery.appendWhere(ProviderTableMeta._ID + "="
  363. + uri.getPathSegments().get(1));
  364. }
  365. break;
  366. default:
  367. throw new IllegalArgumentException("Unknown uri id: " + uri);
  368. }
  369. String order;
  370. if (TextUtils.isEmpty(sortOrder)) {
  371. if (mUriMatcher.match(uri) == SHARES) {
  372. order = ProviderTableMeta.OCSHARES_DEFAULT_SORT_ORDER;
  373. } else {
  374. order = ProviderTableMeta.FILE_DEFAULT_SORT_ORDER;
  375. }
  376. } else {
  377. order = sortOrder;
  378. }
  379. // DB case_sensitive
  380. db.execSQL("PRAGMA case_sensitive_like = true");
  381. Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, null, null, order);
  382. c.setNotificationUri(getContext().getContentResolver(), uri);
  383. return c;
  384. }
  385. @Override
  386. public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
  387. //Log_OC.d(TAG, "Updating " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
  388. int count = 0;
  389. SQLiteDatabase db = mDbHelper.getWritableDatabase();
  390. db.beginTransaction();
  391. try {
  392. count = update(db, uri, values, selection, selectionArgs);
  393. db.setTransactionSuccessful();
  394. } finally {
  395. db.endTransaction();
  396. }
  397. getContext().getContentResolver().notifyChange(uri, null);
  398. return count;
  399. }
  400. private int update(SQLiteDatabase db, Uri uri, ContentValues values, String selection, String[] selectionArgs) {
  401. switch (mUriMatcher.match(uri)) {
  402. case DIRECTORY:
  403. return updateFolderSize(db, selectionArgs[0]);
  404. case SHARES:
  405. return db.update(ProviderTableMeta.OCSHARES_TABLE_NAME, values, selection, selectionArgs);
  406. default:
  407. return db.update(ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs);
  408. }
  409. }
  410. private int updateFolderSize(SQLiteDatabase db, String folderId) {
  411. int count = 0;
  412. String [] whereArgs = new String[] { folderId };
  413. // read current size saved for the folder
  414. long folderSize = 0;
  415. long folderParentId = -1;
  416. Uri selectFolderUri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, folderId);
  417. String[] folderProjection = new String[] { ProviderTableMeta.FILE_CONTENT_LENGTH, ProviderTableMeta.FILE_PARENT};
  418. String folderWhere = ProviderTableMeta._ID + "=?";
  419. Cursor folderCursor = query(db, selectFolderUri, folderProjection, folderWhere, whereArgs, null);
  420. if (folderCursor != null && folderCursor.moveToFirst()) {
  421. folderSize = folderCursor.getLong(folderCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH));;
  422. folderParentId = folderCursor.getLong(folderCursor.getColumnIndex(ProviderTableMeta.FILE_PARENT));;
  423. }
  424. folderCursor.close();
  425. // read and sum sizes of children
  426. long childrenSize = 0;
  427. Uri selectChildrenUri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, folderId);
  428. String[] childrenProjection = new String[] { ProviderTableMeta.FILE_CONTENT_LENGTH, ProviderTableMeta.FILE_PARENT};
  429. String childrenWhere = ProviderTableMeta.FILE_PARENT + "=?";
  430. Cursor childrenCursor = query(db, selectChildrenUri, childrenProjection, childrenWhere, whereArgs, null);
  431. if (childrenCursor != null && childrenCursor.moveToFirst()) {
  432. while (!childrenCursor.isAfterLast()) {
  433. childrenSize += childrenCursor.getLong(childrenCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH));
  434. childrenCursor.moveToNext();
  435. }
  436. }
  437. childrenCursor.close();
  438. // update if needed
  439. if (folderSize != childrenSize) {
  440. Log_OC.d("FileContentProvider", "Updating " + folderSize + " to " + childrenSize);
  441. ContentValues cv = new ContentValues();
  442. cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, childrenSize);
  443. count = db.update(ProviderTableMeta.FILE_TABLE_NAME, cv, folderWhere, whereArgs);
  444. // propagate update until root
  445. if (folderParentId > FileDataStorageManager.ROOT_PARENT_ID) {
  446. Log_OC.d("FileContentProvider", "Propagating update to " + folderParentId);
  447. updateFolderSize(db, String.valueOf(folderParentId));
  448. } else {
  449. Log_OC.d("FileContentProvider", "NOT propagating to " + folderParentId);
  450. }
  451. } else {
  452. Log_OC.d("FileContentProvider", "NOT updating, sizes are " + folderSize + " and " + childrenSize);
  453. }
  454. return count;
  455. }
  456. @Override
  457. public ContentProviderResult[] applyBatch (ArrayList<ContentProviderOperation> operations) throws OperationApplicationException {
  458. Log_OC.d("FileContentProvider", "applying batch in provider " + this + " (temporary: " + isTemporary() + ")" );
  459. ContentProviderResult[] results = new ContentProviderResult[operations.size()];
  460. int i=0;
  461. SQLiteDatabase db = mDbHelper.getWritableDatabase();
  462. db.beginTransaction(); // it's supposed that transactions can be nested
  463. try {
  464. for (ContentProviderOperation operation : operations) {
  465. results[i] = operation.apply(this, results, i);
  466. i++;
  467. }
  468. db.setTransactionSuccessful();
  469. } finally {
  470. db.endTransaction();
  471. }
  472. Log_OC.d("FileContentProvider", "applied batch in provider " + this);
  473. return results;
  474. }
  475. class DataBaseHelper extends SQLiteOpenHelper {
  476. public DataBaseHelper(Context context) {
  477. super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);
  478. }
  479. @Override
  480. public void onCreate(SQLiteDatabase db) {
  481. // files table
  482. Log_OC.i("SQL", "Entering in onCreate");
  483. db.execSQL("CREATE TABLE " + ProviderTableMeta.FILE_TABLE_NAME + "("
  484. + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
  485. + ProviderTableMeta.FILE_NAME + " TEXT, "
  486. + ProviderTableMeta.FILE_PATH + " TEXT, "
  487. + ProviderTableMeta.FILE_PARENT + " INTEGER, "
  488. + ProviderTableMeta.FILE_CREATION + " INTEGER, "
  489. + ProviderTableMeta.FILE_MODIFIED + " INTEGER, "
  490. + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, "
  491. + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, "
  492. + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, "
  493. + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, "
  494. + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, "
  495. + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, "
  496. + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "
  497. + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER, "
  498. + ProviderTableMeta.FILE_ETAG + " TEXT, "
  499. + ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER, "
  500. + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT );"
  501. );
  502. // Create table ocshares
  503. db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "("
  504. + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
  505. + ProviderTableMeta.OCSHARES_FILE_SOURCE + " INTEGER, "
  506. + ProviderTableMeta.OCSHARES_ITEM_SOURCE + " INTEGER, "
  507. + ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, "
  508. + ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, "
  509. + ProviderTableMeta.OCSHARES_PATH + " TEXT, "
  510. + ProviderTableMeta.OCSHARES_PERMISSIONS+ " INTEGER, "
  511. + ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, "
  512. + ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, "
  513. + ProviderTableMeta.OCSHARES_TOKEN + " TEXT, "
  514. + ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, "
  515. + ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, " // boolean
  516. + ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, "
  517. + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER,"
  518. + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" );
  519. }
  520. @Override
  521. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  522. Log_OC.i("SQL", "Entering in onUpgrade");
  523. boolean upgraded = false;
  524. if (oldVersion == 1 && newVersion >= 2) {
  525. Log_OC.i("SQL", "Entering in the #1 ADD in onUpgrade");
  526. db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
  527. " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " +
  528. " DEFAULT 0");
  529. upgraded = true;
  530. }
  531. if (oldVersion < 3 && newVersion >= 3) {
  532. Log_OC.i("SQL", "Entering in the #2 ADD in onUpgrade");
  533. db.beginTransaction();
  534. try {
  535. db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
  536. " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER " +
  537. " DEFAULT 0");
  538. // assume there are not local changes pending to upload
  539. db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
  540. " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() +
  541. " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
  542. upgraded = true;
  543. db.setTransactionSuccessful();
  544. } finally {
  545. db.endTransaction();
  546. }
  547. }
  548. if (oldVersion < 4 && newVersion >= 4) {
  549. Log_OC.i("SQL", "Entering in the #3 ADD in onUpgrade");
  550. db.beginTransaction();
  551. try {
  552. db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
  553. " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER " +
  554. " DEFAULT 0");
  555. db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
  556. " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED +
  557. " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
  558. upgraded = true;
  559. db.setTransactionSuccessful();
  560. } finally {
  561. db.endTransaction();
  562. }
  563. }
  564. if (!upgraded)
  565. Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
  566. if (oldVersion < 5 && newVersion >= 5) {
  567. Log_OC.i("SQL", "Entering in the #4 ADD in onUpgrade");
  568. db.beginTransaction();
  569. try {
  570. db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
  571. " ADD COLUMN " + ProviderTableMeta.FILE_ETAG + " TEXT " +
  572. " DEFAULT NULL");
  573. upgraded = true;
  574. db.setTransactionSuccessful();
  575. } finally {
  576. db.endTransaction();
  577. }
  578. }
  579. if (!upgraded)
  580. Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
  581. if (oldVersion < 6 && newVersion >= 6) {
  582. Log_OC.i("SQL", "Entering in the #5 ADD in onUpgrade");
  583. db.beginTransaction();
  584. try {
  585. db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
  586. " ADD COLUMN " + ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER " +
  587. " DEFAULT 0");
  588. db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
  589. " ADD COLUMN " + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT " +
  590. " DEFAULT NULL");
  591. // Create table ocshares
  592. db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "("
  593. + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
  594. + ProviderTableMeta.OCSHARES_FILE_SOURCE + " INTEGER, "
  595. + ProviderTableMeta.OCSHARES_ITEM_SOURCE + " INTEGER, "
  596. + ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, "
  597. + ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, "
  598. + ProviderTableMeta.OCSHARES_PATH + " TEXT, "
  599. + ProviderTableMeta.OCSHARES_PERMISSIONS+ " INTEGER, "
  600. + ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, "
  601. + ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, "
  602. + ProviderTableMeta.OCSHARES_TOKEN + " TEXT, "
  603. + ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, "
  604. + ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, " // boolean
  605. + ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, "
  606. + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER,"
  607. + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" );
  608. upgraded = true;
  609. db.setTransactionSuccessful();
  610. } finally {
  611. db.endTransaction();
  612. }
  613. }
  614. if (!upgraded)
  615. Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
  616. }
  617. }
  618. }