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