From: tobiasKaminsky Date: Mon, 1 Sep 2014 19:12:51 +0000 (+0200) Subject: Added requested changes. X-Git-Tag: oc-android-1.7.0_signed~163^2~8^2~2 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/db4ccec8ee6668c37550be16a54e49aae830719b?hp=--cc Added requested changes. --- db4ccec8ee6668c37550be16a54e49aae830719b diff --git a/.classpath b/.classpath index fa15a286..51769745 100644 --- a/.classpath +++ b/.classpath @@ -5,6 +5,5 @@ - diff --git a/libs/disklrucache-2.0.2.jar b/libs/disklrucache-2.0.2.jar new file mode 100644 index 00000000..ca7907d0 Binary files /dev/null and b/libs/disklrucache-2.0.2.jar differ diff --git a/lint.xml b/lint.xml index ce54dadc..e69de29b 100644 --- a/lint.xml +++ b/lint.xml @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java b/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java index 5b401c28..d3479af0 100644 --- a/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java +++ b/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java @@ -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 ) { diff --git a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java index e2ad4fa3..5a069e72 100644 --- a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java @@ -19,6 +19,7 @@ package com.owncloud.android.ui.adapter; import java.io.File; import java.io.IOException; +import java.lang.ref.WeakReference; import java.net.URLEncoder; import java.util.Vector; @@ -30,6 +31,8 @@ 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; @@ -69,6 +72,7 @@ import org.apache.http.util.EntityUtils; * instance. * * @author Bartek Przybylski + * @Author Tobias Kaminsky * */ public class FileListListAdapter extends BaseAdapter implements ListAdapter { @@ -81,18 +85,21 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { private FileDataStorageManager mStorageManager; private Account mAccount; private ComponentsGetter mTransferServiceGetter; - private final Object mDiskCacheLock = new Object(); - private DiskLruImageCache mDiskLruCache; - private boolean mDiskCacheStarting = true; + 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 CompressFormat mCompressFormat = CompressFormat.JPEG; - private int mCompressQuality = 70; + private static final CompressFormat mCompressFormat = CompressFormat.JPEG; + private static final int mCompressQuality = 70; private OwnCloudClient mClient; + private Bitmap defaultImg; public FileListListAdapter(Context context, ComponentsGetter transferServiceGetter) { 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(); @@ -101,8 +108,9 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { class InitDiskCacheTask extends AsyncTask { @Override protected Void doInBackground(File... params) { - synchronized (mDiskCacheLock) { - mDiskLruCache = new DiskLruImageCache(mContext, "thumbnailCache", DISK_CACHE_SIZE, mCompressFormat,mCompressQuality); + synchronized (thumbnailDiskCacheLock) { + mThumbnailCache = new DiskLruImageCache(mContext, "thumbnailCache", + DISK_CACHE_SIZE, mCompressFormat, mCompressQuality); try { OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); @@ -122,24 +130,42 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { e.printStackTrace(); } - mDiskCacheStarting = false; // Finished initialization - mDiskCacheLock.notifyAll(); // Wake any waiting threads + mThumbnailCacheStarting = false; // Finished initialization + thumbnailDiskCacheLock.notifyAll(); // Wake any waiting threads } return null; } } + + static class AsyncDrawable extends BitmapDrawable { + private final WeakReference bitmapWorkerTaskReference; + + public AsyncDrawable(Resources res, Bitmap bitmap, + ThumbnailGenerationTask bitmapWorkerTask) { + super(res, bitmap); + bitmapWorkerTaskReference = + new WeakReference(bitmapWorkerTask); + } + + public ThumbnailGenerationTask getBitmapWorkerTask() { + return bitmapWorkerTaskReference.get(); + } + } + + class ThumbnailGenerationTask extends AsyncTask { + private final WeakReference imageViewReference; + private OCFile file; - class BitmapWorkerTask extends AsyncTask { - private final ImageView fileIcon; - public BitmapWorkerTask(ImageView fileIcon) { - this.fileIcon = fileIcon; + public ThumbnailGenerationTask(ImageView imageView) { + // Use a WeakReference to ensure the ImageView can be garbage collected + imageViewReference = new WeakReference(imageView); } // Decode image in background. @Override protected Bitmap doInBackground(OCFile... params) { - OCFile file = params[0]; + file = params[0]; final String imageKey = String.valueOf(file.getRemoteId()); // Check disk cache in background thread @@ -160,64 +186,72 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { } else { // Download thumbnail from server - DefaultHttpClient httpclient = new DefaultHttpClient(); - try { - httpclient.getCredentialsProvider().setCredentials( - new AuthScope(mClient.getBaseUri().toString().replace("https://", ""), 443), - new UsernamePasswordCredentials(mClient.getCredentials().getUsername(), mClient.getCredentials().getAuthToken())); - - - // TODO change to user preview.png - //HttpGet httpget = new HttpGet(mClient.getBaseUri() + "/index.php/core/preview.png?file="+URLEncoder.encode(file.getRemotePath(), "UTF-8")+"&x=36&y=36&forceIcon=1"); - HttpGet httpget = new HttpGet(mClient.getBaseUri() + "/ocs/v1.php/thumbnail?x=50&y=50&path=" + URLEncoder.encode(file.getRemotePath(), "UTF-8")); - HttpResponse response = httpclient.execute(httpget); - HttpEntity entity = response.getEntity(); - - if (entity != null) { - byte[] bytes = EntityUtils.toByteArray(entity); - Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); - thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px); - - // Add thumbnail to cache - if (thumbnail != null){ - addBitmapToCache(imageKey, thumbnail); - } - } - } catch(Exception e){ - e.printStackTrace(); - }finally { - httpclient.getConnectionManager().shutdown(); - } + // Commented out as maybe changes to client library are needed +// DefaultHttpClient httpclient = new DefaultHttpClient(); +// try { +// httpclient.getCredentialsProvider().setCredentials( +// new AuthScope(mClient.getBaseUri().toString().replace("https://", ""), 443), +// new UsernamePasswordCredentials(mClient.getCredentials().getUsername(), mClient.getCredentials().getAuthToken())); +// +// +// HttpGet httpget = new HttpGet(mClient.getBaseUri() + "/ocs/v1.php/thumbnail?x=50&y=50&path=" + URLEncoder.encode(file.getRemotePath(), "UTF-8")); +// HttpResponse response = httpclient.execute(httpget); +// HttpEntity entity = response.getEntity(); +// +// if (entity != null) { +// byte[] bytes = EntityUtils.toByteArray(entity); +// Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); +// thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px); +// +// // Add thumbnail to cache +// if (thumbnail != null){ +// addBitmapToCache(imageKey, thumbnail); +// } +// } +// } catch(Exception e){ +// e.printStackTrace(); +// }finally { +// httpclient.getConnectionManager().shutdown(); +// } } } return thumbnail; } protected void onPostExecute(Bitmap bitmap){ - if (bitmap != null){ - fileIcon.setImageBitmap(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) { + imageView.setImageBitmap(bitmap); + } } } } public void addBitmapToCache(String key, Bitmap bitmap) { - synchronized (mDiskCacheLock) { - if (mDiskLruCache != null && mDiskLruCache.getBitmap(key) == null) { - mDiskLruCache.put(key, bitmap); + synchronized (thumbnailDiskCacheLock) { + if (mThumbnailCache != null && mThumbnailCache.getBitmap(key) == null) { + mThumbnailCache.put(key, bitmap); } } } public Bitmap getBitmapFromDiskCache(String key) { - synchronized (mDiskCacheLock) { + synchronized (thumbnailDiskCacheLock) { // Wait while disk cache is started from background thread - while (mDiskCacheStarting) { + while (mThumbnailCacheStarting) { try { - mDiskCacheLock.wait(); + thumbnailDiskCacheLock.wait(); } catch (InterruptedException e) {} } - if (mDiskLruCache != null) { - return (Bitmap) mDiskLruCache.getBitmap(key); + if (mThumbnailCache != null) { + return (Bitmap) mThumbnailCache.getBitmap(key); } } return null; @@ -321,20 +355,23 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { checkBoxV.setImageResource(android.R.drawable.checkbox_off_background); } checkBoxV.setVisibility(View.VISIBLE); - } - - // first set thumbnail according to Mimetype, prevents empty thumbnails - fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())); + } // get Thumbnail if file is image if (file.isImage()){ - // Thumbnail in Cache? + // Thumbnail in Cache? Bitmap thumbnail = getBitmapFromDiskCache(String.valueOf(file.getRemoteId())); if (thumbnail != null){ fileIcon.setImageBitmap(thumbnail); } else { // generate new Thumbnail - new BitmapWorkerTask(fileIcon).execute(file); + if (cancelPotentialWork(file, fileIcon)) { + final ThumbnailGenerationTask task = new ThumbnailGenerationTask(fileIcon); + final AsyncDrawable asyncDrawable = + new AsyncDrawable(mContext.getResources(), defaultImg, task); + fileIcon.setImageDrawable(asyncDrawable); + task.execute(file); + } } } @@ -373,6 +410,35 @@ 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() { diff --git a/src/com/owncloud/android/ui/adapter/Utils.java b/src/com/owncloud/android/ui/adapter/Utils.java deleted file mode 100644 index 181cc925..00000000 --- a/src/com/owncloud/android/ui/adapter/Utils.java +++ /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 index ca7907d0..00000000 Binary files a/third_party/disklrucache-2.0.2.jar and /dev/null differ