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