Added requested changes.
authortobiasKaminsky <tobias@kaminsky.me>
Mon, 1 Sep 2014 19:12:51 +0000 (21:12 +0200)
committertobiasKaminsky <tobias@kaminsky.me>
Mon, 1 Sep 2014 19:12:51 +0000 (21:12 +0200)
.classpath
libs/disklrucache-2.0.2.jar [new file with mode: 0644]
lint.xml
src/com/owncloud/android/ui/adapter/DiskLruImageCache.java
src/com/owncloud/android/ui/adapter/FileListListAdapter.java
src/com/owncloud/android/ui/adapter/Utils.java [deleted file]
third_party/disklrucache-2.0.2.jar [deleted file]

index fa15a28..5176974 100644 (file)
@@ -5,6 +5,5 @@
        <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
        <classpathentry kind="src" path="src"/>
        <classpathentry kind="src" path="gen"/>
-       <classpathentry exported="true" kind="lib" path="third_party/disklrucache-2.0.2.jar"/>
        <classpathentry kind="output" path="bin/classes"/>
 </classpath>
diff --git a/libs/disklrucache-2.0.2.jar b/libs/disklrucache-2.0.2.jar
new file mode 100644 (file)
index 0000000..ca7907d
Binary files /dev/null and b/libs/disklrucache-2.0.2.jar differ
index ce54dad..e69de29 100644 (file)
--- a/lint.xml
+++ b/lint.xml
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
-    <issue id="NewApi">
-        <ignore path="src/com/owncloud/android/ui/adapter/Utils.java" />
-    </issue>
-</lint>
\ No newline at end of file
index 5b401c2..d3479af 100644 (file)
@@ -22,17 +22,18 @@ import com.owncloud.android.utils.Log_OC;
 public class DiskLruImageCache {
 
     private DiskLruCache mDiskCache;
-    private CompressFormat mCompressFormat = CompressFormat.JPEG;
-    private int mCompressQuality = 70;
-    private static final int APP_VERSION = 1;
+    private CompressFormat mCompressFormat;
+    private int mCompressQuality;
+    private static final int CACHE_VERSION = 1;
     private static final int VALUE_COUNT = 1;
+    private static final int IO_BUFFER_SIZE = 8 * 1024;
     private static final String TAG = "DiskLruImageCache";
 
     public DiskLruImageCache( Context context,String uniqueName, int diskCacheSize,
         CompressFormat compressFormat, int quality ) {
         try {
                 final File diskCacheDir = getDiskCacheDir(context, uniqueName );
-                mDiskCache = DiskLruCache.open( diskCacheDir, APP_VERSION, VALUE_COUNT, diskCacheSize );
+                mDiskCache = DiskLruCache.open( diskCacheDir, CACHE_VERSION, VALUE_COUNT, diskCacheSize );
                 mCompressFormat = compressFormat;
                 mCompressQuality = quality;
             } catch (IOException e) {
@@ -44,7 +45,7 @@ public class DiskLruImageCache {
         throws IOException, FileNotFoundException {
         OutputStream out = null;
         try {
-            out = new BufferedOutputStream( editor.newOutputStream( 0 ), Utils.IO_BUFFER_SIZE );
+            out = new BufferedOutputStream( editor.newOutputStream( 0 ), IO_BUFFER_SIZE );
             return bitmap.compress( mCompressFormat, mCompressQuality, out );
         } finally {
             if ( out != null ) {
@@ -57,11 +58,7 @@ public class DiskLruImageCache {
 
     // 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 =
-            Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
-                    !Utils.isExternalStorageRemovable() ?
-                    Utils.getExternalCacheDir(context).getPath() :
-                    context.getCacheDir().getPath();
+        final String cachePath = context.getExternalCacheDir().getPath();
 
         Log_OC.d("DiskCache", "create dir: " + cachePath + File.separator + uniqueName);
                     
@@ -116,7 +113,7 @@ public class DiskLruImageCache {
             final InputStream in = snapshot.getInputStream( 0 );
             if ( in != null ) {
                 final BufferedInputStream buffIn = 
-                new BufferedInputStream( in, Utils.IO_BUFFER_SIZE );
+                new BufferedInputStream( in, IO_BUFFER_SIZE );
                 bitmap = BitmapFactory.decodeStream( buffIn );              
             }   
         } catch ( IOException e ) {
index e2ad4fa..5a069e7 100644 (file)
@@ -19,6 +19,7 @@ package com.owncloud.android.ui.adapter;
 \r
 import java.io.File;\r
 import java.io.IOException;\r
+import java.lang.ref.WeakReference;\r
 import java.net.URLEncoder;\r
 import java.util.Vector;\r
 \r
@@ -30,6 +31,8 @@ import android.content.res.Resources;
 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
@@ -69,6 +72,7 @@ import org.apache.http.util.EntityUtils;
  * instance.\r
  * \r
  * @author Bartek Przybylski\r
+ * @Author Tobias Kaminsky\r
  * \r
  */\r
 public class FileListListAdapter extends BaseAdapter implements ListAdapter {\r
@@ -81,18 +85,21 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
     private FileDataStorageManager mStorageManager;
     private Account mAccount;
     private ComponentsGetter mTransferServiceGetter;\r
-    private final Object mDiskCacheLock = new Object();\r
-    private DiskLruImageCache mDiskLruCache;\r
-    private boolean mDiskCacheStarting = true;\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 CompressFormat mCompressFormat = CompressFormat.JPEG;\r
-    private int mCompressQuality = 70;\r
+    private static final CompressFormat mCompressFormat = CompressFormat.JPEG;\r
+    private static final int mCompressQuality = 70;\r
     private OwnCloudClient mClient;\r
+    private Bitmap defaultImg;\r
         \r
     public FileListListAdapter(Context context, ComponentsGetter transferServiceGetter) {\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
@@ -101,8 +108,9 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
     class InitDiskCacheTask extends AsyncTask<File, Void, Void> {\r
         @Override\r
         protected Void doInBackground(File... params) {\r
-            synchronized (mDiskCacheLock) {\r
-                mDiskLruCache = new DiskLruImageCache(mContext, "thumbnailCache", DISK_CACHE_SIZE, mCompressFormat,mCompressQuality);\r
+            synchronized (thumbnailDiskCacheLock) {\r
+                mThumbnailCache = new DiskLruImageCache(mContext, "thumbnailCache", \r
+                                    DISK_CACHE_SIZE, mCompressFormat, mCompressQuality);\r
                 \r
                 try {\r
                     OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext);\r
@@ -122,24 +130,42 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                     e.printStackTrace();\r
                 }\r
 \r
-                mDiskCacheStarting = false; // Finished initialization\r
-                mDiskCacheLock.notifyAll(); // Wake any waiting threads\r
+                mThumbnailCacheStarting = false; // Finished initialization\r
+                thumbnailDiskCacheLock.notifyAll(); // Wake any waiting threads\r
             }\r
             return null;\r
         }\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
-    class BitmapWorkerTask extends AsyncTask<OCFile, Void, Bitmap> {\r
-        private final ImageView fileIcon;\r
         \r
-        public BitmapWorkerTask(ImageView fileIcon) {\r
-            this.fileIcon = fileIcon;\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
-            OCFile file = params[0];\r
+            file = params[0];\r
             final String imageKey = String.valueOf(file.getRemoteId());\r
 \r
             // Check disk cache in background thread\r
@@ -160,64 +186,72 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
 \r
                 } else {\r
                     // Download thumbnail from server\r
-                    DefaultHttpClient httpclient = new DefaultHttpClient();\r
-                    try {\r
-                        httpclient.getCredentialsProvider().setCredentials(\r
-                                new AuthScope(mClient.getBaseUri().toString().replace("https://", ""), 443), \r
-                                new UsernamePasswordCredentials(mClient.getCredentials().getUsername(), mClient.getCredentials().getAuthToken()));\r
-                        \r
-\r
-                        // TODO change to user preview.png\r
-                        //HttpGet httpget = new HttpGet(mClient.getBaseUri() + "/index.php/core/preview.png?file="+URLEncoder.encode(file.getRemotePath(), "UTF-8")+"&x=36&y=36&forceIcon=1");\r
-                        HttpGet httpget = new HttpGet(mClient.getBaseUri() + "/ocs/v1.php/thumbnail?x=50&y=50&path=" + URLEncoder.encode(file.getRemotePath(), "UTF-8"));\r
-                        HttpResponse response = httpclient.execute(httpget);\r
-                        HttpEntity entity = response.getEntity();\r
-                        \r
-                        if (entity != null) {\r
-                            byte[] bytes = EntityUtils.toByteArray(entity);\r
-                            Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);\r
-                            thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);\r
-                            \r
-                            // Add thumbnail to cache\r
-                            if (thumbnail != null){\r
-                                addBitmapToCache(imageKey, thumbnail);\r
-                            }\r
-                        }\r
-                    } catch(Exception e){\r
-                        e.printStackTrace();\r
-                    }finally {\r
-                        httpclient.getConnectionManager().shutdown();\r
-                    }\r
+                    // Commented out as maybe changes to client library are needed\r
+//                    DefaultHttpClient httpclient = new DefaultHttpClient();\r
+//                    try {\r
+//                        httpclient.getCredentialsProvider().setCredentials(\r
+//                                new AuthScope(mClient.getBaseUri().toString().replace("https://", ""), 443), \r
+//                                new UsernamePasswordCredentials(mClient.getCredentials().getUsername(), mClient.getCredentials().getAuthToken()));\r
+//                        \r
+//\r
+//                        HttpGet httpget = new HttpGet(mClient.getBaseUri() + "/ocs/v1.php/thumbnail?x=50&y=50&path=" + URLEncoder.encode(file.getRemotePath(), "UTF-8"));\r
+//                        HttpResponse response = httpclient.execute(httpget);\r
+//                        HttpEntity entity = response.getEntity();\r
+//                        \r
+//                        if (entity != null) {\r
+//                            byte[] bytes = EntityUtils.toByteArray(entity);\r
+//                            Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);\r
+//                            thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);\r
+//                            \r
+//                            // Add thumbnail to cache\r
+//                            if (thumbnail != null){\r
+//                                addBitmapToCache(imageKey, thumbnail);\r
+//                            }\r
+//                        }\r
+//                    } catch(Exception e){\r
+//                        e.printStackTrace();\r
+//                    }finally {\r
+//                        httpclient.getConnectionManager().shutdown();\r
+//                    }\r
                 } \r
             }\r
             return thumbnail;\r
         }\r
         \r
         protected void onPostExecute(Bitmap bitmap){\r
-            if (bitmap != null){\r
-                fileIcon.setImageBitmap(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
+                    imageView.setImageBitmap(bitmap);\r
+                }\r
             }\r
         }\r
     }\r
   \r
     public void addBitmapToCache(String key, Bitmap bitmap) {\r
-        synchronized (mDiskCacheLock) {\r
-            if (mDiskLruCache != null && mDiskLruCache.getBitmap(key) == null) {\r
-                mDiskLruCache.put(key, bitmap);\r
+        synchronized (thumbnailDiskCacheLock) {\r
+            if (mThumbnailCache != null && mThumbnailCache.getBitmap(key) == null) {\r
+                mThumbnailCache.put(key, bitmap);\r
             }\r
         }\r
     }\r
 \r
     public Bitmap getBitmapFromDiskCache(String key) {\r
-        synchronized (mDiskCacheLock) {\r
+        synchronized (thumbnailDiskCacheLock) {\r
             // Wait while disk cache is started from background thread\r
-            while (mDiskCacheStarting) {\r
+            while (mThumbnailCacheStarting) {\r
                 try {\r
-                    mDiskCacheLock.wait();\r
+                    thumbnailDiskCacheLock.wait();\r
                 } catch (InterruptedException e) {}\r
             }\r
-            if (mDiskLruCache != null) {\r
-                return (Bitmap) mDiskLruCache.getBitmap(key);\r
+            if (mThumbnailCache != null) {\r
+                return (Bitmap) mThumbnailCache.getBitmap(key);\r
             }\r
         }\r
         return null;\r
@@ -321,20 +355,23 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                         checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);\r
                     }\r
                     checkBoxV.setVisibility(View.VISIBLE);\r
-                }\r
-                \r
-                // first set thumbnail according to Mimetype, prevents empty thumbnails\r
-                fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName()));\r
+                }               \r
                 \r
                 // get Thumbnail if file is image\r
                 if (file.isImage()){\r
-                    // Thumbnail in Cache?\r
+                     // Thumbnail in Cache?\r
                     Bitmap thumbnail = getBitmapFromDiskCache(String.valueOf(file.getRemoteId()));\r
                     if (thumbnail != null){\r
                         fileIcon.setImageBitmap(thumbnail);\r
                     } else {\r
                         // generate new Thumbnail\r
-                        new BitmapWorkerTask(fileIcon).execute(file);\r
+                        if (cancelPotentialWork(file, fileIcon)) {\r
+                            final ThumbnailGenerationTask task = new ThumbnailGenerationTask(fileIcon);\r
+                            final AsyncDrawable asyncDrawable =\r
+                                    new AsyncDrawable(mContext.getResources(), defaultImg, task);\r
+                            fileIcon.setImageDrawable(asyncDrawable);\r
+                            task.execute(file);\r
+                        }\r
                     }\r
                 }\r
 
@@ -373,6 +410,35 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
 \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
diff --git a/src/com/owncloud/android/ui/adapter/Utils.java b/src/com/owncloud/android/ui/adapter/Utils.java
deleted file mode 100644 (file)
index 181cc92..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.owncloud.android.ui.adapter;
-
-import java.io.File;
-
-import android.content.Context;
-import android.os.Build;
-import android.os.Environment;
-
-public class Utils {
-    public static final int IO_BUFFER_SIZE = 8 * 1024;
-
-    private Utils() {};
-
-    public static boolean isExternalStorageRemovable() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
-            return Environment.isExternalStorageRemovable();
-        }
-        return true;
-    }
-
-    public static File getExternalCacheDir(Context context) {
-        if (hasExternalCacheDir()) {
-            return context.getExternalCacheDir();
-        }
-
-        // Before Froyo we need to construct the external cache dir ourselves
-        final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/";
-        return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir);
-    }
-
-    public static boolean hasExternalCacheDir() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
-    }
-
-}
diff --git a/third_party/disklrucache-2.0.2.jar b/third_party/disklrucache-2.0.2.jar
deleted file mode 100644 (file)
index ca7907d..0000000
Binary files a/third_party/disklrucache-2.0.2.jar and /dev/null differ