Messaging: Use ActivityResultContracts for media and contacts
Instead of handling showing and picking the media ourselves, use existing AcitivityResultContracts to pick images, videos or contacts Change-Id: I20079ad94882cc6bbfeae8d57ca0e4aa30612c01
This commit is contained in:
@@ -36,7 +36,6 @@ import com.android.messaging.datamodel.data.ConversationData.ConversationDataLis
|
||||
import com.android.messaging.datamodel.data.ConversationListData;
|
||||
import com.android.messaging.datamodel.data.ConversationListData.ConversationListDataListener;
|
||||
import com.android.messaging.datamodel.data.DraftMessageData;
|
||||
import com.android.messaging.datamodel.data.GalleryGridItemData;
|
||||
import com.android.messaging.datamodel.data.LaunchConversationData;
|
||||
import com.android.messaging.datamodel.data.LaunchConversationData.LaunchConversationDataListener;
|
||||
import com.android.messaging.datamodel.data.MediaPickerData;
|
||||
@@ -81,8 +80,6 @@ public abstract class DataModel {
|
||||
|
||||
public abstract MediaPickerData createMediaPickerData(final Context context);
|
||||
|
||||
public abstract GalleryGridItemData createGalleryGridItemData();
|
||||
|
||||
public abstract LaunchConversationData createLaunchConversationData(
|
||||
LaunchConversationDataListener listener);
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ import com.android.messaging.datamodel.data.ConversationData.ConversationDataLis
|
||||
import com.android.messaging.datamodel.data.ConversationListData;
|
||||
import com.android.messaging.datamodel.data.ConversationListData.ConversationListDataListener;
|
||||
import com.android.messaging.datamodel.data.DraftMessageData;
|
||||
import com.android.messaging.datamodel.data.GalleryGridItemData;
|
||||
import com.android.messaging.datamodel.data.LaunchConversationData;
|
||||
import com.android.messaging.datamodel.data.LaunchConversationData.LaunchConversationDataListener;
|
||||
import com.android.messaging.datamodel.data.MediaPickerData;
|
||||
@@ -113,11 +112,6 @@ public class DataModelImpl extends DataModel {
|
||||
return new MediaPickerData(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GalleryGridItemData createGalleryGridItemData() {
|
||||
return new GalleryGridItemData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchConversationData createLaunchConversationData(
|
||||
final LaunchConversationDataListener listener) {
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.messaging.datamodel;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.provider.MediaStore.Files;
|
||||
import android.provider.MediaStore.Files.FileColumns;
|
||||
import android.provider.MediaStore.MediaColumns;
|
||||
|
||||
import com.android.messaging.datamodel.data.GalleryGridItemData;
|
||||
import com.android.messaging.datamodel.data.MessagePartData;
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
/**
|
||||
* A BoundCursorLoader that reads local media on the device.
|
||||
*/
|
||||
public class GalleryBoundCursorLoader extends BoundCursorLoader {
|
||||
public static final String MEDIA_SCANNER_VOLUME_EXTERNAL = "external";
|
||||
private static final Uri STORAGE_URI = Files.getContentUri(MEDIA_SCANNER_VOLUME_EXTERNAL);
|
||||
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,
|
||||
FileColumns.MEDIA_TYPE_AUDIO
|
||||
});
|
||||
|
||||
public GalleryBoundCursorLoader(final String bindingId, final Context context) {
|
||||
super(bindingId, context, STORAGE_URI, GalleryGridItemData.MEDIA_PROJECTION, SELECTION,
|
||||
null, SORT_ORDER);
|
||||
}
|
||||
|
||||
private static String createSelection(final String[] mimeTypes, Integer[] mediaTypes) {
|
||||
return MediaColumns.MIME_TYPE + " IN ('" + Joiner.on("','").join(mimeTypes) + "') AND "
|
||||
+ FileColumns.MEDIA_TYPE + " IN (" + Joiner.on(',').join(mediaTypes) + ")";
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.messaging.datamodel.data;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
import android.provider.MediaStore.MediaColumns;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.messaging.datamodel.media.FileImageRequestDescriptor;
|
||||
import com.android.messaging.datamodel.media.ImageRequest;
|
||||
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.ContentType;
|
||||
import com.android.messaging.util.UriUtil;
|
||||
|
||||
/**
|
||||
* Provides data for GalleryGridItemView
|
||||
*/
|
||||
public class GalleryGridItemData {
|
||||
public static final String[] MEDIA_PROJECTION = new String[] {
|
||||
MediaColumns._ID,
|
||||
MediaColumns.DATA,
|
||||
MediaColumns.WIDTH,
|
||||
MediaColumns.HEIGHT,
|
||||
MediaColumns.MIME_TYPE,
|
||||
MediaColumns.DATE_MODIFIED,
|
||||
MediaColumns.DISPLAY_NAME};
|
||||
|
||||
public static final String[] SPECIAL_ITEM_COLUMNS = new String[] {
|
||||
BaseColumns._ID
|
||||
};
|
||||
|
||||
private static final int INDEX_ID = 0;
|
||||
|
||||
// For local media gallery.
|
||||
private static final int INDEX_DATA_PATH = 1;
|
||||
private static final int INDEX_WIDTH = 2;
|
||||
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";
|
||||
|
||||
private UriImageRequestDescriptor mImageData;
|
||||
private String mContentType;
|
||||
private boolean mIsDocumentPickerItem;
|
||||
private long mDateSeconds;
|
||||
private String mFileName;
|
||||
private Uri mAudioUri;
|
||||
|
||||
public GalleryGridItemData() {
|
||||
}
|
||||
|
||||
public void bind(final Cursor cursor, final int desiredWidth, final int desiredHeight) {
|
||||
mIsDocumentPickerItem = TextUtils.equals(cursor.getString(INDEX_ID),
|
||||
ID_DOCUMENT_PICKER_ITEM);
|
||||
if (mIsDocumentPickerItem) {
|
||||
mImageData = null;
|
||||
mContentType = null;
|
||||
} else {
|
||||
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.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 */);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDocumentPickerItem() {
|
||||
return mIsDocumentPickerItem;
|
||||
}
|
||||
|
||||
public Uri getImageUri() {
|
||||
return ContentType.isAudioType(mContentType) ? mAudioUri : mImageData.uri;
|
||||
}
|
||||
|
||||
public UriImageRequestDescriptor getImageRequestDescriptor() {
|
||||
return mImageData;
|
||||
}
|
||||
|
||||
public MessagePartData constructMessagePartData(final Rect startRect) {
|
||||
Assert.isTrue(!mIsDocumentPickerItem);
|
||||
return ContentType.isAudioType(mContentType)
|
||||
? new MediaPickerMessagePartData(startRect, mContentType, mAudioUri, 0, 0)
|
||||
: new MediaPickerMessagePartData(startRect, mContentType, mImageData.uri,
|
||||
mImageData.sourceWidth, mImageData.sourceHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The date in seconds. This can be negative if we could not retreive date info
|
||||
*/
|
||||
public long getDateSeconds() {
|
||||
return mDateSeconds;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return mContentType;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return mFileName;
|
||||
}
|
||||
}
|
||||
@@ -18,144 +18,19 @@
|
||||
package com.android.messaging.datamodel.data;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
|
||||
import com.android.messaging.datamodel.BoundCursorLoader;
|
||||
import com.android.messaging.datamodel.GalleryBoundCursorLoader;
|
||||
import com.android.messaging.datamodel.binding.BindableData;
|
||||
import com.android.messaging.datamodel.binding.BindingBase;
|
||||
import com.android.messaging.util.Assert;
|
||||
import com.android.messaging.util.BuglePrefs;
|
||||
import com.android.messaging.util.BuglePrefsKeys;
|
||||
import com.android.messaging.util.LogUtil;
|
||||
|
||||
/**
|
||||
* Services data needs for MediaPicker.
|
||||
*/
|
||||
public class MediaPickerData extends BindableData {
|
||||
public interface MediaPickerDataListener {
|
||||
void onMediaPickerDataUpdated(MediaPickerData mediaPickerData, Object data, int loaderId);
|
||||
}
|
||||
|
||||
private static final String BINDING_ID = "bindingId";
|
||||
private final Context mContext;
|
||||
private LoaderManager mLoaderManager;
|
||||
private final GalleryLoaderCallbacks mGalleryLoaderCallbacks;
|
||||
private MediaPickerDataListener mListener;
|
||||
|
||||
public MediaPickerData(final Context context) {
|
||||
mContext = context;
|
||||
mGalleryLoaderCallbacks = new GalleryLoaderCallbacks();
|
||||
}
|
||||
|
||||
public static final int GALLERY_MEDIA_LOADER = 1;
|
||||
|
||||
/**
|
||||
* A trampoline class so that we can inherit from LoaderManager.LoaderCallbacks multiple times.
|
||||
*/
|
||||
private class GalleryLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
@NonNull
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
|
||||
final String bindingId = args.getString(BINDING_ID);
|
||||
// Check if data still bound to the requesting ui element
|
||||
if (isBound(bindingId)) {
|
||||
switch (id) {
|
||||
case GALLERY_MEDIA_LOADER:
|
||||
return new GalleryBoundCursorLoader(bindingId, mContext);
|
||||
|
||||
default:
|
||||
Assert.fail("Unknown loader id for gallery picker!");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LogUtil.w(LogUtil.BUGLE_TAG, "Loader created after unbinding the media picker");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onLoadFinished(@NonNull final Loader<Cursor> loader, final Cursor data) {
|
||||
final BoundCursorLoader cursorLoader = (BoundCursorLoader) loader;
|
||||
if (isBound(cursorLoader.getBindingId())) {
|
||||
switch (loader.getId()) {
|
||||
case GALLERY_MEDIA_LOADER:
|
||||
mListener.onMediaPickerDataUpdated(MediaPickerData.this, data,
|
||||
GALLERY_MEDIA_LOADER);
|
||||
break;
|
||||
|
||||
default:
|
||||
Assert.fail("Unknown loader id for gallery picker!");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LogUtil.w(LogUtil.BUGLE_TAG, "Loader finished after unbinding the media picker");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onLoaderReset(@NonNull final Loader<Cursor> loader) {
|
||||
final BoundCursorLoader cursorLoader = (BoundCursorLoader) loader;
|
||||
if (isBound(cursorLoader.getBindingId())) {
|
||||
switch (loader.getId()) {
|
||||
case GALLERY_MEDIA_LOADER:
|
||||
mListener.onMediaPickerDataUpdated(MediaPickerData.this, null,
|
||||
GALLERY_MEDIA_LOADER);
|
||||
break;
|
||||
|
||||
default:
|
||||
Assert.fail("Unknown loader id for media picker!");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LogUtil.w(LogUtil.BUGLE_TAG, "Loader reset after unbinding the media picker");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void startLoader(final int loaderId, final BindingBase<MediaPickerData> binding,
|
||||
@Nullable Bundle args, final MediaPickerDataListener listener) {
|
||||
if (args == null) {
|
||||
args = new Bundle();
|
||||
}
|
||||
args.putString(BINDING_ID, binding.getBindingId());
|
||||
if (loaderId == GALLERY_MEDIA_LOADER) {
|
||||
mLoaderManager.initLoader(loaderId, args, mGalleryLoaderCallbacks).forceLoad();
|
||||
} else {
|
||||
Assert.fail("Unsupported loader id for media picker!");
|
||||
}
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public void destroyLoader(final int loaderId) {
|
||||
mLoaderManager.destroyLoader(loaderId);
|
||||
}
|
||||
|
||||
public void init(final LoaderManager loaderManager) {
|
||||
mLoaderManager = loaderManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterListeners() {
|
||||
// This could be null if we bind but the caller doesn't init the BindableData
|
||||
if (mLoaderManager != null) {
|
||||
mLoaderManager.destroyLoader(GALLERY_MEDIA_LOADER);
|
||||
mLoaderManager = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,4 +51,8 @@ public class MediaPickerData extends BindableData {
|
||||
selectedIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterListeners() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.messaging.datamodel.media;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.messaging.util.ImageUtils;
|
||||
import com.android.messaging.util.UriUtil;
|
||||
|
||||
public class VideoThumbnailRequestDescriptor extends UriImageRequestDescriptor {
|
||||
public VideoThumbnailRequestDescriptor(final long id, int desiredWidth, int desiredHeight,
|
||||
int sourceWidth, int sourceHeight) {
|
||||
super(UriUtil.getContentUriForMediaStoreId(id), desiredWidth, desiredHeight, sourceWidth,
|
||||
sourceHeight, false /* canCompress */, false /* isStatic */,
|
||||
false /* cropToCircle */,
|
||||
ImageUtils.DEFAULT_CIRCLE_BACKGROUND_COLOR /* circleBackgroundColor */,
|
||||
ImageUtils.DEFAULT_CIRCLE_STROKE_COLOR /* circleStrokeColor */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaRequest<ImageResource> buildSyncMediaRequest(Context context) {
|
||||
return new VideoThumbnailRequest(context, this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user