blob: 02b05db03b05c6a99c299371ec17fdafc0ff4cf9 [file] [log] [blame]
/*
* Copyright (C) 2017 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.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.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;
import com.android.dialer.time.Clock;
import com.android.dialer.voicemail.model.VoicemailEntry;
/** {@link RecyclerView.ViewHolder} for the new voicemail tab. */
final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
private final Context context;
private final TextView primaryTextView;
private final TextView secondaryTextView;
private final TextView transcriptionTextView;
private final QuickContactBadge quickContactBadge;
private final NewVoicemailMediaPlayerView mediaPlayerView;
private final Clock clock;
private boolean isViewHolderExpanded;
private int viewHolderId;
private VoicemailEntry voicemailEntryOfViewHolder;
@NonNull private Uri viewHolderVoicemailUri;
private final NewVoicemailViewHolderListener voicemailViewHolderListener;
NewVoicemailViewHolder(
View view, Clock clock, NewVoicemailViewHolderListener newVoicemailViewHolderListener) {
super(view);
LogUtil.enterBlock("NewVoicemailViewHolder");
this.context = view.getContext();
primaryTextView = view.findViewById(R.id.primary_text);
secondaryTextView = view.findViewById(R.id.secondary_text);
transcriptionTextView = view.findViewById(R.id.transcription_text);
quickContactBadge = view.findViewById(R.id.quick_contact_photo);
mediaPlayerView = view.findViewById(R.id.new_voicemail_media_player);
this.clock = clock;
voicemailViewHolderListener = newVoicemailViewHolderListener;
viewHolderId = -1;
isViewHolderExpanded = false;
viewHolderVoicemailUri = null;
}
/**
* 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, voicemailEntryOfViewHolder));
String voicemailTranscription = voicemailEntryOfViewHolder.transcription();
if (TextUtils.isEmpty(voicemailTranscription)) {
transcriptionTextView.setVisibility(GONE);
transcriptionTextView.setText(null);
} else {
transcriptionTextView.setVisibility(View.VISIBLE);
transcriptionTextView.setText(voicemailTranscription);
}
itemView.setOnClickListener(this);
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)
private void setPhoto(VoicemailEntry voicemailEntry) {
ContactPhotoManager.getInstance(context)
.loadDialerThumbnailOrPhoto(
quickContactBadge,
voicemailEntry.lookupUri() == null ? null : Uri.parse(voicemailEntry.lookupUri()),
voicemailEntry.photoId(),
voicemailEntry.photoUri() == null ? null : Uri.parse(voicemailEntry.photoUri()),
voicemailEntry.name(),
LetterTileDrawable.TYPE_DEFAULT);
}
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(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);
}
/**
* 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);
}
boolean isViewHolderExpanded() {
return isViewHolderExpanded;
}
public int getViewHolderId() {
return viewHolderId;
}
public Uri getViewHolderVoicemailUri() {
return viewHolderVoicemailUri;
}
interface NewVoicemailViewHolderListener {
void expandViewHolderFirstTimeAndCollapseAllOtherVisibleViewHolders(
NewVoicemailViewHolder expandedViewHolder,
VoicemailEntry voicemailEntryOfViewHolder,
NewVoicemailViewHolderListener listener);
void collapseExpandedViewHolder(NewVoicemailViewHolder expandedViewHolder);
void pauseViewHolder(NewVoicemailViewHolder expandedViewHolder);
void resumePausedViewHolder(NewVoicemailViewHolder expandedViewHolder);
}
@Override
public void onClick(View v) {
LogUtil.i(
"NewVoicemailViewHolder.onClick",
"voicemail id: %d, isViewHolderCurrentlyExpanded:%b",
viewHolderId,
isViewHolderExpanded);
if (isViewHolderExpanded) {
voicemailViewHolderListener.collapseExpandedViewHolder(this);
} else {
voicemailViewHolderListener.expandViewHolderFirstTimeAndCollapseAllOtherVisibleViewHolders(
this,
Assert.isNotNull(voicemailEntryOfViewHolder),
Assert.isNotNull(voicemailViewHolderListener));
}
}
}