From d05d7361fff3b8b7e1ea4d48d0f2488f55aab771 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Sun, 23 Nov 2014 13:34:24 +0100 Subject: [PATCH] - thumbnails on browsing local files during upload --- .../datamodel/ThumbnailsCacheManager.java | 110 ++++++++++++++++++ .../ui/adapter/FileListListAdapter.java | 5 +- .../ui/adapter/LocalFileListAdapter.java | 48 +++++++- 3 files changed, 158 insertions(+), 5 deletions(-) diff --git a/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index 1d2cda8c28..41a0d8b6b1 100644 --- a/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -156,6 +156,24 @@ public class ThumbnailsCacheManager { return true; } + public static boolean cancelPotentialWork(File file, ImageView imageView) { + final ThumbnailLocalGenerationTask bitmapWorkerTask = getBitmapLocalWorkerTask(imageView); + + if (bitmapWorkerTask != null) { + final File 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(); @@ -166,6 +184,84 @@ public class ThumbnailsCacheManager { } return null; } + + public static ThumbnailLocalGenerationTask getBitmapLocalWorkerTask(ImageView imageView) { + if (imageView != null) { + final Drawable drawable = imageView.getDrawable(); + if (drawable instanceof AsyncDrawable) { + final AsyncLocalDrawable asyncDrawable = (AsyncLocalDrawable) drawable; + return asyncDrawable.getBitmapWorkerTask(); + } + } + return null; + } + + public static class ThumbnailLocalGenerationTask extends AsyncTask { + private final WeakReference mImageViewReference; + private File mFile; + + public ThumbnailLocalGenerationTask(ImageView imageView) { + // Use a WeakReference to ensure the ImageView can be garbage collected + mImageViewReference = new WeakReference(imageView); + } + + // Decode image in background. + @Override + protected Bitmap doInBackground(File... params) { + Bitmap thumbnail = null; + + try { + mFile = params[0]; + final String imageKey = String.valueOf(mFile.hashCode()); + + // Check disk cache in background thread + thumbnail = getBitmapFromDiskCache(imageKey); + + // Not found in disk cache + if (thumbnail == null) { + // Converts dp to pixel + Resources r = MainApp.getAppContext().getResources(); + + int px = (int) Math.round(r.getDimension(R.dimen.file_icon_size)); + + Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile( + mFile.getAbsolutePath(), px, px); + + if (bitmap != null) { + thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px); + + // Add thumbnail to cache + addBitmapToCache(imageKey, thumbnail); + } + } + + } 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 ThumbnailLocalGenerationTask bitmapWorkerTask = getBitmapLocalWorkerTask(imageView); + if (this == bitmapWorkerTask && imageView != null) { + if (imageView.getTag().equals(mFile.hashCode())) { + imageView.setImageBitmap(bitmap); + } + } + } + } + } public static class ThumbnailGenerationTask extends AsyncTask { private final WeakReference mImageViewReference; @@ -303,6 +399,20 @@ public class ThumbnailsCacheManager { return bitmapWorkerTaskReference.get(); } } + + public static class AsyncLocalDrawable extends BitmapDrawable { + private final WeakReference bitmapWorkerTaskReference; + + public AsyncLocalDrawable(Resources res, Bitmap bitmap, ThumbnailLocalGenerationTask bitmapWorkerTask) { + super(res, bitmap); + bitmapWorkerTaskReference = + new WeakReference(bitmapWorkerTask); + } + + public ThumbnailLocalGenerationTask getBitmapWorkerTask() { + return bitmapWorkerTaskReference.get(); + } + } /** diff --git a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java index 103563209c..d7c077a57c 100644 --- a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java @@ -47,7 +47,6 @@ 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.DisplayUtils; import com.owncloud.android.utils.FileStorageUtils; @@ -234,9 +233,7 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { } } } else { - fileIcon.setImageResource( - DisplayUtils.getResourceId(file.getMimetype(), file.getFileName()) - ); + fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())); } if (checkIfFileIsSharedWithMe(file)) { diff --git a/src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java b/src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java index 6190ebee24..3d47d0d34e 100644 --- a/src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java @@ -22,9 +22,12 @@ import java.util.Arrays; import java.util.Comparator; import android.content.Context; +import android.graphics.Bitmap; +import android.net.Uri; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.webkit.MimeTypeMap; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListAdapter; @@ -32,6 +35,8 @@ import android.widget.ListView; import android.widget.TextView; import com.owncloud.android.R; +import com.owncloud.android.datamodel.ThumbnailsCacheManager; +import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncLocalDrawable; import com.owncloud.android.utils.DisplayUtils; /** @@ -46,7 +51,7 @@ public class LocalFileListAdapter extends BaseAdapter implements ListAdapter { private Context mContext; private File mDirectory; private File[] mFiles = null; - + public LocalFileListAdapter(File directory, Context context) { mContext = context; swapDirectory(directory); @@ -105,6 +110,7 @@ public class LocalFileListAdapter extends BaseAdapter implements ListAdapter { } else { fileIcon.setImageResource(R.drawable.ic_menu_archive); } + fileIcon.setTag(file.hashCode()); TextView fileSizeV = (TextView) view.findViewById(R.id.file_size); TextView lastModV = (TextView) view.findViewById(R.id.last_mod); @@ -125,6 +131,38 @@ public class LocalFileListAdapter extends BaseAdapter implements ListAdapter { } checkBoxV.setVisibility(View.VISIBLE); } + + // get Thumbnail if file is image + if (isImage(file)){ + // Thumbnail in Cache? + Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( + String.valueOf(file.hashCode()) + ); + if (thumbnail != null){ + fileIcon.setImageBitmap(thumbnail); + } else { + // generate new Thumbnail + if (ThumbnailsCacheManager.cancelPotentialWork(file, fileIcon)) { + final ThumbnailsCacheManager.ThumbnailLocalGenerationTask task = + new ThumbnailsCacheManager.ThumbnailLocalGenerationTask(fileIcon); + if (thumbnail == null) { + thumbnail = ThumbnailsCacheManager.mDefaultImg; + } + final AsyncLocalDrawable asyncDrawable = new AsyncLocalDrawable( + mContext.getResources(), + thumbnail, + task + ); + fileIcon.setImageDrawable(asyncDrawable); + task.execute(file); + } + } + } else { + Uri selectedUri = Uri.fromFile(file); + String fileExtension = MimeTypeMap.getFileExtensionFromUrl(selectedUri.toString()); + String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension); + fileIcon.setImageResource(DisplayUtils.getResourceId(mimeType, file.getName())); + } } else { fileSizeV.setVisibility(View.GONE); @@ -184,4 +222,12 @@ public class LocalFileListAdapter extends BaseAdapter implements ListAdapter { } notifyDataSetChanged(); } + + private boolean isImage(File file) { + Uri selectedUri = Uri.fromFile(file); + String fileExtension = MimeTypeMap.getFileExtensionFromUrl(selectedUri.toString()); + String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension); + + return (mimeType != null && mimeType.startsWith("image/")); + } }