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:
Shri Borde
2015-08-21 19:58:12 +00:00
committed by Android Git Automerger
6 changed files with 90 additions and 23 deletions

View File

@@ -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

View File

@@ -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;
} }

View File

@@ -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();
} }

View File

@@ -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);
} }
}; };

View File

@@ -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(

View File

@@ -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();
}
} }