Make createVideoThumbnail and createImageThumbnail look consistent.

Change-Id: I9a4798fefe3968ac847d46100036a6dde39791c9
diff --git a/api/current.xml b/api/current.xml
index 0d42c2c..8069462 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -86123,6 +86123,8 @@
 >
 <parameter name="filePath" type="java.lang.String">
 </parameter>
+<parameter name="kind" type="int">
+</parameter>
 </method>
 <method name="extractThumbnail"
  return="android.graphics.Bitmap"
@@ -86171,28 +86173,6 @@
  visibility="public"
 >
 </field>
-<field name="TARGET_SIZE_MICRO_THUMBNAIL"
- type="int"
- transient="false"
- volatile="false"
- value="96"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TARGET_SIZE_MINI_THUMBNAIL"
- type="int"
- transient="false"
- volatile="false"
- value="320"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 </class>
 <class name="ToneGenerator"
  extends="java.lang.Object"
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 1d27828..c9d125b 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -374,8 +374,8 @@
 
                 // We probably run out of space, so create the thumbnail in memory.
                 if (bitmap == null) {
-                    Log.v(TAG, "We probably run out of space, so create the thumbnail in memory.");
-
+                    Log.v(TAG, "Create the thumbnail in memory: origId=" + origId
+                            + ", kind=" + kind + ", isVideo="+isVideo);
                     Uri uri = Uri.parse(
                             baseUri.buildUpon().appendPath(String.valueOf(origId))
                                     .toString().replaceFirst("thumbnails", "media"));
@@ -388,16 +388,9 @@
                         filePath = c.getString(1);
                     }
                     if (isVideo) {
-                        bitmap = ThumbnailUtils.createVideoThumbnail(filePath);
-                        if (kind == MICRO_KIND && bitmap != null) {
-                            bitmap = ThumbnailUtils.extractThumbnail(bitmap,
-                                    ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL,
-                                    ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL,
-                                    ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
-                        }
+                        bitmap = ThumbnailUtils.createVideoThumbnail(filePath, kind);
                     } else {
-                        bitmap = ThumbnailUtils.createImageThumbnail(cr, filePath, uri, origId,
-                                kind, false);
+                        bitmap = ThumbnailUtils.createImageThumbnail(filePath, kind);
                     }
                 }
             } catch (SQLiteException ex) {
@@ -613,8 +606,12 @@
                         }
 
                         long id = ContentUris.parseId(url);
-                        Bitmap miniThumb  = StoreThumbnail(cr, source, id, 320F, 240F, Images.Thumbnails.MINI_KIND);
-                        Bitmap microThumb = StoreThumbnail(cr, miniThumb, id, 50F, 50F, Images.Thumbnails.MICRO_KIND);
+                        // Wait until MINI_KIND thumbnail is generated.
+                        Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id,
+                                Images.Thumbnails.MINI_KIND, null);
+                        // This is for backward compatibility.
+                        Bitmap microThumb = StoreThumbnail(cr, miniThumb, id, 50F, 50F,
+                                Images.Thumbnails.MICRO_KIND);
                     } else {
                         Log.e(TAG, "Failed to create thumbnail, removing original");
                         cr.delete(url, null, null);
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index 5062e87..3d85e31 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -34,6 +34,7 @@
 import android.provider.MediaStore.Images.Thumbnails;
 import android.util.Log;
 
+import java.io.FileInputStream;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -61,14 +62,14 @@
     public static final int OPTIONS_RECYCLE_INPUT = 0x2;
 
     /**
-     * Constant used to indicate the dimension of mini thumbnail in
-     * {@link #extractThumbnail(Bitmap, int, int, int)}.
+     * Constant used to indicate the dimension of mini thumbnail.
+     * @hide Only used by media framework and media provider internally.
      */
     public static final int TARGET_SIZE_MINI_THUMBNAIL = 320;
 
     /**
-     * Constant used to indicate the dimension of micro thumbnail in
-     * {@link #extractThumbnail(Bitmap, int, int, int)}.
+     * Constant used to indicate the dimension of micro thumbnail.
+     * @hide Only used by media framework and media provider internally.
      */
     public static final int TARGET_SIZE_MICRO_THUMBNAIL = 96;
 
@@ -80,23 +81,20 @@
      *
      * 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.
+     * @param filePath the path of image file
+     * @param kind could be MINI_KIND or MICRO_KIND
      * @return Bitmap
      *
      * @hide This method is only used by media framework and media provider internally.
      */
-    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 ?
-                TARGET_SIZE_MINI_THUMBNAIL : TARGET_SIZE_MICRO_THUMBNAIL;
-        int maxPixels = wantMini ?
-                MAX_NUM_PIXELS_THUMBNAIL : MAX_NUM_PIXELS_MICRO_THUMBNAIL;
+    public static Bitmap createImageThumbnail(String filePath, int kind) {
+        boolean wantMini = (kind == Images.Thumbnails.MINI_KIND);
+        int targetSize = wantMini
+                ? TARGET_SIZE_MINI_THUMBNAIL
+                : TARGET_SIZE_MICRO_THUMBNAIL;
+        int maxPixels = wantMini
+                ? MAX_NUM_PIXELS_THUMBNAIL
+                : MAX_NUM_PIXELS_MICRO_THUMBNAIL;
         SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap();
         Bitmap bitmap = null;
         MediaFileType fileType = MediaFile.getFileType(filePath);
@@ -106,21 +104,25 @@
         }
 
         if (bitmap == null) {
-            bitmap = makeBitmap(targetSize, maxPixels, uri, cr);
-        }
+            try {
+                FileDescriptor fd = new FileInputStream(filePath).getFD();
+                BitmapFactory.Options options = new BitmapFactory.Options();
+                options.inSampleSize = 1;
+                options.inJustDecodeBounds = true;
+                BitmapFactory.decodeFileDescriptor(fd, null, options);
+                if (options.mCancel || options.outWidth == -1
+                        || options.outHeight == -1) {
+                    return null;
+                }
+                options.inSampleSize = computeSampleSize(
+                        options, targetSize, maxPixels);
+                options.inJustDecodeBounds = false;
 
-        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);
+                options.inDither = false;
+                options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+                bitmap = BitmapFactory.decodeFileDescriptor(fd, null, options);
+            } catch (IOException ex) {
+                Log.e(TAG, "", ex);
             }
         }
 
@@ -137,9 +139,10 @@
      * Create a video thumbnail for a video. May return null if the video is
      * corrupt or the format is not supported.
      *
-     * @param filePath
+     * @param filePath the path of video file
+     * @param kind could be MINI_KIND or MICRO_KIND
      */
-    public static Bitmap createVideoThumbnail(String filePath) {
+    public static Bitmap createVideoThumbnail(String filePath, int kind) {
         Bitmap bitmap = null;
         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
         try {
@@ -157,6 +160,12 @@
                 // Ignore failures while cleaning up.
             }
         }
+        if (kind == Images.Thumbnails.MICRO_KIND && bitmap != null) {
+            bitmap = extractThumbnail(bitmap,
+                    TARGET_SIZE_MICRO_THUMBNAIL,
+                    TARGET_SIZE_MICRO_THUMBNAIL,
+                    OPTIONS_RECYCLE_INPUT);
+        }
         return bitmap;
     }
 
@@ -264,25 +273,6 @@
 
     /**
      * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels.
-     * The image data will be read from specified ContentResolver.
-     */
-    private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels,
-            Uri uri, ContentResolver cr) {
-        ParcelFileDescriptor input = null;
-        try {
-            input = cr.openFileDescriptor(uri, "r");
-            return makeBitmap(minSideLength, maxNumOfPixels, uri, cr, input,
-                    null);
-        } catch (IOException ex) {
-            Log.e(TAG, "", ex);
-            return null;
-        } finally {
-            closeSilently(input);
-        }
-    }
-
-    /**
-     * 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.
      *
@@ -438,81 +428,6 @@
         return b2;
     }
 
-    private static final String[] THUMB_PROJECTION = new String[] {
-        BaseColumns._ID // 0
-    };
-
-    /**
-     * 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.
-     */
-    private static Uri getImageThumbnailUri(ContentResolver cr, long origId, int width, int height) {
-        Uri thumbUri = Images.Thumbnails.EXTERNAL_CONTENT_URI;
-        Cursor c = cr.query(thumbUri, THUMB_PROJECTION,
-              Thumbnails.IMAGE_ID + "=?",
-              new String[]{String.valueOf(origId)}, null);
-        if (c == null) return null;
-        try {
-            if (c.moveToNext()) {
-                return ContentUris.withAppendedId(thumbUri, c.getLong(0));
-            }
-        } finally {
-            if (c != null) c.close();
-        }
-
-        ContentValues values = new ContentValues(4);
-        values.put(Thumbnails.KIND, Thumbnails.MINI_KIND);
-        values.put(Thumbnails.IMAGE_ID, origId);
-        values.put(Thumbnails.HEIGHT, height);
-        values.put(Thumbnails.WIDTH, width);
-        try {
-            return cr.insert(thumbUri, values);
-        } catch (Exception ex) {
-            Log.w(TAG, ex);
-            return null;
-        }
-    }
-
-    /**
-     * Store a given thumbnail in the database. (Bitmap)
-     */
-    private static boolean storeThumbnail(ContentResolver cr, long origId, Bitmap thumb) {
-        if (thumb == null) return false;
-        try {
-            Uri uri = getImageThumbnailUri(cr, origId, thumb.getWidth(), thumb.getHeight());
-            if (uri == null) return false;
-            OutputStream thumbOut = cr.openOutputStream(uri);
-            thumb.compress(Bitmap.CompressFormat.JPEG, 85, thumbOut);
-            thumbOut.close();
-            return true;
-        } catch (Throwable t) {
-            Log.e(TAG, "Unable to store thumbnail", t);
-            return false;
-        }
-    }
-
-    /**
-     * Store a given thumbnail in the database. (byte array)
-     */
-    private static boolean storeThumbnail(ContentResolver cr, long origId, byte[] jpegThumbnail,
-            int width, int height) {
-        if (jpegThumbnail == null) return false;
-
-        Uri uri = getImageThumbnailUri(cr, origId, width, height);
-        if (uri == null) {
-            return false;
-        }
-        try {
-            OutputStream thumbOut = cr.openOutputStream(uri);
-            thumbOut.write(jpegThumbnail);
-            thumbOut.close();
-            return true;
-        } catch (Throwable t) {
-            Log.e(TAG, "Unable to store thumbnail", t);
-            return false;
-        }
-    }
-
     /**
      * SizedThumbnailBitmap contains the bitmap, which is downsampled either from
      * the thumbnail in exif or the full image.