From 63de8e9229feb7dd09aab988c2d7baae354ef3d6 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Tue, 23 Sep 2014 13:34:25 +0200 Subject: [PATCH] Minimized memory use in load of bitmaps for thumbnails generated from local files --- .../ui/adapter/FileListListAdapter.java | 22 +---- .../owncloud/android/utils/BitmapUtils.java | 99 +++++++++++++++++++ 2 files changed, 102 insertions(+), 19 deletions(-) create mode 100644 src/com/owncloud/android/utils/BitmapUtils.java diff --git a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java index e8615f08b8..11874f74c6 100644 --- a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java @@ -18,14 +18,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.util.Vector; import android.accounts.Account; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; @@ -51,23 +47,10 @@ import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; -import com.owncloud.android.lib.common.OwnCloudAccount; -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; -import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException; import com.owncloud.android.ui.activity.ComponentsGetter; +import com.owncloud.android.utils.BitmapUtils; 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 @@ -171,7 +154,8 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { )); if (file.isDown()){ - Bitmap bitmap = BitmapFactory.decodeFile(file.getStoragePath()); + Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile( + file.getStoragePath(), px, px); if (bitmap != null) { thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px); diff --git a/src/com/owncloud/android/utils/BitmapUtils.java b/src/com/owncloud/android/utils/BitmapUtils.java new file mode 100644 index 0000000000..687b5a4ffe --- /dev/null +++ b/src/com/owncloud/android/utils/BitmapUtils.java @@ -0,0 +1,99 @@ +/* ownCloud Android client application + * Copyright (C) 2012-2014 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.owncloud.android.utils; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapFactory.Options; + +/** + * Utility class with methods for decoding Bitmaps. + * + * @author David A. Velasco + */ +public class BitmapUtils { + + + /** + * Decodes a bitmap from a file containing it minimizing the memory use, known that the bitmap + * will be drawn in a surface of reqWidth x reqHeight + * + * @param srcPath Absolute path to the file containing the image. + * @param reqWidth Width of the surface where the Bitmap will be drawn on, in pixels. + * @param reqHeight Height of the surface where the Bitmap will be drawn on, in pixels. + * @return + */ + public static Bitmap decodeSampledBitmapFromFile(String srcPath, int reqWidth, int reqHeight) { + + // set desired options that will affect the size of the bitmap + final Options options = new Options(); + options.inScaled = true; + options.inPurgeable = true; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { + options.inPreferQualityOverSpeed = false; + } + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + options.inMutable = false; + } + + // make a false load of the bitmap to get its dimensions + options.inJustDecodeBounds = true; + + BitmapFactory.decodeFile(srcPath, options); + + // calculate factor to subsample the bitmap + options.inSampleSize = calculateSampleFactor(options, reqWidth, reqHeight); + + // decode bitmap with inSampleSize set + options.inJustDecodeBounds = false; + return BitmapFactory.decodeFile(srcPath, options); + + } + + + /** + * Calculates a proper value for options.inSampleSize in order to decode a Bitmap minimizing + * the memory overload and covering a target surface of reqWidth x reqHeight if the original + * image is big enough. + * + * @param options Bitmap decoding options; options.outHeight and options.inHeight should + * be set. + * @param reqWidth Width of the surface where the Bitmap will be drawn on, in pixels. + * @param reqHeight Height of the surface where the Bitmap will be drawn on, in pixels. + * @return The largest inSampleSize value that is a power of 2 and keeps both + * height and width larger than reqWidth and reqHeight. + */ + private static int calculateSampleFactor(Options options, int reqWidth, int reqHeight) { + + final int height = options.outHeight; + final int width = options.outWidth; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + while ((halfHeight / inSampleSize) > reqHeight + && (halfWidth / inSampleSize) > reqWidth) { + inSampleSize *= 2; + } + } + + return inSampleSize; + } + +}