Handle OutOfMemory when decoding images

Decoding images and videos in the messaging app appears to be a
vulnerable point for running out of memory. Catch those exceptions,
log an error, and continue on without loading the image. Most of these
"catches" are around situations where there's been a problem decoding
the original image in the first place, and now we're simply trying
to decode a small missing stand-in image. However, since BitmapFactory.decodeResource
seems to be in an inordinate number of bug reports, I want to log every
use in the code in case of failure.
Handles the 2nd part of bug 2994057.

Change-Id: Iaa8035f6ef28385b353d31507b9753934881d3e8
diff --git a/src/com/android/mms/ui/BasicSlideEditorView.java b/src/com/android/mms/ui/BasicSlideEditorView.java
index df31be6..c5676c7 100644
--- a/src/com/android/mms/ui/BasicSlideEditorView.java
+++ b/src/com/android/mms/ui/BasicSlideEditorView.java
@@ -98,11 +98,15 @@
     }
 
     public void setImage(String name, Bitmap bitmap) {
-        if (null == bitmap) {
-            bitmap = BitmapFactory.decodeResource(getResources(),
-                    R.drawable.ic_missing_thumbnail_picture);
+        try {
+            if (null == bitmap) {
+                bitmap = BitmapFactory.decodeResource(getResources(),
+                        R.drawable.ic_missing_thumbnail_picture);
+            }
+            mImageView.setImageBitmap(bitmap);
+        } catch (java.lang.OutOfMemoryError e) {
+            Log.e(TAG, "setImage: out of memory: ", e);
         }
-        mImageView.setImageBitmap(bitmap);
     }
 
     public void setImageRegionFit(String fit) {
@@ -127,12 +131,16 @@
     }
 
     public void setVideo(String name, Uri video) {
-        Bitmap bitmap = VideoAttachmentView.createVideoThumbnail(mContext, video);
-        if (null == bitmap) {
-            bitmap = BitmapFactory.decodeResource(getResources(),
-                    R.drawable.ic_missing_thumbnail_video);
+        try {
+            Bitmap bitmap = VideoAttachmentView.createVideoThumbnail(mContext, video);
+            if (null == bitmap) {
+                bitmap = BitmapFactory.decodeResource(getResources(),
+                        R.drawable.ic_missing_thumbnail_video);
+            }
+            mImageView.setImageBitmap(bitmap);
+        } catch (java.lang.OutOfMemoryError e) {
+            Log.e(TAG, "setVideo: out of memory: ", e);
         }
-        mImageView.setImageBitmap(bitmap);
     }
 
     public void setVideoVisibility(boolean visible) {
diff --git a/src/com/android/mms/ui/ImageAttachmentView.java b/src/com/android/mms/ui/ImageAttachmentView.java
index 90f52ef..c6f59b9 100644
--- a/src/com/android/mms/ui/ImageAttachmentView.java
+++ b/src/com/android/mms/ui/ImageAttachmentView.java
@@ -24,6 +24,7 @@
 import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -35,6 +36,7 @@
  */
 public class ImageAttachmentView extends LinearLayout implements SlideViewInterface {
     private ImageView mImageView;
+    private static final String TAG = "ImageAttachmentView";
 
     public ImageAttachmentView(Context context) {
         super(context);
@@ -65,11 +67,15 @@
     }
 
     public void setImage(String name, Bitmap bitmap) {
-        if (null == bitmap) {
-            bitmap = BitmapFactory.decodeResource(getResources(),
-                    R.drawable.ic_missing_thumbnail_picture);
+        try {
+            if (null == bitmap) {
+                bitmap = BitmapFactory.decodeResource(getResources(),
+                        R.drawable.ic_missing_thumbnail_picture);
+            }
+            mImageView.setImageBitmap(bitmap);
+        } catch (java.lang.OutOfMemoryError e) {
+            Log.e(TAG, "setImage: out of memory: ", e);
         }
-        mImageView.setImageBitmap(bitmap);
     }
 
     public void setImageRegionFit(String fit) {
diff --git a/src/com/android/mms/ui/MessageListAdapter.java b/src/com/android/mms/ui/MessageListAdapter.java
index 2f4e00d..222df63 100644
--- a/src/com/android/mms/ui/MessageListAdapter.java
+++ b/src/com/android/mms/ui/MessageListAdapter.java
@@ -590,12 +590,16 @@
              * doing that here.
              */
             private void loadDefaultAvatar() {
-                if (mDefaultAvatarDrawable == null) {
-                    Bitmap b = BitmapFactory.decodeResource(mContext.getResources(),
-                            R.drawable.ic_contact_picture);
-                    mDefaultAvatarDrawable = new BitmapDrawable(mContext.getResources(), b);
+                try {
+                    if (mDefaultAvatarDrawable == null) {
+                        Bitmap b = BitmapFactory.decodeResource(mContext.getResources(),
+                                R.drawable.ic_contact_picture);
+                        mDefaultAvatarDrawable = new BitmapDrawable(mContext.getResources(), b);
+                    }
+                    mPhoto = mDefaultAvatarDrawable;
+                } catch (java.lang.OutOfMemoryError e) {
+                    Log.e(TAG, "loadDefaultAvatar: out of memory: ", e);
                 }
-                mPhoto = mDefaultAvatarDrawable;
             }
 
         };
diff --git a/src/com/android/mms/ui/MessageListItem.java b/src/com/android/mms/ui/MessageListItem.java
index 79db2e4..352772b 100644
--- a/src/com/android/mms/ui/MessageListItem.java
+++ b/src/com/android/mms/ui/MessageListItem.java
@@ -54,6 +54,7 @@
 import android.text.style.TextAppearanceSpan;
 import android.text.style.URLSpan;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnClickListener;
@@ -311,12 +312,16 @@
     public void setImage(String name, Bitmap bitmap) {
         inflateMmsView();
 
-        if (null == bitmap) {
-            bitmap = BitmapFactory.decodeResource(getResources(),
-                    R.drawable.ic_missing_thumbnail_picture);
+        try {
+            if (null == bitmap) {
+                bitmap = BitmapFactory.decodeResource(getResources(),
+                        R.drawable.ic_missing_thumbnail_picture);
+            }
+            mImageView.setImageBitmap(bitmap);
+            mImageView.setVisibility(VISIBLE);
+        } catch (java.lang.OutOfMemoryError e) {
+            Log.e(TAG, "setImage: out of memory: ", e);
         }
-        mImageView.setImageBitmap(bitmap);
-        mImageView.setVisibility(VISIBLE);
     }
 
     private void inflateMmsView() {
@@ -629,13 +634,18 @@
 
     public void setVideo(String name, Uri video) {
         inflateMmsView();
-        Bitmap bitmap = VideoAttachmentView.createVideoThumbnail(mContext, video);
-        if (null == bitmap) {
-            bitmap = BitmapFactory.decodeResource(getResources(),
-                    R.drawable.ic_missing_thumbnail_video);
+
+        try {
+            Bitmap bitmap = VideoAttachmentView.createVideoThumbnail(mContext, video);
+            if (null == bitmap) {
+                bitmap = BitmapFactory.decodeResource(getResources(),
+                        R.drawable.ic_missing_thumbnail_video);
+            }
+            mImageView.setImageBitmap(bitmap);
+            mImageView.setVisibility(VISIBLE);
+        } catch (java.lang.OutOfMemoryError e) {
+            Log.e(TAG, "setVideo: out of memory: ", e);
         }
-        mImageView.setImageBitmap(bitmap);
-        mImageView.setVisibility(VISIBLE);
     }
 
     public void setVideoVisibility(boolean visible) {
diff --git a/src/com/android/mms/ui/MmsThumbnailPresenter.java b/src/com/android/mms/ui/MmsThumbnailPresenter.java
index 2b62774..00e679c 100644
--- a/src/com/android/mms/ui/MmsThumbnailPresenter.java
+++ b/src/com/android/mms/ui/MmsThumbnailPresenter.java
@@ -28,8 +28,10 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.util.Log;
 
 public class MmsThumbnailPresenter extends Presenter {
+    private static final String TAG = "MmsThumbnailPresenter";
 
     public MmsThumbnailPresenter(Context context, ViewInterface view, Model model) {
         super(context, view, model);
@@ -81,9 +83,13 @@
 
     // Show an icon instead of real content in the thumbnail.
     private void showDrmIcon(SlideViewInterface view, String name) {
-        Bitmap bitmap = BitmapFactory.decodeResource(
-                mContext.getResources(), R.drawable.ic_mms_drm_protected);
-        view.setImage(name, bitmap);
+        try {
+            Bitmap bitmap = BitmapFactory.decodeResource(
+                    mContext.getResources(), R.drawable.ic_mms_drm_protected);
+            view.setImage(name, bitmap);
+        } catch (java.lang.OutOfMemoryError e) {
+            Log.e(TAG, "showDrmIcon: out of memory: ", e);
+        }
     }
 
     public void onModelChanged(Model model, boolean dataChanged) {
diff --git a/src/com/android/mms/ui/SlideListItemView.java b/src/com/android/mms/ui/SlideListItemView.java
index 87a0f9e..c35694b 100644
--- a/src/com/android/mms/ui/SlideListItemView.java
+++ b/src/com/android/mms/ui/SlideListItemView.java
@@ -83,11 +83,15 @@
     }
 
     public void setImage(String name, Bitmap bitmap) {
-        if (null == bitmap) {
-            bitmap = BitmapFactory.decodeResource(getResources(),
-                    R.drawable.ic_missing_thumbnail_picture);
+        try {
+            if (null == bitmap) {
+                bitmap = BitmapFactory.decodeResource(getResources(),
+                        R.drawable.ic_missing_thumbnail_picture);
+            }
+            mImagePreview.setImageBitmap(bitmap);
+        } catch (java.lang.OutOfMemoryError e) {
+            Log.e(TAG, "setImage: out of memory: ", e);
         }
-        mImagePreview.setImageBitmap(bitmap);
     }
 
     public void setImageRegionFit(String fit) {
diff --git a/src/com/android/mms/ui/SlideView.java b/src/com/android/mms/ui/SlideView.java
index 9925744..ada1f7f 100644
--- a/src/com/android/mms/ui/SlideView.java
+++ b/src/com/android/mms/ui/SlideView.java
@@ -114,12 +114,16 @@
                 mImageView.setBackgroundColor(0xFFFF0000);
             }
         }
-        if (null == bitmap) {
-            bitmap = BitmapFactory.decodeResource(getResources(),
-                    R.drawable.ic_missing_thumbnail_picture);
+        try {
+            if (null == bitmap) {
+                bitmap = BitmapFactory.decodeResource(getResources(),
+                        R.drawable.ic_missing_thumbnail_picture);
+            }
+            mImageView.setVisibility(View.VISIBLE);
+            mImageView.setImageBitmap(bitmap);
+        } catch (java.lang.OutOfMemoryError e) {
+            Log.e(TAG, "setImage: out of memory: ", e);
         }
-        mImageView.setVisibility(View.VISIBLE);
-        mImageView.setImageBitmap(bitmap);
     }
 
     public void setImageRegion(int left, int top, int width, int height) {
@@ -434,7 +438,7 @@
      *
      * 2. The TextView is fixed in the small area of screen, and other part of screen
      * is empty once there is no image in the current slide.
-     * 
+     *
      * 3. The TextView is scrollable in a small area of screen and the font size is
      * small which make the user experience bad.
      *
diff --git a/src/com/android/mms/ui/UriImage.java b/src/com/android/mms/ui/UriImage.java
index f22ff96..fae3acf 100644
--- a/src/com/android/mms/ui/UriImage.java
+++ b/src/com/android/mms/ui/UriImage.java
@@ -270,7 +270,8 @@
                         }
                     }
                 } catch (java.lang.OutOfMemoryError e) {
-                    Log.e(TAG, e.getMessage(), e);
+                    Log.w(TAG, "getResizedImageData - image too big (OutOfMemoryError), will try "
+                            + " with smaller scale factor, cur scale factor: " + scaleFactor);
                     // fall through and keep trying with a smaller scale factor.
                 }
                 if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
diff --git a/src/com/android/mms/ui/VideoAttachmentView.java b/src/com/android/mms/ui/VideoAttachmentView.java
index a9ee971..b394983 100644
--- a/src/com/android/mms/ui/VideoAttachmentView.java
+++ b/src/com/android/mms/ui/VideoAttachmentView.java
@@ -26,6 +26,7 @@
 import android.net.Uri;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.View;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
@@ -86,12 +87,16 @@
     }
 
     public void setVideo(String name, Uri video) {
-        Bitmap bitmap = createVideoThumbnail(mContext, video);
-        if (null == bitmap) {
-            bitmap = BitmapFactory.decodeResource(getResources(),
-                    R.drawable.ic_missing_thumbnail_video);
+        try {
+            Bitmap bitmap = createVideoThumbnail(mContext, video);
+            if (null == bitmap) {
+                bitmap = BitmapFactory.decodeResource(getResources(),
+                        R.drawable.ic_missing_thumbnail_video);
+            }
+            mThumbnailView.setImageBitmap(bitmap);
+        } catch (java.lang.OutOfMemoryError e) {
+            Log.e(TAG, "setVideo: out of memory: ", e);
         }
-        mThumbnailView.setImageBitmap(bitmap);
     }
 
     public static Bitmap createVideoThumbnail(Context context, Uri uri) {