FileContentProvider.java 42 KB

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