am eba0949b: Access incoming audio files after user taps Play
* commit 'eba0949bc60e9002adf0c96044677b4c281b2819': Access incoming audio files after user taps Play
This commit is contained in:
@@ -23,6 +23,7 @@ import android.provider.MediaStore.Video.Thumbnails;
|
|||||||
|
|
||||||
import com.android.messaging.Factory;
|
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.OsUtil;
|
import com.android.messaging.util.OsUtil;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@@ -41,7 +42,7 @@ public class VideoThumbnailRequest extends ImageRequest<UriImageRequestDescripto
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldShowIncomingVideoThumbnails() {
|
public static boolean shouldShowIncomingVideoThumbnails() {
|
||||||
return OsUtil.isAtLeastM();
|
return MediaUtil.canAutoAccessIncomingMedia();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -269,7 +269,8 @@ public class AttachmentPreviewFactory {
|
|||||||
final View view = layoutInflater.inflate(layoutId, parent, false /* attachToRoot */);
|
final View view = layoutInflater.inflate(layoutId, parent, false /* attachToRoot */);
|
||||||
final AudioAttachmentView audioView = (AudioAttachmentView)
|
final AudioAttachmentView audioView = (AudioAttachmentView)
|
||||||
view.findViewById(R.id.audio_attachment_view);
|
view.findViewById(R.id.audio_attachment_view);
|
||||||
audioView.bindMessagePartData(attachmentData, false /* incoming */);
|
audioView.bindMessagePartData(
|
||||||
|
attachmentData, false /* incoming */, false /* showAsSelected */);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import com.android.messaging.ui.mediapicker.PausableChronometer;
|
|||||||
import com.android.messaging.util.Assert;
|
import com.android.messaging.util.Assert;
|
||||||
import com.android.messaging.util.ContentType;
|
import com.android.messaging.util.ContentType;
|
||||||
import com.android.messaging.util.LogUtil;
|
import com.android.messaging.util.LogUtil;
|
||||||
|
import com.android.messaging.util.MediaUtil;
|
||||||
import com.android.messaging.util.UiUtils;
|
import com.android.messaging.util.UiUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,11 +75,15 @@ public class AudioAttachmentView extends LinearLayout {
|
|||||||
private int mClipPathWidth;
|
private int mClipPathWidth;
|
||||||
private int mClipPathHeight;
|
private int mClipPathHeight;
|
||||||
|
|
||||||
// Indicates whether the attachment view is to be styled as a part of an incoming message.
|
private boolean mUseIncomingStyle;
|
||||||
private boolean mShowAsIncoming;
|
private int mThemeColor;
|
||||||
|
|
||||||
|
private boolean mStartPlayAfterPrepare;
|
||||||
|
// should the MediaPlayer be prepared lazily when the user chooses to play the audio (as
|
||||||
|
// opposed to preparing it early, on bind)
|
||||||
|
private boolean mPrepareOnPlayback;
|
||||||
private boolean mPrepared;
|
private boolean mPrepared;
|
||||||
private boolean mPlaybackFinished;
|
private boolean mPlaybackFinished; // Was the audio played all the way to the end
|
||||||
private final int mMode;
|
private final int mMode;
|
||||||
|
|
||||||
public AudioAttachmentView(final Context context, final AttributeSet attrs) {
|
public AudioAttachmentView(final Context context, final AttributeSet attrs) {
|
||||||
@@ -108,7 +113,7 @@ public class AudioAttachmentView extends LinearLayout {
|
|||||||
mPlayPauseButton.setOnClickListener(new OnClickListener() {
|
mPlayPauseButton.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final View v) {
|
public void onClick(final View v) {
|
||||||
setupMediaPlayer();
|
// Has the MediaPlayer already been prepared?
|
||||||
if (mMediaPlayer != null && mPrepared) {
|
if (mMediaPlayer != null && mPrepared) {
|
||||||
if (mMediaPlayer.isPlaying()) {
|
if (mMediaPlayer.isPlaying()) {
|
||||||
mMediaPlayer.pause();
|
mMediaPlayer.pause();
|
||||||
@@ -117,6 +122,17 @@ public class AudioAttachmentView extends LinearLayout {
|
|||||||
} else {
|
} else {
|
||||||
playAudio();
|
playAudio();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Either eager preparation is still going on (the user must have clicked
|
||||||
|
// the Play button immediately after the view is bound) or this is lazy
|
||||||
|
// preparation.
|
||||||
|
if (mStartPlayAfterPrepare) {
|
||||||
|
// The user is (starting and) pausing before the MediaPlayer is prepared
|
||||||
|
mStartPlayAfterPrepare = false;
|
||||||
|
} else {
|
||||||
|
mStartPlayAfterPrepare = true;
|
||||||
|
setupMediaPlayer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
updatePlayPauseButtonState();
|
updatePlayPauseButtonState();
|
||||||
}
|
}
|
||||||
@@ -125,26 +141,52 @@ public class AudioAttachmentView extends LinearLayout {
|
|||||||
initializeViewsForMode();
|
initializeViewsForMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateChronometerVisibility(final boolean playing) {
|
||||||
|
if (mChronometer.getVisibility() == View.GONE) {
|
||||||
|
// The chronometer is always GONE for LAYOUT_MODE_SUB_COMPACT
|
||||||
|
Assert.equals(LAYOUT_MODE_SUB_COMPACT, mMode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPrepareOnPlayback) {
|
||||||
|
// For lazy preparation, the chronometer will only be shown during playback
|
||||||
|
mChronometer.setVisibility(playing ? View.VISIBLE : View.INVISIBLE);
|
||||||
|
} else {
|
||||||
|
mChronometer.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind the audio attachment view with a MessagePartData.
|
* Bind the audio attachment view with a MessagePartData.
|
||||||
* @param incoming indicates whether the attachment view is to be styled as a part of an
|
* @param incoming indicates whether the attachment view is to be styled as a part of an
|
||||||
* incoming message.
|
* incoming message.
|
||||||
*/
|
*/
|
||||||
public void bindMessagePartData(final MessagePartData messagePartData,
|
public void bindMessagePartData(final MessagePartData messagePartData,
|
||||||
final boolean incoming) {
|
final boolean incoming, final boolean showAsSelected) {
|
||||||
Assert.isTrue(messagePartData == null ||
|
Assert.isTrue(messagePartData == null ||
|
||||||
ContentType.isAudioType(messagePartData.getContentType()));
|
ContentType.isAudioType(messagePartData.getContentType()));
|
||||||
final Uri contentUri = (messagePartData == null) ? null : messagePartData.getContentUri();
|
final Uri contentUri = (messagePartData == null) ? null : messagePartData.getContentUri();
|
||||||
bind(contentUri, incoming);
|
bind(contentUri, incoming, showAsSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bind(final Uri dataSourceUri, final boolean incoming) {
|
public void bind(
|
||||||
|
final Uri dataSourceUri, final boolean incoming, final boolean showAsSelected) {
|
||||||
final String currentUriString = (mDataSourceUri == null) ? "" : mDataSourceUri.toString();
|
final String currentUriString = (mDataSourceUri == null) ? "" : mDataSourceUri.toString();
|
||||||
final String newUriString = (dataSourceUri == null) ? "" : dataSourceUri.toString();
|
final String newUriString = (dataSourceUri == null) ? "" : dataSourceUri.toString();
|
||||||
mShowAsIncoming = incoming;
|
final int themeColor = ConversationDrawables.get().getConversationThemeColor();
|
||||||
|
final boolean useIncomingStyle = incoming || showAsSelected;
|
||||||
|
final boolean visualStyleChanged = mThemeColor != themeColor ||
|
||||||
|
mUseIncomingStyle != useIncomingStyle;
|
||||||
|
|
||||||
|
mUseIncomingStyle = useIncomingStyle;
|
||||||
|
mThemeColor = themeColor;
|
||||||
|
mPrepareOnPlayback = incoming && !MediaUtil.canAutoAccessIncomingMedia();
|
||||||
|
|
||||||
if (!TextUtils.equals(currentUriString, newUriString)) {
|
if (!TextUtils.equals(currentUriString, newUriString)) {
|
||||||
mDataSourceUri = dataSourceUri;
|
mDataSourceUri = dataSourceUri;
|
||||||
resetToZeroState();
|
resetToZeroState();
|
||||||
|
} else if (visualStyleChanged) {
|
||||||
|
updateVisualStyle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,11 +215,15 @@ public class AudioAttachmentView extends LinearLayout {
|
|||||||
releaseMediaPlayer();
|
releaseMediaPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the MediaPlayer, and if mPrepareOnPlayback, start playing the audio
|
||||||
|
*/
|
||||||
private void setupMediaPlayer() {
|
private void setupMediaPlayer() {
|
||||||
Assert.notNull(mDataSourceUri);
|
Assert.notNull(mDataSourceUri);
|
||||||
if (mMediaPlayer == null) {
|
if (mMediaPlayer == null) {
|
||||||
Assert.isTrue(!mPrepared);
|
Assert.isTrue(!mPrepared);
|
||||||
mMediaPlayer = new MediaPlayer();
|
mMediaPlayer = new MediaPlayer();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||||
mMediaPlayer.setDataSource(Factory.get().getApplicationContext(), mDataSourceUri);
|
mMediaPlayer.setDataSource(Factory.get().getApplicationContext(), mDataSourceUri);
|
||||||
@@ -188,6 +234,7 @@ public class AudioAttachmentView extends LinearLayout {
|
|||||||
mChronometer.reset();
|
mChronometer.reset();
|
||||||
mChronometer.setBase(SystemClock.elapsedRealtime() -
|
mChronometer.setBase(SystemClock.elapsedRealtime() -
|
||||||
mMediaPlayer.getDuration());
|
mMediaPlayer.getDuration());
|
||||||
|
updateChronometerVisibility(false /* playing */);
|
||||||
mProgressBar.reset();
|
mProgressBar.reset();
|
||||||
|
|
||||||
mPlaybackFinished = true;
|
mPlaybackFinished = true;
|
||||||
@@ -203,16 +250,24 @@ public class AudioAttachmentView extends LinearLayout {
|
|||||||
mProgressBar.setDuration(mMediaPlayer.getDuration());
|
mProgressBar.setDuration(mMediaPlayer.getDuration());
|
||||||
mMediaPlayer.seekTo(0);
|
mMediaPlayer.seekTo(0);
|
||||||
mPrepared = true;
|
mPrepared = true;
|
||||||
|
|
||||||
|
if (mStartPlayAfterPrepare) {
|
||||||
|
mStartPlayAfterPrepare = false;
|
||||||
|
playAudio();
|
||||||
|
updatePlayPauseButtonState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mMediaPlayer.setOnErrorListener(new OnErrorListener() {
|
mMediaPlayer.setOnErrorListener(new OnErrorListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onError(final MediaPlayer mp, final int what, final int extra) {
|
public boolean onError(final MediaPlayer mp, final int what, final int extra) {
|
||||||
|
mStartPlayAfterPrepare = false;
|
||||||
onAudioReplayError(what, extra, null);
|
onAudioReplayError(what, extra, null);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mMediaPlayer.prepareAsync();
|
mMediaPlayer.prepareAsync();
|
||||||
} catch (final Exception exception) {
|
} catch (final Exception exception) {
|
||||||
onAudioReplayError(0, 0, exception);
|
onAudioReplayError(0, 0, exception);
|
||||||
@@ -226,13 +281,17 @@ public class AudioAttachmentView extends LinearLayout {
|
|||||||
mMediaPlayer.release();
|
mMediaPlayer.release();
|
||||||
mMediaPlayer = null;
|
mMediaPlayer = null;
|
||||||
mPrepared = false;
|
mPrepared = false;
|
||||||
|
mStartPlayAfterPrepare = false;
|
||||||
mPlaybackFinished = false;
|
mPlaybackFinished = false;
|
||||||
|
mChronometer.reset();
|
||||||
|
mProgressBar.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDetachedFromWindow() {
|
protected void onDetachedFromWindow() {
|
||||||
super.onDetachedFromWindow();
|
super.onDetachedFromWindow();
|
||||||
|
// The view must have scrolled off. Stop playback.
|
||||||
releaseMediaPlayer();
|
releaseMediaPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,22 +317,23 @@ public class AudioAttachmentView extends LinearLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updatePlayPauseButtonState() {
|
private void updatePlayPauseButtonState() {
|
||||||
if (mMediaPlayer == null || !mMediaPlayer.isPlaying()) {
|
final boolean playing = mMediaPlayer != null && mMediaPlayer.isPlaying();
|
||||||
mPlayPauseButton.setDisplayedChild(PLAY_BUTTON);
|
updateChronometerVisibility(playing);
|
||||||
} else {
|
if (mStartPlayAfterPrepare || playing) {
|
||||||
mPlayPauseButton.setDisplayedChild(PAUSE_BUTTON);
|
mPlayPauseButton.setDisplayedChild(PAUSE_BUTTON);
|
||||||
|
} else {
|
||||||
|
mPlayPauseButton.setDisplayedChild(PLAY_BUTTON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetToZeroState() {
|
private void resetToZeroState() {
|
||||||
// Release the media player so it may be set up with the new audio source.
|
// Release the media player so it may be set up with the new audio source.
|
||||||
releaseMediaPlayer();
|
releaseMediaPlayer();
|
||||||
mChronometer.reset();
|
|
||||||
mProgressBar.reset();
|
|
||||||
updateVisualStyle();
|
updateVisualStyle();
|
||||||
|
updateChronometerVisibility(false /* playing */);
|
||||||
|
|
||||||
if (mDataSourceUri != null) {
|
if (mDataSourceUri != null && !mPrepareOnPlayback) {
|
||||||
// Re-ensure the media player, so we can read the duration of the audio.
|
// Prepare the media player, so we can read the duration of the audio.
|
||||||
setupMediaPlayer();
|
setupMediaPlayer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,13 +344,13 @@ public class AudioAttachmentView extends LinearLayout {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mShowAsIncoming) {
|
if (mUseIncomingStyle) {
|
||||||
mChronometer.setTextColor(getResources().getColor(R.color.message_text_color_incoming));
|
mChronometer.setTextColor(getResources().getColor(R.color.message_text_color_incoming));
|
||||||
} else {
|
} else {
|
||||||
mChronometer.setTextColor(getResources().getColor(R.color.message_text_color_outgoing));
|
mChronometer.setTextColor(getResources().getColor(R.color.message_text_color_outgoing));
|
||||||
}
|
}
|
||||||
mProgressBar.setVisualStyle(mShowAsIncoming);
|
mProgressBar.setVisualStyle(mUseIncomingStyle);
|
||||||
mPlayPauseButton.setVisualStyle(mShowAsIncoming);
|
mPlayPauseButton.setVisualStyle(mUseIncomingStyle);
|
||||||
updatePlayPauseButtonState();
|
updatePlayPauseButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1110,7 +1110,7 @@ public class ConversationMessageView extends FrameLayout implements View.OnClick
|
|||||||
@Override
|
@Override
|
||||||
public void bindView(final View view, final MessagePartData attachment) {
|
public void bindView(final View view, final MessagePartData attachment) {
|
||||||
final AudioAttachmentView audioView = (AudioAttachmentView) view;
|
final AudioAttachmentView audioView = (AudioAttachmentView) view;
|
||||||
audioView.bindMessagePartData(attachment, isSelected() || mData.getIsIncoming());
|
audioView.bindMessagePartData(attachment, mData.getIsIncoming(), isSelected());
|
||||||
audioView.setBackground(ConversationDrawables.get().getBubbleDrawable(
|
audioView.setBackground(ConversationDrawables.get().getBubbleDrawable(
|
||||||
isSelected(), mData.getIsIncoming(), false /* needArrow */,
|
isSelected(), mData.getIsIncoming(), false /* needArrow */,
|
||||||
mData.hasIncomingErrorStatus()));
|
mData.hasIncomingErrorStatus()));
|
||||||
@@ -1118,7 +1118,7 @@ public class ConversationMessageView extends FrameLayout implements View.OnClick
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unbind(final View view) {
|
public void unbind(final View view) {
|
||||||
((AudioAttachmentView) view).bindMessagePartData(null, mData.getIsIncoming());
|
((AudioAttachmentView) view).bindMessagePartData(null, mData.getIsIncoming(), false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -465,7 +465,8 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
|
|||||||
int audioPreviewVisiblity = GONE;
|
int audioPreviewVisiblity = GONE;
|
||||||
if (previewUri != null && !TextUtils.isEmpty(previewContentType)) {
|
if (previewUri != null && !TextUtils.isEmpty(previewContentType)) {
|
||||||
if (ContentType.isAudioType(previewContentType)) {
|
if (ContentType.isAudioType(previewContentType)) {
|
||||||
mAudioAttachmentView.bind(previewUri, false);
|
boolean incoming = !(mData.getShowDraft() || mData.getIsMessageTypeOutgoing());
|
||||||
|
mAudioAttachmentView.bind(previewUri, incoming, false);
|
||||||
audioPreviewVisiblity = VISIBLE;
|
audioPreviewVisiblity = VISIBLE;
|
||||||
} else if (ContentType.isVideoType(previewContentType)) {
|
} else if (ContentType.isVideoType(previewContentType)) {
|
||||||
previewImageUri = UriUtil.getUriForResourceId(
|
previewImageUri = UriUtil.getUriForResourceId(
|
||||||
|
|||||||
@@ -33,4 +33,8 @@ public abstract class MediaUtil {
|
|||||||
*/
|
*/
|
||||||
public abstract void playSound(final Context context, final int resId,
|
public abstract void playSound(final Context context, final int resId,
|
||||||
final OnCompletionListener completionListener);
|
final OnCompletionListener completionListener);
|
||||||
|
|
||||||
|
public static boolean canAutoAccessIncomingMedia() {
|
||||||
|
return OsUtil.isAtLeastM();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user