--- /dev/null
-import android.os.Environment;
+ 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;
- private static final String TAG = "DiskLruImageCache";
+ 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;
- mDiskCache = DiskLruCache.open( diskCacheDir, CACHE_VERSION, VALUE_COUNT, diskCacheSize );
++ //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 );
- Log.d( "cache_test_DISK_", bitmap == null ? "not found" : "image read from disk " + key);
++ 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);
+ }
+
+ 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();
+ }
+
+ }
*/\r
package com.owncloud.android.ui.adapter;\r
\r
-import java.net.URLEncoder;\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
import android.accounts.Account;\r
+ import android.accounts.AuthenticatorException;\r
+ import android.accounts.OperationCanceledException;\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.datamodel.OCFile;\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.OwnCloudAccount;\r
+ import com.owncloud.android.lib.common.OwnCloudClient;\r
+ import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;\r
+ import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;\r
import com.owncloud.android.ui.activity.ComponentsGetter;\r
import com.owncloud.android.utils.DisplayUtils;\r
\r
++/*\r
+ import org.apache.http.HttpEntity;\r
+ import org.apache.http.HttpResponse;\r
+ import org.apache.http.auth.AuthScope;\r
+ import org.apache.http.auth.UsernamePasswordCredentials;\r
+ import org.apache.http.client.methods.HttpGet;\r
+ import org.apache.http.impl.client.DefaultHttpClient;\r
+ import org.apache.http.util.EntityUtils;\r
++*/\r
+ \r
\r
/**\r
* This Adapter populates a ListView with all files and folders in an ownCloud\r
* instance.\r
* \r
* @author Bartek Przybylski\r
+ * @Author Tobias Kaminsky\r
* \r
*/\r
public class FileListListAdapter extends BaseAdapter implements ListAdapter {\r
private Context mContext;\r
private OCFile mFile = null;\r
private Vector<OCFile> mFiles = null;\r
+ private boolean mJustFolders;\r
\r
private FileDataStorageManager mStorageManager;
private Account mAccount;
private ComponentsGetter mTransferServiceGetter;\r
- public FileListListAdapter(Context context, ComponentsGetter transferServiceGetter) {\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 OwnCloudClient mClient;\r
+ private Bitmap defaultImg;\r
+ \r
+ public FileListListAdapter(\r
+ boolean justFolders, \r
+ Context context, \r
+ ComponentsGetter transferServiceGetter\r
+ ) {\r
++ \r
+ mJustFolders = justFolders;\r
mContext = context;\r
mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);\r
mTransferServiceGetter = transferServiceGetter;\r
- int px = (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, r.getDisplayMetrics()));\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
+ mThumbnailCache = new DiskLruImageCache(mContext, "thumbnailCache", \r
+ DISK_CACHE_SIZE, mCompressFormat, mCompressQuality);\r
+ \r
+ try {\r
+ OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext);\r
+ mClient = OwnCloudClientManagerFactory.getDefaultSingleton().\r
+ getClientFor(ocAccount, mContext);\r
+ } catch (AccountNotFoundException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } catch (AuthenticatorException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } catch (OperationCanceledException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } catch (IOException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ }\r
+ \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
+ \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
+ file = params[0];\r
+ final String imageKey = String.valueOf(file.getRemoteId());\r
+ \r
+ // Check disk cache in background thread\r
+ Bitmap thumbnail = getBitmapFromDiskCache(imageKey);\r
+ \r
+ // Not found in disk cache\r
+ if (thumbnail == null) { \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 = BitmapFactory.decodeFile(file.getStoragePath());\r
+ thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);\r
+ \r
+ // Add thumbnail to cache\r
+ addBitmapToCache(imageKey, thumbnail);\r
+ \r
+ } else {\r
+ // Download thumbnail from server\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 (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 (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 (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
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
view = inflator.inflate(R.layout.list_item, null);\r
}\r
- \r
+ \r
if (mFiles != null && mFiles.size() > position) {\r
OCFile file = mFiles.get(position);\r
- TextView fileName = (TextView) view.findViewById(R.id.Filename);\r
+ TextView fileName = (TextView) view.findViewById(R.id.Filename); \r
String name = file.getFileName();\r
\r
fileName.setText(name);\r
\r
ImageView localStateView = (ImageView) view.findViewById(R.id.imageView2);\r
localStateView.bringToFront();\r
-- FileDownloaderBinder downloaderBinder = mTransferServiceGetter.getFileDownloaderBinder();\r
++ FileDownloaderBinder downloaderBinder = \r
++ mTransferServiceGetter.getFileDownloaderBinder();\r
FileUploaderBinder uploaderBinder = mTransferServiceGetter.getFileUploaderBinder();\r
if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) {\r
localStateView.setImageResource(R.drawable.downloading_file_indicator);\r
fileSizeV.setVisibility(View.VISIBLE);\r
fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\r
lastModV.setVisibility(View.VISIBLE);\r
-- lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()));\r
++ lastModV.setText(\r
++ DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())\r
++ );\r
// this if-else is needed even thoe fav icon is visible by default\r
// because android reuses views in listview\r
if (!file.keepInSync()) {\r
checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);\r
}\r
checkBoxV.setVisibility(View.VISIBLE);\r
- final ThumbnailGenerationTask task = new ThumbnailGenerationTask(fileIcon);\r
+ } \r
+ \r
+ // get Thumbnail if file is image\r
+ if (file.isImage()){\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
+ if (cancelPotentialWork(file, fileIcon)) {\r
- fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName()));\r
++ final ThumbnailGenerationTask task = \r
++ 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
+ } else {\r
++ fileIcon.setImageResource(\r
++ DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())\r
++ );\r
}\r
- \r
- fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName()));\r
- \r
+
if (checkIfFileIsSharedWithMe(file)) {\r
sharedWithMeIconV.setVisibility(View.VISIBLE);\r
}\r
} \r
else {\r
- \r
fileSizeV.setVisibility(View.INVISIBLE);\r
//fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\r
lastModV.setVisibility(View.VISIBLE);\r
-- lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()));\r
++ lastModV.setText(\r
++ DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())\r
++ );\r
checkBoxV.setVisibility(View.GONE);\r
view.findViewById(R.id.imageView3).setVisibility(View.GONE);\r
\r
fileIcon.setImageResource(R.drawable.shared_with_me_folder);\r
sharedWithMeIconV.setVisibility(View.VISIBLE);\r
} else {\r
-- fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName()));\r
++ fileIcon.setImageResource(\r
++ DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())\r
++ );\r
}\r
\r
// If folder is sharedByLink, icon folder must be changed to\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
\r
/**\r
* Change the adapted directory for a new one\r
-- * @param directory New file to adapt. Can be NULL, meaning "no content to adapt".\r
-- * @param updatedStorageManager Optional updated storage manager; used to replace mStorageManager if is different (and not NULL)\r
++ * @param directory New file to adapt. Can be NULL, meaning \r
++ * "no content to adapt".\r
++ * @param updatedStorageManager Optional updated storage manager; used to replace \r
++ * mStorageManager if is different (and not NULL)\r
*/\r
public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager) {\r
mFile = directory;\r
}\r
if (mStorageManager != null) {\r
mFiles = mStorageManager.getFolderContent(mFile);\r
+ if (mJustFolders) {\r
+ mFiles = getFolders(mFiles);\r
+ }\r
} else {\r
mFiles = null;\r
}\r
notifyDataSetChanged();\r
}\r
\r
+ \r
+ /**\r
+ * Filter for getting only the folders\r
+ * @param files\r
+ * @return Vector<OCFile>\r
+ */\r
+ public Vector<OCFile> getFolders(Vector<OCFile> files) {\r
+ Vector<OCFile> ret = new Vector<OCFile>(); \r
+ OCFile current = null; \r
+ for (int i=0; i<files.size(); i++) {\r
+ current = files.get(i);\r
+ if (current.isFolder()) {\r
+ ret.add(current);\r
+ }\r
+ }\r
+ return ret;\r
+ }\r
+ \r
+ \r
/**\r
* Check if parent folder does not include 'S' permission and if file/folder\r
* is shared with me\r
* @return boolean: True if it is shared with me and false if it is not\r
*/\r
private boolean checkIfFileIsSharedWithMe(OCFile file) {\r
-- return (mFile.getPermissions() != null && !mFile.getPermissions().contains(PERMISSION_SHARED_WITH_ME)\r
-- && file.getPermissions() != null && file.getPermissions().contains(PERMISSION_SHARED_WITH_ME));\r
++ return (mFile.getPermissions() != null \r
++ && !mFile.getPermissions().contains(PERMISSION_SHARED_WITH_ME)\r
++ && file.getPermissions() != null \r
++ && file.getPermissions().contains(PERMISSION_SHARED_WITH_ME));\r
}\r
}\r