Creation of ThumbnailsCacheManager class, grouping all the methods needed to access the thumbnails cache

This commit is contained in:
David A. Velasco 2014-10-15 11:25:29 +02:00
parent 778ed30b58
commit 395ad3248e
4 changed files with 397 additions and 282 deletions

View file

@ -0,0 +1,262 @@
/* ownCloud Android client application
* Copyright (C) 2012-2014 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.owncloud.android.datamodel;
import java.io.File;
import java.lang.ref.WeakReference;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ThumbnailUtils;
import android.os.AsyncTask;
import android.util.TypedValue;
import android.widget.ImageView;
import com.owncloud.android.MainApp;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.ui.adapter.DiskLruImageCache;
import com.owncloud.android.utils.BitmapUtils;
import com.owncloud.android.utils.DisplayUtils;
/**
* Manager for concurrent access to thumbnails cache.
*
* @author Tobias Kaminsky
* @author David A. Velasco
*/
public class ThumbnailsCacheManager {
private static final String TAG = ThumbnailsCacheManager.class.getSimpleName();
private static final String CACHE_FOLDER = "thumbnailCache";
private static final Object mThumbnailsDiskCacheLock = new Object();
private static DiskLruImageCache mThumbnailCache;
private static boolean mThumbnailCacheStarting = true;
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
private static final CompressFormat mCompressFormat = CompressFormat.JPEG;
private static final int mCompressQuality = 70;
public static Bitmap mDefaultImg =
BitmapFactory.decodeResource(
MainApp.getAppContext().getResources(),
DisplayUtils.getResourceId("image/png", "default.png")
);
public static class InitDiskCacheTask extends AsyncTask<File, Void, Void> {
@Override
protected Void doInBackground(File... params) {
synchronized (mThumbnailsDiskCacheLock) {
try {
// Check if media is mounted or storage is built-in, if so,
// try and use external cache dir; otherwise use internal cache dir
final String cachePath =
MainApp.getAppContext().getExternalCacheDir().getPath() +
File.separator + CACHE_FOLDER;
Log_OC.d(TAG, "create dir: " + cachePath);
final File diskCacheDir = new File(cachePath);
mThumbnailCache = new DiskLruImageCache(
diskCacheDir,
DISK_CACHE_SIZE,
mCompressFormat,
mCompressQuality
);
} catch (Exception e) {
Log_OC.d(TAG, "Thumbnail cache could not be opened ", e);
mThumbnailCache = null;
}
mThumbnailCacheStarting = false; // Finished initialization
mThumbnailsDiskCacheLock.notifyAll(); // Wake any waiting threads
}
return null;
}
}
public static void addBitmapToCache(String key, Bitmap bitmap) {
synchronized (mThumbnailsDiskCacheLock) {
if (mThumbnailCache != null) {
mThumbnailCache.put(key, bitmap);
}
}
}
public static Bitmap getBitmapFromDiskCache(String key) {
synchronized (mThumbnailsDiskCacheLock) {
// Wait while disk cache is started from background thread
while (mThumbnailCacheStarting) {
try {
mThumbnailsDiskCacheLock.wait();
} catch (InterruptedException e) {}
}
if (mThumbnailCache != null) {
return (Bitmap) mThumbnailCache.getBitmap(key);
}
}
return null;
}
public static boolean cancelPotentialWork(OCFile file, ImageView imageView) {
final ThumbnailGenerationTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (bitmapWorkerTask != null) {
final OCFile bitmapData = bitmapWorkerTask.mFile;
// If bitmapData is not yet set or it differs from the new data
if (bitmapData == null || bitmapData != file) {
// Cancel previous task
bitmapWorkerTask.cancel(true);
} else {
// The same work is already in progress
return false;
}
}
// No task associated with the ImageView, or an existing task was cancelled
return true;
}
public static ThumbnailGenerationTask getBitmapWorkerTask(ImageView imageView) {
if (imageView != null) {
final Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncDrawable) {
final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
return asyncDrawable.getBitmapWorkerTask();
}
}
return null;
}
public static class ThumbnailGenerationTask extends AsyncTask<OCFile, Void, Bitmap> {
private final WeakReference<ImageView> mImageViewReference;
private OCFile mFile;
private FileDataStorageManager mStorageManager;
public ThumbnailGenerationTask(ImageView imageView, FileDataStorageManager storageManager) {
// Use a WeakReference to ensure the ImageView can be garbage collected
mImageViewReference = new WeakReference<ImageView>(imageView);
if (storageManager == null)
throw new IllegalArgumentException("storageManager must not be NULL");
mStorageManager = storageManager;
}
// Decode image in background.
@Override
protected Bitmap doInBackground(OCFile... params) {
Bitmap thumbnail = null;
try {
mFile = params[0];
final String imageKey = String.valueOf(mFile.getRemoteId());
// Check disk cache in background thread
thumbnail = getBitmapFromDiskCache(imageKey);
// Not found in disk cache
if (thumbnail == null || mFile.needsUpdateThumbnail()) {
// Converts dp to pixel
Resources r = MainApp.getAppContext().getResources();
int px = (int) Math.round(TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 150, r.getDisplayMetrics()
));
if (mFile.isDown()){
Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
mFile.getStoragePath(), px, px);
if (bitmap != null) {
thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
// Add thumbnail to cache
addBitmapToCache(imageKey, thumbnail);
mFile.setNeedsUpdateThumbnail(false);
mStorageManager.saveFile(mFile);
}
}
}
} catch (Throwable t) {
// the app should never break due to a problem with thumbnails
Log_OC.e(TAG, "Generation of thumbnail for " + mFile + " failed", t);
if (t instanceof OutOfMemoryError) {
System.gc();
}
}
return thumbnail;
}
protected void onPostExecute(Bitmap bitmap){
if (isCancelled()) {
bitmap = null;
}
if (mImageViewReference != null && bitmap != null) {
final ImageView imageView = mImageViewReference.get();
final ThumbnailGenerationTask bitmapWorkerTask =
getBitmapWorkerTask(imageView);
if (this == bitmapWorkerTask && imageView != null) {
if (imageView.getTag().equals(mFile.getFileId())) {
imageView.setImageBitmap(bitmap);
}
}
}
}
}
public static class AsyncDrawable extends BitmapDrawable {
private final WeakReference<ThumbnailGenerationTask> bitmapWorkerTaskReference;
public AsyncDrawable(
Resources res, Bitmap bitmap, ThumbnailGenerationTask bitmapWorkerTask
) {
super(res, bitmap);
bitmapWorkerTaskReference =
new WeakReference<ThumbnailGenerationTask>(bitmapWorkerTask);
}
public ThumbnailGenerationTask getBitmapWorkerTask() {
return bitmapWorkerTaskReference.get();
}
}
/**
* Remove from cache the remoteId passed
* @param fileRemoteId: remote id of mFile passed
*/
public static void removeFileFromCache(String fileRemoteId){
synchronized (mThumbnailsDiskCacheLock) {
if (mThumbnailCache != null) {
mThumbnailCache.removeKey(fileRemoteId);
}
mThumbnailsDiskCacheLock.notifyAll(); // Wake any waiting threads
}
}
}

View file

@ -22,13 +22,11 @@ import java.util.ArrayList;
import java.util.HashMap;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
import com.owncloud.android.db.ProviderMeta;
import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.ui.adapter.DiskLruImageCache;
import android.content.ContentProvider;
import android.content.ContentProviderOperation;
@ -43,7 +41,6 @@ import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.text.TextUtils;
@ -57,12 +54,6 @@ import android.text.TextUtils;
public class FileContentProvider extends ContentProvider {
private DataBaseHelper mDbHelper;
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
private static final CompressFormat mCompressFormat = CompressFormat.JPEG;
private static final int mCompressQuality = 70;
private final Object thumbnailDiskCacheLock = new Object();
private DiskLruImageCache mThumbnailCache;
// Projection for filelist table
private static HashMap<String, String> mFileProjectionMap;
@ -177,7 +168,7 @@ public class FileContentProvider extends ContentProvider {
String remoteId = "";
if (c != null && c.moveToFirst()) {
remoteId = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID));
removeFileFromCache(remoteId);
ThumbnailsCacheManager.removeFileFromCache(remoteId);
}
Log_OC.d(TAG, "Removing FILE " + remoteId);
@ -210,12 +201,24 @@ public class FileContentProvider extends ContentProvider {
//String remotePath;
while (!children.isAfterLast()) {
childId = children.getLong(children.getColumnIndex(ProviderTableMeta._ID));
isDir = "DIR".equals(children.getString(children.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
isDir = "DIR".equals(children.getString(
children.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)
));
//remotePath = children.getString(children.getColumnIndex(ProviderTableMeta.FILE_PATH));
if (isDir) {
count += delete(db, ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId), null, null);
count += delete(
db,
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId),
null,
null
);
} else {
count += delete(db, ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, childId), null, null);
count += delete(
db,
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, childId),
null,
null
);
}
children.moveToNext();
}
@ -250,29 +253,6 @@ public class FileContentProvider extends ContentProvider {
return count;
}
/**
* Remove from cache the remoteId passed
* @param fileRemoteId: remote id of file passed
*/
private void removeFileFromCache(String fileRemoteId){
Context context = getContext();
if (context != null) {
synchronized (thumbnailDiskCacheLock) {
try {
mThumbnailCache = new DiskLruImageCache(context, "thumbnailCache",
DISK_CACHE_SIZE, mCompressFormat, mCompressQuality);
mThumbnailCache.removeKey(fileRemoteId);
} catch (Exception e) {
Log_OC.d(TAG, "Thumbnail cache could not be opened ", e);
mThumbnailCache = null;
}
thumbnailDiskCacheLock.notifyAll(); // Wake any waiting threads
}
}
}
@Override
public String getType(Uri uri) {
switch (mUriMatcher.match(uri)) {
@ -288,7 +268,6 @@ public class FileContentProvider extends ContentProvider {
@Override
public Uri insert(Uri uri, ContentValues values) {
//Log_OC.d(TAG, "Inserting " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
Uri newUri = null;
SQLiteDatabase db = mDbHelper.getWritableDatabase();
db.beginTransaction();
@ -308,23 +287,31 @@ public class FileContentProvider extends ContentProvider {
case SINGLE_FILE:
String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH);
String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER);
String[] projection = new String[] {ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH, ProviderTableMeta.FILE_ACCOUNT_OWNER };
String where = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
String[] projection = new String[] {
ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH,
ProviderTableMeta.FILE_ACCOUNT_OWNER
};
String where = ProviderTableMeta.FILE_PATH + "=? AND " +
ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
String[] whereArgs = new String[] {remotePath, accountName};
Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null);
if (doubleCheck == null || !doubleCheck.moveToFirst()) { // ugly patch; serious refactorization is needed to reduce work in FileDataStorageManager and bring it to FileContentProvider
// ugly patch; serious refactorization is needed to reduce work in
// FileDataStorageManager and bring it to FileContentProvider
if (doubleCheck == null || !doubleCheck.moveToFirst()) {
long rowId = db.insert(ProviderTableMeta.FILE_TABLE_NAME, null, values);
if (rowId > 0) {
Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
//Log_OC.d(TAG, "Inserted " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
Uri insertedFileUri =
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
return insertedFileUri;
} else {
//Log_OC.d(TAG, "Error while inserting " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
throw new SQLException("ERROR " + uri);
}
} else {
// file is already inserted; race condition, let's avoid a duplicated entry
Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID)));
Uri insertedFileUri = ContentUris.withAppendedId(
ProviderTableMeta.CONTENT_URI_FILE,
doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID))
);
doubleCheck.close();
return insertedFileUri;
@ -333,22 +320,35 @@ public class FileContentProvider extends ContentProvider {
case SHARES:
String path = values.getAsString(ProviderTableMeta.OCSHARES_PATH);
String accountNameShare= values.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER);
String[] projectionShare = new String[] {ProviderTableMeta._ID, ProviderTableMeta.OCSHARES_PATH, ProviderTableMeta.OCSHARES_ACCOUNT_OWNER };
String whereShare = ProviderTableMeta.OCSHARES_PATH + "=? AND " + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
String[] projectionShare = new String[] {
ProviderTableMeta._ID, ProviderTableMeta.OCSHARES_PATH,
ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
};
String whereShare = ProviderTableMeta.OCSHARES_PATH + "=? AND " +
ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
String[] whereArgsShare = new String[] {path, accountNameShare};
Uri insertedShareUri = null;
Cursor doubleCheckShare = query(db, uri, projectionShare, whereShare, whereArgsShare, null);
if (doubleCheckShare == null || !doubleCheckShare.moveToFirst()) { // ugly patch; serious refactorization is needed to reduce work in FileDataStorageManager and bring it to FileContentProvider
Cursor doubleCheckShare =
query(db, uri, projectionShare, whereShare, whereArgsShare, null);
// ugly patch; serious refactorization is needed to reduce work in
// FileDataStorageManager and bring it to FileContentProvider
if (doubleCheckShare == null || !doubleCheckShare.moveToFirst()) {
long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values);
if (rowId >0) {
insertedShareUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId);
insertedShareUri =
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId);
} else {
throw new SQLException("ERROR " + uri);
}
} else {
// file is already inserted; race condition, let's avoid a duplicated entry
insertedShareUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, doubleCheckShare.getLong(doubleCheckShare.getColumnIndex(ProviderTableMeta._ID)));
insertedShareUri = ContentUris.withAppendedId(
ProviderTableMeta.CONTENT_URI_SHARE,
doubleCheckShare.getLong(
doubleCheckShare.getColumnIndex(ProviderTableMeta._ID)
)
);
doubleCheckShare.close();
}
updateFilesTableAccordingToShareInsertion(db, uri, values);
@ -361,11 +361,17 @@ public class FileContentProvider extends ContentProvider {
}
private void updateFilesTableAccordingToShareInsertion(SQLiteDatabase db, Uri uri, ContentValues shareValues) {
private void updateFilesTableAccordingToShareInsertion(
SQLiteDatabase db, Uri uri, ContentValues shareValues
) {
ContentValues fileValues = new ContentValues();
fileValues.put(ProviderTableMeta.FILE_SHARE_BY_LINK,
ShareType.PUBLIC_LINK.getValue() == shareValues.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE)? 1 : 0);
String whereShare = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
fileValues.put(
ProviderTableMeta.FILE_SHARE_BY_LINK,
ShareType.PUBLIC_LINK.getValue() ==
shareValues.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE)? 1 : 0
);
String whereShare = ProviderTableMeta.FILE_PATH + "=? AND " +
ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
String[] whereArgsShare = new String[] {
shareValues.getAsString(ProviderTableMeta.OCSHARES_PATH),
shareValues.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER)
@ -393,7 +399,14 @@ public class FileContentProvider extends ContentProvider {
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
public Cursor query(
Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder
) {
Cursor result = null;
SQLiteDatabase db = mDbHelper.getReadableDatabase();
db.beginTransaction();
@ -406,7 +419,15 @@ public class FileContentProvider extends ContentProvider {
return result;
}
private Cursor query(SQLiteDatabase db, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
private Cursor query(
SQLiteDatabase db,
Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder
) {
SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();
sqlQuery.setTables(ProviderTableMeta.FILE_TABLE_NAME);
@ -460,7 +481,6 @@ public class FileContentProvider extends ContentProvider {
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
//Log_OC.d(TAG, "Updating " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this);
int count = 0;
SQLiteDatabase db = mDbHelper.getWritableDatabase();
db.beginTransaction();
@ -476,14 +496,24 @@ public class FileContentProvider extends ContentProvider {
private int update(SQLiteDatabase db, Uri uri, ContentValues values, String selection, String[] selectionArgs) {
private int update(
SQLiteDatabase db,
Uri uri,
ContentValues values,
String selection,
String[] selectionArgs
) {
switch (mUriMatcher.match(uri)) {
case DIRECTORY:
return 0; //updateFolderSize(db, selectionArgs[0]);
case SHARES:
return db.update(ProviderTableMeta.OCSHARES_TABLE_NAME, values, selection, selectionArgs);
return db.update(
ProviderTableMeta.OCSHARES_TABLE_NAME, values, selection, selectionArgs
);
default:
return db.update(ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs);
return db.update(
ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs
);
}
}
@ -541,8 +571,10 @@ public class FileContentProvider extends ContentProvider {
*/
@Override
public ContentProviderResult[] applyBatch (ArrayList<ContentProviderOperation> operations) throws OperationApplicationException {
Log_OC.d("FileContentProvider", "applying batch in provider " + this + " (temporary: " + isTemporary() + ")" );
public ContentProviderResult[] applyBatch (ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
Log_OC.d("FileContentProvider", "applying batch in provider " + this +
" (temporary: " + isTemporary() + ")" );
ContentProviderResult[] results = new ContentProviderResult[operations.size()];
int i=0;
@ -631,12 +663,13 @@ public class FileContentProvider extends ContentProvider {
db.beginTransaction();
try {
db.execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
" ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER " +
" DEFAULT 0");
" ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA +
" INTEGER " + " DEFAULT 0");
// assume there are not local changes pending to upload
db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
" SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() +
" SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = "
+ System.currentTimeMillis() +
" WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
upgraded = true;
@ -650,11 +683,12 @@ public class FileContentProvider extends ContentProvider {
db.beginTransaction();
try {
db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
" ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER " +
" DEFAULT 0");
" ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA +
" INTEGER " + " DEFAULT 0");
db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME +
" SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED +
" SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " +
ProviderTableMeta.FILE_MODIFIED +
" WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
upgraded = true;
@ -664,7 +698,8 @@ public class FileContentProvider extends ContentProvider {
}
}
if (!upgraded)
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
", newVersion == " + newVersion);
if (oldVersion < 5 && newVersion >= 5) {
Log_OC.i("SQL", "Entering in the #4 ADD in onUpgrade");
@ -681,7 +716,8 @@ public class FileContentProvider extends ContentProvider {
}
}
if (!upgraded)
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
", newVersion == " + newVersion);
if (oldVersion < 6 && newVersion >= 6) {
Log_OC.i("SQL", "Entering in the #5 ADD in onUpgrade");
@ -720,7 +756,8 @@ public class FileContentProvider extends ContentProvider {
}
}
if (!upgraded)
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
", newVersion == " + newVersion);
if (oldVersion < 7 && newVersion >= 7) {
Log_OC.i("SQL", "Entering in the #7 ADD in onUpgrade");
@ -741,7 +778,8 @@ public class FileContentProvider extends ContentProvider {
}
}
if (!upgraded)
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
", newVersion == " + newVersion);
if (oldVersion < 8 && newVersion >= 8) {
Log_OC.i("SQL", "Entering in the #8 ADD in onUpgrade");
@ -758,7 +796,8 @@ public class FileContentProvider extends ContentProvider {
}
}
if (!upgraded)
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
", newVersion == " + newVersion);
}
}

View file

@ -25,7 +25,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
@ -45,9 +44,11 @@ public class DiskLruImageCache {
private static final String TAG = DiskLruImageCache.class.getSimpleName();
public DiskLruImageCache( Context context,String uniqueName, int diskCacheSize,
CompressFormat compressFormat, int quality ) throws IOException {
final File diskCacheDir = getDiskCacheDir(context, uniqueName );
//public DiskLruImageCache( Context context,String uniqueName, int diskCacheSize,
public DiskLruImageCache(
File diskCacheDir, int diskCacheSize, CompressFormat compressFormat, int quality
) throws IOException {
mDiskCache = DiskLruCache.open(
diskCacheDir, CACHE_VERSION, VALUE_COUNT, diskCacheSize
);
@ -68,17 +69,6 @@ public class DiskLruImageCache {
}
}
private File getDiskCacheDir(Context context, String uniqueName) {
// Check if media is mounted or storage is built-in, if so, try and use external cache dir
// otherwise use internal cache dir
final String cachePath = context.getExternalCacheDir().getPath();
Log_OC.d(TAG, "create dir: " + cachePath + File.separator + uniqueName);
return new File(cachePath + File.separator + uniqueName);
}
public void put( String key, Bitmap data ) {
DiskLruCache.Editor editor = null;

View file

@ -17,21 +17,11 @@
*/
package com.owncloud.android.ui.adapter;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.Vector;
import android.accounts.Account;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ThumbnailUtils;
import android.os.AsyncTask;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -45,11 +35,11 @@ import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncDrawable;
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.ui.activity.ComponentsGetter;
import com.owncloud.android.utils.BitmapUtils;
import com.owncloud.android.utils.DisplayUtils;
@ -64,8 +54,6 @@ import com.owncloud.android.utils.DisplayUtils;
public class FileListListAdapter extends BaseAdapter implements ListAdapter {
private final static String PERMISSION_SHARED_WITH_ME = "S";
private static final String TAG = FileListListAdapter.class.getSimpleName();
private Context mContext;
private OCFile mFile = null;
private Vector<OCFile> mFiles = null;
@ -75,14 +63,6 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
private Account mAccount;
private ComponentsGetter mTransferServiceGetter;
private final Object thumbnailDiskCacheLock = new Object();
private DiskLruImageCache mThumbnailCache;
private boolean mThumbnailCacheStarting = true;
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
private static final CompressFormat mCompressFormat = CompressFormat.JPEG;
private static final int mCompressQuality = 70;
private Bitmap defaultImg;
public FileListListAdapter(
boolean justFolders,
Context context,
@ -93,145 +73,11 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
mContext = context;
mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);
mTransferServiceGetter = transferServiceGetter;
defaultImg = BitmapFactory.decodeResource(mContext.getResources(),
DisplayUtils.getResourceId("image/png", "default.png"));
// Initialise disk cache on background thread
new InitDiskCacheTask().execute();
// initialise thumbnails cache on background thread
new ThumbnailsCacheManager.InitDiskCacheTask().execute();
}
class InitDiskCacheTask extends AsyncTask<File, Void, Void> {
@Override
protected Void doInBackground(File... params) {
synchronized (thumbnailDiskCacheLock) {
try {
mThumbnailCache = new DiskLruImageCache(mContext, "thumbnailCache",
DISK_CACHE_SIZE, mCompressFormat, mCompressQuality);
} catch (Exception e) {
Log_OC.d(TAG, "Thumbnail cache could not be opened ", e);
mThumbnailCache = null;
}
mThumbnailCacheStarting = false; // Finished initialization
thumbnailDiskCacheLock.notifyAll(); // Wake any waiting threads
}
return null;
}
}
static class AsyncDrawable extends BitmapDrawable {
private final WeakReference<ThumbnailGenerationTask> bitmapWorkerTaskReference;
public AsyncDrawable(Resources res, Bitmap bitmap,
ThumbnailGenerationTask bitmapWorkerTask) {
super(res, bitmap);
bitmapWorkerTaskReference =
new WeakReference<ThumbnailGenerationTask>(bitmapWorkerTask);
}
public ThumbnailGenerationTask getBitmapWorkerTask() {
return bitmapWorkerTaskReference.get();
}
}
class ThumbnailGenerationTask extends AsyncTask<OCFile, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private OCFile file;
public ThumbnailGenerationTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
@Override
protected Bitmap doInBackground(OCFile... params) {
Bitmap thumbnail = null;
try {
file = params[0];
final String imageKey = String.valueOf(file.getRemoteId());
// Check disk cache in background thread
thumbnail = getBitmapFromDiskCache(imageKey);
// Not found in disk cache
if (thumbnail == null || file.needsUpdateThumbnail()) {
// Converts dp to pixel
Resources r = mContext.getResources();
int px = (int) Math.round(TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 150, r.getDisplayMetrics()
));
if (file.isDown()){
Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
file.getStoragePath(), px, px);
if (bitmap != null) {
thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
// Add thumbnail to cache
addBitmapToCache(imageKey, thumbnail);
file.setNeedsUpdateThumbnail(false);
mStorageManager.saveFile(file);
}
}
}
} catch (Throwable t) {
// the app should never break due to a problem with thumbnails
Log_OC.e(TAG, "Generation of thumbnail for " + file + " failed", t);
if (t instanceof OutOfMemoryError) {
System.gc();
}
}
return thumbnail;
}
protected void onPostExecute(Bitmap bitmap){
if (isCancelled()) {
bitmap = null;
}
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
final ThumbnailGenerationTask bitmapWorkerTask =
getBitmapWorkerTask(imageView);
if (this == bitmapWorkerTask && imageView != null) {
if (imageView.getTag().equals(file.getFileId())) {
imageView.setImageBitmap(bitmap);
}
}
}
}
}
public void addBitmapToCache(String key, Bitmap bitmap) {
synchronized (thumbnailDiskCacheLock) {
if (mThumbnailCache != null) {
mThumbnailCache.put(key, bitmap);
}
}
}
public Bitmap getBitmapFromDiskCache(String key) {
synchronized (thumbnailDiskCacheLock) {
// Wait while disk cache is started from background thread
while (mThumbnailCacheStarting) {
try {
thumbnailDiskCacheLock.wait();
} catch (InterruptedException e) {}
}
if (mThumbnailCache != null) {
return (Bitmap) mThumbnailCache.getBitmap(key);
}
}
return null;
}
@Override
public boolean areAllItemsEnabled() {
return true;
@ -339,16 +185,23 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
// get Thumbnail if file is image
if (file.isImage()){
// Thumbnail in Cache?
Bitmap thumbnail = getBitmapFromDiskCache(String.valueOf(file.getRemoteId()));
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
String.valueOf(file.getRemoteId())
);
if (thumbnail != null && !file.needsUpdateThumbnail()){
fileIcon.setImageBitmap(thumbnail);
} else {
// generate new Thumbnail
if (cancelPotentialWork(file, fileIcon)) {
final ThumbnailGenerationTask task =
new ThumbnailGenerationTask(fileIcon);
final AsyncDrawable asyncDrawable =
new AsyncDrawable(mContext.getResources(), defaultImg, task);
if (ThumbnailsCacheManager.cancelPotentialWork(file, fileIcon)) {
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
new ThumbnailsCacheManager.ThumbnailGenerationTask(
fileIcon, mStorageManager
);
final AsyncDrawable asyncDrawable = new AsyncDrawable(
mContext.getResources(),
ThumbnailsCacheManager.mDefaultImg,
task
);
fileIcon.setImageDrawable(asyncDrawable);
task.execute(file);
}
@ -399,35 +252,6 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
return view;
}
public static boolean cancelPotentialWork(OCFile file, ImageView imageView) {
final ThumbnailGenerationTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (bitmapWorkerTask != null) {
final OCFile bitmapData = bitmapWorkerTask.file;
// If bitmapData is not yet set or it differs from the new data
if (bitmapData == null || bitmapData != file) {
// Cancel previous task
bitmapWorkerTask.cancel(true);
} else {
// The same work is already in progress
return false;
}
}
// No task associated with the ImageView, or an existing task was cancelled
return true;
}
private static ThumbnailGenerationTask getBitmapWorkerTask(ImageView imageView) {
if (imageView != null) {
final Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncDrawable) {
final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
return asyncDrawable.getBitmapWorkerTask();
}
}
return null;
}
@Override
public int getViewTypeCount() {
return 1;