FileContentProvider.java 40 KB

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