public static final boolean HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER =
Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN;
+ public static final boolean HAS_REUSING_BITMAP_IN_BITMAP_FACTORY =
+ Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB;
+
private static boolean hasField(Class<?> klass, String fieldName) {
try {
klass.getDeclaredField(fieldName);
import android.view.WindowManager;
import com.android.gallery3d.R;
+import com.android.gallery3d.data.BitmapPool;
import com.android.gallery3d.data.DataManager;
import com.android.gallery3d.data.MediaItem;
import com.android.gallery3d.ui.GLRoot;
} finally {
mGLRootView.unlockRenderThread();
}
- MediaItem.getMicroThumbPool().clear();
- MediaItem.getThumbPool().clear();
+ clearBitmapPool(MediaItem.getMicroThumbPool());
+ clearBitmapPool(MediaItem.getThumbPool());
+
MediaItem.getBytesBufferPool().clear();
}
+ private static void clearBitmapPool(BitmapPool pool) {
+ if (pool != null) pool.clear();
+ }
+
@Override
protected void onDestroy() {
super.onDestroy();
import android.graphics.RectF;
import android.media.ExifInterface;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
}
}
- @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static void setImageSize(ContentValues values, int width, int height) {
// The two fields are available since ICS but got published in JB
if (ApiHelper.HAS_MEDIA_COLUMNS_WIDTH_AND_HEIGHT) {
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
}
}
- @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void setOnSystemUiVisibilityChangeListener() {
if (!ApiHelper.HAS_VIEW_SYSTEM_UI_FLAG_HIDE_NAVIGATION) return;
});
}
- @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void showSystemUi(boolean visible) {
if (!ApiHelper.HAS_VIEW_SYSTEM_UI_FLAG_LAYOUT_STABLE) return;
}
@SuppressWarnings("deprecation")
- @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB_MR2)
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
private Point getDefaultDisplaySize(Point size) {
Display d = getWindowManager().getDefaultDisplay();
if (Build.VERSION.SDK_INT >= ApiHelper.VERSION_CODES.HONEYCOMB_MR2) {
package com.android.gallery3d.data;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapFactory.Options;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.ui.Log;
-import com.android.gallery3d.util.ThreadPool.JobContext;
-import java.io.FileDescriptor;
import java.util.ArrayList;
public class BitmapPool {
mPool.clear();
}
- private Bitmap findCachedBitmap(JobContext jc,
- byte[] data, int offset, int length, Options options) {
- if (mOneSize) return getBitmap();
- DecodeUtils.decodeBounds(jc, data, offset, length, options);
- return getBitmap(options.outWidth, options.outHeight);
- }
-
- private Bitmap findCachedBitmap(JobContext jc,
- FileDescriptor fileDescriptor, Options options) {
- if (mOneSize) return getBitmap();
- DecodeUtils.decodeBounds(jc, fileDescriptor, options);
- return getBitmap(options.outWidth, options.outHeight);
- }
-
- public Bitmap decode(JobContext jc,
- byte[] data, int offset, int length, BitmapFactory.Options options) {
- if (options == null) options = new BitmapFactory.Options();
- if (options.inSampleSize < 1) options.inSampleSize = 1;
- options.inPreferredConfig = Bitmap.Config.ARGB_8888;
- options.inBitmap = (options.inSampleSize == 1)
- ? findCachedBitmap(jc, data, offset, length, options) : null;
- try {
- Bitmap bitmap = DecodeUtils.decode(jc, data, offset, length, options);
- if (options.inBitmap != null && options.inBitmap != bitmap) {
- recycle(options.inBitmap);
- options.inBitmap = null;
- }
- return bitmap;
- } catch (IllegalArgumentException e) {
- if (options.inBitmap == null) throw e;
-
- Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
- recycle(options.inBitmap);
- options.inBitmap = null;
- return DecodeUtils.decode(jc, data, offset, length, options);
- }
- }
-
- // This is the same as the method above except the source data comes
- // from a file descriptor instead of a byte array.
- public Bitmap decode(JobContext jc,
- FileDescriptor fileDescriptor, Options options) {
- if (options == null) options = new BitmapFactory.Options();
- if (options.inSampleSize < 1) options.inSampleSize = 1;
- options.inPreferredConfig = Bitmap.Config.ARGB_8888;
- options.inBitmap = (options.inSampleSize == 1)
- ? findCachedBitmap(jc, fileDescriptor, options) : null;
- try {
- Bitmap bitmap = DecodeUtils.decode(jc, fileDescriptor, options);
- if (options.inBitmap != null&& options.inBitmap != bitmap) {
- recycle(options.inBitmap);
- options.inBitmap = null;
- }
- return bitmap;
- } catch (IllegalArgumentException e) {
- if (options.inBitmap == null) throw e;
-
- Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
- recycle(options.inBitmap);
- options.inBitmap = null;
- return DecodeUtils.decode(jc, fileDescriptor, options);
- }
+ public boolean isOneSize() {
+ return mOneSize;
}
}
package com.android.gallery3d.data;
+import android.annotation.TargetApi;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.BitmapRegionDecoder;
+import android.os.Build;
import android.util.FloatMath;
import com.android.gallery3d.common.BitmapUtils;
import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.ui.Log;
import com.android.gallery3d.util.ThreadPool.CancelListener;
import com.android.gallery3d.util.ThreadPool.JobContext;
import java.io.InputStream;
public class DecodeUtils {
- private static final String TAG = "DecodeService";
+ private static final String TAG = "DecodeUtils";
private static class DecodeCanceller implements CancelListener {
Options mOptions;
return null;
}
}
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public static Bitmap decode(JobContext jc, byte[] data, int offset,
+ int length, BitmapFactory.Options options, BitmapPool pool) {
+ if (pool == null) {
+ return decode(jc, data, offset, length, options);
+ }
+
+ if (options == null) options = new BitmapFactory.Options();
+ if (options.inSampleSize < 1) options.inSampleSize = 1;
+ options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ options.inBitmap = (options.inSampleSize == 1)
+ ? findCachedBitmap(pool, jc, data, offset, length, options) : null;
+ try {
+ Bitmap bitmap = decode(jc, data, offset, length, options);
+ if (options.inBitmap != null && options.inBitmap != bitmap) {
+ pool.recycle(options.inBitmap);
+ options.inBitmap = null;
+ }
+ return bitmap;
+ } catch (IllegalArgumentException e) {
+ if (options.inBitmap == null) throw e;
+
+ Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
+ pool.recycle(options.inBitmap);
+ options.inBitmap = null;
+ return decode(jc, data, offset, length, options);
+ }
+ }
+
+ // This is the same as the method above except the source data comes
+ // from a file descriptor instead of a byte array.
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public static Bitmap decode(JobContext jc,
+ FileDescriptor fileDescriptor, Options options, BitmapPool pool) {
+ if (pool == null) {
+ return decode(jc, fileDescriptor, options);
+ }
+
+ if (options == null) options = new BitmapFactory.Options();
+ if (options.inSampleSize < 1) options.inSampleSize = 1;
+ options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ options.inBitmap = (options.inSampleSize == 1)
+ ? findCachedBitmap(pool, jc, fileDescriptor, options) : null;
+ try {
+ Bitmap bitmap = DecodeUtils.decode(jc, fileDescriptor, options);
+ if (options.inBitmap != null && options.inBitmap != bitmap) {
+ pool.recycle(options.inBitmap);
+ options.inBitmap = null;
+ }
+ return bitmap;
+ } catch (IllegalArgumentException e) {
+ if (options.inBitmap == null) throw e;
+
+ Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
+ pool.recycle(options.inBitmap);
+ options.inBitmap = null;
+ return decode(jc, fileDescriptor, options);
+ }
+ }
+
+ private static Bitmap findCachedBitmap(BitmapPool pool, JobContext jc,
+ byte[] data, int offset, int length, Options options) {
+ if (pool.isOneSize()) return pool.getBitmap();
+ decodeBounds(jc, data, offset, length, options);
+ return pool.getBitmap(options.outWidth, options.outHeight);
+ }
+
+ private static Bitmap findCachedBitmap(BitmapPool pool, JobContext jc,
+ FileDescriptor fileDescriptor, Options options) {
+ if (pool.isOneSize()) return pool.getBitmap();
+ decodeBounds(jc, fileDescriptor, options);
+ return pool.getBitmap(options.outWidth, options.outHeight);
+ }
}
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap;
if (mType == MediaItem.TYPE_MICROTHUMBNAIL) {
- bitmap = MediaItem.getMicroThumbPool().decode(jc,
- buffer.data, buffer.offset, buffer.length, options);
+ bitmap = DecodeUtils.decode(jc,
+ buffer.data, buffer.offset, buffer.length, options,
+ MediaItem.getMicroThumbPool());
} else {
- bitmap = MediaItem.getThumbPool().decode(jc,
- buffer.data, buffer.offset, buffer.length, options);
+ bitmap = DecodeUtils.decode(jc,
+ buffer.data, buffer.offset, buffer.length, options,
+ MediaItem.getThumbPool());
}
if (bitmap == null && !jc.isCancelled()) {
Log.w(TAG, "decode cached failed " + debugTag);
import android.graphics.BitmapRegionDecoder;
import android.media.ExifInterface;
import android.net.Uri;
+import android.os.Build;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Images.ImageColumns;
import android.provider.MediaStore.MediaColumns;
updateWidthAndHeightProjection();
}
- @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static void updateWidthAndHeightProjection() {
if (ApiHelper.HAS_MEDIA_COLUMNS_WIDTH_AND_HEIGHT) {
PROJECTION[INDEX_WIDTH] = MediaColumns.WIDTH;
import android.graphics.Bitmap;
import android.graphics.BitmapRegionDecoder;
+import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.ui.ScreenNail;
import com.android.gallery3d.util.ThreadPool.Job;
private static final int BYTESBUFFE_POOL_SIZE = 4;
private static final int BYTESBUFFER_SIZE = 200 * 1024;
- private static final BitmapPool sMicroThumbPool = new BitmapPool(
- MICROTHUMBNAIL_TARGET_SIZE, MICROTHUMBNAIL_TARGET_SIZE, 16);
- private static final BitmapPool sThumbPool = new BitmapPool(4);
+ private static final BitmapPool sMicroThumbPool =
+ ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_FACTORY
+ ? new BitmapPool(MICROTHUMBNAIL_TARGET_SIZE, MICROTHUMBNAIL_TARGET_SIZE, 16)
+ : null;
+
+ private static final BitmapPool sThumbPool =
+ ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_FACTORY
+ ? new BitmapPool(4)
+ : null;
+
private static final BytesBufferPool sMicroThumbBufferPool =
new BytesBufferPool(BYTESBUFFE_POOL_SIZE, BYTESBUFFER_SIZE);
import com.android.gallery3d.app.AlbumSetDataLoader;
import com.android.gallery3d.app.GalleryActivity;
import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.data.BitmapPool;
import com.android.gallery3d.data.DataSourceType;
import com.android.gallery3d.data.MediaItem;
import com.android.gallery3d.data.MediaObject;
@Override
protected void recycleBitmap(Bitmap bitmap) {
- MediaItem.getMicroThumbPool().recycle(bitmap);
+ BitmapPool pool = MediaItem.getMicroThumbPool();
+ if (pool != null) pool.recycle(bitmap);
}
@Override
import com.android.gallery3d.app.AlbumDataLoader;
import com.android.gallery3d.app.GalleryActivity;
import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.data.BitmapPool;
import com.android.gallery3d.data.MediaItem;
import com.android.gallery3d.data.Path;
import com.android.gallery3d.util.Future;
@Override
protected void recycleBitmap(Bitmap bitmap) {
- MediaItem.getMicroThumbPool().recycle(bitmap);
+ BitmapPool pool = MediaItem.getMicroThumbPool();
+ if (pool != null) pool.recycle(bitmap);
}
@Override
import android.graphics.RectF;
import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.data.BitmapPool;
import com.android.gallery3d.data.MediaItem;
// This is a ScreenNail wraps a Bitmap. There are some extra functions:
mHeight = Math.round(scale * height);
}
+ private static void recycleBitmap(BitmapPool pool, Bitmap bitmap) {
+ if (pool == null || bitmap == null) return;
+ pool.recycle(bitmap);
+ }
+
// Combines the two ScreenNails.
// Returns the used one and recycle the unused one.
public ScreenNail combine(ScreenNail other) {
mWidth = newer.mWidth;
mHeight = newer.mHeight;
if (newer.mBitmap != null) {
- if (mBitmap != null) {
- MediaItem.getThumbPool().recycle(mBitmap);
- }
+ recycleBitmap(MediaItem.getThumbPool(), mBitmap);
mBitmap = newer.mBitmap;
newer.mBitmap = null;
mTexture.recycle();
mTexture = null;
}
- if (mBitmap != null) {
- MediaItem.getThumbPool().recycle(mBitmap);
- mBitmap = null;
- }
+ recycleBitmap(MediaItem.getThumbPool(), mBitmap);
+ mBitmap = null;
}
@Override
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.opengl.GLSurfaceView;
+import android.os.Build;
import android.os.Process;
import android.os.SystemClock;
import android.util.AttributeSet;
}
@Override
- @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public void setLightsOutMode(boolean enabled) {
int flags = 0;
if (enabled) {