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