Merge "Expand Voicemails on tapping"
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
index ca0b5dc..d04143f 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
@@ -17,17 +17,27 @@
 
 import android.database.Cursor;
 import android.support.v7.widget.RecyclerView;
+import android.util.ArraySet;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.dialer.common.LogUtil;
 import com.android.dialer.time.Clock;
+import com.android.dialer.voicemail.listui.NewVoicemailViewHolder.NewVoicemailViewHolderListener;
+import com.android.dialer.voicemail.model.VoicemailEntry;
+import java.util.Set;
 
 /** {@link RecyclerView.Adapter} for the new voicemail call log fragment. */
-final class NewVoicemailAdapter extends RecyclerView.Adapter<NewVoicemailViewHolder> {
+final class NewVoicemailAdapter extends RecyclerView.Adapter<NewVoicemailViewHolder>
+    implements NewVoicemailViewHolderListener {
 
   private final Cursor cursor;
   private final Clock clock;
+  /** A valid id for {@link VoicemailEntry} is greater than 0 */
+  private int currentlyExpandedViewHolderId = -1;
+
+  // A set of (re-usable) view holders being used by the recycler view to display voicemails
+  private final Set<NewVoicemailViewHolder> newVoicemailViewHolderSet = new ArraySet<>();
 
   /** @param cursor whose projection is {@link VoicemailCursorLoader.VOICEMAIL_COLUMNS} */
   NewVoicemailAdapter(Cursor cursor, Clock clock) {
@@ -39,7 +49,8 @@
   public NewVoicemailViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
     LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
     View view = inflater.inflate(R.layout.new_voicemail_entry, viewGroup, false);
-    NewVoicemailViewHolder newVoicemailViewHolder = new NewVoicemailViewHolder(view, clock);
+    NewVoicemailViewHolder newVoicemailViewHolder = new NewVoicemailViewHolder(view, clock, this);
+    newVoicemailViewHolderSet.add(newVoicemailViewHolder);
     return newVoicemailViewHolder;
   }
 
@@ -48,10 +59,43 @@
     LogUtil.i("onBindViewHolder", "position" + position);
     cursor.moveToPosition(position);
     viewHolder.bind(cursor);
+    expandOrCollapseViewHolder(viewHolder);
+  }
+
+  /**
+   * Ensures a voicemail {@link NewVoicemailViewHolder} that was expanded and scrolled out of view,
+   * doesn't have it's corresponding recycled view also expanded. It also ensures than when the
+   * expanded voicemail is scrolled back into view, it still remains expanded.
+   *
+   * @param viewHolder an {@link NewVoicemailViewHolder} that is either expanded or collapsed
+   */
+  private void expandOrCollapseViewHolder(NewVoicemailViewHolder viewHolder) {
+    if (viewHolder.getViewHolderId() == currentlyExpandedViewHolderId) {
+      viewHolder.expandViewHolder();
+    } else {
+      viewHolder.collapseViewHolder();
+    }
   }
 
   @Override
   public int getItemCount() {
     return cursor.getCount();
   }
+
+  /**
+   * We can only have one expanded voicemail view holder. This allows us to ensure that except for
+   * the currently expanded view holder, all the other view holders visible on the screen are
+   * collapsed.
+   *
+   * @param expandedViewHolder is the view holder that is currently expanded.
+   */
+  @Override
+  public void onViewHolderExpanded(NewVoicemailViewHolder expandedViewHolder) {
+    currentlyExpandedViewHolderId = expandedViewHolder.getViewHolderId();
+    for (NewVoicemailViewHolder viewHolder : newVoicemailViewHolderSet) {
+      if (!viewHolder.equals(expandedViewHolder)) {
+        viewHolder.collapseViewHolder();
+      }
+    }
+  }
 }
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
index 8016563..5580cb4 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
@@ -18,9 +18,11 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
+import android.support.annotation.VisibleForTesting;
 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.contactphoto.ContactPhotoManager;
@@ -29,7 +31,7 @@
 import com.android.dialer.voicemail.model.VoicemailEntry;
 
 /** {@link RecyclerView.ViewHolder} for the new voicemail tab. */
-final class NewVoicemailViewHolder extends RecyclerView.ViewHolder {
+final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
 
   private final Context context;
   private final TextView primaryTextView;
@@ -37,8 +39,12 @@
   private final TextView transcriptionTextView;
   private final QuickContactBadge quickContactBadge;
   private final Clock clock;
+  private boolean isViewHolderExpanded;
+  private int viewHolderId;
+  private final NewVoicemailViewHolderListener voicemailViewHolderListener;
 
-  NewVoicemailViewHolder(View view, Clock clock) {
+  NewVoicemailViewHolder(
+      View view, Clock clock, NewVoicemailViewHolderListener newVoicemailViewHolderListener) {
     super(view);
     this.context = view.getContext();
     primaryTextView = view.findViewById(R.id.primary_text);
@@ -46,10 +52,12 @@
     transcriptionTextView = view.findViewById(R.id.transcription_text);
     quickContactBadge = view.findViewById(R.id.quick_contact_photo);
     this.clock = clock;
+    voicemailViewHolderListener = newVoicemailViewHolderListener;
   }
 
   void bind(Cursor cursor) {
     VoicemailEntry voicemailEntry = VoicemailCursorLoader.toVoicemailEntry(cursor);
+    viewHolderId = voicemailEntry.id();
     primaryTextView.setText(VoicemailEntryText.buildPrimaryVoicemailText(context, voicemailEntry));
     secondaryTextView.setText(
         VoicemailEntryText.buildSecondaryVoicemailText(context, clock, voicemailEntry));
@@ -64,6 +72,7 @@
       transcriptionTextView.setText(voicemailTranscription);
     }
 
+    itemView.setOnClickListener(this);
     setPhoto(voicemailEntry);
   }
 
@@ -78,4 +87,37 @@
             voicemailEntry.name(),
             LetterTileDrawable.TYPE_DEFAULT);
   }
+
+  void collapseViewHolder() {
+    transcriptionTextView.setMaxLines(1);
+    isViewHolderExpanded = false;
+  }
+
+  void expandViewHolder() {
+    transcriptionTextView.setMaxLines(999);
+    isViewHolderExpanded = true;
+  }
+
+  @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+  boolean isViewHolderExpanded() {
+    return isViewHolderExpanded;
+  }
+
+  public int getViewHolderId() {
+    return viewHolderId;
+  }
+
+  interface NewVoicemailViewHolderListener {
+    void onViewHolderExpanded(NewVoicemailViewHolder expandedViewHolder);
+  }
+
+  @Override
+  public void onClick(View v) {
+    if (isViewHolderExpanded) {
+      collapseViewHolder();
+    } else {
+      expandViewHolder();
+      voicemailViewHolderListener.onViewHolderExpanded(this);
+    }
+  }
 }
diff --git a/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry.xml b/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry.xml
index fe00992..d9c557f 100644
--- a/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry.xml
+++ b/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry.xml
@@ -72,25 +72,24 @@
           android:layout_marginStart="@dimen/call_log_entry_photo_text_margin"/>
     </LinearLayout>
 
-    <!-- TODO(uabdullah): Fix text cropping issue -->
+    <!-- TODO(a bug): Fix text cropping issue, make text selectable -->
     <TextView
         android:id="@+id/transcription_text"
         style="@style/SecondaryText"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:visibility="gone"
         android:layout_marginStart="@dimen/call_log_entry_photo_text_margin"
-        android:layout_gravity="center_vertical"/>
-
+        android:layout_gravity="center_vertical"
+        android:visibility="gone"/>
   </LinearLayout>
 
+  <!-- TODO(a bug): Add ripple effect -->
   <ImageView
       android:id="@+id/menu_button"
       android:layout_width="@dimen/call_log_entry_menu_button_size"
       android:layout_height="@dimen/call_log_entry_menu_button_size"
       android:layout_alignParentEnd="true"
       android:layout_centerVertical="true"
-      android:background="?android:attr/selectableItemBackgroundBorderless"
       android:scaleType="center"
       android:src="@drawable/quantum_ic_more_vert_vd_theme_24"
       android:tint="@color/dialer_secondary_text_color"/>