Support audio attachments through GalleryMediaChooser

GalleryMediaChooser supports audio types also. It displays simple audio
icon and file info for audio files on grid views.

Test: Manual

Change-Id: I98b605156af3c1909c0141a2b99380b5da11c1e2
Signed-off-by: Taesu Lee <taesu82.lee@samsung.com>
diff --git a/res/layout/gallery_grid_item_view.xml b/res/layout/gallery_grid_item_view.xml
index f474a6b..fc857ca 100644
--- a/res/layout/gallery_grid_item_view.xml
+++ b/res/layout/gallery_grid_item_view.xml
@@ -21,12 +21,67 @@
     android:background="@color/gallery_image_default_background"
     android:clickable="true">
 
+    <!-- Thumbnail for image and video contents. -->
     <com.android.messaging.ui.AsyncImageView
-        android:id="@+id/image"
+        android:id="@+id/thumbnail"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:scaleType="centerCrop" />
 
+    <!-- Additional info such as icon, name and etc. -->
+    <RelativeLayout
+        android:id="@+id/additional_info"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center"
+        android:orientation="vertical"
+        android:visibility="gone" >
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_above="@id/file_info" >
+            <ImageView
+                android:id="@+id/icon"
+                android:layout_width="@dimen/gallery_icon_size"
+                android:layout_height="@dimen/gallery_icon_size"
+                android:layout_gravity="center"
+                android:scaleType="fitCenter"
+                android:background="@color/background_item_transparent"
+                android:visibility="gone" />
+        </FrameLayout>
+
+        <!-- File info for audio contents only -->
+        <LinearLayout
+            android:id="@+id/file_info"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_marginBottom="4dp"
+            android:paddingLeft="4dp"
+            android:paddingRight="4dp"
+            android:orientation="vertical"
+            android:visibility="gone" >
+
+            <TextView
+                android:id="@+id/file_name"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:textAppearance="@android:style/TextAppearance.Material.Subhead" />
+
+            <TextView
+                android:id="@+id/file_type"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:gravity="right"
+                android:textAppearance="@android:style/TextAppearance.Material.Caption" />
+        </LinearLayout>
+    </RelativeLayout>
+
     <View
         android:layout_width="match_parent"
         android:layout_height="match_parent"
@@ -44,13 +99,4 @@
         android:visibility="gone"
         android:contentDescription="@string/gallery_checkbox_content_description" />
 
-    <!-- Play button image for video contents only -->
-    <ImageView
-        android:id="@+id/video_thumbnail_play_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:background="@color/background_item_transparent"
-        android:src="@drawable/ic_video_play_light"
-        android:visibility="gone" />
 </com.android.messaging.ui.mediapicker.GalleryGridItemView>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 5c34b6f..d775c7e 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -85,6 +85,7 @@
     <!-- Flings faster than this length / sec will go from fullscreen straight to closed -->
     <dimen name="mediapicker_big_fling_threshold">1000dp</dimen>
     <dimen name="gallery_image_cell_size">110dp</dimen>
+    <dimen name="gallery_icon_size">40dp</dimen>
     <dimen name="single_attachment_min_dimen">50dp</dimen>
     <dimen name="single_attachment_max_height">150dp</dimen>
     <dimen name="multiple_attachment_preview_height">130dp</dimen>
diff --git a/src/com/android/messaging/datamodel/GalleryBoundCursorLoader.java b/src/com/android/messaging/datamodel/GalleryBoundCursorLoader.java
index a820ac1..1974a5e 100644
--- a/src/com/android/messaging/datamodel/GalleryBoundCursorLoader.java
+++ b/src/com/android/messaging/datamodel/GalleryBoundCursorLoader.java
@@ -35,7 +35,11 @@
     private static final String SORT_ORDER = MediaColumns.DATE_MODIFIED + " DESC";
     private static final String SELECTION = createSelection(
             MessagePartData.ACCEPTABLE_GALLERY_MEDIA_TYPES,
-            new Integer[] {FileColumns.MEDIA_TYPE_IMAGE, FileColumns.MEDIA_TYPE_VIDEO});
+            new Integer[] {
+                FileColumns.MEDIA_TYPE_IMAGE,
+                FileColumns.MEDIA_TYPE_VIDEO,
+                FileColumns.MEDIA_TYPE_AUDIO
+            });
 
     public GalleryBoundCursorLoader(final String bindingId, final Context context) {
         super(bindingId, context, STORAGE_URI, GalleryGridItemData.MEDIA_PROJECTION, SELECTION,
diff --git a/src/com/android/messaging/datamodel/data/GalleryGridItemData.java b/src/com/android/messaging/datamodel/data/GalleryGridItemData.java
index 1536897..941d38d 100644
--- a/src/com/android/messaging/datamodel/data/GalleryGridItemData.java
+++ b/src/com/android/messaging/datamodel/data/GalleryGridItemData.java
@@ -29,6 +29,7 @@
 import com.android.messaging.datamodel.media.VideoThumbnailRequestDescriptor;
 import com.android.messaging.util.Assert;
 import com.android.messaging.util.ContentType;
+import com.android.messaging.util.UriUtil;
 
 /**
  * Provides data for GalleryGridItemView
@@ -40,7 +41,8 @@
         MediaColumns.WIDTH,
         MediaColumns.HEIGHT,
         MediaColumns.MIME_TYPE,
-        MediaColumns.DATE_MODIFIED};
+        MediaColumns.DATE_MODIFIED,
+        MediaColumns.DISPLAY_NAME};
 
     public static final String[] SPECIAL_ITEM_COLUMNS = new String[] {
         BaseColumns._ID
@@ -54,6 +56,7 @@
     private static final int INDEX_HEIGHT = 3;
     private static final int INDEX_MIME_TYPE = 4;
     private static final int INDEX_DATE_MODIFIED = 5;
+    private static final int INDEX_DISPLAY_NAME = 6;
 
     /** A special item's id for picking a media from document picker */
     public static final String ID_DOCUMENT_PICKER_ITEM = "-1";
@@ -62,6 +65,8 @@
     private String mContentType;
     private boolean mIsDocumentPickerItem;
     private long mDateSeconds;
+    private String mFileName;
+    private Uri mAudioUri;
 
     public GalleryGridItemData() {
     }
@@ -73,37 +78,44 @@
             mImageData = null;
             mContentType = null;
         } else {
-            int sourceWidth = cursor.getInt(INDEX_WIDTH);
-            int sourceHeight = cursor.getInt(INDEX_HEIGHT);
-
-            // Guard against bad data
-            if (sourceWidth <= 0) {
-                sourceWidth = ImageRequest.UNSPECIFIED_SIZE;
-            }
-            if (sourceHeight <= 0) {
-                sourceHeight = ImageRequest.UNSPECIFIED_SIZE;
-            }
-
             mContentType = cursor.getString(INDEX_MIME_TYPE);
+            final String filePath = cursor.getString(INDEX_DATA_PATH);
             final String dateModified = cursor.getString(INDEX_DATE_MODIFIED);
             mDateSeconds = !TextUtils.isEmpty(dateModified) ? Long.parseLong(dateModified) : -1;
-            if (ContentType.isVideoType(mContentType)) {
-                mImageData = new VideoThumbnailRequestDescriptor(
-                        cursor.getLong(INDEX_ID),
-                        desiredWidth,
-                        desiredHeight,
-                        sourceWidth,
-                        sourceHeight);
-            } else {
-                mImageData = new FileImageRequestDescriptor(
-                        cursor.getString(INDEX_DATA_PATH),
-                        desiredWidth,
-                        desiredHeight,
-                        sourceWidth,
-                        sourceHeight,
-                        true /* canUseThumbnail */,
-                        true /* allowCompression */,
-                        true /* isStatic */);
+            if (ContentType.isAudioType(mContentType)) {
+                mImageData = null;
+                mAudioUri = UriUtil.getUriForResourceFile(filePath);
+                mFileName = cursor.getString(INDEX_DISPLAY_NAME);
+            } else { // For image and video types
+                int sourceWidth = cursor.getInt(INDEX_WIDTH);
+                int sourceHeight = cursor.getInt(INDEX_HEIGHT);
+
+                // Guard against bad data
+                if (sourceWidth <= 0) {
+                    sourceWidth = ImageRequest.UNSPECIFIED_SIZE;
+                }
+                if (sourceHeight <= 0) {
+                    sourceHeight = ImageRequest.UNSPECIFIED_SIZE;
+                }
+
+                if (ContentType.isVideoType(mContentType)) {
+                    mImageData = new VideoThumbnailRequestDescriptor(
+                            cursor.getLong(INDEX_ID),
+                            desiredWidth,
+                            desiredHeight,
+                            sourceWidth,
+                            sourceHeight);
+                } else {
+                    mImageData = new FileImageRequestDescriptor(
+                            filePath,
+                            desiredWidth,
+                            desiredHeight,
+                            sourceWidth,
+                            sourceHeight,
+                            true /* canUseThumbnail */,
+                            true /* allowCompression */,
+                            true /* isStatic */);
+                }
             }
         }
     }
@@ -113,7 +125,7 @@
     }
 
     public Uri getImageUri() {
-        return mImageData.uri;
+        return ContentType.isAudioType(mContentType) ? mAudioUri : mImageData.uri;
     }
 
     public UriImageRequestDescriptor getImageRequestDescriptor() {
@@ -122,8 +134,10 @@
 
     public MessagePartData constructMessagePartData(final Rect startRect) {
         Assert.isTrue(!mIsDocumentPickerItem);
-        return new MediaPickerMessagePartData(startRect, mContentType,
-                mImageData.uri, mImageData.sourceWidth, mImageData.sourceHeight);
+        return ContentType.isAudioType(mContentType)
+                ? new MediaPickerMessagePartData(startRect, mContentType, mAudioUri, 0, 0)
+                : new MediaPickerMessagePartData(startRect, mContentType, mImageData.uri,
+                        mImageData.sourceWidth, mImageData.sourceHeight);
     }
 
     /**
@@ -136,4 +150,8 @@
     public String getContentType() {
         return mContentType;
     }
+
+    public String getFileName() {
+        return mFileName;
+    }
 }
diff --git a/src/com/android/messaging/datamodel/data/MessagePartData.java b/src/com/android/messaging/datamodel/data/MessagePartData.java
index a6d825c..5846c97 100644
--- a/src/com/android/messaging/datamodel/data/MessagePartData.java
+++ b/src/com/android/messaging/datamodel/data/MessagePartData.java
@@ -61,7 +61,12 @@
                 // Acceptable video types
                 ContentType.VIDEO_3GP, ContentType.VIDEO_3GPP, ContentType.VIDEO_3G2,
                 ContentType.VIDEO_H263, ContentType.VIDEO_M4V, ContentType.VIDEO_MP4,
-                ContentType.VIDEO_MPEG, ContentType.VIDEO_MPEG4, ContentType.VIDEO_WEBM
+                ContentType.VIDEO_MPEG, ContentType.VIDEO_MPEG4, ContentType.VIDEO_WEBM,
+                // Acceptable audio types
+                ContentType.AUDIO_MP3, ContentType.AUDIO_MP4, ContentType.AUDIO_MIDI,
+                ContentType.AUDIO_MID, ContentType.AUDIO_AMR, ContentType.AUDIO_X_WAV,
+                ContentType.AUDIO_AAC, ContentType.AUDIO_X_MIDI, ContentType.AUDIO_X_MID,
+                ContentType.AUDIO_X_MP3
             };
 
     private static final String[] sProjection = {
diff --git a/src/com/android/messaging/ui/mediapicker/DocumentImagePicker.java b/src/com/android/messaging/ui/mediapicker/DocumentImagePicker.java
index 1e52dc4..d6de128 100644
--- a/src/com/android/messaging/ui/mediapicker/DocumentImagePicker.java
+++ b/src/com/android/messaging/ui/mediapicker/DocumentImagePicker.java
@@ -30,7 +30,7 @@
 import com.android.messaging.util.SafeAsyncTask;
 
 /**
- * Wraps around the functionalities to allow the user to pick an image/video from the document
+ * Wraps around the functionalities to allow the user to pick an image/video/audio from the document
  * picker. Instances of this class must be tied to a Fragment which is able to delegate activity
  * result callbacks.
  */
diff --git a/src/com/android/messaging/ui/mediapicker/GalleryGridItemView.java b/src/com/android/messaging/ui/mediapicker/GalleryGridItemView.java
index 4337d5e..48eaa5d 100644
--- a/src/com/android/messaging/ui/mediapicker/GalleryGridItemView.java
+++ b/src/com/android/messaging/ui/mediapicker/GalleryGridItemView.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.database.Cursor;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -25,6 +26,9 @@
 import android.widget.CheckBox;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
 
 import com.android.messaging.R;
 import com.android.messaging.datamodel.DataModel;
@@ -54,6 +58,11 @@
     GalleryGridItemData mData;
     private AsyncImageView mImageView;
     private CheckBox mCheckBox;
+    private RelativeLayout mAdditionalInfo;
+    private ImageView mIcon;
+    private LinearLayout mFileInfo;
+    private TextView mFileName;
+    private TextView mFileType;
     private HostInterface mHostInterface;
     private final OnClickListener mOnClickListener = new OnClickListener() {
         @Override
@@ -70,9 +79,14 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mImageView = (AsyncImageView) findViewById(R.id.image);
+        mImageView = (AsyncImageView) findViewById(R.id.thumbnail);
         mCheckBox = (CheckBox) findViewById(R.id.checkbox);
         mCheckBox.setOnClickListener(mOnClickListener);
+        mAdditionalInfo = (RelativeLayout) findViewById(R.id.additional_info);
+        mIcon = (ImageView) findViewById(R.id.icon);
+        mFileInfo = (LinearLayout) findViewById(R.id.file_info);
+        mFileName = (TextView) findViewById(R.id.file_name);
+        mFileType = (TextView) findViewById(R.id.file_type);
         setOnClickListener(mOnClickListener);
         final OnLongClickListener longClickListener = new OnLongClickListener() {
             @Override
@@ -136,32 +150,59 @@
     }
 
     private void updateImageView() {
-        ImageView playButton = (ImageView) findViewById(R.id.video_thumbnail_play_button);
         if (mData.isDocumentPickerItem()) {
-            mImageView.setScaleType(ImageView.ScaleType.CENTER);
             setBackgroundColor(ConversationDrawables.get().getConversationThemeColor());
-            mImageView.setImageResourceId(null);
-            mImageView.setImageResource(R.drawable.ic_photo_library_light);
-            playButton.setVisibility(GONE);
-            mImageView.setContentDescription(getResources().getString(
-                    R.string.pick_image_from_document_library_content_description));
+            mIcon.setImageResource(R.drawable.ic_photo_library_light);
+            mIcon.clearColorFilter();
+            mImageView.setVisibility(GONE);
+            mIcon.setVisibility(VISIBLE);
+            mFileInfo.setVisibility(GONE);
+            mAdditionalInfo.setVisibility(VISIBLE);
         } else {
-            mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
-            setBackgroundColor(getResources().getColor(R.color.gallery_image_default_background));
-            mImageView.setImageResourceId(mData.getImageRequestDescriptor());
-            if (ContentType.isVideoType(mData.getContentType())) {
-                playButton.setVisibility(VISIBLE);
-            } else {
-                playButton.setVisibility(GONE);
+            final String contentType = mData.getContentType();
+            if (ContentType.isAudioType(contentType)) {
+                final Context context = getContext();
+                setBackgroundColor(
+                        getResources().getColor(R.color.gallery_image_default_background));
+                mIcon.setImageDrawable(
+                        context.getContentResolver()
+                                .getTypeInfo(contentType)
+                                .getIcon()
+                                .loadDrawable(context));
+                mIcon.setColorFilter(
+                        ConversationDrawables.get().getConversationThemeColor(),
+                        PorterDuff.Mode.SRC_IN);
+                mFileName.setText(mData.getFileName());
+                String[] type = contentType.split("/");
+                mFileType.setText(type[1].toUpperCase() + " " + type[0]);
+                mImageView.setVisibility(GONE);
+                mIcon.setVisibility(VISIBLE);
+                mFileInfo.setVisibility(VISIBLE);
+                mAdditionalInfo.setVisibility(VISIBLE);
+            } else { // For image and video types
+                mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
+                setBackgroundColor(
+                        getResources().getColor(R.color.gallery_image_default_background));
+                mImageView.setImageResourceId(mData.getImageRequestDescriptor());
+                mImageView.setVisibility(VISIBLE);
+                if (ContentType.isVideoType(mData.getContentType())) {
+                    mIcon.setImageResource(R.drawable.ic_video_play_light);
+                    mIcon.clearColorFilter();
+                    mIcon.setVisibility(VISIBLE);
+                } else {
+                    mIcon.setVisibility(GONE);
+                }
+                mFileInfo.setVisibility(GONE);
+                mAdditionalInfo.setVisibility(VISIBLE);
+                final long dateSeconds = mData.getDateSeconds();
+                final boolean isValidDate = (dateSeconds > 0);
+                final int templateId = isValidDate ?
+                        R.string.mediapicker_gallery_image_item_description :
+                        R.string.mediapicker_gallery_image_item_description_no_date;
+                String contentDescription = String.format(getResources().getString(templateId),
+                        dateSeconds * TimeUnit.SECONDS.toMillis(1));
+                mImageView.setContentDescription(contentDescription);
             }
-            final long dateSeconds = mData.getDateSeconds();
-            final boolean isValidDate = (dateSeconds > 0);
-            final int templateId = isValidDate ?
-                    R.string.mediapicker_gallery_image_item_description :
-                    R.string.mediapicker_gallery_image_item_description_no_date;
-            String contentDescription = String.format(getResources().getString(templateId),
-                    dateSeconds * TimeUnit.SECONDS.toMillis(1));
-            mImageView.setContentDescription(contentDescription);
         }
     }
 }
diff --git a/src/com/android/messaging/ui/mediapicker/GalleryMediaChooser.java b/src/com/android/messaging/ui/mediapicker/GalleryMediaChooser.java
index 8db13db..c9b544d 100644
--- a/src/com/android/messaging/ui/mediapicker/GalleryMediaChooser.java
+++ b/src/com/android/messaging/ui/mediapicker/GalleryMediaChooser.java
@@ -39,7 +39,7 @@
 import com.android.messaging.util.OsUtil;
 
 /**
- * Chooser which allows the user to select one or more existing images or videos
+ * Chooser which allows the user to select one or more existing images or videos or audios.
  */
 class GalleryMediaChooser extends MediaChooser implements
         GalleryGridView.GalleryGridViewListener, MediaPickerDataListener {
@@ -54,7 +54,9 @@
 
     @Override
     public int getSupportedMediaTypes() {
-        return MediaPicker.MEDIA_TYPE_IMAGE | MediaPicker.MEDIA_TYPE_VIDEO;
+        return (MediaPicker.MEDIA_TYPE_IMAGE
+                | MediaPicker.MEDIA_TYPE_VIDEO
+                | MediaPicker.MEDIA_TYPE_AUDIO);
     }
 
     @Override
diff --git a/tests/src/com/android/messaging/ui/mediapicker/GalleryGridItemViewTest.java b/tests/src/com/android/messaging/ui/mediapicker/GalleryGridItemViewTest.java
index 83d8ac9..304cc74 100644
--- a/tests/src/com/android/messaging/ui/mediapicker/GalleryGridItemViewTest.java
+++ b/tests/src/com/android/messaging/ui/mediapicker/GalleryGridItemViewTest.java
@@ -55,7 +55,7 @@
             final String imageUrl,
             final boolean showCheckbox,
             final boolean isSelected) {
-        final AsyncImageView imageView = (AsyncImageView) view.findViewById(R.id.image);
+        final AsyncImageView imageView = (AsyncImageView) view.findViewById(R.id.thumbnail);
         final CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox);
 
         assertNotNull(imageView);