Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 64262064 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Play voicemails, update seekbar timer, allow seeking, and maintain state after recycling."

parents b6c72647 1fab0cca
Loading
Loading
Loading
Loading
+25 −0
Original line number Original line Diff line number Diff line
<!--
  ~ 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
  -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0"
    android:tint="?attr/colorControlNormal">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
</vector>
 No newline at end of file
+468 −31

File changed.

Preview size limit exceeded, changes collapsed.

+188 −0
Original line number Original line Diff line number Diff line
/*
 * 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 android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.support.annotation.NonNull;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import java.io.IOException;

/** A wrapper around {@link MediaPlayer} */
public class NewVoicemailMediaPlayer {

  private final MediaPlayer mediaPlayer;
  private Uri voicemailLastPlayedOrPlayingUri;
  private Uri voicemailUriLastPreparedOrPreparingToPlay;

  private OnErrorListener newVoicemailMediaPlayerOnErrorListener;
  private OnPreparedListener newVoicemailMediaPlayerOnPreparedListener;
  private OnCompletionListener newVoicemailMediaPlayerOnCompletionListener;
  private Uri pausedUri;

  public NewVoicemailMediaPlayer(@NonNull MediaPlayer player) {
    mediaPlayer = Assert.isNotNull(player);
  }

  public void prepareMediaPlayerAndPlayVoicemailWhenReady(Context context, Uri uri)
      throws IOException {
    Assert.checkArgument(uri != null, "Media player cannot play a null uri");
    LogUtil.i(
        "NewVoicemailMediaPlayer",
        "trying to prepare playing voicemail uri: %s",
        String.valueOf(uri));
    try {
      reset();
      voicemailUriLastPreparedOrPreparingToPlay = uri;
      verifyListenersNotNull();
      LogUtil.i("NewVoicemailMediaPlayer", "setData source");
      mediaPlayer.setDataSource(context, uri);
      LogUtil.i("NewVoicemailMediaPlayer", "prepare async");
      mediaPlayer.prepareAsync();
    } catch (IllegalStateException e) {
      LogUtil.i(
          "NewVoicemailMediaPlayer", "caught an IllegalStateException state exception : \n" + e);
    } catch (Exception e) {
      LogUtil.i(
          "NewVoicemailMediaPlayer",
          "threw an Exception " + e + " for uri: " + uri + "for context : " + context);
    }
  }

  private void verifyListenersNotNull() {
    Assert.isNotNull(
        newVoicemailMediaPlayerOnErrorListener,
        "newVoicemailMediaPlayerOnErrorListener must be set before preparing to "
            + "play voicemails");
    Assert.isNotNull(
        newVoicemailMediaPlayerOnCompletionListener,
        "newVoicemailMediaPlayerOnCompletionListener must be set before preparing"
            + " to play voicemails");
    Assert.isNotNull(
        newVoicemailMediaPlayerOnPreparedListener,
        "newVoicemailMediaPlayerOnPreparedListener must be set before preparing to"
            + " play voicemails");
  }

  // Must be called from onPrepared
  public void start(Uri startPlayingVoicemailUri) {
    Assert.checkArgument(
        startPlayingVoicemailUri.equals(voicemailUriLastPreparedOrPreparingToPlay),
        "uri:%s was not prepared before calling start. Uri that is currently prepared: %s",
        startPlayingVoicemailUri,
        getLastPreparedOrPreparingToPlayVoicemailUri());

    mediaPlayer.start();
    voicemailLastPlayedOrPlayingUri = startPlayingVoicemailUri;
    pausedUri = null;
  }

  public void reset() {
    LogUtil.enterBlock("NewVoicemailMediaPlayer.reset");
    mediaPlayer.reset();
    voicemailLastPlayedOrPlayingUri = null;
    voicemailUriLastPreparedOrPreparingToPlay = null;
    pausedUri = null;
  }

  public void pauseMediaPlayer(Uri voicemailUri) {
    pausedUri = voicemailUri;
    Assert.checkArgument(
        voicemailUriLastPreparedOrPreparingToPlay.equals(voicemailLastPlayedOrPlayingUri),
        "last prepared and last playing should be the same");
    Assert.checkArgument(
        pausedUri.equals(voicemailLastPlayedOrPlayingUri),
        "only the last played uri can be paused");
    mediaPlayer.pause();
  }

  public void seekTo(int progress) {
    mediaPlayer.seekTo(progress);
  }

  public void setOnErrorListener(OnErrorListener onErrorListener) {
    mediaPlayer.setOnErrorListener(onErrorListener);
    newVoicemailMediaPlayerOnErrorListener = onErrorListener;
  }

  public void setOnPreparedListener(OnPreparedListener onPreparedListener) {
    mediaPlayer.setOnPreparedListener(onPreparedListener);
    newVoicemailMediaPlayerOnPreparedListener = onPreparedListener;
  }

  public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
    mediaPlayer.setOnCompletionListener(onCompletionListener);
    newVoicemailMediaPlayerOnCompletionListener = onCompletionListener;
  }

  /**
   * Note: In some cases it's possible mediaPlayer.isPlaying() can return true, but
   * mediaPlayer.getCurrentPosition() can be greater than mediaPlayer.getDuration(), after which
   * mediaPlayer.isPlaying() will be false. This is a weird corner case and adding the
   * mediaPlayer.getCurrentPosition() < mediaPlayer.getDuration() check here messes with the
   * mediaPlayer.start() (doesn't return mediaPlayer.isPlaying() to be true immediately).
   *
   * @return if the media plaer;
   */
  public boolean isPlaying() {
    return mediaPlayer.isPlaying();
  }

  public int getCurrentPosition() {
    return mediaPlayer.getCurrentPosition();
  }

  public Uri getLastPlayedOrPlayingVoicemailUri() {
    if (mediaPlayer.isPlaying()) {
      Assert.isNotNull(voicemailLastPlayedOrPlayingUri);
    }

    return voicemailLastPlayedOrPlayingUri == null ? Uri.EMPTY : voicemailLastPlayedOrPlayingUri;
  }

  /**
   * All the places that call this function, we expect the voicemail to have been prepared, but we
   * could get rid of the assert check in the future if needed.
   */
  public Uri getLastPreparedOrPreparingToPlayVoicemailUri() {
    return Assert.isNotNull(
        voicemailUriLastPreparedOrPreparingToPlay,
        "we expect whoever called this to have prepared a voicemail before calling this function");
  }

  public Uri getLastPausedVoicemailUri() {
    return pausedUri;
  }

  public MediaPlayer getMediaPlayer() {
    return mediaPlayer;
  }

  public int getDuration() {
    Assert.checkArgument(mediaPlayer != null);
    return mediaPlayer.getDuration();
  }

  public boolean isPaused() {
    return pausedUri != null;
  }
}
+334 −61

File changed.

Preview size limit exceeded, changes collapsed.

+236 −22
Original line number Original line Diff line number Diff line
@@ -15,17 +15,22 @@
 */
 */
package com.android.dialer.voicemail.listui;
package com.android.dialer.voicemail.listui;


import static android.view.View.GONE;
import static android.view.View.VISIBLE;

import android.app.FragmentManager;
import android.app.FragmentManager;
import android.content.Context;
import android.content.Context;
import android.database.Cursor;
import android.database.Cursor;
import android.net.Uri;
import android.net.Uri;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.text.TextUtils;
import android.view.View;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnClickListener;
import android.widget.QuickContactBadge;
import android.widget.QuickContactBadge;
import android.widget.TextView;
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.common.LogUtil;
import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.lettertile.LetterTileDrawable;
@@ -44,6 +49,8 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
  private final Clock clock;
  private final Clock clock;
  private boolean isViewHolderExpanded;
  private boolean isViewHolderExpanded;
  private int viewHolderId;
  private int viewHolderId;
  private VoicemailEntry voicemailEntryOfViewHolder;
  @NonNull private Uri viewHolderVoicemailUri;
  private final NewVoicemailViewHolderListener voicemailViewHolderListener;
  private final NewVoicemailViewHolderListener voicemailViewHolderListener;


  NewVoicemailViewHolder(
  NewVoicemailViewHolder(
@@ -58,19 +65,45 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
    mediaPlayerView = view.findViewById(R.id.new_voicemail_media_player);
    mediaPlayerView = view.findViewById(R.id.new_voicemail_media_player);
    this.clock = clock;
    this.clock = clock;
    voicemailViewHolderListener = newVoicemailViewHolderListener;
    voicemailViewHolderListener = newVoicemailViewHolderListener;

    viewHolderId = -1;
    isViewHolderExpanded = false;
    viewHolderVoicemailUri = null;
  }
  }


  void bind(Cursor cursor, FragmentManager fragmentManager) {
  /**
    VoicemailEntry voicemailEntry = VoicemailCursorLoader.toVoicemailEntry(cursor);
   * When the {@link RecyclerView} displays voicemail entries, it might recycle the views upon
    viewHolderId = voicemailEntry.id();
   * scrolling. In that case we need to ensure that the member variables of this {@link
    primaryTextView.setText(VoicemailEntryText.buildPrimaryVoicemailText(context, voicemailEntry));
   * 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(
    secondaryTextView.setText(
        VoicemailEntryText.buildSecondaryVoicemailText(context, clock, voicemailEntry));
        VoicemailEntryText.buildSecondaryVoicemailText(context, clock, voicemailEntryOfViewHolder));


    String voicemailTranscription = voicemailEntry.transcription();
    String voicemailTranscription = voicemailEntryOfViewHolder.transcription();


    if (TextUtils.isEmpty(voicemailTranscription)) {
    if (TextUtils.isEmpty(voicemailTranscription)) {
      transcriptionTextView.setVisibility(View.GONE);
      transcriptionTextView.setVisibility(GONE);
      transcriptionTextView.setText(null);
      transcriptionTextView.setText(null);
    } else {
    } else {
      transcriptionTextView.setVisibility(View.VISIBLE);
      transcriptionTextView.setVisibility(View.VISIBLE);
@@ -78,9 +111,49 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
    }
    }


    itemView.setOnClickListener(this);
    itemView.setOnClickListener(this);
    setPhoto(voicemailEntry);
    setPhoto(voicemailEntryOfViewHolder);
    mediaPlayerView.setVoicemailEntryValues(voicemailEntry);

    mediaPlayerView.setFragmentManager(fragmentManager);
    // 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)
  // TODO(uabdullah): Consider/Implement TYPE (e.g Spam, TYPE_VOICEMAIL)
@@ -96,19 +169,148 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
  }
  }


  void collapseViewHolder() {
  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);
    transcriptionTextView.setMaxLines(1);
    isViewHolderExpanded = false;
    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);
    transcriptionTextView.setMaxLines(999);
    isViewHolderExpanded = true;
    isViewHolderExpanded = true;
    // Once the media player is visible update its state
    mediaPlayerView.setVisibility(View.VISIBLE);
    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() {
  boolean isViewHolderExpanded() {
    return isViewHolderExpanded;
    return isViewHolderExpanded;
  }
  }
@@ -117,25 +319,37 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
    return viewHolderId;
    return viewHolderId;
  }
  }


  public Uri getViewHolderVoicemailUri() {
    return viewHolderVoicemailUri;
  }

  interface NewVoicemailViewHolderListener {
  interface NewVoicemailViewHolderListener {
    void onViewHolderExpanded(NewVoicemailViewHolder expandedViewHolder);
    void expandViewHolderFirstTimeAndCollapseAllOtherVisibleViewHolders(
        NewVoicemailViewHolder expandedViewHolder,
        VoicemailEntry voicemailEntryOfViewHolder,
        NewVoicemailViewHolderListener listener);


    void onViewHolderCollapsed(NewVoicemailViewHolder expandedViewHolder);
    void collapseExpandedViewHolder(NewVoicemailViewHolder expandedViewHolder);

    void pauseViewHolder(NewVoicemailViewHolder expandedViewHolder);

    void resumePausedViewHolder(NewVoicemailViewHolder expandedViewHolder);
  }
  }


  @Override
  @Override
  public void onClick(View v) {
  public void onClick(View v) {
    LogUtil.i(
    LogUtil.i(
        "NewVoicemailViewHolder.onClick",
        "NewVoicemailViewHolder.onClick",
        "voicemail id: %d, isViewHolderExpanded:%b",
        "voicemail id: %d, isViewHolderCurrentlyExpanded:%b",
        viewHolderId,
        viewHolderId,
        isViewHolderExpanded);
        isViewHolderExpanded);
    if (isViewHolderExpanded) {
    if (isViewHolderExpanded) {
      collapseViewHolder();
      voicemailViewHolderListener.collapseExpandedViewHolder(this);
      voicemailViewHolderListener.onViewHolderCollapsed(this);
    } else {
    } else {
      expandViewHolder();
      voicemailViewHolderListener.expandViewHolderFirstTimeAndCollapseAllOtherVisibleViewHolders(
      voicemailViewHolderListener.onViewHolderExpanded(this);
          this,
          Assert.isNotNull(voicemailEntryOfViewHolder),
          Assert.isNotNull(voicemailViewHolderListener));
    }
    }
  }
  }
}
}
Loading