summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
diff options
context:
space:
mode:
authoruabdullah <uabdullah@google.com>2017-12-11 15:20:15 -0800
committerCopybara-Service <copybara-piper@google.com>2017-12-11 15:23:08 -0800
commit1fab0cca2259a7f8dd0b4349bc38f282eb4209a8 (patch)
treea677be3a11bd33ba9aa9903cc868ec607fc213f4 /java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
parentc875a5b7630376c767d86b708e4aab8382de8acc (diff)
Play voicemails, update seekbar timer, allow seeking, and maintain state after recycling.
This CL adds the support for playing voicemails, changing the play button to pause button when playing the voicemail, updating the seekbar and duration timer when the voicemail is being played. It also adds the support to preserve the state of the media player such that when scrolling and recycling views, when an expanded and playing voicemail is recycled back into view, it's most recent state is shown i.e the duration and the seekbar are upto date. Video: https://drive.google.com/open?id=1CKbLK5-1YDeXBZFiKvuTxoPuFJQ1rbj7 Test: Unit tests PiperOrigin-RevId: 178681663 Change-Id: Ifdd1d945572926bdc7d652aa7a876d3156fc21ce
Diffstat (limited to 'java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java')
-rw-r--r--java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java258
1 files changed, 236 insertions, 22 deletions
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
index f08e6bfd7..02b05db03 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
@@ -15,17 +15,22 @@
*/
package com.android.dialer.voicemail.listui;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
import android.app.FragmentManager;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
-import android.support.annotation.VisibleForTesting;
+import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.QuickContactBadge;
import android.widget.TextView;
+import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog;
+import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.lettertile.LetterTileDrawable;
@@ -44,6 +49,8 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
private final Clock clock;
private boolean isViewHolderExpanded;
private int viewHolderId;
+ private VoicemailEntry voicemailEntryOfViewHolder;
+ @NonNull private Uri viewHolderVoicemailUri;
private final NewVoicemailViewHolderListener voicemailViewHolderListener;
NewVoicemailViewHolder(
@@ -58,19 +65,45 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
mediaPlayerView = view.findViewById(R.id.new_voicemail_media_player);
this.clock = clock;
voicemailViewHolderListener = newVoicemailViewHolderListener;
+
+ viewHolderId = -1;
+ isViewHolderExpanded = false;
+ viewHolderVoicemailUri = null;
}
- void bind(Cursor cursor, FragmentManager fragmentManager) {
- VoicemailEntry voicemailEntry = VoicemailCursorLoader.toVoicemailEntry(cursor);
- viewHolderId = voicemailEntry.id();
- primaryTextView.setText(VoicemailEntryText.buildPrimaryVoicemailText(context, voicemailEntry));
+ /**
+ * When the {@link RecyclerView} displays voicemail entries, it might recycle the views upon
+ * scrolling. In that case we need to ensure that the member variables of this {@link
+ * NewVoicemailViewHolder} and its views are correctly set, especially when this {@link
+ * NewVoicemailViewHolder} is recycled.
+ *
+ * @param cursor the voicemail data from {@link AnnotatedCallLog} generated by the {@link
+ * VoicemailCursorLoader} related
+ * @param fragmentManager FragmentManager retrieved from {@link
+ * NewVoicemailFragment#getActivity()}
+ * @param mediaPlayer
+ * @param position the position of the item within the adapter's data set.
+ * @param currentlyExpandedViewHolderId the value the adapter keeps track of which viewholder if
+ */
+ void bindViewHolderValuesFromAdapter(
+ Cursor cursor,
+ FragmentManager fragmentManager,
+ NewVoicemailMediaPlayer mediaPlayer,
+ int position,
+ int currentlyExpandedViewHolderId) {
+
+ voicemailEntryOfViewHolder = VoicemailCursorLoader.toVoicemailEntry(cursor);
+ viewHolderId = voicemailEntryOfViewHolder.id();
+ viewHolderVoicemailUri = Uri.parse(voicemailEntryOfViewHolder.voicemailUri());
+ primaryTextView.setText(
+ VoicemailEntryText.buildPrimaryVoicemailText(context, voicemailEntryOfViewHolder));
secondaryTextView.setText(
- VoicemailEntryText.buildSecondaryVoicemailText(context, clock, voicemailEntry));
+ VoicemailEntryText.buildSecondaryVoicemailText(context, clock, voicemailEntryOfViewHolder));
- String voicemailTranscription = voicemailEntry.transcription();
+ String voicemailTranscription = voicemailEntryOfViewHolder.transcription();
if (TextUtils.isEmpty(voicemailTranscription)) {
- transcriptionTextView.setVisibility(View.GONE);
+ transcriptionTextView.setVisibility(GONE);
transcriptionTextView.setText(null);
} else {
transcriptionTextView.setVisibility(View.VISIBLE);
@@ -78,9 +111,49 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
}
itemView.setOnClickListener(this);
- setPhoto(voicemailEntry);
- mediaPlayerView.setVoicemailEntryValues(voicemailEntry);
- mediaPlayerView.setFragmentManager(fragmentManager);
+ setPhoto(voicemailEntryOfViewHolder);
+
+ // Update the expanded/collapsed state of this view holder
+ // Only update the binding of the mediaPlayerView of the expanded view holder
+ if (viewHolderId == currentlyExpandedViewHolderId) {
+ LogUtil.i(
+ "NewVoicemailViewHolder.bindViewHolderValuesFromAdapter",
+ "viewHolderId:%d is expanded, update its mediaplayer view",
+ viewHolderId);
+ expandAndBindViewHolderAndMediaPlayerViewWithAdapterValues(
+ voicemailEntryOfViewHolder, fragmentManager, mediaPlayer, voicemailViewHolderListener);
+ LogUtil.i(
+ "NewVoicemailViewHolder.bindViewHolderValuesFromAdapter",
+ "After 2nd updating the MPPlayerView: viewHolderId:%d, uri:%s, MediaplayerView(after "
+ + "updated):%s, adapter position passed down:%d, getAdapterPos:%d",
+ viewHolderId,
+ String.valueOf(viewHolderVoicemailUri),
+ String.valueOf(mediaPlayerView.getVoicemailUri()),
+ position,
+ getAdapterPosition());
+ Assert.checkArgument(
+ mediaPlayerView.getVisibility() == VISIBLE,
+ "a expanded viewholder should have its media player view visible");
+ } else {
+ LogUtil.i(
+ "NewVoicemailViewHolder.bindViewHolderValuesFromAdapter",
+ "viewHolderId:%d is not the expanded one, collapse it and don't update the MpView",
+ viewHolderId);
+ collapseViewHolder();
+ Assert.checkArgument(
+ mediaPlayerView.getVisibility() == GONE,
+ "a collapsed viewholder should not have its media player view visible");
+ }
+ LogUtil.i(
+ "NewVoicemailViewHolder.bindViewHolderValuesFromAdapter",
+ "Final value after updating: viewHolderId:%d, uri:%s, MediaplayerView(not updated):%s,"
+ + " adapter position passed down:%d, getAdapterPos:%d, MPPlayerVisibility:%b",
+ viewHolderId,
+ String.valueOf(viewHolderVoicemailUri),
+ String.valueOf(mediaPlayerView.getVoicemailUri()),
+ position,
+ getAdapterPosition(),
+ mediaPlayerView.getVisibility() == VISIBLE);
}
// TODO(uabdullah): Consider/Implement TYPE (e.g Spam, TYPE_VOICEMAIL)
@@ -96,19 +169,148 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
}
void collapseViewHolder() {
+ LogUtil.i(
+ "NewVoicemailViewHolder.collapseViewHolder",
+ "viewHolderId:%d is being collapsed, its MPViewUri:%s, its Uri is :%s",
+ viewHolderId,
+ String.valueOf(mediaPlayerView.getVoicemailUri()),
+ String.valueOf(viewHolderVoicemailUri));
transcriptionTextView.setMaxLines(1);
isViewHolderExpanded = false;
- mediaPlayerView.setVisibility(View.GONE);
+ mediaPlayerView.setVisibility(GONE);
+ }
+
+ // When we are recycling the views ensure that we reset the viewHolder, as if its brand new
+ public void reset() {
+ LogUtil.i(
+ "NewVoicemailViewHolder.reset()",
+ "Reset the viewholder, currently viewHolderId:%d, uri:%s, isViewHolderExpanded:%b, "
+ + "its MediaPlayerViewUri:%s",
+ viewHolderId,
+ String.valueOf(viewHolderVoicemailUri),
+ isViewHolderExpanded,
+ String.valueOf(mediaPlayerView.getVoicemailUri()));
+
+ viewHolderId = -1;
+ isViewHolderExpanded = false;
+ viewHolderVoicemailUri = null;
+
+ mediaPlayerView.reset();
+
+ LogUtil.i(
+ "NewVoicemailViewHolder.reset()",
+ "Reset the viewholder, after resetting viewHolderId:%d, uri:%s, isViewHolderExpanded:%b",
+ viewHolderId,
+ String.valueOf(viewHolderVoicemailUri),
+ isViewHolderExpanded);
}
- void expandViewHolder() {
- LogUtil.i("NewVoicemailViewHolder.expandViewHolder", "voicemail id: %d", viewHolderId);
+ /**
+ * Is only called when a user either clicks a {@link NewVoicemailViewHolder} to expand it or if
+ * the user had already expanded, then scrolled the {@link NewVoicemailViewHolder} out of view and
+ * then scrolled it back into view, and during the binding (as the views are recyled in {@link
+ * RecyclerView}) we restore the expanded state of the {@link NewVoicemailViewHolder}.
+ *
+ * <p>This function also tracks if the state of this viewholder is expanded.
+ *
+ * @param voicemailEntry are the voicemail related values from the {@link AnnotatedCallLog}
+ * @param fragmentManager FragmentManager retrieved from {@link
+ * NewVoicemailFragment#getActivity()}
+ * @param mediaPlayer there should only be one instance of this passed down from the {@link
+ * NewVoicemailAdapter}
+ * @param voicemailViewHolderListener
+ */
+ void expandAndBindViewHolderAndMediaPlayerViewWithAdapterValues(
+ VoicemailEntry voicemailEntry,
+ FragmentManager fragmentManager,
+ NewVoicemailMediaPlayer mediaPlayer,
+ NewVoicemailViewHolderListener voicemailViewHolderListener) {
+
+ Assert.isNotNull(voicemailViewHolderListener);
+ Assert.checkArgument(
+ voicemailEntry.id() == viewHolderId, "ensure that the adapter binding has taken place");
+ Assert.checkArgument(
+ Uri.parse(voicemailEntry.voicemailUri()).equals(viewHolderVoicemailUri),
+ "ensure that the adapter binding has taken place");
+ LogUtil.i(
+ "NewVoicemailViewHolder.expandAndBindViewHolderAndMediaPlayerViewWithAdapterValues",
+ "voicemail id: %d, value of isViewHolderExpanded:%b, before setting it to be true, and"
+ + " value of ViewholderUri:%s, MPView:%s, before updating it",
+ viewHolderId,
+ isViewHolderExpanded,
+ String.valueOf(viewHolderVoicemailUri),
+ String.valueOf(mediaPlayerView.getVoicemailUri()));
+
transcriptionTextView.setMaxLines(999);
isViewHolderExpanded = true;
+ // Once the media player is visible update its state
mediaPlayerView.setVisibility(View.VISIBLE);
+ mediaPlayerView.bindValuesFromAdapterOfExpandedViewHolderMediaPlayerView(
+ this, voicemailEntry, fragmentManager, mediaPlayer, voicemailViewHolderListener);
+ LogUtil.i(
+ "NewVoicemailViewHolder.expandAndBindViewHolderAndMediaPlayerViewWithAdapterValues",
+ "voicemail id: %d, value of isViewHolderExpanded:%b, after setting it to be true, and"
+ + " value of ViewholderUri:%s, MPView:%s, after updating it",
+ viewHolderId,
+ isViewHolderExpanded,
+ String.valueOf(viewHolderVoicemailUri),
+ String.valueOf(mediaPlayerView.getVoicemailUri()));
+ }
+
+ /**
+ * Called when we want to update the voicemail that is currently playing Updates the Seekbar,
+ * duration timer and the play/pause button visibility when the expanded voicemail is being
+ * played.
+ */
+ public void updateMediaPlayerViewWithPlayingState(
+ NewVoicemailViewHolder newVoicemailViewHolder, NewVoicemailMediaPlayer mp) {
+
+ LogUtil.i(
+ "NewVoicemailViewHolder.updateMediaPlayerViewWithPlayingState",
+ "viewholderUri:%s, mediaPlayerViewUri:%s, MPPosition:%d, MpDuration:%d, MpIsPlaying:%b",
+ newVoicemailViewHolder.getViewHolderVoicemailUri().toString(),
+ mediaPlayerView.getVoicemailUri().toString(),
+ mp.getCurrentPosition(),
+ mp.getDuration(),
+ mp.isPlaying());
+
+ Assert.checkArgument(
+ mp.isPlaying(),
+ "this method is only called when we are certain that the media player is playing");
+
+ LogUtil.i(
+ "NewVoicemailViewHolder.updateMediaPlayerViewWithPlayingState",
+ "viewholderUri:%s, mediaPlayerViewUri:%s",
+ newVoicemailViewHolder.getViewHolderVoicemailUri().toString(),
+ mediaPlayerView.getVoicemailUri().toString());
+ Assert.checkArgument(
+ newVoicemailViewHolder
+ .getViewHolderVoicemailUri()
+ .equals(mediaPlayerView.getVoicemailUri()),
+ "the mediaplayer view must be that of the viewholder we are updating");
+ Assert.checkArgument(
+ mp.getLastPlayedOrPlayingVoicemailUri()
+ .equals(mp.getLastPreparedOrPreparingToPlayVoicemailUri()),
+ "the media player view we are attempting to update should be of the "
+ + "currently prepared and playing voicemail");
+
+ mediaPlayerView.updateSeekBarDurationAndShowPlayButton(mp);
+ }
+
+ public void setMediaPlayerViewToResetState(
+ NewVoicemailViewHolder currentlyExpandedViewHolderOnScreen,
+ NewVoicemailMediaPlayer mediaPlayer) {
+ Assert.isNotNull(currentlyExpandedViewHolderOnScreen);
+ mediaPlayerView.setToResetState(currentlyExpandedViewHolderOnScreen, mediaPlayer);
+ }
+
+ public void setPausedStateOfMediaPlayerView(Uri uri, NewVoicemailMediaPlayer mediaPlayer) {
+ Assert.checkArgument(viewHolderVoicemailUri.equals(uri));
+ Assert.checkArgument(mediaPlayerView.getVoicemailUri().equals(uri));
+ Assert.checkArgument(mediaPlayerView.getVoicemailUri().equals(viewHolderVoicemailUri));
+ mediaPlayerView.setToPausedState(uri, mediaPlayer);
}
- @VisibleForTesting(otherwise = VisibleForTesting.NONE)
boolean isViewHolderExpanded() {
return isViewHolderExpanded;
}
@@ -117,25 +319,37 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
return viewHolderId;
}
+ public Uri getViewHolderVoicemailUri() {
+ return viewHolderVoicemailUri;
+ }
+
interface NewVoicemailViewHolderListener {
- void onViewHolderExpanded(NewVoicemailViewHolder expandedViewHolder);
+ void expandViewHolderFirstTimeAndCollapseAllOtherVisibleViewHolders(
+ NewVoicemailViewHolder expandedViewHolder,
+ VoicemailEntry voicemailEntryOfViewHolder,
+ NewVoicemailViewHolderListener listener);
+
+ void collapseExpandedViewHolder(NewVoicemailViewHolder expandedViewHolder);
- void onViewHolderCollapsed(NewVoicemailViewHolder expandedViewHolder);
+ void pauseViewHolder(NewVoicemailViewHolder expandedViewHolder);
+
+ void resumePausedViewHolder(NewVoicemailViewHolder expandedViewHolder);
}
@Override
public void onClick(View v) {
LogUtil.i(
"NewVoicemailViewHolder.onClick",
- "voicemail id: %d, isViewHolderExpanded:%b",
+ "voicemail id: %d, isViewHolderCurrentlyExpanded:%b",
viewHolderId,
isViewHolderExpanded);
if (isViewHolderExpanded) {
- collapseViewHolder();
- voicemailViewHolderListener.onViewHolderCollapsed(this);
+ voicemailViewHolderListener.collapseExpandedViewHolder(this);
} else {
- expandViewHolder();
- voicemailViewHolderListener.onViewHolderExpanded(this);
+ voicemailViewHolderListener.expandViewHolderFirstTimeAndCollapseAllOtherVisibleViewHolders(
+ this,
+ Assert.isNotNull(voicemailEntryOfViewHolder),
+ Assert.isNotNull(voicemailViewHolderListener));
}
}
}