Support video attachments through GalleryMediaChooser am: 6c77158718 am: 98391bc0d1
Change-Id: Ib883cd3e8b798795cb5ce2dbb7fb8a4a96038027
This commit is contained in:
@@ -43,4 +43,14 @@
|
|||||||
android:paddingTop="4dp"
|
android:paddingTop="4dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:contentDescription="@string/gallery_checkbox_content_description" />
|
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>
|
</com.android.messaging.ui.mediapicker.GalleryGridItemView>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
<string name="mediapicker_cameraChooserDescription">Capture pictures or video</string>
|
<string name="mediapicker_cameraChooserDescription">Capture pictures or video</string>
|
||||||
<string name="mediapicker_galleryChooserDescription">Choose images from this device</string>
|
<string name="mediapicker_galleryChooserDescription">Choose images from this device</string>
|
||||||
<string name="mediapicker_audioChooserDescription">Record audio</string>
|
<string name="mediapicker_audioChooserDescription">Record audio</string>
|
||||||
<string name="mediapicker_gallery_title">Choose photo</string>
|
<string name="mediapicker_gallery_title">Choose media</string>
|
||||||
<string name="mediapicker_gallery_item_selected_content_description">The media is selected.</string>
|
<string name="mediapicker_gallery_item_selected_content_description">The media is selected.</string>
|
||||||
<string name="mediapicker_gallery_item_unselected_content_description">The media is unselected.</string>
|
<string name="mediapicker_gallery_item_unselected_content_description">The media is unselected.</string>
|
||||||
<string name="mediapicker_gallery_title_selection"><xliff:g id="count">%d</xliff:g> selected</string>
|
<string name="mediapicker_gallery_title_selection"><xliff:g id="count">%d</xliff:g> selected</string>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import android.content.Context;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.MediaStore.Files;
|
import android.provider.MediaStore.Files;
|
||||||
import android.provider.MediaStore.Files.FileColumns;
|
import android.provider.MediaStore.Files.FileColumns;
|
||||||
import android.provider.MediaStore.Images.Media;
|
import android.provider.MediaStore.MediaColumns;
|
||||||
|
|
||||||
import com.android.messaging.datamodel.data.GalleryGridItemData;
|
import com.android.messaging.datamodel.data.GalleryGridItemData;
|
||||||
import com.android.messaging.datamodel.data.MessagePartData;
|
import com.android.messaging.datamodel.data.MessagePartData;
|
||||||
@@ -32,18 +32,18 @@ import com.google.common.base.Joiner;
|
|||||||
public class GalleryBoundCursorLoader extends BoundCursorLoader {
|
public class GalleryBoundCursorLoader extends BoundCursorLoader {
|
||||||
public static final String MEDIA_SCANNER_VOLUME_EXTERNAL = "external";
|
public static final String MEDIA_SCANNER_VOLUME_EXTERNAL = "external";
|
||||||
private static final Uri STORAGE_URI = Files.getContentUri(MEDIA_SCANNER_VOLUME_EXTERNAL);
|
private static final Uri STORAGE_URI = Files.getContentUri(MEDIA_SCANNER_VOLUME_EXTERNAL);
|
||||||
private static final String SORT_ORDER = Media.DATE_MODIFIED + " DESC";
|
private static final String SORT_ORDER = MediaColumns.DATE_MODIFIED + " DESC";
|
||||||
private static final String IMAGE_SELECTION = createSelection(
|
private static final String SELECTION = createSelection(
|
||||||
MessagePartData.ACCEPTABLE_IMAGE_TYPES,
|
MessagePartData.ACCEPTABLE_GALLERY_MEDIA_TYPES,
|
||||||
new Integer[] { FileColumns.MEDIA_TYPE_IMAGE });
|
new Integer[] {FileColumns.MEDIA_TYPE_IMAGE, FileColumns.MEDIA_TYPE_VIDEO});
|
||||||
|
|
||||||
public GalleryBoundCursorLoader(final String bindingId, final Context context) {
|
public GalleryBoundCursorLoader(final String bindingId, final Context context) {
|
||||||
super(bindingId, context, STORAGE_URI, GalleryGridItemData.IMAGE_PROJECTION,
|
super(bindingId, context, STORAGE_URI, GalleryGridItemData.MEDIA_PROJECTION, SELECTION,
|
||||||
IMAGE_SELECTION, null, SORT_ORDER);
|
null, SORT_ORDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String createSelection(final String[] mimeTypes, Integer[] mediaTypes) {
|
private static String createSelection(final String[] mimeTypes, Integer[] mediaTypes) {
|
||||||
return Media.MIME_TYPE + " IN ('" + Joiner.on("','").join(mimeTypes) + "') AND "
|
return MediaColumns.MIME_TYPE + " IN ('" + Joiner.on("','").join(mimeTypes) + "') AND "
|
||||||
+ FileColumns.MEDIA_TYPE + " IN (" + Joiner.on(',').join(mediaTypes) + ")";
|
+ FileColumns.MEDIA_TYPE + " IN (" + Joiner.on(',').join(mediaTypes) + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,25 +20,27 @@ import android.database.Cursor;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.BaseColumns;
|
import android.provider.BaseColumns;
|
||||||
import android.provider.MediaStore.Images.Media;
|
import android.provider.MediaStore.MediaColumns;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.android.messaging.datamodel.media.FileImageRequestDescriptor;
|
import com.android.messaging.datamodel.media.FileImageRequestDescriptor;
|
||||||
import com.android.messaging.datamodel.media.ImageRequest;
|
import com.android.messaging.datamodel.media.ImageRequest;
|
||||||
import com.android.messaging.datamodel.media.UriImageRequestDescriptor;
|
import com.android.messaging.datamodel.media.UriImageRequestDescriptor;
|
||||||
|
import com.android.messaging.datamodel.media.VideoThumbnailRequestDescriptor;
|
||||||
import com.android.messaging.util.Assert;
|
import com.android.messaging.util.Assert;
|
||||||
|
import com.android.messaging.util.ContentType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides data for GalleryGridItemView
|
* Provides data for GalleryGridItemView
|
||||||
*/
|
*/
|
||||||
public class GalleryGridItemData {
|
public class GalleryGridItemData {
|
||||||
public static final String[] IMAGE_PROJECTION = new String[] {
|
public static final String[] MEDIA_PROJECTION = new String[] {
|
||||||
Media._ID,
|
MediaColumns._ID,
|
||||||
Media.DATA,
|
MediaColumns.DATA,
|
||||||
Media.WIDTH,
|
MediaColumns.WIDTH,
|
||||||
Media.HEIGHT,
|
MediaColumns.HEIGHT,
|
||||||
Media.MIME_TYPE,
|
MediaColumns.MIME_TYPE,
|
||||||
Media.DATE_MODIFIED};
|
MediaColumns.DATE_MODIFIED};
|
||||||
|
|
||||||
public static final String[] SPECIAL_ITEM_COLUMNS = new String[] {
|
public static final String[] SPECIAL_ITEM_COLUMNS = new String[] {
|
||||||
BaseColumns._ID
|
BaseColumns._ID
|
||||||
@@ -46,14 +48,14 @@ public class GalleryGridItemData {
|
|||||||
|
|
||||||
private static final int INDEX_ID = 0;
|
private static final int INDEX_ID = 0;
|
||||||
|
|
||||||
// For local image gallery.
|
// For local media gallery.
|
||||||
private static final int INDEX_DATA_PATH = 1;
|
private static final int INDEX_DATA_PATH = 1;
|
||||||
private static final int INDEX_WIDTH = 2;
|
private static final int INDEX_WIDTH = 2;
|
||||||
private static final int INDEX_HEIGHT = 3;
|
private static final int INDEX_HEIGHT = 3;
|
||||||
private static final int INDEX_MIME_TYPE = 4;
|
private static final int INDEX_MIME_TYPE = 4;
|
||||||
private static final int INDEX_DATE_MODIFIED = 5;
|
private static final int INDEX_DATE_MODIFIED = 5;
|
||||||
|
|
||||||
/** A special item's id for picking images from document picker */
|
/** A special item's id for picking a media from document picker */
|
||||||
public static final String ID_DOCUMENT_PICKER_ITEM = "-1";
|
public static final String ID_DOCUMENT_PICKER_ITEM = "-1";
|
||||||
|
|
||||||
private UriImageRequestDescriptor mImageData;
|
private UriImageRequestDescriptor mImageData;
|
||||||
@@ -85,15 +87,24 @@ public class GalleryGridItemData {
|
|||||||
mContentType = cursor.getString(INDEX_MIME_TYPE);
|
mContentType = cursor.getString(INDEX_MIME_TYPE);
|
||||||
final String dateModified = cursor.getString(INDEX_DATE_MODIFIED);
|
final String dateModified = cursor.getString(INDEX_DATE_MODIFIED);
|
||||||
mDateSeconds = !TextUtils.isEmpty(dateModified) ? Long.parseLong(dateModified) : -1;
|
mDateSeconds = !TextUtils.isEmpty(dateModified) ? Long.parseLong(dateModified) : -1;
|
||||||
mImageData = new FileImageRequestDescriptor(
|
if (ContentType.isVideoType(mContentType)) {
|
||||||
cursor.getString(INDEX_DATA_PATH),
|
mImageData = new VideoThumbnailRequestDescriptor(
|
||||||
desiredWidth,
|
cursor.getLong(INDEX_ID),
|
||||||
desiredHeight,
|
desiredWidth,
|
||||||
sourceWidth,
|
desiredHeight,
|
||||||
sourceHeight,
|
sourceWidth,
|
||||||
true /* canUseThumbnail */,
|
sourceHeight);
|
||||||
true /* allowCompression */,
|
} else {
|
||||||
true /* isStatic */);
|
mImageData = new FileImageRequestDescriptor(
|
||||||
|
cursor.getString(INDEX_DATA_PATH),
|
||||||
|
desiredWidth,
|
||||||
|
desiredHeight,
|
||||||
|
sourceWidth,
|
||||||
|
sourceHeight,
|
||||||
|
true /* canUseThumbnail */,
|
||||||
|
true /* allowCompression */,
|
||||||
|
true /* isStatic */);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class MediaPickerData extends BindableData {
|
|||||||
mGalleryLoaderCallbacks = new GalleryLoaderCallbacks();
|
mGalleryLoaderCallbacks = new GalleryLoaderCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final int GALLERY_IMAGE_LOADER = 1;
|
public static final int GALLERY_MEDIA_LOADER = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A trampoline class so that we can inherit from LoaderManager.LoaderCallbacks multiple times.
|
* A trampoline class so that we can inherit from LoaderManager.LoaderCallbacks multiple times.
|
||||||
@@ -63,7 +63,7 @@ public class MediaPickerData extends BindableData {
|
|||||||
// Check if data still bound to the requesting ui element
|
// Check if data still bound to the requesting ui element
|
||||||
if (isBound(bindingId)) {
|
if (isBound(bindingId)) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case GALLERY_IMAGE_LOADER:
|
case GALLERY_MEDIA_LOADER:
|
||||||
return new GalleryBoundCursorLoader(bindingId, mContext);
|
return new GalleryBoundCursorLoader(bindingId, mContext);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -84,9 +84,9 @@ public class MediaPickerData extends BindableData {
|
|||||||
final BoundCursorLoader cursorLoader = (BoundCursorLoader) loader;
|
final BoundCursorLoader cursorLoader = (BoundCursorLoader) loader;
|
||||||
if (isBound(cursorLoader.getBindingId())) {
|
if (isBound(cursorLoader.getBindingId())) {
|
||||||
switch (loader.getId()) {
|
switch (loader.getId()) {
|
||||||
case GALLERY_IMAGE_LOADER:
|
case GALLERY_MEDIA_LOADER:
|
||||||
mListener.onMediaPickerDataUpdated(MediaPickerData.this, data,
|
mListener.onMediaPickerDataUpdated(MediaPickerData.this, data,
|
||||||
GALLERY_IMAGE_LOADER);
|
GALLERY_MEDIA_LOADER);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -106,9 +106,9 @@ public class MediaPickerData extends BindableData {
|
|||||||
final BoundCursorLoader cursorLoader = (BoundCursorLoader) loader;
|
final BoundCursorLoader cursorLoader = (BoundCursorLoader) loader;
|
||||||
if (isBound(cursorLoader.getBindingId())) {
|
if (isBound(cursorLoader.getBindingId())) {
|
||||||
switch (loader.getId()) {
|
switch (loader.getId()) {
|
||||||
case GALLERY_IMAGE_LOADER:
|
case GALLERY_MEDIA_LOADER:
|
||||||
mListener.onMediaPickerDataUpdated(MediaPickerData.this, null,
|
mListener.onMediaPickerDataUpdated(MediaPickerData.this, null,
|
||||||
GALLERY_IMAGE_LOADER);
|
GALLERY_MEDIA_LOADER);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -129,7 +129,7 @@ public class MediaPickerData extends BindableData {
|
|||||||
args = new Bundle();
|
args = new Bundle();
|
||||||
}
|
}
|
||||||
args.putString(BINDING_ID, binding.getBindingId());
|
args.putString(BINDING_ID, binding.getBindingId());
|
||||||
if (loaderId == GALLERY_IMAGE_LOADER) {
|
if (loaderId == GALLERY_MEDIA_LOADER) {
|
||||||
mLoaderManager.initLoader(loaderId, args, mGalleryLoaderCallbacks).forceLoad();
|
mLoaderManager.initLoader(loaderId, args, mGalleryLoaderCallbacks).forceLoad();
|
||||||
} else {
|
} else {
|
||||||
Assert.fail("Unsupported loader id for media picker!");
|
Assert.fail("Unsupported loader id for media picker!");
|
||||||
@@ -149,7 +149,7 @@ public class MediaPickerData extends BindableData {
|
|||||||
protected void unregisterListeners() {
|
protected void unregisterListeners() {
|
||||||
// This could be null if we bind but the caller doesn't init the BindableData
|
// This could be null if we bind but the caller doesn't init the BindableData
|
||||||
if (mLoaderManager != null) {
|
if (mLoaderManager != null) {
|
||||||
mLoaderManager.destroyLoader(GALLERY_IMAGE_LOADER);
|
mLoaderManager.destroyLoader(GALLERY_MEDIA_LOADER);
|
||||||
mLoaderManager = null;
|
mLoaderManager = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,9 +52,17 @@ import java.util.concurrent.TimeUnit;
|
|||||||
*/
|
*/
|
||||||
public class MessagePartData implements Parcelable {
|
public class MessagePartData implements Parcelable {
|
||||||
public static final int UNSPECIFIED_SIZE = MessagingContentProvider.UNSPECIFIED_SIZE;
|
public static final int UNSPECIFIED_SIZE = MessagingContentProvider.UNSPECIFIED_SIZE;
|
||||||
public static final String[] ACCEPTABLE_IMAGE_TYPES =
|
|
||||||
new String[] { ContentType.IMAGE_JPEG, ContentType.IMAGE_JPG, ContentType.IMAGE_PNG,
|
public static final String[] ACCEPTABLE_GALLERY_MEDIA_TYPES =
|
||||||
ContentType.IMAGE_GIF };
|
new String[] {
|
||||||
|
// Acceptable image types
|
||||||
|
ContentType.IMAGE_JPEG, ContentType.IMAGE_JPG, ContentType.IMAGE_PNG,
|
||||||
|
ContentType.IMAGE_GIF, ContentType.IMAGE_WBMP, ContentType.IMAGE_X_MS_BMP,
|
||||||
|
// 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
|
||||||
|
};
|
||||||
|
|
||||||
private static final String[] sProjection = {
|
private static final String[] sProjection = {
|
||||||
PartColumns._ID,
|
PartColumns._ID,
|
||||||
|
|||||||
@@ -87,9 +87,4 @@ public class UriImageRequestDescriptor extends ImageRequestDescriptor {
|
|||||||
return new NetworkUriImageRequest<UriImageRequestDescriptor>(context, this);
|
return new NetworkUriImageRequest<UriImageRequestDescriptor>(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ID of the resource in MediaStore or null if this resource didn't come from MediaStore */
|
|
||||||
public Long getMediaStoreId() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -16,15 +16,11 @@
|
|||||||
|
|
||||||
package com.android.messaging.datamodel.media;
|
package com.android.messaging.datamodel.media;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.provider.MediaStore.Video.Thumbnails;
|
|
||||||
|
|
||||||
import com.android.messaging.Factory;
|
|
||||||
import com.android.messaging.util.MediaMetadataRetrieverWrapper;
|
import com.android.messaging.util.MediaMetadataRetrieverWrapper;
|
||||||
import com.android.messaging.util.MediaUtil;
|
import com.android.messaging.util.MediaUtil;
|
||||||
import com.android.messaging.util.OsUtil;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -57,19 +53,15 @@ public class VideoThumbnailRequest extends ImageRequest<UriImageRequestDescripto
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Bitmap getBitmapForResource() throws IOException {
|
protected Bitmap getBitmapForResource() throws IOException {
|
||||||
final Long mediaId = mDescriptor.getMediaStoreId();
|
|
||||||
Bitmap bitmap = null;
|
Bitmap bitmap = null;
|
||||||
if (mediaId != null) {
|
// Get a thumbnail through MediaMetadataRetriever to get a representative frame at any time
|
||||||
final ContentResolver cr = Factory.get().getApplicationContext().getContentResolver();
|
// position instead.
|
||||||
bitmap = Thumbnails.getThumbnail(cr, mediaId, Thumbnails.MICRO_KIND, null);
|
final MediaMetadataRetrieverWrapper retriever = new MediaMetadataRetrieverWrapper();
|
||||||
} else {
|
try {
|
||||||
final MediaMetadataRetrieverWrapper retriever = new MediaMetadataRetrieverWrapper();
|
retriever.setDataSource(mDescriptor.uri);
|
||||||
try {
|
bitmap = retriever.getFrameAtTime();
|
||||||
retriever.setDataSource(mDescriptor.uri);
|
} finally {
|
||||||
bitmap = retriever.getFrameAtTime();
|
retriever.release();
|
||||||
} finally {
|
|
||||||
retriever.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (bitmap != null) {
|
if (bitmap != null) {
|
||||||
mDescriptor.updateSourceDimensions(bitmap.getWidth(), bitmap.getHeight());
|
mDescriptor.updateSourceDimensions(bitmap.getWidth(), bitmap.getHeight());
|
||||||
|
|||||||
@@ -21,24 +21,17 @@ import com.android.messaging.util.ImageUtils;
|
|||||||
import com.android.messaging.util.UriUtil;
|
import com.android.messaging.util.UriUtil;
|
||||||
|
|
||||||
public class VideoThumbnailRequestDescriptor extends UriImageRequestDescriptor {
|
public class VideoThumbnailRequestDescriptor extends UriImageRequestDescriptor {
|
||||||
protected final long mMediaId;
|
public VideoThumbnailRequestDescriptor(final long id, int desiredWidth, int desiredHeight,
|
||||||
public VideoThumbnailRequestDescriptor(final long id, String path, int desiredWidth,
|
int sourceWidth, int sourceHeight) {
|
||||||
int desiredHeight, int sourceWidth, int sourceHeight) {
|
super(UriUtil.getContentUriForMediaStoreId(id), desiredWidth, desiredHeight, sourceWidth,
|
||||||
super(UriUtil.getUriForResourceFile(path), desiredWidth, desiredHeight, sourceWidth,
|
|
||||||
sourceHeight, false /* canCompress */, false /* isStatic */,
|
sourceHeight, false /* canCompress */, false /* isStatic */,
|
||||||
false /* cropToCircle */,
|
false /* cropToCircle */,
|
||||||
ImageUtils.DEFAULT_CIRCLE_BACKGROUND_COLOR /* circleBackgroundColor */,
|
ImageUtils.DEFAULT_CIRCLE_BACKGROUND_COLOR /* circleBackgroundColor */,
|
||||||
ImageUtils.DEFAULT_CIRCLE_STROKE_COLOR /* circleStrokeColor */);
|
ImageUtils.DEFAULT_CIRCLE_STROKE_COLOR /* circleStrokeColor */);
|
||||||
mMediaId = id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MediaRequest<ImageResource> buildSyncMediaRequest(Context context) {
|
public MediaRequest<ImageResource> buildSyncMediaRequest(Context context) {
|
||||||
return new VideoThumbnailRequest(context, this);
|
return new VideoThumbnailRequest(context, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long getMediaStoreId() {
|
|
||||||
return mMediaId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ public abstract class UIIntents {
|
|||||||
// Sending draft data (from share intent / message forwarding) to the ConversationActivity.
|
// Sending draft data (from share intent / message forwarding) to the ConversationActivity.
|
||||||
public static final String UI_INTENT_EXTRA_DRAFT_DATA = "draft_data";
|
public static final String UI_INTENT_EXTRA_DRAFT_DATA = "draft_data";
|
||||||
|
|
||||||
// The request code for picking image from the Document picker.
|
// The request code for picking a media from the Document picker.
|
||||||
public static final int REQUEST_PICK_IMAGE_FROM_DOCUMENT_PICKER = 1400;
|
public static final int REQUEST_PICK_MEDIA_FROM_DOCUMENT_PICKER = 1400;
|
||||||
|
|
||||||
// Indicates what type of notification this applies to (See BugleNotifications:
|
// Indicates what type of notification this applies to (See BugleNotifications:
|
||||||
// UPDATE_NONE, UPDATE_MESSAGES, UPDATE_ERRORS, UPDATE_ALL)
|
// UPDATE_NONE, UPDATE_MESSAGES, UPDATE_ERRORS, UPDATE_ALL)
|
||||||
@@ -166,7 +166,8 @@ public abstract class UIIntents {
|
|||||||
public abstract void launchAddContactActivity(final Context context, final String destination);
|
public abstract void launchAddContactActivity(final Context context, final String destination);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch an activity to show the document picker to pick an image.
|
* Launch an activity to show the document picker to pick an image/video.
|
||||||
|
*
|
||||||
* @param fragment the requesting fragment
|
* @param fragment the requesting fragment
|
||||||
*/
|
*/
|
||||||
public abstract void launchDocumentImagePicker(final Fragment fragment);
|
public abstract void launchDocumentImagePicker(final Fragment fragment);
|
||||||
|
|||||||
@@ -236,11 +236,11 @@ public class UIIntentsImpl extends UIIntents {
|
|||||||
@Override
|
@Override
|
||||||
public void launchDocumentImagePicker(final Fragment fragment) {
|
public void launchDocumentImagePicker(final Fragment fragment) {
|
||||||
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, MessagePartData.ACCEPTABLE_IMAGE_TYPES);
|
intent.putExtra(Intent.EXTRA_MIME_TYPES, MessagePartData.ACCEPTABLE_GALLERY_MEDIA_TYPES);
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
intent.setType(ContentType.IMAGE_UNSPECIFIED);
|
intent.setType(ContentType.ANY_TYPE);
|
||||||
|
|
||||||
fragment.startActivityForResult(intent, REQUEST_PICK_IMAGE_FROM_DOCUMENT_PICKER);
|
fragment.startActivityForResult(intent, REQUEST_PICK_MEDIA_FROM_DOCUMENT_PICKER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ import com.android.messaging.util.ImageUtils;
|
|||||||
import com.android.messaging.util.SafeAsyncTask;
|
import com.android.messaging.util.SafeAsyncTask;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps around the functionalities to allow the user to pick images from the document
|
* Wraps around the functionalities to allow the user to pick an image/video from the document
|
||||||
* picker. Instances of this class must be tied to a Fragment which is able to delegate activity
|
* picker. Instances of this class must be tied to a Fragment which is able to delegate activity
|
||||||
* result callbacks.
|
* result callbacks.
|
||||||
*/
|
*/
|
||||||
public class DocumentImagePicker {
|
public class DocumentImagePicker {
|
||||||
@@ -79,8 +79,8 @@ public class DocumentImagePicker {
|
|||||||
* Must be called from the fragment/activity's onActivityResult().
|
* Must be called from the fragment/activity's onActivityResult().
|
||||||
*/
|
*/
|
||||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||||
if (requestCode == UIIntents.REQUEST_PICK_IMAGE_FROM_DOCUMENT_PICKER &&
|
if (requestCode == UIIntents.REQUEST_PICK_MEDIA_FROM_DOCUMENT_PICKER
|
||||||
resultCode == Activity.RESULT_OK) {
|
&& resultCode == Activity.RESULT_OK) {
|
||||||
// Sometimes called after media item has been picked from the document picker.
|
// Sometimes called after media item has been picked from the document picker.
|
||||||
String url = data.getStringExtra(EXTRA_PHOTO_URL);
|
String url = data.getStringExtra(EXTRA_PHOTO_URL);
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
|
|||||||
@@ -24,13 +24,14 @@ import android.view.TouchDelegate;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView.ScaleType;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import com.android.messaging.R;
|
import com.android.messaging.R;
|
||||||
import com.android.messaging.datamodel.DataModel;
|
import com.android.messaging.datamodel.DataModel;
|
||||||
import com.android.messaging.datamodel.data.GalleryGridItemData;
|
import com.android.messaging.datamodel.data.GalleryGridItemData;
|
||||||
import com.android.messaging.ui.AsyncImageView;
|
import com.android.messaging.ui.AsyncImageView;
|
||||||
import com.android.messaging.ui.ConversationDrawables;
|
import com.android.messaging.ui.ConversationDrawables;
|
||||||
|
import com.android.messaging.util.ContentType;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -135,17 +136,24 @@ public class GalleryGridItemView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateImageView() {
|
private void updateImageView() {
|
||||||
|
ImageView playButton = (ImageView) findViewById(R.id.video_thumbnail_play_button);
|
||||||
if (mData.isDocumentPickerItem()) {
|
if (mData.isDocumentPickerItem()) {
|
||||||
mImageView.setScaleType(ScaleType.CENTER);
|
mImageView.setScaleType(ImageView.ScaleType.CENTER);
|
||||||
setBackgroundColor(ConversationDrawables.get().getConversationThemeColor());
|
setBackgroundColor(ConversationDrawables.get().getConversationThemeColor());
|
||||||
mImageView.setImageResourceId(null);
|
mImageView.setImageResourceId(null);
|
||||||
mImageView.setImageResource(R.drawable.ic_photo_library_light);
|
mImageView.setImageResource(R.drawable.ic_photo_library_light);
|
||||||
|
playButton.setVisibility(GONE);
|
||||||
mImageView.setContentDescription(getResources().getString(
|
mImageView.setContentDescription(getResources().getString(
|
||||||
R.string.pick_image_from_document_library_content_description));
|
R.string.pick_image_from_document_library_content_description));
|
||||||
} else {
|
} else {
|
||||||
mImageView.setScaleType(ScaleType.CENTER_CROP);
|
mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||||
setBackgroundColor(getResources().getColor(R.color.gallery_image_default_background));
|
setBackgroundColor(getResources().getColor(R.color.gallery_image_default_background));
|
||||||
mImageView.setImageResourceId(mData.getImageRequestDescriptor());
|
mImageView.setImageResourceId(mData.getImageRequestDescriptor());
|
||||||
|
if (ContentType.isVideoType(mData.getContentType())) {
|
||||||
|
playButton.setVisibility(VISIBLE);
|
||||||
|
} else {
|
||||||
|
playButton.setVisibility(GONE);
|
||||||
|
}
|
||||||
final long dateSeconds = mData.getDateSeconds();
|
final long dateSeconds = mData.getDateSeconds();
|
||||||
final boolean isValidDate = (dateSeconds > 0);
|
final boolean isValidDate = (dateSeconds > 0);
|
||||||
final int templateId = isValidDate ?
|
final int templateId = isValidDate ?
|
||||||
|
|||||||
@@ -43,16 +43,16 @@ import java.util.Iterator;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a list of galley images from external storage in a GridView with multi-select
|
* Shows a list of galley mediae from external storage in a GridView with multi-select capabilities,
|
||||||
* capabilities, and with the option to intent out to a standalone image picker.
|
* and with the option to intent out to a standalone media picker.
|
||||||
*/
|
*/
|
||||||
public class GalleryGridView extends MediaPickerGridView implements
|
public class GalleryGridView extends MediaPickerGridView implements
|
||||||
GalleryGridItemView.HostInterface,
|
GalleryGridItemView.HostInterface,
|
||||||
PersistentInstanceState,
|
PersistentInstanceState,
|
||||||
DraftMessageDataListener {
|
DraftMessageDataListener {
|
||||||
/**
|
/**
|
||||||
* Implemented by the owner of this GalleryGridView instance to communicate on image
|
* Implemented by the owner of this GalleryGridView instance to communicate on media picking and
|
||||||
* picking and multi-image selection events.
|
* multi-media selection events.
|
||||||
*/
|
*/
|
||||||
public interface GalleryGridViewListener {
|
public interface GalleryGridViewListener {
|
||||||
void onDocumentPickerItemClicked();
|
void onDocumentPickerItemClicked();
|
||||||
@@ -127,7 +127,7 @@ public class GalleryGridView extends MediaPickerGridView implements
|
|||||||
final MessagePartData item = mSelectedImages.remove(data.getImageUri());
|
final MessagePartData item = mSelectedImages.remove(data.getImageUri());
|
||||||
mListener.onItemUnselected(item);
|
mListener.onItemUnselected(item);
|
||||||
if (mSelectedImages.size() == 0) {
|
if (mSelectedImages.size() == 0) {
|
||||||
// No image is selected any more, turn off multi-select mode.
|
// No media is selected any more, turn off multi-select mode.
|
||||||
setMultiSelectEnabled(false);
|
setMultiSelectEnabled(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class GalleryMediaChooser extends MediaChooser implements
|
|||||||
mAdapter.setHostInterface(null);
|
mAdapter.setHostInterface(null);
|
||||||
// The loader is started only if startMediaPickerDataLoader() is called
|
// The loader is started only if startMediaPickerDataLoader() is called
|
||||||
if (OsUtil.hasStoragePermission()) {
|
if (OsUtil.hasStoragePermission()) {
|
||||||
mBindingRef.getData().destroyLoader(MediaPickerData.GALLERY_IMAGE_LOADER);
|
mBindingRef.getData().destroyLoader(MediaPickerData.GALLERY_MEDIA_LOADER);
|
||||||
}
|
}
|
||||||
return super.destroyView();
|
return super.destroyView();
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,7 @@ class GalleryMediaChooser extends MediaChooser implements
|
|||||||
protected View createView(final ViewGroup container) {
|
protected View createView(final ViewGroup container) {
|
||||||
final LayoutInflater inflater = getLayoutInflater();
|
final LayoutInflater inflater = getLayoutInflater();
|
||||||
final View view = inflater.inflate(
|
final View view = inflater.inflate(
|
||||||
R.layout.mediapicker_image_chooser,
|
R.layout.mediapicker_gallery_chooser,
|
||||||
container /* root */,
|
container /* root */,
|
||||||
false /* attachToRoot */);
|
false /* attachToRoot */);
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ class GalleryMediaChooser extends MediaChooser implements
|
|||||||
public void onMediaPickerDataUpdated(final MediaPickerData mediaPickerData, final Object data,
|
public void onMediaPickerDataUpdated(final MediaPickerData mediaPickerData, final Object data,
|
||||||
final int loaderId) {
|
final int loaderId) {
|
||||||
mBindingRef.ensureBound(mediaPickerData);
|
mBindingRef.ensureBound(mediaPickerData);
|
||||||
Assert.equals(MediaPickerData.GALLERY_IMAGE_LOADER, loaderId);
|
Assert.equals(MediaPickerData.GALLERY_MEDIA_LOADER, loaderId);
|
||||||
Cursor rawCursor = null;
|
Cursor rawCursor = null;
|
||||||
if (data instanceof Cursor) {
|
if (data instanceof Cursor) {
|
||||||
rawCursor = (Cursor) data;
|
rawCursor = (Cursor) data;
|
||||||
@@ -202,8 +202,9 @@ class GalleryMediaChooser extends MediaChooser implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startMediaPickerDataLoader() {
|
private void startMediaPickerDataLoader() {
|
||||||
mBindingRef.getData().startLoader(MediaPickerData.GALLERY_IMAGE_LOADER, mBindingRef, null,
|
mBindingRef
|
||||||
this);
|
.getData()
|
||||||
|
.startLoader(MediaPickerData.GALLERY_MEDIA_LOADER, mBindingRef, null, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ public class MediaPicker extends Fragment implements DraftMessageSubscriptionDat
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final Binding<MediaPickerData> mBinding = BindingBase.createBinding(this);
|
final Binding<MediaPickerData> mBinding = BindingBase.createBinding(this);
|
||||||
|
|
||||||
/** Handles picking image from the document picker */
|
/** Handles picking a media from the document picker. */
|
||||||
private DocumentImagePicker mDocumentImagePicker;
|
private DocumentImagePicker mDocumentImagePicker;
|
||||||
|
|
||||||
/** Provides subscription-related data to access per-subscription configurations. */
|
/** Provides subscription-related data to access per-subscription configurations. */
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import androidx.annotation.NonNull;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.android.messaging.Factory;
|
import com.android.messaging.Factory;
|
||||||
|
import com.android.messaging.datamodel.GalleryBoundCursorLoader;
|
||||||
import com.android.messaging.datamodel.MediaScratchFileProvider;
|
import com.android.messaging.datamodel.MediaScratchFileProvider;
|
||||||
import com.android.messaging.util.Assert.DoesNotRunOnMainThread;
|
import com.android.messaging.util.Assert.DoesNotRunOnMainThread;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
@@ -129,6 +130,18 @@ public class UriUtil {
|
|||||||
TextUtils.equals(MEDIA_STORE_URI_KLP, uriAuthority));
|
TextUtils.equals(MEDIA_STORE_URI_KLP, uriAuthority));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the content:// style URI for the given MediaStore row Id in the files table on the
|
||||||
|
* external volume.
|
||||||
|
*
|
||||||
|
* @param id the MediaStore row Id to get the URI for
|
||||||
|
* @return the URI to the files table on the external storage.
|
||||||
|
*/
|
||||||
|
public static Uri getContentUriForMediaStoreId(final long id) {
|
||||||
|
return MediaStore.Files.getContentUri(
|
||||||
|
GalleryBoundCursorLoader.MEDIA_SCANNER_VOLUME_EXTERNAL, id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the size in bytes for the content uri. Currently we only support content in the
|
* Gets the size in bytes for the content uri. Currently we only support content in the
|
||||||
* scratch space.
|
* scratch space.
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ public class TestDataFactory {
|
|||||||
new Object[] { Long.valueOf(1), "/sdcard/image2", 200, 200, "image/png" },
|
new Object[] { Long.valueOf(1), "/sdcard/image2", 200, 200, "image/png" },
|
||||||
new Object[] { Long.valueOf(2), "/sdcard/image3", 300, 300, "image/jpeg" },
|
new Object[] { Long.valueOf(2), "/sdcard/image3", 300, 300, "image/jpeg" },
|
||||||
};
|
};
|
||||||
return new FakeCursor(GalleryGridItemData.IMAGE_PROJECTION, sGalleryCursorColumns,
|
return new FakeCursor(GalleryGridItemData.MEDIA_PROJECTION, sGalleryCursorColumns,
|
||||||
cursorData);
|
cursorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ public class MediaPickerTest extends FragmentTestCase<MediaPicker> {
|
|||||||
public void testDefaultTabs() {
|
public void testDefaultTabs() {
|
||||||
Mockito.when(mMockMediaPickerData.getSelectedChooserIndex()).thenReturn(0);
|
Mockito.when(mMockMediaPickerData.getSelectedChooserIndex()).thenReturn(0);
|
||||||
initFragment(MediaPicker.MEDIA_TYPE_ALL, new Integer[] {
|
initFragment(MediaPicker.MEDIA_TYPE_ALL, new Integer[] {
|
||||||
MediaPickerData.GALLERY_IMAGE_LOADER },
|
MediaPickerData.GALLERY_MEDIA_LOADER },
|
||||||
false);
|
false);
|
||||||
final MediaPicker mediaPicker = getFragment();
|
final MediaPicker mediaPicker = getFragment();
|
||||||
final View view = mediaPicker.getView();
|
final View view = mediaPicker.getView();
|
||||||
@@ -114,7 +114,7 @@ public class MediaPickerTest extends FragmentTestCase<MediaPicker> {
|
|||||||
public void testFilterTabsBeforeAttach() {
|
public void testFilterTabsBeforeAttach() {
|
||||||
Mockito.when(mMockMediaPickerData.getSelectedChooserIndex()).thenReturn(0);
|
Mockito.when(mMockMediaPickerData.getSelectedChooserIndex()).thenReturn(0);
|
||||||
initFragment(MediaPicker.MEDIA_TYPE_IMAGE, new Integer[] {
|
initFragment(MediaPicker.MEDIA_TYPE_IMAGE, new Integer[] {
|
||||||
MediaPickerData.GALLERY_IMAGE_LOADER },
|
MediaPickerData.GALLERY_MEDIA_LOADER },
|
||||||
true);
|
true);
|
||||||
final MediaPicker mediaPicker = getFragment();
|
final MediaPicker mediaPicker = getFragment();
|
||||||
final View view = mediaPicker.getView();
|
final View view = mediaPicker.getView();
|
||||||
|
|||||||
Reference in New Issue
Block a user