summaryrefslogtreecommitdiffstats
path: root/media/java/android
diff options
context:
space:
mode:
authorRay Chen <raychen@google.com>2010-01-26 14:43:35 -0800
committerRay Chen <raychen@google.com>2010-01-29 14:30:05 -0800
commitbf124e7e41f7850ac1b7be808221a462db6f3447 (patch)
treee831e6443bc122c5c8f35c4560517cd09ec7852b /media/java/android
parentc88ed5dc5de7b2a7a02f975c83ee12e0fc1df27f (diff)
downloadframeworks_base-bf124e7e41f7850ac1b7be808221a462db6f3447.zip
frameworks_base-bf124e7e41f7850ac1b7be808221a462db6f3447.tar.gz
frameworks_base-bf124e7e41f7850ac1b7be808221a462db6f3447.tar.bz2
Unhide ThumbnailUtils to support Camera unbundling.
http://b/2375978
Diffstat (limited to 'media/java/android')
-rw-r--r--media/java/android/media/MiniThumbFile.java1
-rw-r--r--media/java/android/media/ThumbnailUtils.java (renamed from media/java/android/media/ThumbnailUtil.java)414
2 files changed, 230 insertions, 185 deletions
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index f6e6317..df141c1 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -17,7 +17,6 @@
package android.media;
import android.graphics.Bitmap;
-import android.media.ThumbnailUtil;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
diff --git a/media/java/android/media/ThumbnailUtil.java b/media/java/android/media/ThumbnailUtils.java
index 0cf4e76..225d4b6 100644
--- a/media/java/android/media/ThumbnailUtil.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -16,13 +16,6 @@
package android.media;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.provider.BaseColumns;
-import android.provider.MediaStore.Images;
-import android.provider.MediaStore.Images.Thumbnails;
-import android.util.Log;
-
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -34,47 +27,171 @@ import android.graphics.Matrix;
import android.graphics.Rect;
import android.media.MediaMetadataRetriever;
import android.media.MediaFile.MediaFileType;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.provider.BaseColumns;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.Images.Thumbnails;
+import android.util.Log;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.OutputStream;
/**
- * Thumbnail generation routines for media provider. This class should only be used internaly.
- * {@hide} THIS IS NOT FOR PUBLIC API.
+ * Thumbnail generation routines for media provider.
*/
-public class ThumbnailUtil {
- private static final String TAG = "ThumbnailUtil";
- //Whether we should recycle the input (unless the output is the input).
+public class ThumbnailUtils {
+ private static final String TAG = "ThumbnailUtils";
+
+ /* Maximum pixels size for created bitmap. */
+ private static final int THUMBNAIL_MAX_NUM_PIXELS = 512 * 384;
+ private static final int MINI_THUMB_MAX_NUM_PIXELS = 128 * 128;
+ private static final int UNCONSTRAINED = -1;
+
+ /* Whether we should rotate the resulting bitmap. */
+ private static final boolean ROTATE_AS_NEEDED = true;
+ private static final boolean NO_ROTATE = false;
+
+ /* Whether we should create bitmap in native memory. */
+ private static final boolean USE_NATIVE = true;
+ private static final boolean NO_NATIVE = false;
+
+ /**
+ * Constant used to indicate we should recycle the input in
+ * {@link #extractMiniThumb(Bitmap, int, int, boolean)} unless the output is the input.
+ */
public static final boolean RECYCLE_INPUT = true;
+
+ /**
+ * Constant used to indicate we should not recycle the input in
+ * {@link #extractMiniThumb(Bitmap, int, int, boolean)}.
+ */
public static final boolean NO_RECYCLE_INPUT = false;
- public static final boolean ROTATE_AS_NEEDED = true;
- public static final boolean NO_ROTATE = false;
- public static final boolean USE_NATIVE = true;
- public static final boolean NO_NATIVE = false;
+ /**
+ * Constant used to indicate the dimension of normal thumbnail in
+ * {@link #extractMiniThumb(Bitmap, int, int, boolean)}.
+ */
public static final int THUMBNAIL_TARGET_SIZE = 320;
+
+ /**
+ * Constant used to indicate the dimension of mini thumbnail in
+ * {@link #extractMiniThumb(Bitmap, int, int, boolean)}.
+ */
public static final int MINI_THUMB_TARGET_SIZE = 96;
- public static final int THUMBNAIL_MAX_NUM_PIXELS = 512 * 384;
- public static final int MINI_THUMB_MAX_NUM_PIXELS = 128 * 128;
- public static final int UNCONSTRAINED = -1;
- // Returns Options that set the native alloc flag for Bitmap decode.
- public static BitmapFactory.Options createNativeAllocOptions() {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inNativeAlloc = true;
- return options;
+ /**
+ * This method first examines if the thumbnail embedded in EXIF is bigger than our target
+ * size. If not, then it'll create a thumbnail from original image. Due to efficiency
+ * consideration, we want to let MediaThumbRequest avoid calling this method twice for
+ * both kinds, so it only requests for MICRO_KIND and set saveImage to true.
+ *
+ * This method always returns a "square thumbnail" for MICRO_KIND thumbnail.
+ *
+ * @param cr ContentResolver
+ * @param filePath file path needed by EXIF interface
+ * @param uri URI of original image
+ * @param origId image id
+ * @param kind either MINI_KIND or MICRO_KIND
+ * @param saveMini Whether to save MINI_KIND thumbnail obtained in this method.
+ * @return Bitmap
+ */
+ public static Bitmap createImageThumbnail(ContentResolver cr, String filePath, Uri uri,
+ long origId, int kind, boolean saveMini) {
+ boolean wantMini = (kind == Images.Thumbnails.MINI_KIND || saveMini);
+ int targetSize = wantMini ?
+ THUMBNAIL_TARGET_SIZE : MINI_THUMB_TARGET_SIZE;
+ int maxPixels = wantMini ?
+ THUMBNAIL_MAX_NUM_PIXELS : MINI_THUMB_MAX_NUM_PIXELS;
+ SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap();
+ Bitmap bitmap = null;
+ MediaFileType fileType = MediaFile.getFileType(filePath);
+ if (fileType != null && fileType.fileType == MediaFile.FILE_TYPE_JPEG) {
+ createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap);
+ bitmap = sizedThumbnailBitmap.mBitmap;
+ }
+
+ if (bitmap == null) {
+ bitmap = makeBitmap(targetSize, maxPixels, uri, cr);
+ }
+
+ if (bitmap == null) {
+ return null;
+ }
+
+ if (saveMini) {
+ if (sizedThumbnailBitmap.mThumbnailData != null) {
+ storeThumbnail(cr, origId,
+ sizedThumbnailBitmap.mThumbnailData,
+ sizedThumbnailBitmap.mThumbnailWidth,
+ sizedThumbnailBitmap.mThumbnailHeight);
+ } else {
+ storeThumbnail(cr, origId, bitmap);
+ }
+ }
+
+ if (kind == Images.Thumbnails.MICRO_KIND) {
+ // now we make it a "square thumbnail" for MICRO_KIND thumbnail
+ bitmap = extractMiniThumb(bitmap,
+ MINI_THUMB_TARGET_SIZE,
+ MINI_THUMB_TARGET_SIZE, RECYCLE_INPUT);
+ }
+ return bitmap;
}
+
/**
- * Make a bitmap from a given Uri.
+ * Create a video thumbnail for a video. May return null if the video is
+ * corrupt.
*
- * @param uri
+ * @param filePath
*/
- public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels,
- Uri uri, ContentResolver cr) {
- return makeBitmap(minSideLength, maxNumOfPixels, uri, cr,
- NO_NATIVE);
+ public static Bitmap createVideoThumbnail(String filePath) {
+ Bitmap bitmap = null;
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ try {
+ retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
+ retriever.setDataSource(filePath);
+ bitmap = retriever.captureFrame();
+ } catch (IllegalArgumentException ex) {
+ // Assume this is a corrupt video file
+ } catch (RuntimeException ex) {
+ // Assume this is a corrupt video file.
+ } finally {
+ try {
+ retriever.release();
+ } catch (RuntimeException ex) {
+ // Ignore failures while cleaning up.
+ }
+ }
+ return bitmap;
+ }
+
+ /**
+ * Creates a centered bitmap of the desired size.
+ *
+ * @param source original bitmap source
+ * @param width targeted width
+ * @param height targeted height
+ * @param recycle whether we want to recycle the input
+ */
+ public static Bitmap extractMiniThumb(
+ Bitmap source, int width, int height, boolean recycle) {
+ if (source == null) {
+ return null;
+ }
+
+ float scale;
+ if (source.getWidth() < source.getHeight()) {
+ scale = width / (float) source.getWidth();
+ } else {
+ scale = height / (float) source.getHeight();
+ }
+ Matrix matrix = new Matrix();
+ matrix.setScale(scale, scale);
+ Bitmap miniThumbnail = transform(matrix, source, width, height, true, recycle);
+ return miniThumbnail;
}
/*
@@ -96,7 +213,7 @@ public class ThumbnailUtil {
* For example, BitmapFactory downsamples an image by 2 even though the
* request is 3. So we round up the sample size to avoid OOM.
*/
- public static int computeSampleSize(BitmapFactory.Options options,
+ private static int computeSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
int initialSize = computeInitialSampleSize(options, minSideLength,
maxNumOfPixels);
@@ -140,7 +257,30 @@ public class ThumbnailUtil {
}
}
- public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels,
+ /**
+ * Returns Options that set the native alloc flag for Bitmap decode.
+ */
+ private static BitmapFactory.Options createNativeAllocOptions() {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inNativeAlloc = true;
+ return options;
+ }
+
+ /**
+ * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels.
+ */
+ private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels,
+ Uri uri, ContentResolver cr) {
+ return makeBitmap(minSideLength, maxNumOfPixels, uri, cr,
+ NO_NATIVE);
+ }
+
+ /**
+ * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels.
+ * The image data will be read from specified ContentResolver and clients are allowed to specify
+ * whether they want the Bitmap be created in native memory.
+ */
+ private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels,
Uri uri, ContentResolver cr, boolean useNative) {
ParcelFileDescriptor input = null;
try {
@@ -159,49 +299,18 @@ public class ThumbnailUtil {
}
}
- // Rotates the bitmap by the specified degree.
- // If a new bitmap is created, the original bitmap is recycled.
- public static Bitmap rotate(Bitmap b, int degrees) {
- if (degrees != 0 && b != null) {
- Matrix m = new Matrix();
- m.setRotate(degrees,
- (float) b.getWidth() / 2, (float) b.getHeight() / 2);
- try {
- Bitmap b2 = Bitmap.createBitmap(
- b, 0, 0, b.getWidth(), b.getHeight(), m, true);
- if (b != b2) {
- b.recycle();
- b = b2;
- }
- } catch (OutOfMemoryError ex) {
- // We have no memory to rotate. Return the original bitmap.
- }
- }
- return b;
- }
-
- private static void closeSilently(ParcelFileDescriptor c) {
- if (c == null) return;
- try {
- c.close();
- } catch (Throwable t) {
- // do nothing
- }
- }
-
- private static ParcelFileDescriptor makeInputStream(
- Uri uri, ContentResolver cr) {
- try {
- return cr.openFileDescriptor(uri, "r");
- } catch (IOException ex) {
- return null;
- }
- }
-
- public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels,
- Uri uri, ContentResolver cr, ParcelFileDescriptor pfd,
- BitmapFactory.Options options) {
- Bitmap b = null;
+ /**
+ * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels.
+ * The image data will be read from specified pfd if it's not null, otherwise
+ * a new input stream will be created using specified ContentResolver.
+ *
+ * Clients are allowed to pass their own BitmapFactory.Options used for bitmap decoding. A
+ * new BitmapFactory.Options will be created if options is null.
+ */
+ private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels,
+ Uri uri, ContentResolver cr, ParcelFileDescriptor pfd,
+ BitmapFactory.Options options) {
+ Bitmap b = null;
try {
if (pfd == null) pfd = makeInputStream(uri, cr);
if (pfd == null) return null;
@@ -232,115 +341,50 @@ public class ThumbnailUtil {
}
/**
- * Creates a centered bitmap of the desired size.
- * @param source
- * @param recycle whether we want to recycle the input
- */
- public static Bitmap extractMiniThumb(
- Bitmap source, int width, int height, boolean recycle) {
- if (source == null) {
- return null;
- }
-
- float scale;
- if (source.getWidth() < source.getHeight()) {
- scale = width / (float) source.getWidth();
- } else {
- scale = height / (float) source.getHeight();
- }
- Matrix matrix = new Matrix();
- matrix.setScale(scale, scale);
- Bitmap miniThumbnail = transform(matrix, source, width, height, true, recycle);
- return miniThumbnail;
- }
-
- /**
- * Create a video thumbnail for a video. May return null if the video is
- * corrupt.
- *
- * @param filePath
+ * Rotates the bitmap by the specified degree.
+ * If a new bitmap is created, the original bitmap is recycled.
*/
- public static Bitmap createVideoThumbnail(String filePath) {
- Bitmap bitmap = null;
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- try {
- retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
- retriever.setDataSource(filePath);
- bitmap = retriever.captureFrame();
- } catch (IllegalArgumentException ex) {
- // Assume this is a corrupt video file
- } catch (RuntimeException ex) {
- // Assume this is a corrupt video file.
- } finally {
+ private static Bitmap rotate(Bitmap b, int degrees) {
+ if (degrees != 0 && b != null) {
+ Matrix m = new Matrix();
+ m.setRotate(degrees,
+ (float) b.getWidth() / 2, (float) b.getHeight() / 2);
try {
- retriever.release();
- } catch (RuntimeException ex) {
- // Ignore failures while cleaning up.
+ Bitmap b2 = Bitmap.createBitmap(
+ b, 0, 0, b.getWidth(), b.getHeight(), m, true);
+ if (b != b2) {
+ b.recycle();
+ b = b2;
+ }
+ } catch (OutOfMemoryError ex) {
+ // We have no memory to rotate. Return the original bitmap.
}
}
- return bitmap;
+ return b;
}
- /**
- * This method first examines if the thumbnail embedded in EXIF is bigger than our target
- * size. If not, then it'll create a thumbnail from original image. Due to efficiency
- * consideration, we want to let MediaThumbRequest avoid calling this method twice for
- * both kinds, so it only requests for MICRO_KIND and set saveImage to true.
- *
- * This method always returns a "square thumbnail" for MICRO_KIND thumbnail.
- *
- * @param cr ContentResolver
- * @param filePath file path needed by EXIF interface
- * @param uri URI of original image
- * @param origId image id
- * @param kind either MINI_KIND or MICRO_KIND
- * @param saveMini Whether to save MINI_KIND thumbnail obtained in this method.
- * @return Bitmap
- */
- public static Bitmap createImageThumbnail(ContentResolver cr, String filePath, Uri uri,
- long origId, int kind, boolean saveMini) {
- boolean wantMini = (kind == Images.Thumbnails.MINI_KIND || saveMini);
- int targetSize = wantMini ?
- ThumbnailUtil.THUMBNAIL_TARGET_SIZE : ThumbnailUtil.MINI_THUMB_TARGET_SIZE;
- int maxPixels = wantMini ?
- ThumbnailUtil.THUMBNAIL_MAX_NUM_PIXELS : ThumbnailUtil.MINI_THUMB_MAX_NUM_PIXELS;
- SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap();
- Bitmap bitmap = null;
- MediaFileType fileType = MediaFile.getFileType(filePath);
- if (fileType != null && fileType.fileType == MediaFile.FILE_TYPE_JPEG) {
- createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap);
- bitmap = sizedThumbnailBitmap.mBitmap;
- }
-
- if (bitmap == null) {
- bitmap = ThumbnailUtil.makeBitmap(targetSize, maxPixels, uri, cr);
- }
+ private static void closeSilently(ParcelFileDescriptor c) {
+ if (c == null) return;
+ try {
+ c.close();
+ } catch (Throwable t) {
+ // do nothing
+ }
+ }
- if (bitmap == null) {
+ private static ParcelFileDescriptor makeInputStream(
+ Uri uri, ContentResolver cr) {
+ try {
+ return cr.openFileDescriptor(uri, "r");
+ } catch (IOException ex) {
return null;
}
-
- if (saveMini) {
- if (sizedThumbnailBitmap.mThumbnailData != null) {
- ThumbnailUtil.storeThumbnail(cr, origId,
- sizedThumbnailBitmap.mThumbnailData,
- sizedThumbnailBitmap.mThumbnailWidth,
- sizedThumbnailBitmap.mThumbnailHeight);
- } else {
- ThumbnailUtil.storeThumbnail(cr, origId, bitmap);
- }
- }
-
- if (kind == Images.Thumbnails.MICRO_KIND) {
- // now we make it a "square thumbnail" for MICRO_KIND thumbnail
- bitmap = ThumbnailUtil.extractMiniThumb(bitmap,
- ThumbnailUtil.MINI_THUMB_TARGET_SIZE,
- ThumbnailUtil.MINI_THUMB_TARGET_SIZE, ThumbnailUtil.RECYCLE_INPUT);
- }
- return bitmap;
}
- public static Bitmap transform(Matrix scaler,
+ /**
+ * Transform source Bitmap to targeted width and height.
+ */
+ private static Bitmap transform(Matrix scaler,
Bitmap source,
int targetWidth,
int targetHeight,
@@ -441,10 +485,6 @@ public class ThumbnailUtil {
/**
* Look up thumbnail uri by given imageId, it will be automatically created if it's not created
* yet. Most of the time imageId is identical to thumbId, but it's not always true.
- * @param req
- * @param width
- * @param height
- * @return Uri Thumbnail uri
*/
private static Uri getImageThumbnailUri(ContentResolver cr, long origId, int width, int height) {
Uri thumbUri = Images.Thumbnails.EXTERNAL_CONTENT_URI;
@@ -513,10 +553,14 @@ public class ThumbnailUtil {
}
}
- // SizedThumbnailBitmap contains the bitmap, which is downsampled either from
- // the thumbnail in exif or the full image.
- // mThumbnailData, mThumbnailWidth and mThumbnailHeight are set together only if mThumbnail is not null.
- // The width/height of the sized bitmap may be different from mThumbnailWidth/mThumbnailHeight.
+ /**
+ * SizedThumbnailBitmap contains the bitmap, which is downsampled either from
+ * the thumbnail in exif or the full image.
+ * mThumbnailData, mThumbnailWidth and mThumbnailHeight are set together only if mThumbnail
+ * is not null.
+ *
+ * The width/height of the sized bitmap may be different from mThumbnailWidth/mThumbnailHeight.
+ */
private static class SizedThumbnailBitmap {
public byte[] mThumbnailData;
public Bitmap mBitmap;
@@ -524,9 +568,11 @@ public class ThumbnailUtil {
public int mThumbnailHeight;
}
- // Creates a bitmap by either downsampling from the thumbnail in EXIF or the full image.
- // The functions returns a SizedThumbnailBitmap,
- // which contains a downsampled bitmap and the thumbnail data in EXIF if exists.
+ /**
+ * Creates a bitmap by either downsampling from the thumbnail in EXIF or the full image.
+ * The functions returns a SizedThumbnailBitmap,
+ * which contains a downsampled bitmap and the thumbnail data in EXIF if exists.
+ */
private static void createThumbnailFromEXIF(String filePath, int targetSize,
int maxPixels, SizedThumbnailBitmap sizedThumbBitmap) {
if (filePath == null) return;