From: David A. Velasco Date: Mon, 15 Sep 2014 07:41:25 +0000 (+0200) Subject: Merge branch 'develop' of https://github.com/tobiasKaminsky/android into thumbnails_f... X-Git-Tag: oc-android-1.7.0_signed~163^2~8 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/aae90eb1aa42a11449e30330e3e23e1e9e5eebb6?ds=sidebyside;hp=--cc Merge branch 'develop' of https://github.com/tobiasKaminsky/android into thumbnails_for_downloaded_images --- aae90eb1aa42a11449e30330e3e23e1e9e5eebb6 diff --cc lint.xml index ee0eead5,e69de29b..00000000 deleted file mode 100644,100644 --- a/lint.xml +++ /dev/null diff --cc src/com/owncloud/android/ui/adapter/DiskLruImageCache.java index 00000000,d3479af0..7d122491 mode 000000,100644..100644 --- a/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java +++ b/src/com/owncloud/android/ui/adapter/DiskLruImageCache.java @@@ -1,0 -1,169 +1,170 @@@ + package com.owncloud.android.ui.adapter; + + import java.io.BufferedInputStream; + import java.io.BufferedOutputStream; + import java.io.File; + import java.io.FileNotFoundException; + 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; -import android.os.Environment; + import android.util.Log; + + import com.jakewharton.disklrucache.DiskLruCache; + import com.owncloud.android.BuildConfig; + import com.owncloud.android.utils.Log_OC; + + public class DiskLruImageCache { + + private DiskLruCache mDiskCache; + 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"; ++ //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, CACHE_VERSION, VALUE_COUNT, diskCacheSize ); ++ mDiskCache = DiskLruCache.open( ++ diskCacheDir, CACHE_VERSION, VALUE_COUNT, diskCacheSize ++ ); + mCompressFormat = compressFormat; + mCompressQuality = quality; + } catch (IOException e) { + e.printStackTrace(); + } + } + + private boolean writeBitmapToFile( Bitmap bitmap, DiskLruCache.Editor editor ) + throws IOException, FileNotFoundException { + OutputStream out = null; + try { + out = new BufferedOutputStream( editor.newOutputStream( 0 ), IO_BUFFER_SIZE ); + return bitmap.compress( mCompressFormat, mCompressQuality, out ); + } finally { + if ( out != null ) { + out.close(); + } + } + } + + 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("DiskCache", "create dir: " + cachePath + File.separator + uniqueName); + + return new File(cachePath + File.separator + uniqueName); + } + + public void put( String key, Bitmap data ) { + + DiskLruCache.Editor editor = null; + try { + editor = mDiskCache.edit( key ); + if ( editor == null ) { + return; + } + + if( writeBitmapToFile( data, editor ) ) { + mDiskCache.flush(); + editor.commit(); + if ( BuildConfig.DEBUG ) { + Log.d( "cache_test_DISK_", "image put on disk cache " + key ); + } + } else { + editor.abort(); + if ( BuildConfig.DEBUG ) { + Log.d( "cache_test_DISK_", "ERROR on: image put on disk cache " + key ); + } + } + } catch (IOException e) { + if ( BuildConfig.DEBUG ) { + Log.d( "cache_test_DISK_", "ERROR on: image put on disk cache " + key ); + } + try { + if ( editor != null ) { + editor.abort(); + } + } catch (IOException ignored) { + } + } + + } + + public Bitmap getBitmap( String key ) { + + Bitmap bitmap = null; + DiskLruCache.Snapshot snapshot = null; + try { + + snapshot = mDiskCache.get( key ); + if ( snapshot == null ) { + return null; + } + final InputStream in = snapshot.getInputStream( 0 ); + if ( in != null ) { + final BufferedInputStream buffIn = + new BufferedInputStream( in, IO_BUFFER_SIZE ); + bitmap = BitmapFactory.decodeStream( buffIn ); + } + } catch ( IOException e ) { + e.printStackTrace(); + } finally { + if ( snapshot != null ) { + snapshot.close(); + } + } + + if ( BuildConfig.DEBUG ) { - Log.d( "cache_test_DISK_", bitmap == null ? "not found" : "image read from disk " + key); ++ Log.d("cache_test_DISK_", bitmap == null ? "not found" : "image read from disk " + key); + } + + return bitmap; + + } + + public boolean containsKey( String key ) { + + boolean contained = false; + DiskLruCache.Snapshot snapshot = null; + try { + snapshot = mDiskCache.get( key ); + contained = snapshot != null; + } catch (IOException e) { + e.printStackTrace(); + } finally { + if ( snapshot != null ) { + snapshot.close(); + } + } + + return contained; + + } + + public void clearCache() { + if ( BuildConfig.DEBUG ) { + Log.d( "cache_test_DISK_", "disk cache CLEARED"); + } + try { + mDiskCache.delete(); + } catch ( IOException e ) { + e.printStackTrace(); + } + } + + public File getCacheFolder() { + return mDiskCache.getDirectory(); + } + + } diff --cc src/com/owncloud/android/ui/adapter/FileListListAdapter.java index 65a9c83c,c1ab8aa4..172341c4 --- a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java @@@ -17,6 -17,10 +17,10 @@@ */ 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.net.URLEncoder; import java.util.Vector; import android.accounts.Account; @@@ -39,6 -58,14 +58,16 @@@ import com.owncloud.android.lib.common. import com.owncloud.android.ui.activity.ComponentsGetter; import com.owncloud.android.utils.DisplayUtils; ++/* + import org.apache.http.HttpEntity; + import org.apache.http.HttpResponse; + import org.apache.http.auth.AuthScope; + import org.apache.http.auth.UsernamePasswordCredentials; + import org.apache.http.client.methods.HttpGet; + import org.apache.http.impl.client.DefaultHttpClient; + import org.apache.http.util.EntityUtils; ++*/ + /** * This Adapter populates a ListView with all files and folders in an ownCloud @@@ -58,16 -85,176 +88,185 @@@ public class FileListListAdapter extend private FileDataStorageManager mStorageManager; 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 OwnCloudClient mClient; + private Bitmap defaultImg; + - public FileListListAdapter(Context context, ComponentsGetter transferServiceGetter) { + public FileListListAdapter( + boolean justFolders, + Context context, + ComponentsGetter transferServiceGetter + ) { ++ + mJustFolders = justFolders; 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(); + } + + class InitDiskCacheTask extends AsyncTask { + @Override + protected Void doInBackground(File... params) { + synchronized (thumbnailDiskCacheLock) { + mThumbnailCache = new DiskLruImageCache(mContext, "thumbnailCache", + DISK_CACHE_SIZE, mCompressFormat, mCompressQuality); + + try { + OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); + mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). + getClientFor(ocAccount, mContext); + } catch (AccountNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (AuthenticatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (OperationCanceledException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + 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; + + + 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) { + file = params[0]; + final String imageKey = String.valueOf(file.getRemoteId()); + + // Check disk cache in background thread + Bitmap thumbnail = getBitmapFromDiskCache(imageKey); + + // Not found in disk cache + if (thumbnail == null) { + // Converts dp to pixel + Resources r = mContext.getResources(); - int px = (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, r.getDisplayMetrics())); ++ int px = (int) Math.round(TypedValue.applyDimension( ++ TypedValue.COMPLEX_UNIT_DIP, 150, r.getDisplayMetrics() ++ )); + + if (file.isDown()){ + Bitmap bitmap = BitmapFactory.decodeFile(file.getStoragePath()); + thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px); + + // Add thumbnail to cache + addBitmapToCache(imageKey, thumbnail); + + } else { + // Download thumbnail from server + // 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 (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 (thumbnailDiskCacheLock) { + if (mThumbnailCache != null && mThumbnailCache.getBitmap(key) == 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 @@@ -126,7 -313,7 +325,8 @@@ ImageView localStateView = (ImageView) view.findViewById(R.id.imageView2); localStateView.bringToFront(); -- FileDownloaderBinder downloaderBinder = mTransferServiceGetter.getFileDownloaderBinder(); ++ FileDownloaderBinder downloaderBinder = ++ mTransferServiceGetter.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = mTransferServiceGetter.getFileUploaderBinder(); if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) { localStateView.setImageResource(R.drawable.downloading_file_indicator); @@@ -149,7 -336,7 +349,9 @@@ fileSizeV.setVisibility(View.VISIBLE); fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength())); lastModV.setVisibility(View.VISIBLE); -- lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())); ++ lastModV.setText( ++ DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()) ++ ); // this if-else is needed even thoe fav icon is visible by default // because android reuses views in listview if (!file.keepInSync()) { @@@ -168,10 -355,28 +370,31 @@@ checkBoxV.setImageResource(android.R.drawable.checkbox_off_background); } checkBoxV.setVisibility(View.VISIBLE); + } + + // get Thumbnail if file is image + if (file.isImage()){ + // Thumbnail in Cache? + Bitmap thumbnail = getBitmapFromDiskCache(String.valueOf(file.getRemoteId())); + if (thumbnail != null){ + fileIcon.setImageBitmap(thumbnail); + } else { + // generate new Thumbnail + if (cancelPotentialWork(file, fileIcon)) { - final ThumbnailGenerationTask task = new ThumbnailGenerationTask(fileIcon); ++ final ThumbnailGenerationTask task = ++ new ThumbnailGenerationTask(fileIcon); + final AsyncDrawable asyncDrawable = + new AsyncDrawable(mContext.getResources(), defaultImg, task); + fileIcon.setImageDrawable(asyncDrawable); + task.execute(file); + } + } + } else { - fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())); ++ fileIcon.setImageResource( ++ DisplayUtils.getResourceId(file.getMimetype(), file.getFileName()) ++ ); } - - fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())); - + if (checkIfFileIsSharedWithMe(file)) { sharedWithMeIconV.setVisibility(View.VISIBLE); } @@@ -180,8 -385,7 +403,9 @@@ fileSizeV.setVisibility(View.INVISIBLE); //fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength())); lastModV.setVisibility(View.VISIBLE); -- lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())); ++ lastModV.setText( ++ DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()) ++ ); checkBoxV.setVisibility(View.GONE); view.findViewById(R.id.imageView3).setVisibility(View.GONE); @@@ -189,7 -393,7 +413,9 @@@ fileIcon.setImageResource(R.drawable.shared_with_me_folder); sharedWithMeIconV.setVisibility(View.VISIBLE); } else { -- fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())); ++ fileIcon.setImageResource( ++ DisplayUtils.getResourceId(file.getMimetype(), file.getFileName()) ++ ); } // If folder is sharedByLink, icon folder must be changed to @@@ -226,8 -459,8 +481,10 @@@ /** * Change the adapted directory for a new one -- * @param directory New file to adapt. Can be NULL, meaning "no content to adapt". -- * @param updatedStorageManager Optional updated storage manager; used to replace mStorageManager if is different (and not NULL) ++ * @param directory New file to adapt. Can be NULL, meaning ++ * "no content to adapt". ++ * @param updatedStorageManager Optional updated storage manager; used to replace ++ * mStorageManager if is different (and not NULL) */ public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager) { mFile = directory; @@@ -273,7 -484,7 +530,9 @@@ * @return boolean: True if it is shared with me and false if it is not */ private boolean checkIfFileIsSharedWithMe(OCFile file) { -- return (mFile.getPermissions() != null && !mFile.getPermissions().contains(PERMISSION_SHARED_WITH_ME) -- && file.getPermissions() != null && file.getPermissions().contains(PERMISSION_SHARED_WITH_ME)); ++ return (mFile.getPermissions() != null ++ && !mFile.getPermissions().contains(PERMISSION_SHARED_WITH_ME) ++ && file.getPermissions() != null ++ && file.getPermissions().contains(PERMISSION_SHARED_WITH_ME)); } }