Fixed. When removing a file inside a folder and then upload another, thumbnails are...
[pub/Android/ownCloud.git] / src / com / owncloud / android / providers / FileContentProvider.java
1 /* ownCloud Android client application
2 * Copyright (C) 2011 Bartek Przybylski
3 * Copyright (C) 2012-2013 ownCloud Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 package com.owncloud.android.providers;
20
21 import java.util.ArrayList;
22 import java.util.HashMap;
23
24 import com.owncloud.android.R;
25 import com.owncloud.android.db.ProviderMeta;
26 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
27 import com.owncloud.android.lib.common.utils.Log_OC;
28 import com.owncloud.android.lib.resources.shares.ShareType;
29 import com.owncloud.android.ui.adapter.DiskLruImageCache;
30
31
32
33 import android.content.ContentProvider;
34 import android.content.ContentProviderOperation;
35 import android.content.ContentProviderResult;
36 import android.content.ContentUris;
37 import android.content.ContentValues;
38 import android.content.Context;
39 import android.content.OperationApplicationException;
40 import android.content.UriMatcher;
41 import android.database.Cursor;
42 import android.database.SQLException;
43 import android.database.sqlite.SQLiteDatabase;
44 import android.database.sqlite.SQLiteOpenHelper;
45 import android.database.sqlite.SQLiteQueryBuilder;
46 import android.graphics.Bitmap.CompressFormat;
47 import android.net.Uri;
48 import android.text.TextUtils;
49
50 /**
51 * The ContentProvider for the ownCloud App.
52 *
53 * @author Bartek Przybylski
54 * @author David A. Velasco
55 *
56 */
57 public class FileContentProvider extends ContentProvider {
58
59 private DataBaseHelper mDbHelper;
60 private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
61 private static final CompressFormat mCompressFormat = CompressFormat.JPEG;
62 private static final int mCompressQuality = 70;
63
64 private final Object thumbnailDiskCacheLock = new Object();
65 private DiskLruImageCache mThumbnailCache;
66
67 // Projection for filelist table
68 private static HashMap<String, String> mFileProjectionMap;
69 static {
70 mFileProjectionMap = new HashMap<String, String>();
71 mFileProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);
72 mFileProjectionMap.put(ProviderTableMeta.FILE_PARENT,
73 ProviderTableMeta.FILE_PARENT);
74 mFileProjectionMap.put(ProviderTableMeta.FILE_PATH,
75 ProviderTableMeta.FILE_PATH);
76 mFileProjectionMap.put(ProviderTableMeta.FILE_NAME,
77 ProviderTableMeta.FILE_NAME);
78 mFileProjectionMap.put(ProviderTableMeta.FILE_CREATION,
79 ProviderTableMeta.FILE_CREATION);
80 mFileProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,
81 ProviderTableMeta.FILE_MODIFIED);
82 mFileProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
83 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA);
84 mFileProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,
85 ProviderTableMeta.FILE_CONTENT_LENGTH);
86 mFileProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,
87 ProviderTableMeta.FILE_CONTENT_TYPE);
88 mFileProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,
89 ProviderTableMeta.FILE_STORAGE_PATH);
90 mFileProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE,
91 ProviderTableMeta.FILE_LAST_SYNC_DATE);
92 mFileProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,
93 ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA);
94 mFileProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC,
95 ProviderTableMeta.FILE_KEEP_IN_SYNC);
96 mFileProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER,
97 ProviderTableMeta.FILE_ACCOUNT_OWNER);
98 mFileProjectionMap.put(ProviderTableMeta.FILE_ETAG,
99 ProviderTableMeta.FILE_ETAG);
100 mFileProjectionMap.put(ProviderTableMeta.FILE_SHARE_BY_LINK,
101 ProviderTableMeta.FILE_SHARE_BY_LINK);
102 mFileProjectionMap.put(ProviderTableMeta.FILE_PUBLIC_LINK,
103 ProviderTableMeta.FILE_PUBLIC_LINK);
104 mFileProjectionMap.put(ProviderTableMeta.FILE_PERMISSIONS,
105 ProviderTableMeta.FILE_PERMISSIONS);
106 mFileProjectionMap.put(ProviderTableMeta.FILE_REMOTE_ID,
107 ProviderTableMeta.FILE_REMOTE_ID);
108 mFileProjectionMap.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL,
109 ProviderTableMeta.FILE_UPDATE_THUMBNAIL);
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 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(children.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
214 //remotePath = children.getString(children.getColumnIndex(ProviderTableMeta.FILE_PATH));
215 if (isDir) {
216 count += delete(db, ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId), null, null);
217 } else {
218 count += delete(db, ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, childId), null, null);
219 }
220 children.moveToNext();
221 }
222 children.close();
223 } /*else {
224 Log_OC.d(TAG, "No child to remove in DIRECTORY " + folderName);
225 }
226 Log_OC.d(TAG, "Removing DIRECTORY " + folderName + " (or maybe not) ");
227 */
228 count += db.delete(ProviderTableMeta.FILE_TABLE_NAME,
229 ProviderTableMeta._ID
230 + "="
231 + uri.getPathSegments().get(1)
232 + (!TextUtils.isEmpty(where) ? " AND (" + where
233 + ")" : ""), whereArgs);
234 /* Just for log
235 if (folder != null) {
236 folder.close();
237 }*/
238 break;
239 case ROOT_DIRECTORY:
240 //Log_OC.d(TAG, "Removing ROOT!");
241 count = db.delete(ProviderTableMeta.FILE_TABLE_NAME, where, whereArgs);
242 break;
243 case SHARES:
244 count = db.delete(ProviderTableMeta.OCSHARES_TABLE_NAME, where, whereArgs);
245 break;
246 default:
247 //Log_OC.e(TAG, "Unknown uri " + uri);
248 throw new IllegalArgumentException("Unknown uri: " + uri.toString());
249 }
250 return count;
251 }
252
253 /**
254 * Remove from cache the remoteId passed
255 * @param fileRemoteId: remote id of file passed
256 */
257 private void removeFileFromCache(String fileRemoteId){
258 Context context = getContext();
259 if (context != null) {
260 synchronized (thumbnailDiskCacheLock) {
261 try {
262 mThumbnailCache = new DiskLruImageCache(context, "thumbnailCache",
263 DISK_CACHE_SIZE, mCompressFormat, mCompressQuality);
264
265 mThumbnailCache.removeKey(fileRemoteId);
266
267 } catch (Exception e) {
268 Log_OC.d(TAG, "Thumbnail cache could not be opened ", e);
269 mThumbnailCache = null;
270 }
271 thumbnailDiskCacheLock.notifyAll(); // Wake any waiting threads
272 }
273 }
274 }
275
276 @Override
277 public String getType(Uri uri) {
278 switch (mUriMatcher.match(uri)) {
279 case ROOT_DIRECTORY:
280 return ProviderTableMeta.CONTENT_TYPE;
281 case SINGLE_FILE:
282 return ProviderTableMeta.CONTENT_TYPE_ITEM;
283 default:
284 throw new IllegalArgumentException("Unknown Uri id."
285 + uri.toString());
286 }
287 }
288
289 @Override
290 public Uri insert(Uri uri, ContentValues values) {
291 //Log_OC.d(TAG, "Inserting " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
292 Uri newUri = null;
293 SQLiteDatabase db = mDbHelper.getWritableDatabase();
294 db.beginTransaction();
295 try {
296 newUri = insert(db, uri, values);
297 db.setTransactionSuccessful();
298 } finally {
299 db.endTransaction();
300 }
301 getContext().getContentResolver().notifyChange(newUri, null);
302 return newUri;
303 }
304
305 private Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) {
306 switch (mUriMatcher.match(uri)){
307 case ROOT_DIRECTORY:
308 case SINGLE_FILE:
309 String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH);
310 String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER);
311 String[] projection = new String[] {ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH, ProviderTableMeta.FILE_ACCOUNT_OWNER };
312 String where = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
313 String[] whereArgs = new String[] {remotePath, accountName};
314 Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null);
315 if (doubleCheck == null || !doubleCheck.moveToFirst()) { // ugly patch; serious refactorization is needed to reduce work in FileDataStorageManager and bring it to FileContentProvider
316 long rowId = db.insert(ProviderTableMeta.FILE_TABLE_NAME, null, values);
317 if (rowId > 0) {
318 Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
319 //Log_OC.d(TAG, "Inserted " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
320 return insertedFileUri;
321 } else {
322 //Log_OC.d(TAG, "Error while inserting " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
323 throw new SQLException("ERROR " + uri);
324 }
325 } else {
326 // file is already inserted; race condition, let's avoid a duplicated entry
327 Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID)));
328 doubleCheck.close();
329
330 return insertedFileUri;
331 }
332
333 case SHARES:
334 String path = values.getAsString(ProviderTableMeta.OCSHARES_PATH);
335 String accountNameShare= values.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER);
336 String[] projectionShare = new String[] {ProviderTableMeta._ID, ProviderTableMeta.OCSHARES_PATH, ProviderTableMeta.OCSHARES_ACCOUNT_OWNER };
337 String whereShare = ProviderTableMeta.OCSHARES_PATH + "=? AND " + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
338 String[] whereArgsShare = new String[] {path, accountNameShare};
339 Uri insertedShareUri = null;
340 Cursor doubleCheckShare = query(db, uri, projectionShare, whereShare, whereArgsShare, null);
341 if (doubleCheckShare == null || !doubleCheckShare.moveToFirst()) { // ugly patch; serious refactorization is needed to reduce work in FileDataStorageManager and bring it to FileContentProvider
342 long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values);
343 if (rowId >0) {
344 insertedShareUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId);
345 } else {
346 throw new SQLException("ERROR " + uri);
347
348 }
349 } else {
350 // file is already inserted; race condition, let's avoid a duplicated entry
351 insertedShareUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, doubleCheckShare.getLong(doubleCheckShare.getColumnIndex(ProviderTableMeta._ID)));
352 doubleCheckShare.close();
353 }
354 updateFilesTableAccordingToShareInsertion(db, uri, values);
355 return insertedShareUri;
356
357
358 default:
359 throw new IllegalArgumentException("Unknown uri id: " + uri);
360 }
361
362 }
363
364 private void updateFilesTableAccordingToShareInsertion(SQLiteDatabase db, Uri uri, ContentValues shareValues) {
365 ContentValues fileValues = new ContentValues();
366 fileValues.put(ProviderTableMeta.FILE_SHARE_BY_LINK,
367 ShareType.PUBLIC_LINK.getValue() == shareValues.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE)? 1 : 0);
368 String whereShare = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
369 String[] whereArgsShare = new String[] {
370 shareValues.getAsString(ProviderTableMeta.OCSHARES_PATH),
371 shareValues.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER)
372 };
373 db.update(ProviderTableMeta.FILE_TABLE_NAME, fileValues, whereShare, whereArgsShare);
374 }
375
376
377 @Override
378 public boolean onCreate() {
379 mDbHelper = new DataBaseHelper(getContext());
380
381 String authority = getContext().getResources().getString(R.string.authority);
382 mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
383 mUriMatcher.addURI(authority, null, ROOT_DIRECTORY);
384 mUriMatcher.addURI(authority, "file/", SINGLE_FILE);
385 mUriMatcher.addURI(authority, "file/#", SINGLE_FILE);
386 mUriMatcher.addURI(authority, "dir/", DIRECTORY);
387 mUriMatcher.addURI(authority, "dir/#", DIRECTORY);
388 mUriMatcher.addURI(authority, "shares/", SHARES);
389 mUriMatcher.addURI(authority, "shares/#", SHARES);
390
391 return true;
392 }
393
394
395 @Override
396 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
397 Cursor result = null;
398 SQLiteDatabase db = mDbHelper.getReadableDatabase();
399 db.beginTransaction();
400 try {
401 result = query(db, uri, projection, selection, selectionArgs, sortOrder);
402 db.setTransactionSuccessful();
403 } finally {
404 db.endTransaction();
405 }
406 return result;
407 }
408
409 private Cursor query(SQLiteDatabase db, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
410 SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();
411
412 sqlQuery.setTables(ProviderTableMeta.FILE_TABLE_NAME);
413 sqlQuery.setProjectionMap(mFileProjectionMap);
414
415 switch (mUriMatcher.match(uri)) {
416 case ROOT_DIRECTORY:
417 break;
418 case DIRECTORY:
419 String folderId = uri.getPathSegments().get(1);
420 sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="
421 + folderId);
422 break;
423 case SINGLE_FILE:
424 if (uri.getPathSegments().size() > 1) {
425 sqlQuery.appendWhere(ProviderTableMeta._ID + "="
426 + uri.getPathSegments().get(1));
427 }
428 break;
429 case SHARES:
430 sqlQuery.setTables(ProviderTableMeta.OCSHARES_TABLE_NAME);
431 sqlQuery.setProjectionMap(mOCSharesProjectionMap);
432 if (uri.getPathSegments().size() > 1) {
433 sqlQuery.appendWhere(ProviderTableMeta._ID + "="
434 + uri.getPathSegments().get(1));
435 }
436 break;
437 default:
438 throw new IllegalArgumentException("Unknown uri id: " + uri);
439 }
440
441 String order;
442 if (TextUtils.isEmpty(sortOrder)) {
443 if (mUriMatcher.match(uri) == SHARES) {
444 order = ProviderTableMeta.OCSHARES_DEFAULT_SORT_ORDER;
445 } else {
446
447 order = ProviderTableMeta.FILE_DEFAULT_SORT_ORDER;
448 }
449 } else {
450 order = sortOrder;
451 }
452
453 // DB case_sensitive
454 db.execSQL("PRAGMA case_sensitive_like = true");
455 Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, null, null, order);
456 c.setNotificationUri(getContext().getContentResolver(), uri);
457 return c;
458 }
459
460 @Override
461 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
462
463 //Log_OC.d(TAG, "Updating " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
464 int count = 0;
465 SQLiteDatabase db = mDbHelper.getWritableDatabase();
466 db.beginTransaction();
467 try {
468 count = update(db, uri, values, selection, selectionArgs);
469 db.setTransactionSuccessful();
470 } finally {
471 db.endTransaction();
472 }
473 getContext().getContentResolver().notifyChange(uri, null);
474 return count;
475 }
476
477
478
479 private int update(SQLiteDatabase db, Uri uri, ContentValues values, String selection, String[] selectionArgs) {
480 switch (mUriMatcher.match(uri)) {
481 case DIRECTORY:
482 return 0; //updateFolderSize(db, selectionArgs[0]);
483 case SHARES:
484 return db.update(ProviderTableMeta.OCSHARES_TABLE_NAME, values, selection, selectionArgs);
485 default:
486 return db.update(ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs);
487 }
488 }
489
490 /*
491 private int updateFolderSize(SQLiteDatabase db, String folderId) {
492 int count = 0;
493 String [] whereArgs = new String[] { folderId };
494
495 // read current size saved for the folder
496 long folderSize = 0;
497 long folderParentId = -1;
498 Uri selectFolderUri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, folderId);
499 String[] folderProjection = new String[] { ProviderTableMeta.FILE_CONTENT_LENGTH, ProviderTableMeta.FILE_PARENT};
500 String folderWhere = ProviderTableMeta._ID + "=?";
501 Cursor folderCursor = query(db, selectFolderUri, folderProjection, folderWhere, whereArgs, null);
502 if (folderCursor != null && folderCursor.moveToFirst()) {
503 folderSize = folderCursor.getLong(folderCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH));;
504 folderParentId = folderCursor.getLong(folderCursor.getColumnIndex(ProviderTableMeta.FILE_PARENT));;
505 }
506 folderCursor.close();
507
508 // read and sum sizes of children
509 long childrenSize = 0;
510 Uri selectChildrenUri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, folderId);
511 String[] childrenProjection = new String[] { ProviderTableMeta.FILE_CONTENT_LENGTH, ProviderTableMeta.FILE_PARENT};
512 String childrenWhere = ProviderTableMeta.FILE_PARENT + "=?";
513 Cursor childrenCursor = query(db, selectChildrenUri, childrenProjection, childrenWhere, whereArgs, null);
514 if (childrenCursor != null && childrenCursor.moveToFirst()) {
515 while (!childrenCursor.isAfterLast()) {
516 childrenSize += childrenCursor.getLong(childrenCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH));
517 childrenCursor.moveToNext();
518 }
519 }
520 childrenCursor.close();
521
522 // update if needed
523 if (folderSize != childrenSize) {
524 Log_OC.d("FileContentProvider", "Updating " + folderSize + " to " + childrenSize);
525 ContentValues cv = new ContentValues();
526 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, childrenSize);
527 count = db.update(ProviderTableMeta.FILE_TABLE_NAME, cv, folderWhere, whereArgs);
528
529 // propagate update until root
530 if (folderParentId > FileDataStorageManager.ROOT_PARENT_ID) {
531 Log_OC.d("FileContentProvider", "Propagating update to " + folderParentId);
532 updateFolderSize(db, String.valueOf(folderParentId));
533 } else {
534 Log_OC.d("FileContentProvider", "NOT propagating to " + folderParentId);
535 }
536 } else {
537 Log_OC.d("FileContentProvider", "NOT updating, sizes are " + folderSize + " and " + childrenSize);
538 }
539 return count;
540 }
541 */
542
543 @Override
544 public ContentProviderResult[] applyBatch (ArrayList<ContentProviderOperation> operations) throws OperationApplicationException {
545 Log_OC.d("FileContentProvider", "applying batch in provider " + this + " (temporary: " + isTemporary() + ")" );
546 ContentProviderResult[] results = new ContentProviderResult[operations.size()];
547 int i=0;
548
549 SQLiteDatabase db = mDbHelper.getWritableDatabase();
550 db.beginTransaction(); // it's supposed that transactions can be nested
551 try {
552 for (ContentProviderOperation operation : operations) {
553 results[i] = operation.apply(this, results, i);
554 i++;
555 }
556 db.setTransactionSuccessful();
557 } finally {
558 db.endTransaction();
559 }
560 Log_OC.d("FileContentProvider", "applied batch in provider " + this);
561 return results;
562 }
563
564
565 class DataBaseHelper extends SQLiteOpenHelper {
566
567 public DataBaseHelper(Context context) {
568 super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);
569
570 }
571
572 @Override
573 public void onCreate(SQLiteDatabase db) {
574 // files table
575 Log_OC.i("SQL", "Entering in onCreate");
576 db.execSQL("CREATE TABLE " + ProviderTableMeta.FILE_TABLE_NAME + "("
577 + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
578 + ProviderTableMeta.FILE_NAME + " TEXT, "
579 + ProviderTableMeta.FILE_PATH + " TEXT, "
580 + ProviderTableMeta.FILE_PARENT + " INTEGER, "
581 + ProviderTableMeta.FILE_CREATION + " INTEGER, "
582 + ProviderTableMeta.FILE_MODIFIED + " INTEGER, "
583 + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, "
584 + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, "
585 + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, "
586 + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, "
587 + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, "
588 + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, "
589 + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "
590 + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER, "
591 + ProviderTableMeta.FILE_ETAG + " TEXT, "
592 + ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER, "
593 + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT, "
594 + ProviderTableMeta.FILE_PERMISSIONS + " TEXT null,"
595 + ProviderTableMeta.FILE_REMOTE_ID + " TEXT null,"
596 + ProviderTableMeta.FILE_UPDATE_THUMBNAIL + " INTEGER);" //boolean
597 );
598
599 // Create table ocshares
600 db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "("
601 + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
602 + ProviderTableMeta.OCSHARES_FILE_SOURCE + " INTEGER, "
603 + ProviderTableMeta.OCSHARES_ITEM_SOURCE + " INTEGER, "
604 + ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, "
605 + ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, "
606 + ProviderTableMeta.OCSHARES_PATH + " TEXT, "
607 + ProviderTableMeta.OCSHARES_PERMISSIONS+ " INTEGER, "
608 + ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, "
609 + ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, "
610 + ProviderTableMeta.OCSHARES_TOKEN + " TEXT, "
611 + ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, "
612 + ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, " // boolean
613 + ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, "
614 + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER,"
615 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" );
616 }
617
618 @Override
619 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
620 Log_OC.i("SQL", "Entering in onUpgrade");
621 boolean upgraded = false;
622 if (oldVersion == 1 && newVersion >= 2) {
623 Log_OC.i("SQL", "Entering in the #1 ADD in onUpgrade");
624 db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
625 " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " +
626 " DEFAULT 0");
627 upgraded = true;
628 }
629 if (oldVersion < 3 && newVersion >= 3) {
630 Log_OC.i("SQL", "Entering in the #2 ADD in onUpgrade");
631 db.beginTransaction();
632 try {
633 db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
634 " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER " +
635 " DEFAULT 0");
636
637 // assume there are not local changes pending to upload
638 db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
639 " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() +
640 " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
641
642 upgraded = true;
643 db.setTransactionSuccessful();
644 } finally {
645 db.endTransaction();
646 }
647 }
648 if (oldVersion < 4 && newVersion >= 4) {
649 Log_OC.i("SQL", "Entering in the #3 ADD in onUpgrade");
650 db.beginTransaction();
651 try {
652 db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
653 " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER " +
654 " DEFAULT 0");
655
656 db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
657 " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED +
658 " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
659
660 upgraded = true;
661 db.setTransactionSuccessful();
662 } finally {
663 db.endTransaction();
664 }
665 }
666 if (!upgraded)
667 Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
668
669 if (oldVersion < 5 && newVersion >= 5) {
670 Log_OC.i("SQL", "Entering in the #4 ADD in onUpgrade");
671 db.beginTransaction();
672 try {
673 db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
674 " ADD COLUMN " + ProviderTableMeta.FILE_ETAG + " TEXT " +
675 " DEFAULT NULL");
676
677 upgraded = true;
678 db.setTransactionSuccessful();
679 } finally {
680 db.endTransaction();
681 }
682 }
683 if (!upgraded)
684 Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
685
686 if (oldVersion < 6 && newVersion >= 6) {
687 Log_OC.i("SQL", "Entering in the #5 ADD in onUpgrade");
688 db.beginTransaction();
689 try {
690 db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
691 " ADD COLUMN " + ProviderTableMeta.FILE_SHARE_BY_LINK + " INTEGER " +
692 " DEFAULT 0");
693
694 db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
695 " ADD COLUMN " + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT " +
696 " DEFAULT NULL");
697
698 // Create table ocshares
699 db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "("
700 + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
701 + ProviderTableMeta.OCSHARES_FILE_SOURCE + " INTEGER, "
702 + ProviderTableMeta.OCSHARES_ITEM_SOURCE + " INTEGER, "
703 + ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, "
704 + ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, "
705 + ProviderTableMeta.OCSHARES_PATH + " TEXT, "
706 + ProviderTableMeta.OCSHARES_PERMISSIONS+ " INTEGER, "
707 + ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, "
708 + ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, "
709 + ProviderTableMeta.OCSHARES_TOKEN + " TEXT, "
710 + ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, "
711 + ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, " // boolean
712 + ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, "
713 + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER,"
714 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" );
715
716 upgraded = true;
717 db.setTransactionSuccessful();
718 } finally {
719 db.endTransaction();
720 }
721 }
722 if (!upgraded)
723 Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
724
725 if (oldVersion < 7 && newVersion >= 7) {
726 Log_OC.i("SQL", "Entering in the #7 ADD in onUpgrade");
727 db.beginTransaction();
728 try {
729 db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
730 " ADD COLUMN " + ProviderTableMeta.FILE_PERMISSIONS + " TEXT " +
731 " DEFAULT NULL");
732
733 db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
734 " ADD COLUMN " + ProviderTableMeta.FILE_REMOTE_ID + " TEXT " +
735 " DEFAULT NULL");
736
737 upgraded = true;
738 db.setTransactionSuccessful();
739 } finally {
740 db.endTransaction();
741 }
742 }
743 if (!upgraded)
744 Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
745
746 if (oldVersion < 8 && newVersion >= 8) {
747 Log_OC.i("SQL", "Entering in the #8 ADD in onUpgrade");
748 db.beginTransaction();
749 try {
750 db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
751 " ADD COLUMN " + ProviderTableMeta.FILE_UPDATE_THUMBNAIL + " INTEGER " +
752 " DEFAULT 0");
753
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 + ", newVersion == " + newVersion);
762 }
763 }
764
765 }