FileContentProvider.java 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  1. /**
  2. * ownCloud Android client application
  3. *
  4. * @author Bartek Przybylski
  5. * @author David A. Velasco
  6. * @author masensio
  7. * Copyright (C) 2011 Bartek Przybylski
  8. * Copyright (C) 2016 ownCloud Inc.
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2,
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. package com.owncloud.android.providers;
  24. import android.accounts.Account;
  25. import android.accounts.AccountManager;
  26. import android.content.ContentProvider;
  27. import android.content.ContentProviderOperation;
  28. import android.content.ContentProviderResult;
  29. import android.content.ContentUris;
  30. import android.content.ContentValues;
  31. import android.content.Context;
  32. import android.content.OperationApplicationException;
  33. import android.content.UriMatcher;
  34. import android.database.Cursor;
  35. import android.database.SQLException;
  36. import android.database.sqlite.SQLiteDatabase;
  37. import android.database.sqlite.SQLiteOpenHelper;
  38. import android.database.sqlite.SQLiteQueryBuilder;
  39. import android.net.Uri;
  40. import android.text.TextUtils;
  41. import com.owncloud.android.MainApp;
  42. import com.owncloud.android.R;
  43. import com.owncloud.android.datamodel.OCFile;
  44. import com.owncloud.android.datamodel.UploadsStorageManager;
  45. import com.owncloud.android.db.ProviderMeta;
  46. import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
  47. import com.owncloud.android.lib.common.accounts.AccountUtils;
  48. import com.owncloud.android.lib.common.utils.Log_OC;
  49. import com.owncloud.android.lib.resources.shares.ShareType;
  50. import com.owncloud.android.utils.FileStorageUtils;
  51. import com.owncloud.android.utils.MimeType;
  52. import java.io.File;
  53. import java.util.ArrayList;
  54. import java.util.Locale;
  55. /**
  56. * The ContentProvider for the ownCloud App.
  57. */
  58. @SuppressWarnings("PMD.AvoidDuplicateLiterals")
  59. public class FileContentProvider extends ContentProvider {
  60. private DataBaseHelper mDbHelper;
  61. private static final int SINGLE_FILE = 1;
  62. private static final int DIRECTORY = 2;
  63. private static final int ROOT_DIRECTORY = 3;
  64. private static final int SHARES = 4;
  65. private static final int CAPABILITIES = 5;
  66. private static final int UPLOADS = 6;
  67. private static final String TAG = FileContentProvider.class.getSimpleName();
  68. private UriMatcher mUriMatcher;
  69. // todo avoid string concatenation and use string formatting instead later.
  70. private static final String ERROR = "ERROR ";
  71. private static final String SQL = "SQL";
  72. private static final String INTEGER = " INTEGER, ";
  73. private static final String TEXT = " TEXT, ";
  74. private static final String ALTER_TABLE = "ALTER TABLE ";
  75. private static final String ADD_COLUMN = " ADD COLUMN ";
  76. private static final String UPGRADE_VERSION_MSG = "OUT of the ADD in onUpgrade; oldVersion == %d, newVersion == %d";
  77. @Override
  78. public int delete(Uri uri, String where, String[] whereArgs) {
  79. //Log_OC.d(TAG, "Deleting " + uri + " at provider " + this);
  80. int count = 0;
  81. SQLiteDatabase db = mDbHelper.getWritableDatabase();
  82. db.beginTransaction();
  83. try {
  84. count = delete(db, uri, where, whereArgs);
  85. db.setTransactionSuccessful();
  86. } finally {
  87. db.endTransaction();
  88. }
  89. getContext().getContentResolver().notifyChange(uri, null);
  90. return count;
  91. }
  92. private int delete(SQLiteDatabase db, Uri uri, String where, String[] whereArgs) {
  93. int count = 0;
  94. switch (mUriMatcher.match(uri)) {
  95. case SINGLE_FILE:
  96. Cursor c = query(db, uri, null, where, whereArgs, null);
  97. String remoteId = "";
  98. try {
  99. if (c != null && c.moveToFirst()) {
  100. remoteId = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID));
  101. //ThumbnailsCacheManager.removeFileFromCache(remoteId);
  102. }
  103. Log_OC.d(TAG, "Removing FILE " + remoteId);
  104. count = db.delete(ProviderTableMeta.FILE_TABLE_NAME,
  105. ProviderTableMeta._ID
  106. + "="
  107. + uri.getPathSegments().get(1)
  108. + (!TextUtils.isEmpty(where) ? " AND (" + where + ")" : ""),
  109. whereArgs);
  110. } catch (Exception e) {
  111. Log_OC.d(TAG, "DB-Error removing file!", e);
  112. } finally {
  113. if (c != null) {
  114. c.close();
  115. }
  116. }
  117. break;
  118. case DIRECTORY:
  119. // deletion of folder is recursive
  120. /*
  121. Uri folderUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, Long.parseLong(uri.getPathSegments().get(1)));
  122. Cursor folder = query(db, folderUri, null, null, null, null);
  123. String folderName = "(unknown)";
  124. if (folder != null && folder.moveToFirst()) {
  125. folderName = folder.getString(folder.getColumnIndex(ProviderTableMeta.FILE_PATH));
  126. }
  127. */
  128. Cursor children = query(uri, null, null, null, null);
  129. if (children != null && children.moveToFirst()) {
  130. long childId;
  131. boolean isDir;
  132. while (!children.isAfterLast()) {
  133. childId = children.getLong(children.getColumnIndex(ProviderTableMeta._ID));
  134. isDir = MimeType.DIRECTORY.equals(children.getString(
  135. children.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)
  136. ));
  137. //remotePath = children.getString(children.getColumnIndex(ProviderTableMeta.FILE_PATH));
  138. if (isDir) {
  139. count += delete(
  140. db,
  141. ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId),
  142. null,
  143. null
  144. );
  145. } else {
  146. count += delete(
  147. db,
  148. ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, childId),
  149. null,
  150. null
  151. );
  152. }
  153. children.moveToNext();
  154. }
  155. children.close();
  156. } /*else {
  157. Log_OC.d(TAG, "No child to remove in DIRECTORY " + folderName);
  158. }
  159. Log_OC.d(TAG, "Removing DIRECTORY " + folderName + " (or maybe not) ");
  160. */
  161. count += db.delete(ProviderTableMeta.FILE_TABLE_NAME,
  162. ProviderTableMeta._ID
  163. + "="
  164. + uri.getPathSegments().get(1)
  165. + (!TextUtils.isEmpty(where) ? " AND (" + where
  166. + ")" : ""), whereArgs);
  167. /* Just for log
  168. if (folder != null) {
  169. folder.close();
  170. }*/
  171. break;
  172. case ROOT_DIRECTORY:
  173. //Log_OC.d(TAG, "Removing ROOT!");
  174. count = db.delete(ProviderTableMeta.FILE_TABLE_NAME, where, whereArgs);
  175. break;
  176. case SHARES:
  177. count = db.delete(ProviderTableMeta.OCSHARES_TABLE_NAME, where, whereArgs);
  178. break;
  179. case CAPABILITIES:
  180. count = db.delete(ProviderTableMeta.CAPABILITIES_TABLE_NAME, where, whereArgs);
  181. break;
  182. case UPLOADS:
  183. count = db.delete(ProviderTableMeta.UPLOADS_TABLE_NAME, where, whereArgs);
  184. break;
  185. default:
  186. //Log_OC.e(TAG, "Unknown uri " + uri);
  187. throw new IllegalArgumentException("Unknown uri: " + uri.toString());
  188. }
  189. return count;
  190. }
  191. @Override
  192. public String getType(Uri uri) {
  193. switch (mUriMatcher.match(uri)) {
  194. case ROOT_DIRECTORY:
  195. return ProviderTableMeta.CONTENT_TYPE;
  196. case SINGLE_FILE:
  197. return ProviderTableMeta.CONTENT_TYPE_ITEM;
  198. default:
  199. throw new IllegalArgumentException("Unknown Uri id."
  200. + uri.toString());
  201. }
  202. }
  203. @Override
  204. public Uri insert(Uri uri, ContentValues values) {
  205. Uri newUri = null;
  206. SQLiteDatabase db = mDbHelper.getWritableDatabase();
  207. db.beginTransaction();
  208. try {
  209. newUri = insert(db, uri, values);
  210. db.setTransactionSuccessful();
  211. } finally {
  212. db.endTransaction();
  213. }
  214. getContext().getContentResolver().notifyChange(newUri, null);
  215. return newUri;
  216. }
  217. private Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) {
  218. switch (mUriMatcher.match(uri)){
  219. case ROOT_DIRECTORY:
  220. case SINGLE_FILE:
  221. String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH);
  222. String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER);
  223. String[] projection = new String[] {
  224. ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH,
  225. ProviderTableMeta.FILE_ACCOUNT_OWNER
  226. };
  227. String where = ProviderTableMeta.FILE_PATH + "=? AND " +
  228. ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
  229. String[] whereArgs = new String[] {remotePath, accountName};
  230. Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null);
  231. // ugly patch; serious refactorization is needed to reduce work in
  232. // FileDataStorageManager and bring it to FileContentProvider
  233. if (doubleCheck == null || !doubleCheck.moveToFirst()) {
  234. if (doubleCheck != null) {
  235. doubleCheck.close();
  236. }
  237. long rowId = db.insert(ProviderTableMeta.FILE_TABLE_NAME, null, values);
  238. if (rowId > 0) {
  239. return ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
  240. } else {
  241. throw new SQLException(ERROR + uri);
  242. }
  243. } else {
  244. // file is already inserted; race condition, let's avoid a duplicated entry
  245. Uri insertedFileUri = ContentUris.withAppendedId(
  246. ProviderTableMeta.CONTENT_URI_FILE,
  247. doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID))
  248. );
  249. doubleCheck.close();
  250. return insertedFileUri;
  251. }
  252. case SHARES:
  253. Uri insertedShareUri = null;
  254. long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values);
  255. if (rowId >0) {
  256. insertedShareUri =
  257. ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId);
  258. } else {
  259. throw new SQLException(ERROR + uri);
  260. }
  261. updateFilesTableAccordingToShareInsertion(db, values);
  262. return insertedShareUri;
  263. case CAPABILITIES:
  264. Uri insertedCapUri = null;
  265. long id = db.insert(ProviderTableMeta.CAPABILITIES_TABLE_NAME, null, values);
  266. if (id >0) {
  267. insertedCapUri =
  268. ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_CAPABILITIES, id);
  269. } else {
  270. throw new SQLException(ERROR + uri);
  271. }
  272. return insertedCapUri;
  273. case UPLOADS:
  274. Uri insertedUploadUri = null;
  275. long uploadId = db.insert(ProviderTableMeta.UPLOADS_TABLE_NAME, null, values);
  276. if (uploadId >0) {
  277. insertedUploadUri =
  278. ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_UPLOADS, uploadId);
  279. trimSuccessfulUploads(db);
  280. } else {
  281. throw new SQLException(ERROR + uri);
  282. }
  283. return insertedUploadUri;
  284. default:
  285. throw new IllegalArgumentException("Unknown uri id: " + uri);
  286. }
  287. }
  288. private void updateFilesTableAccordingToShareInsertion(
  289. SQLiteDatabase db, ContentValues newShare
  290. ) {
  291. ContentValues fileValues = new ContentValues();
  292. int newShareType = newShare.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE);
  293. if (newShareType == ShareType.PUBLIC_LINK.getValue()) {
  294. fileValues.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, 1);
  295. } else if (
  296. newShareType == ShareType.USER.getValue() ||
  297. newShareType == ShareType.GROUP.getValue() ||
  298. newShareType == ShareType.FEDERATED.getValue() ) {
  299. fileValues.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, 1);
  300. }
  301. String where = ProviderTableMeta.FILE_PATH + "=? AND " +
  302. ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
  303. String[] whereArgs = new String[] {
  304. newShare.getAsString(ProviderTableMeta.OCSHARES_PATH),
  305. newShare.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER)
  306. };
  307. db.update(ProviderTableMeta.FILE_TABLE_NAME, fileValues, where, whereArgs);
  308. }
  309. @Override
  310. public boolean onCreate() {
  311. mDbHelper = new DataBaseHelper(getContext());
  312. String authority = getContext().getResources().getString(R.string.authority);
  313. mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  314. mUriMatcher.addURI(authority, null, ROOT_DIRECTORY);
  315. mUriMatcher.addURI(authority, "file/", SINGLE_FILE);
  316. mUriMatcher.addURI(authority, "file/#", SINGLE_FILE);
  317. mUriMatcher.addURI(authority, "dir/", DIRECTORY);
  318. mUriMatcher.addURI(authority, "dir/#", DIRECTORY);
  319. mUriMatcher.addURI(authority, "shares/", SHARES);
  320. mUriMatcher.addURI(authority, "shares/#", SHARES);
  321. mUriMatcher.addURI(authority, "capabilities/", CAPABILITIES);
  322. mUriMatcher.addURI(authority, "capabilities/#", CAPABILITIES);
  323. mUriMatcher.addURI(authority, "uploads/", UPLOADS);
  324. mUriMatcher.addURI(authority, "uploads/#", UPLOADS);
  325. return true;
  326. }
  327. @Override
  328. public Cursor query(
  329. Uri uri,
  330. String[] projection,
  331. String selection,
  332. String[] selectionArgs,
  333. String sortOrder
  334. ) {
  335. Cursor result = null;
  336. SQLiteDatabase db = mDbHelper.getReadableDatabase();
  337. db.beginTransaction();
  338. try {
  339. result = query(db, uri, projection, selection, selectionArgs, sortOrder);
  340. db.setTransactionSuccessful();
  341. } finally {
  342. db.endTransaction();
  343. }
  344. return result;
  345. }
  346. private Cursor query(
  347. SQLiteDatabase db,
  348. Uri uri,
  349. String[] projection,
  350. String selection,
  351. String[] selectionArgs,
  352. String sortOrder
  353. ) {
  354. SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();
  355. sqlQuery.setTables(ProviderTableMeta.FILE_TABLE_NAME);
  356. switch (mUriMatcher.match(uri)) {
  357. case ROOT_DIRECTORY:
  358. break;
  359. case DIRECTORY:
  360. String folderId = uri.getPathSegments().get(1);
  361. sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="
  362. + folderId);
  363. break;
  364. case SINGLE_FILE:
  365. if (uri.getPathSegments().size() > 1) {
  366. sqlQuery.appendWhere(ProviderTableMeta._ID + "="
  367. + uri.getPathSegments().get(1));
  368. }
  369. break;
  370. case SHARES:
  371. sqlQuery.setTables(ProviderTableMeta.OCSHARES_TABLE_NAME);
  372. if (uri.getPathSegments().size() > 1) {
  373. sqlQuery.appendWhere(ProviderTableMeta._ID + "="
  374. + uri.getPathSegments().get(1));
  375. }
  376. break;
  377. case CAPABILITIES:
  378. sqlQuery.setTables(ProviderTableMeta.CAPABILITIES_TABLE_NAME);
  379. if (uri.getPathSegments().size() > 1) {
  380. sqlQuery.appendWhere(ProviderTableMeta._ID + "="
  381. + uri.getPathSegments().get(1));
  382. }
  383. break;
  384. case UPLOADS:
  385. sqlQuery.setTables(ProviderTableMeta.UPLOADS_TABLE_NAME);
  386. if (uri.getPathSegments().size() > 1) {
  387. sqlQuery.appendWhere(ProviderTableMeta._ID + "="
  388. + uri.getPathSegments().get(1));
  389. }
  390. break;
  391. default:
  392. throw new IllegalArgumentException("Unknown uri id: " + uri);
  393. }
  394. String order;
  395. if (TextUtils.isEmpty(sortOrder)) {
  396. switch (mUriMatcher.match(uri)) {
  397. case SHARES:
  398. order = ProviderTableMeta.OCSHARES_DEFAULT_SORT_ORDER;
  399. break;
  400. case CAPABILITIES:
  401. order = ProviderTableMeta.CAPABILITIES_DEFAULT_SORT_ORDER;
  402. break;
  403. case UPLOADS:
  404. order = ProviderTableMeta.UPLOADS_DEFAULT_SORT_ORDER;
  405. break;
  406. default: // Files
  407. order = ProviderTableMeta.FILE_DEFAULT_SORT_ORDER;
  408. break;
  409. }
  410. } else {
  411. order = sortOrder;
  412. }
  413. // DB case_sensitive
  414. db.execSQL("PRAGMA case_sensitive_like = true");
  415. Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, null, null, order);
  416. c.setNotificationUri(getContext().getContentResolver(), uri);
  417. return c;
  418. }
  419. @Override
  420. public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
  421. int count = 0;
  422. SQLiteDatabase db = mDbHelper.getWritableDatabase();
  423. db.beginTransaction();
  424. try {
  425. count = update(db, uri, values, selection, selectionArgs);
  426. db.setTransactionSuccessful();
  427. } finally {
  428. db.endTransaction();
  429. }
  430. getContext().getContentResolver().notifyChange(uri, null);
  431. return count;
  432. }
  433. private int update(
  434. SQLiteDatabase db,
  435. Uri uri,
  436. ContentValues values,
  437. String selection,
  438. String[] selectionArgs
  439. ) {
  440. switch (mUriMatcher.match(uri)) {
  441. case DIRECTORY:
  442. return 0; //updateFolderSize(db, selectionArgs[0]);
  443. case SHARES:
  444. return db.update(
  445. ProviderTableMeta.OCSHARES_TABLE_NAME, values, selection, selectionArgs
  446. );
  447. case CAPABILITIES:
  448. return db.update(
  449. ProviderTableMeta.CAPABILITIES_TABLE_NAME, values, selection, selectionArgs
  450. );
  451. case UPLOADS:
  452. int ret = db.update(
  453. ProviderTableMeta.UPLOADS_TABLE_NAME, values, selection, selectionArgs
  454. );
  455. trimSuccessfulUploads(db);
  456. return ret;
  457. default:
  458. return db.update(
  459. ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs
  460. );
  461. }
  462. }
  463. @Override
  464. public ContentProviderResult[] applyBatch (ArrayList<ContentProviderOperation> operations)
  465. throws OperationApplicationException {
  466. Log_OC.d("FileContentProvider", "applying batch in provider " + this +
  467. " (temporary: " + isTemporary() + ")" );
  468. ContentProviderResult[] results = new ContentProviderResult[operations.size()];
  469. int i=0;
  470. SQLiteDatabase db = mDbHelper.getWritableDatabase();
  471. db.beginTransaction(); // it's supposed that transactions can be nested
  472. try {
  473. for (ContentProviderOperation operation : operations) {
  474. results[i] = operation.apply(this, results, i);
  475. i++;
  476. }
  477. db.setTransactionSuccessful();
  478. } finally {
  479. db.endTransaction();
  480. }
  481. Log_OC.d("FileContentProvider", "applied batch in provider " + this);
  482. return results;
  483. }
  484. class DataBaseHelper extends SQLiteOpenHelper {
  485. public DataBaseHelper(Context context) {
  486. super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);
  487. }
  488. @Override
  489. public void onCreate(SQLiteDatabase db) {
  490. // files table
  491. Log_OC.i(SQL, "Entering in onCreate");
  492. createFilesTable(db);
  493. // Create ocshares table
  494. createOCSharesTable(db);
  495. // Create capabilities table
  496. createCapabilitiesTable(db);
  497. // Create uploads table
  498. createUploadsTable(db);
  499. }
  500. @Override
  501. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  502. Log_OC.i(SQL, "Entering in onUpgrade");
  503. boolean upgraded = false;
  504. if (oldVersion == 1 && newVersion >= 2) {
  505. Log_OC.i(SQL, "Entering in the #1 ADD in onUpgrade");
  506. db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  507. ADD_COLUMN + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " +
  508. " DEFAULT 0");
  509. upgraded = true;
  510. }
  511. if (oldVersion < 3 && newVersion >= 3) {
  512. Log_OC.i(SQL, "Entering in the #2 ADD in onUpgrade");
  513. db.beginTransaction();
  514. try {
  515. db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  516. ADD_COLUMN + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA +
  517. " INTEGER " + " DEFAULT 0");
  518. // assume there are not local changes pending to upload
  519. db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
  520. " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = "
  521. + System.currentTimeMillis() +
  522. " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
  523. upgraded = true;
  524. db.setTransactionSuccessful();
  525. } finally {
  526. db.endTransaction();
  527. }
  528. }
  529. if (oldVersion < 4 && newVersion >= 4) {
  530. Log_OC.i(SQL, "Entering in the #3 ADD in onUpgrade");
  531. db.beginTransaction();
  532. try {
  533. db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  534. ADD_COLUMN + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA +
  535. " INTEGER " + " DEFAULT 0");
  536. db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
  537. " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " +
  538. ProviderTableMeta.FILE_MODIFIED +
  539. " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
  540. upgraded = true;
  541. db.setTransactionSuccessful();
  542. } finally {
  543. db.endTransaction();
  544. }
  545. }
  546. if (!upgraded) {
  547. Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
  548. }
  549. if (oldVersion < 5 && newVersion >= 5) {
  550. Log_OC.i(SQL, "Entering in the #4 ADD in onUpgrade");
  551. db.beginTransaction();
  552. try {
  553. db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  554. ADD_COLUMN + ProviderTableMeta.FILE_ETAG + " TEXT " +
  555. " DEFAULT NULL");
  556. upgraded = true;
  557. db.setTransactionSuccessful();
  558. } finally {
  559. db.endTransaction();
  560. }
  561. }
  562. if (!upgraded) {
  563. Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
  564. }
  565. if (oldVersion < 6 && newVersion >= 6) {
  566. Log_OC.i(SQL, "Entering in the #5 ADD in onUpgrade");
  567. db.beginTransaction();
  568. try {
  569. db .execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  570. ADD_COLUMN + ProviderTableMeta.FILE_SHARED_VIA_LINK + " INTEGER " +
  571. " DEFAULT 0");
  572. db .execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  573. ADD_COLUMN + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT " +
  574. " DEFAULT NULL");
  575. // Create table ocshares
  576. createOCSharesTable(db);
  577. upgraded = true;
  578. db.setTransactionSuccessful();
  579. } finally {
  580. db.endTransaction();
  581. }
  582. }
  583. if (!upgraded) {
  584. Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
  585. }
  586. if (oldVersion < 7 && newVersion >= 7) {
  587. Log_OC.i(SQL, "Entering in the #7 ADD in onUpgrade");
  588. db.beginTransaction();
  589. try {
  590. db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  591. ADD_COLUMN + ProviderTableMeta.FILE_PERMISSIONS + " TEXT " +
  592. " DEFAULT NULL");
  593. db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  594. ADD_COLUMN + ProviderTableMeta.FILE_REMOTE_ID + " TEXT " +
  595. " DEFAULT NULL");
  596. upgraded = true;
  597. db.setTransactionSuccessful();
  598. } finally {
  599. db.endTransaction();
  600. }
  601. }
  602. if (!upgraded) {
  603. Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
  604. }
  605. if (oldVersion < 8 && newVersion >= 8) {
  606. Log_OC.i(SQL, "Entering in the #8 ADD in onUpgrade");
  607. db.beginTransaction();
  608. try {
  609. db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  610. ADD_COLUMN + ProviderTableMeta.FILE_UPDATE_THUMBNAIL + " INTEGER " +
  611. " DEFAULT 0");
  612. upgraded = true;
  613. db.setTransactionSuccessful();
  614. } finally {
  615. db.endTransaction();
  616. }
  617. }
  618. if (!upgraded) {
  619. Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
  620. }
  621. if (oldVersion < 9 && newVersion >= 9) {
  622. Log_OC.i(SQL, "Entering in the #9 ADD in onUpgrade");
  623. db.beginTransaction();
  624. try {
  625. db .execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  626. ADD_COLUMN + ProviderTableMeta.FILE_IS_DOWNLOADING + " INTEGER " +
  627. " DEFAULT 0");
  628. upgraded = true;
  629. db.setTransactionSuccessful();
  630. } finally {
  631. db.endTransaction();
  632. }
  633. }
  634. if (!upgraded) {
  635. Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
  636. }
  637. if (oldVersion < 10 && newVersion >= 10) {
  638. Log_OC.i(SQL, "Entering in the #10 ADD in onUpgrade");
  639. updateAccountName(db);
  640. upgraded = true;
  641. }
  642. if (!upgraded) {
  643. Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
  644. }
  645. if (oldVersion < 11 && newVersion >= 11) {
  646. Log_OC.i(SQL, "Entering in the #11 ADD in onUpgrade");
  647. db.beginTransaction();
  648. try {
  649. db .execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  650. ADD_COLUMN + ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " TEXT " +
  651. " DEFAULT NULL");
  652. upgraded = true;
  653. db.setTransactionSuccessful();
  654. } finally {
  655. db.endTransaction();
  656. }
  657. }
  658. if (!upgraded) {
  659. Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
  660. }
  661. if (oldVersion < 12 && newVersion >= 12) {
  662. Log_OC.i(SQL, "Entering in the #12 ADD in onUpgrade");
  663. db.beginTransaction();
  664. try {
  665. db .execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
  666. ADD_COLUMN + ProviderTableMeta.FILE_SHARED_WITH_SHAREE + " INTEGER " +
  667. " DEFAULT 0");
  668. upgraded = true;
  669. db.setTransactionSuccessful();
  670. } finally {
  671. db.endTransaction();
  672. }
  673. }
  674. if (!upgraded) {
  675. Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
  676. }
  677. if (oldVersion < 13 && newVersion >= 13) {
  678. Log_OC.i(SQL, "Entering in the #13 ADD in onUpgrade");
  679. db.beginTransaction();
  680. try {
  681. // Create capabilities table
  682. createCapabilitiesTable(db);
  683. upgraded = true;
  684. db.setTransactionSuccessful();
  685. } finally {
  686. db.endTransaction();
  687. }
  688. }
  689. if (oldVersion < 14 && newVersion >= 14) {
  690. Log_OC.i(SQL, "Entering in the #14 ADD in onUpgrade");
  691. db.beginTransaction();
  692. try {
  693. // drop old instant_upload table
  694. db.execSQL("DROP TABLE IF EXISTS " + "instant_upload" + ";");
  695. // Create uploads table
  696. createUploadsTable(db);
  697. upgraded = true;
  698. db.setTransactionSuccessful();
  699. } finally {
  700. db.endTransaction();
  701. }
  702. }
  703. if (oldVersion < 15 && newVersion >= 15) {
  704. Log_OC.i(SQL, "Entering in the #15 ADD in onUpgrade");
  705. db.beginTransaction();
  706. try {
  707. // drop old capabilities table
  708. db.execSQL("DROP TABLE IF EXISTS " + "capabilities" + ";");
  709. // Create uploads table
  710. createCapabilitiesTable(db);
  711. upgraded = true;
  712. db.setTransactionSuccessful();
  713. } finally {
  714. db.endTransaction();
  715. }
  716. }
  717. if (!upgraded) {
  718. Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
  719. }
  720. }
  721. }
  722. private void createFilesTable(SQLiteDatabase db){
  723. db.execSQL("CREATE TABLE " + ProviderTableMeta.FILE_TABLE_NAME + "("
  724. + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
  725. + ProviderTableMeta.FILE_NAME + TEXT
  726. + ProviderTableMeta.FILE_PATH + TEXT
  727. + ProviderTableMeta.FILE_PARENT + INTEGER
  728. + ProviderTableMeta.FILE_CREATION + INTEGER
  729. + ProviderTableMeta.FILE_MODIFIED + INTEGER
  730. + ProviderTableMeta.FILE_CONTENT_TYPE + TEXT
  731. + ProviderTableMeta.FILE_CONTENT_LENGTH + INTEGER
  732. + ProviderTableMeta.FILE_STORAGE_PATH + TEXT
  733. + ProviderTableMeta.FILE_ACCOUNT_OWNER + TEXT
  734. + ProviderTableMeta.FILE_LAST_SYNC_DATE + INTEGER
  735. + ProviderTableMeta.FILE_KEEP_IN_SYNC + INTEGER
  736. + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + INTEGER
  737. + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + INTEGER
  738. + ProviderTableMeta.FILE_ETAG + TEXT
  739. + ProviderTableMeta.FILE_SHARED_VIA_LINK + INTEGER
  740. + ProviderTableMeta.FILE_PUBLIC_LINK + TEXT
  741. + ProviderTableMeta.FILE_PERMISSIONS + " TEXT null,"
  742. + ProviderTableMeta.FILE_REMOTE_ID + " TEXT null,"
  743. + ProviderTableMeta.FILE_UPDATE_THUMBNAIL + INTEGER //boolean
  744. + ProviderTableMeta.FILE_IS_DOWNLOADING + INTEGER //boolean
  745. + ProviderTableMeta.FILE_ETAG_IN_CONFLICT + TEXT
  746. + ProviderTableMeta.FILE_SHARED_WITH_SHAREE + " INTEGER);"
  747. );
  748. }
  749. private void createOCSharesTable(SQLiteDatabase db) {
  750. // Create ocshares table
  751. db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "("
  752. + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
  753. + ProviderTableMeta.OCSHARES_FILE_SOURCE + INTEGER
  754. + ProviderTableMeta.OCSHARES_ITEM_SOURCE + INTEGER
  755. + ProviderTableMeta.OCSHARES_SHARE_TYPE + INTEGER
  756. + ProviderTableMeta.OCSHARES_SHARE_WITH + TEXT
  757. + ProviderTableMeta.OCSHARES_PATH + TEXT
  758. + ProviderTableMeta.OCSHARES_PERMISSIONS+ INTEGER
  759. + ProviderTableMeta.OCSHARES_SHARED_DATE + INTEGER
  760. + ProviderTableMeta.OCSHARES_EXPIRATION_DATE + INTEGER
  761. + ProviderTableMeta.OCSHARES_TOKEN + TEXT
  762. + ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + TEXT
  763. + ProviderTableMeta.OCSHARES_IS_DIRECTORY + INTEGER // boolean
  764. + ProviderTableMeta.OCSHARES_USER_ID + INTEGER
  765. + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + INTEGER
  766. + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" );
  767. }
  768. private void createCapabilitiesTable(SQLiteDatabase db){
  769. // Create capabilities table
  770. db.execSQL("CREATE TABLE " + ProviderTableMeta.CAPABILITIES_TABLE_NAME + "("
  771. + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
  772. + ProviderTableMeta.CAPABILITIES_ACCOUNT_NAME + TEXT
  773. + ProviderTableMeta.CAPABILITIES_VERSION_MAYOR + INTEGER
  774. + ProviderTableMeta.CAPABILITIES_VERSION_MINOR + INTEGER
  775. + ProviderTableMeta.CAPABILITIES_VERSION_MICRO + INTEGER
  776. + ProviderTableMeta.CAPABILITIES_VERSION_STRING + TEXT
  777. + ProviderTableMeta.CAPABILITIES_VERSION_EDITION + TEXT
  778. + ProviderTableMeta.CAPABILITIES_CORE_POLLINTERVAL + INTEGER
  779. + ProviderTableMeta.CAPABILITIES_SHARING_API_ENABLED + INTEGER // boolean
  780. + ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_ENABLED + INTEGER // boolean
  781. + ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_PASSWORD_ENFORCED + INTEGER // boolean
  782. + ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_ENABLED + INTEGER // boolean
  783. + ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_DAYS + INTEGER
  784. + ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_ENFORCED + INTEGER // boolean
  785. + ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_SEND_MAIL + INTEGER // boolean
  786. + ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_UPLOAD + INTEGER // boolean
  787. + ProviderTableMeta.CAPABILITIES_SHARING_USER_SEND_MAIL + INTEGER // boolean
  788. + ProviderTableMeta.CAPABILITIES_SHARING_RESHARING + INTEGER // boolean
  789. + ProviderTableMeta.CAPABILITIES_SHARING_FEDERATION_OUTGOING + INTEGER // boolean
  790. + ProviderTableMeta.CAPABILITIES_SHARING_FEDERATION_INCOMING + INTEGER // boolean
  791. + ProviderTableMeta.CAPABILITIES_FILES_BIGFILECHUNKING + INTEGER // boolean
  792. + ProviderTableMeta.CAPABILITIES_FILES_UNDELETE + INTEGER // boolean
  793. + ProviderTableMeta.CAPABILITIES_FILES_VERSIONING + INTEGER // boolean
  794. + ProviderTableMeta.CAPABILITIES_FILES_DROP + " INTEGER );" ); // boolean
  795. }
  796. private void createUploadsTable(SQLiteDatabase db){
  797. // Create uploads table
  798. db.execSQL("CREATE TABLE " + ProviderTableMeta.UPLOADS_TABLE_NAME + "("
  799. + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
  800. + ProviderTableMeta.UPLOADS_LOCAL_PATH + TEXT
  801. + ProviderTableMeta.UPLOADS_REMOTE_PATH + TEXT
  802. + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + TEXT
  803. + ProviderTableMeta.UPLOADS_FILE_SIZE + " LONG, "
  804. + ProviderTableMeta.UPLOADS_STATUS + INTEGER // UploadStatus
  805. + ProviderTableMeta.UPLOADS_LOCAL_BEHAVIOUR + INTEGER // Upload LocalBehaviour
  806. + ProviderTableMeta.UPLOADS_UPLOAD_TIME + INTEGER
  807. + ProviderTableMeta.UPLOADS_FORCE_OVERWRITE + INTEGER // boolean
  808. + ProviderTableMeta.UPLOADS_IS_CREATE_REMOTE_FOLDER + INTEGER // boolean
  809. + ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP + INTEGER
  810. + ProviderTableMeta.UPLOADS_LAST_RESULT + INTEGER // Upload LastResult
  811. + ProviderTableMeta.UPLOADS_CREATED_BY + " INTEGER );" // Upload createdBy
  812. );
  813. /* before:
  814. // PRIMARY KEY should always imply NOT NULL. Unfortunately, due to a
  815. // bug in some early versions, this is not the case in SQLite.
  816. //db.execSQL("CREATE TABLE " + TABLE_UPLOAD + " (" + " path TEXT PRIMARY KEY NOT NULL UNIQUE,"
  817. // + " uploadStatus INTEGER NOT NULL, uploadObject TEXT NOT NULL);");
  818. // uploadStatus is used to easy filtering, it has precedence over
  819. // uploadObject.getUploadStatus()
  820. */
  821. }
  822. /**
  823. * Version 10 of database does not modify its scheme. It coincides with the upgrade of the ownCloud account names
  824. * structure to include in it the path to the server instance. Updating the account names and path to local files
  825. * in the files table is a must to keep the existing account working and the database clean.
  826. *
  827. * See {@link com.owncloud.android.authentication.AccountUtils#updateAccountVersion(android.content.Context)}
  828. *
  829. * @param db Database where table of files is included.
  830. */
  831. private void updateAccountName(SQLiteDatabase db){
  832. Log_OC.d(SQL, "THREAD: " + Thread.currentThread().getName());
  833. AccountManager ama = AccountManager.get(getContext());
  834. try {
  835. // get accounts from AccountManager ; we can't be sure if accounts in it are updated or not although
  836. // we know the update was previously done in {link @FileActivity#onCreate} because the changes through
  837. // AccountManager are not synchronous
  838. Account[] accounts = AccountManager.get(getContext()).getAccountsByType(
  839. MainApp.getAccountType());
  840. String serverUrl, username, oldAccountName, newAccountName;
  841. for (Account account : accounts) {
  842. // build both old and new account name
  843. serverUrl = ama.getUserData(account, AccountUtils.Constants.KEY_OC_BASE_URL);
  844. username = AccountUtils.getUsernameForAccount(account);
  845. oldAccountName = AccountUtils.buildAccountNameOld(Uri.parse(serverUrl), username);
  846. newAccountName = AccountUtils.buildAccountName(Uri.parse(serverUrl), username);
  847. // update values in database
  848. db.beginTransaction();
  849. try {
  850. ContentValues cv = new ContentValues();
  851. cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, newAccountName);
  852. int num = db.update(ProviderTableMeta.FILE_TABLE_NAME,
  853. cv,
  854. ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
  855. new String[]{oldAccountName});
  856. Log_OC.d(SQL, "Updated account in database: old name == " + oldAccountName +
  857. ", new name == " + newAccountName + " (" + num + " rows updated )");
  858. // update path for downloaded files
  859. updateDownloadedFiles(db, newAccountName, oldAccountName);
  860. db.setTransactionSuccessful();
  861. } catch (SQLException e) {
  862. Log_OC.e(TAG, "SQL Exception upgrading account names or paths in database", e);
  863. } finally {
  864. db.endTransaction();
  865. }
  866. }
  867. } catch (Exception e) {
  868. Log_OC.e(TAG, "Exception upgrading account names or paths in database", e);
  869. }
  870. }
  871. /**
  872. * Rename the local ownCloud folder of one account to match the a rename of the account itself. Updates the
  873. * table of files in database so that the paths to the local files keep being the same.
  874. *
  875. * @param db Database where table of files is included.
  876. * @param newAccountName New name for the target OC account.
  877. * @param oldAccountName Old name of the target OC account.
  878. */
  879. private void updateDownloadedFiles(SQLiteDatabase db, String newAccountName,
  880. String oldAccountName) {
  881. String whereClause = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
  882. ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL";
  883. Cursor c = db.query(ProviderTableMeta.FILE_TABLE_NAME,
  884. null,
  885. whereClause,
  886. new String[]{newAccountName},
  887. null, null, null);
  888. try {
  889. if (c.moveToFirst()) {
  890. // create storage path
  891. String oldAccountPath = FileStorageUtils.getSavePath(oldAccountName);
  892. String newAccountPath = FileStorageUtils.getSavePath(newAccountName);
  893. // move files
  894. File oldAccountFolder = new File(oldAccountPath);
  895. File newAccountFolder = new File(newAccountPath);
  896. oldAccountFolder.renameTo(newAccountFolder);
  897. // update database
  898. do {
  899. // Update database
  900. String oldPath = c.getString(
  901. c.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH));
  902. OCFile file = new OCFile(
  903. c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH)));
  904. String newPath = FileStorageUtils.getDefaultSavePathFor(newAccountName, file);
  905. ContentValues cv = new ContentValues();
  906. cv.put(ProviderTableMeta.FILE_STORAGE_PATH, newPath);
  907. db.update(ProviderTableMeta.FILE_TABLE_NAME,
  908. cv,
  909. ProviderTableMeta.FILE_STORAGE_PATH + "=?",
  910. new String[]{oldPath});
  911. Log_OC.v(SQL, "Updated path of downloaded file: old file name == " + oldPath +
  912. ", new file name == " + newPath);
  913. } while (c.moveToNext());
  914. }
  915. } finally {
  916. c.close();
  917. }
  918. }
  919. /**
  920. * Grants that total count of successful uploads stored is not greater than MAX_SUCCESSFUL_UPLOADS.
  921. *
  922. * Removes older uploads if needed.
  923. */
  924. private void trimSuccessfulUploads(SQLiteDatabase db) {
  925. Cursor c = null;
  926. try {
  927. String MAX_SUCCESSFUL_UPLOADS = "30";
  928. c = db.rawQuery(
  929. "delete from " + ProviderTableMeta.UPLOADS_TABLE_NAME +
  930. " where " + ProviderTableMeta.UPLOADS_STATUS + " == "
  931. + UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED.getValue() +
  932. " and " + ProviderTableMeta._ID +
  933. " not in (select " + ProviderTableMeta._ID +
  934. " from " + ProviderTableMeta.UPLOADS_TABLE_NAME +
  935. " where " + ProviderTableMeta.UPLOADS_STATUS + " == "
  936. + UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED.getValue() +
  937. " order by " + ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP +
  938. " desc limit " + MAX_SUCCESSFUL_UPLOADS +
  939. ")",
  940. null
  941. );
  942. c.moveToFirst(); // do something with the cursor, or deletion doesn't happen; true story
  943. } catch (Exception e) {
  944. Log_OC.e(
  945. TAG,
  946. "Something wrong trimming successful uploads, database could grow more than expected",
  947. e
  948. );
  949. } finally {
  950. if (c!= null) {
  951. c.close();
  952. }
  953. }
  954. }
  955. }