Merge "MTP: Add MTP Thumbnail feature"
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index a828e2d..e6962a1 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -27,7 +27,9 @@
 import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
 import android.media.ExifInterface;
+import android.media.ThumbnailUtils;
 import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.RemoteException;
@@ -49,6 +51,7 @@
 
 import com.google.android.collect.Sets;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Path;
@@ -71,6 +74,7 @@
  */
 public class MtpDatabase implements AutoCloseable {
     private static final String TAG = MtpDatabase.class.getSimpleName();
+    private static final int MAX_THUMB_SIZE = (200 * 1024);
 
     private final Context mContext;
     private final ContentProviderClient mMediaProvider;
@@ -803,6 +807,28 @@
         return obj.getFormat();
     }
 
+    private byte[] getThumbnailProcess(String path, Bitmap bitmap) {
+        try {
+            if (bitmap == null) {
+                Log.d(TAG, "getThumbnailProcess: Fail to generate thumbnail. Probably unsupported or corrupted image");
+                return null;
+            }
+
+            ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteStream);
+
+            if (byteStream.size() > MAX_THUMB_SIZE)
+                return null;
+
+            byte[] byteArray = byteStream.toByteArray();
+
+            return byteArray;
+        } catch (OutOfMemoryError oomEx) {
+            Log.w(TAG, "OutOfMemoryError:" + oomEx);
+        }
+        return null;
+    }
+
     @VisibleForNative
     private boolean getThumbnailInfo(int handle, long[] outLongs) {
         MtpStorageManager.MtpObject obj = mManager.getObject(handle);
@@ -825,6 +851,16 @@
                 } catch (IOException e) {
                     // ignore and fall through
                 }
+
+// Note: above formats will fall through and go on below thumbnail generation if Exif processing fails
+            case MtpConstants.FORMAT_PNG:
+            case MtpConstants.FORMAT_GIF:
+            case MtpConstants.FORMAT_BMP:
+                outLongs[0] = MAX_THUMB_SIZE;
+            // only non-zero Width & Height needed. Actual size will be retrieved upon getThumbnailData by Host
+                outLongs[1] = 320;
+                outLongs[2] = 240;
+                return true;
         }
         return false;
     }
@@ -847,6 +883,17 @@
                 } catch (IOException e) {
                     // ignore and fall through
                 }
+
+// Note: above formats will fall through and go on below thumbnail generation if Exif processing fails
+            case MtpConstants.FORMAT_PNG:
+            case MtpConstants.FORMAT_GIF:
+            case MtpConstants.FORMAT_BMP:
+                {
+                    Bitmap bitmap = ThumbnailUtils.createImageThumbnail(path, MediaStore.Images.Thumbnails.MINI_KIND);
+                    byte[] byteArray = getThumbnailProcess(path, bitmap);
+
+                    return byteArray;
+                }
         }
         return null;
     }
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 0a3b47b..17189fd 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -820,7 +820,10 @@
     switch (info.mFormat) {
         case MTP_FORMAT_EXIF_JPEG:
         case MTP_FORMAT_HEIF:
-        case MTP_FORMAT_JFIF: {
+        case MTP_FORMAT_JFIF:
+        case MTP_FORMAT_PNG:
+        case MTP_FORMAT_BMP:
+        case MTP_FORMAT_GIF: {
             env = AndroidRuntime::getJNIEnv();
             if (env->CallBooleanMethod(
                     mDatabase, method_getThumbnailInfo, (jint)handle, mLongBuffer)) {
@@ -881,7 +884,10 @@
         switch (format) {
             case MTP_FORMAT_EXIF_JPEG:
             case MTP_FORMAT_HEIF:
-            case MTP_FORMAT_JFIF: {
+            case MTP_FORMAT_JFIF:
+            case MTP_FORMAT_PNG:
+            case MTP_FORMAT_BMP:
+            case MTP_FORMAT_GIF: {
                 JNIEnv* env = AndroidRuntime::getJNIEnv();
                 jbyteArray thumbData = (jbyteArray) env->CallObjectMethod(
                         mDatabase, method_getThumbnailData, (jint)handle);