Move call log actions into expandable view.

This isn't the prettiest thing ever, but with this the "framework" of
all of the changes for the new visual style of the call logs is in
place. From here on out, the remainder of tasks should be unblocked
and relatively independent.

+ Rename ...ItemViews to ...ItemViewHolder. This probably wasn't
completely necessary, but is more proper given the new architecture.

+ ViewHolder is now officially where most of the independent UI logic
for a single call log list item should live. This changelist moves
further in that direction by storing references and helpers in it, to
lessen what must be passed in from the adapter.

+ Split out the call action from the rest of the actions, since it
has a special treatment  on the card.

+ Convert text action buttons into a vertical stack.

+ Consolidate action stylings into a single style, for simplicity.

+ Miscellaneous style and string changes to put things in a better
state. This included tweaking some of the (ripple) backgrounds.

+ Update tests, according to changes.

Bug: 19372817
Change-Id: Ic923c0bcbbc1c153952131d0c772df9e9589fb03
diff --git a/res/drawable/call_log_background.xml b/res/drawable/call_log_background.xml
deleted file mode 100644
index 1b3dbc9..0000000
--- a/res/drawable/call_log_background.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 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.
--->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight" />
\ No newline at end of file
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index 9ea3db8..7a826d9 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -44,15 +44,13 @@
         android:layout_height="wrap_content"
         android:layout_margin="4dp"
         android:baselineAligned="false"
-        android:orientation="vertical"
-        android:gravity="center_vertical"
         card_view:cardCornerRadius="4dp"
         card_view:cardBackgroundColor="@color/background_dialer_call_log_list_item">
 
         <!-- Primary area containing the contact badge and caller information -->
         <LinearLayout
             android:id="@+id/primary_action_view"
-            android:background="@drawable/call_log_background"
+            android:background="?android:attr/selectableItemBackground"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:paddingStart="@dimen/call_log_start_margin"
@@ -142,26 +140,28 @@
             </LinearLayout>
 
             <ImageView
-                android:id="@+id/call_indicator_icon"
+                android:id="@+id/call_icon"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_vertical"
                 android:layout_marginEnd="@dimen/call_log_icon_margin"
+                android:background="?android:attr/selectableItemBackgroundBorderless"
                 android:src="@drawable/ic_card_phone"
                 android:tint="@color/recent_call_log_item_phone_icon_tint"
                 android:alpha="0.3"
-                android:importantForAccessibility="no"
+                android:contentDescription="@string/description_call_log_call_action"
                 android:visibility="gone" />
 
-            <!-- Viewstub with additional expandable actions for a call log entry -->
-            <ViewStub android:id="@+id/call_log_entry_actions_stub"
-                      android:inflatedId="@+id/call_log_entry_actions"
-                      android:layout="@layout/call_log_list_item_actions"
-                      android:layout_width="match_parent"
-                      android:layout_height="wrap_content"/>
-
         </LinearLayout>
 
+        <!-- Viewstub with additional expandable actions for a call log entry -->
+        <ViewStub android:id="@+id/call_log_entry_actions_stub"
+            android:inflatedId="@+id/call_log_entry_actions"
+            android:layout="@layout/call_log_list_item_actions"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom" />
+
     </android.support.v7.widget.CardView>
 
 </LinearLayout>
diff --git a/res/layout/call_log_list_item_actions.xml b/res/layout/call_log_list_item_actions.xml
index 1280089..8ef92bf 100644
--- a/res/layout/call_log_list_item_actions.xml
+++ b/res/layout/call_log_list_item_actions.xml
@@ -14,100 +14,53 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:layout_width="match_parent"
-             android:layout_height="wrap_content"
-             android:id="@+id/call_log_action_container">
-    <LinearLayout
-        android:id="@+id/call_log_entry_actions_ll"
-        android:gravity="center_vertical"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/call_log_action_container"
+    android:gravity="center_vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:visibility="visible"
+    android:importantForAccessibility="1">
+
+    <!-- Temporary border spacer. -->
+    <View
         android:layout_width="match_parent"
-        android:layout_height="@dimen/call_log_action_height"
-        android:orientation="horizontal"
-        android:paddingStart="@dimen/call_log_actions_left_padding"
-        android:visibility="visible"
-        android:importantForAccessibility="1"
-        >
-        <TextView
-            android:id="@+id/call_back_action"
-            android:background="?android:attr/selectableItemBackground"
-            android:gravity="center"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:paddingStart="@dimen/call_log_action_horizontal_padding"
-            android:paddingEnd="@dimen/call_log_action_horizontal_padding"
-            android:text="@string/call_log_action_call_back"
-            android:textColor="@color/call_log_action_text"
-            android:textSize="@dimen/call_log_list_item_actions_text_size"
-            android:textStyle="bold"
-            android:nextFocusLeft="@+id/primary_action_view"
-            android:nextFocusRight="@+id/video_call_action"
-            android:focusable="true"
-            android:singleLine="true"/>
-        <TextView
-            android:id="@+id/video_call_action"
-            android:background="?android:attr/selectableItemBackground"
-            android:gravity="center"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:paddingStart="@dimen/call_log_action_horizontal_padding"
-            android:paddingEnd="@dimen/call_log_action_horizontal_padding"
-            android:text="@string/call_log_action_video_call"
-            android:textColor="?attr/call_log_secondary_text_color"
-            android:textSize="@dimen/call_log_list_item_actions_text_size"
-            android:textStyle="bold"
-            android:nextFocusLeft="@+id/call_back_action"
-            android:nextFocusRight="@+id/voicemail_action"
-            android:focusable="true"
-            android:singleLine="true"/>
-        <TextView
-            android:id="@+id/voicemail_action"
-            android:background="?android:attr/selectableItemBackground"
-            android:gravity="center"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:paddingStart="@dimen/call_log_action_horizontal_padding"
-            android:paddingEnd="@dimen/call_log_action_horizontal_padding"
-            android:text="@string/call_log_action_voicemail"
-            android:textColor="@color/call_log_action_text"
-            android:textSize="@dimen/call_log_list_item_actions_text_size"
-            android:textStyle="bold"
-            android:nextFocusLeft="@+id/video_call_action"
-            android:nextFocusRight="@+id/details_action"
-            android:focusable="true"
-            android:singleLine="true"/>
-        <TextView
-            android:id="@+id/details_action"
-            android:background="?android:attr/selectableItemBackground"
-            android:gravity="center"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:paddingStart="@dimen/call_log_action_horizontal_padding"
-            android:paddingEnd="@dimen/call_log_action_horizontal_padding"
-            android:text="@string/call_log_action_details"
-            android:textColor="?attr/call_log_secondary_text_color"
-            android:textSize="@dimen/call_log_list_item_actions_text_size"
-            android:textStyle="bold"
-            android:nextFocusLeft="@+id/voicemail_action"
-            android:nextFocusRight="@+id/report_action"
-            android:focusable="true"
-            android:singleLine="true"/>
-        <TextView
-            android:id="@+id/report_action"
-            android:background="?android:attr/selectableItemBackground"
-            android:gravity="center"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:paddingStart="@dimen/call_log_action_horizontal_padding"
-            android:paddingEnd="@dimen/call_log_action_horizontal_padding"
-            android:text="@string/call_log_action_report"
-            android:textColor="?attr/call_log_secondary_text_color"
-            android:textSize="@dimen/call_log_list_item_actions_text_size"
-            android:textStyle="bold"
-            android:nextFocusLeft="@+id/details_action"
-            android:nextFocusRight="@+id/primary_action_view"
-            android:focusable="true"
-            android:singleLine="true"
-            android:visibility="gone"/>
-    </LinearLayout>
-</FrameLayout>
+        android:layout_height="1dp"
+        android:layout_weight="1"
+        android:background="#eeeeee" />
+
+    <TextView
+        android:id="@+id/video_call_action"
+        style="@style/CallLogActionsStyle"
+        android:background="?android:attr/selectableItemBackground"
+        android:text="@string/call_log_action_video_call"
+        android:nextFocusLeft="@+id/primary_action_view"
+        android:nextFocusRight="@+id/voicemail_action" />
+
+    <TextView
+        android:id="@+id/voicemail_action"
+        style="@style/CallLogActionsStyle"
+        android:background="?android:attr/selectableItemBackground"
+        android:text="@string/call_log_action_voicemail"
+        android:nextFocusLeft="@+id/video_call_action"
+        android:nextFocusRight="@+id/details_action" />
+
+    <TextView
+        android:id="@+id/details_action"
+        style="@style/CallLogActionsStyle"
+        android:background="?android:attr/selectableItemBackground"
+        android:text="@string/call_log_action_details"
+        android:nextFocusLeft="@+id/voicemail_action"
+        android:nextFocusRight="@+id/report_action" />
+
+    <TextView
+        android:id="@+id/report_action"
+        style="@style/CallLogActionsStyle"
+        android:background="?android:attr/selectableItemBackground"
+        android:text="@string/call_log_action_report"
+        android:nextFocusLeft="@+id/details_action"
+        android:nextFocusRight="@+id/primary_action_view"
+        android:visibility="gone" />
+
+</LinearLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 0902cb7..502b21a 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -99,14 +99,14 @@
     <dimen name="search_list_padding_top">16dp</dimen>
     <dimen name="search_box_elevation">3dp</dimen>
 
-    <!-- Padding to the left and right of call log action buttons. -->
-    <dimen name="call_log_action_horizontal_padding">8dp</dimen>
+    <dimen name="call_log_action_height">48dp</dimen>
+    <dimen name="call_log_action_horizontal_padding">24dp</dimen>
     <!-- Left-padding for the call log action buttons - ensures the buttons align with the text
          to the right of the contact badge.  Adjust when any of the following change:
          call_log_action_horizontal_padding
          call_log_list_contact_photo_size  -->
     <dimen name="call_log_actions_left_padding">64dp</dimen>
-    <dimen name="call_log_primary_text_size">16sp</dimen>
+    <dimen name="call_log_primary_text_size">14sp</dimen>
     <dimen name="call_log_secondary_text_size">14sp</dimen>
     <dimen name="call_log_list_item_actions_text_size">12sp</dimen>
     <!-- Height of the call log actions section for each call log entry -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4c4921d..4ee5b45 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -539,30 +539,10 @@
          [CHAR LIMIT=21] -->
     <string name="favorites_menu_all_contacts">ALL CONTACTS</string>
 
-    <!-- Button text for the "call back" button displayed underneath an entry in the call log. This
-         is used to describe the action of calling a phone number that the user previously received
-         an incoming call from. Tapping causes a call to be placed to the number represented by the
-         call log entry.
-         [CHAR LIMIT=30] -->
-    <string name="call_log_action_call_back">CALL BACK</string>
-
-    <!-- BUTTON text for the "call" button displayed underneath an entry in the call log. This
-         is used to describe the action of calling a phone number. Tapping causes a call to be
-         placed to the number represented by the call log entry.
-         [CHAR LIMIT=30] -->
-    <string name="call_log_action_call">CALL</string>
-
-    <!-- BUTTON text for the "redial" button displayed underneath an entry in the call log. This
-         is used to describe the action of calling a phone number that the user previously made an
-         outgoing call to. Tapping causes a call to be placed to the number represented by the call
-         log entry.
-         [CHAR LIMIT=30] -->
-    <string name="call_log_action_redial">REDIAL</string>
-
-    <!-- Button text for the "video call" button displayed underneath an entry in the call log.
+    <!-- Button text for the "video call" displayed underneath an entry in the call log.
          Tapping causes a video call to be placed to the caller represented by the call log entry.
-         [CHAR LIMIT=30] -->
-    <string name="call_log_action_video_call">VIDEO CALL</string>
+         [CHAR LIMIT=50] -->
+    <string name="call_log_action_video_call">Video call</string>
 
     <!-- Button text for the "LISTEN" button displayed underneath an entry in the call log.
          Tapping navigates the user to the call details screen where the user can listen to the
@@ -570,11 +550,10 @@
          [CHAR LIMIT=30] -->
     <string name="call_log_action_voicemail">LISTEN</string>
 
-    <!-- Button text for the "DETAILS" button displayed underneath an entry in the call log.
+    <!-- Button text for the button displayed underneath an entry in the call log.
          Tapping navigates the user to the call details screen where the user can view details for
-         the call log entry.
-         [CHAR LIMIT=30] -->
-    <string name="call_log_action_details">DETAILS</string>
+         the call log entry. [CHAR LIMIT=50] -->
+    <string name="call_log_action_details">View details</string>
 
     <!-- String describing an incoming missed call entry in the call log.
          Note: AccessibilityServices uses this attribute to announce what the view represents.
@@ -598,11 +577,15 @@
          [CHAR LIMIT=NONE] -->
     <string name="description_phone_account">on <xliff:g id="phoneAccount" example="SIM 1">^1</xliff:g></string>
 
-    <!-- String describing the "call back" action for an entry in the call log.  The call back
+    <!-- String describing the phone icon on a call log list item. When tapped, it will place a
+         call to the number represented by that call log entry. [CHAR LIMIT=NONE]-->
+    <string name="description_call_log_call_action">Call</string>
+
+    <!-- String describing the "call" action for an entry in the call log.  The call back
          action triggers a return call to the named user.
          Note: AccessibilityServices uses this attribute to announce the purpose of the button.
          [CHAR LIMIT=NONE] -->
-    <string name="description_call_back_action">Call back <xliff:g id="nameOrNumber" example="John Smith">^1</xliff:g></string>
+    <string name="description_call_action">Call <xliff:g id="nameOrNumber" example="John Smith">^1</xliff:g></string>
 
     <!-- String describing the "video call" action for an entry in the call log.  The video call
          action triggers a return video call to the named person/number.
@@ -630,7 +613,7 @@
     <!-- Button text for the "report" button displayed underneath an entry in the call log.
          Tapping causes the call log entry to be reported to Google as a bad id.
          [CHAR LIMIT=30] -->
-    <string name="call_log_action_report">REPORT</string>
+    <string name="call_log_action_report">Report</string>
 
     <!-- String used as a header in the call log above calls which occurred today.
          [CHAR LIMIT=65] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 8bd5f9d..cfb2480 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -158,6 +158,19 @@
         <item name="android:overScrollMode">always</item>
     </style>
 
+    <style name="CallLogActionsStyle">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">@dimen/call_log_action_height</item>
+        <item name="android:gravity">start|center_vertical</item>
+        <item name="android:paddingStart">@dimen/call_log_action_horizontal_padding</item>
+        <item name="android:paddingEnd">@dimen/call_log_action_horizontal_padding</item>
+        <item name="android:textColor">?attr/call_log_secondary_text_color</item>
+        <item name="android:textSize">@dimen/call_log_list_item_actions_text_size</item>
+        <item name="android:fontFamily">"sans-serif-medium"</item>
+        <item name="android:focusable">true</item>
+        <item name="android:singleLine">true</item>
+    </style>
+
     <style name="DismissButtonStyle">
         <item name="android:paddingLeft">@dimen/dismiss_button_padding_start</item>
         <item name="android:paddingRight">@dimen/dismiss_button_padding_end</item>
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 07cd215..cc1a4a6 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -153,8 +153,7 @@
     private final View.OnClickListener mExpandCollapseListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
-            final View callLogItem = (View) v.getParent().getParent();
-            handleRowExpanded(callLogItem, false /* forceExpand */);
+            handleRowExpanded(v, false /* forceExpand */);
         }
     };
 
@@ -266,15 +265,15 @@
         LayoutInflater inflater = LayoutInflater.from(mContext);
         View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
 
-        // Get the views to bind to and cache them.
-        CallLogListItemViews views = CallLogListItemViews.fromView(mContext, view);
-        view.setTag(views);
+        CallLogListItemViewHolder viewHolder = CallLogListItemViewHolder.create(
+                view,
+                mContext,
+                mActionListener,
+                mPhoneNumberUtilsWrapper,
+                mCallLogViewsHelper);
+        viewHolder.primaryActionView.setTag(viewHolder);
 
-        // Set text height to false on the TextViews so they don't have extra padding.
-        views.phoneCallDetailsViews.nameView.setElegantTextHeight(false);
-        views.phoneCallDetailsViews.callLocationAndDate.setElegantTextHeight(false);
-
-        return (CallLogListItemViews) view.getTag();
+        return viewHolder;
     }
 
     /**
@@ -292,7 +291,7 @@
         }
         int count = getGroupSize(position);
 
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
+        CallLogListItemViewHolder views = (CallLogListItemViewHolder) viewHolder;
         views.rootView.setAccessibilityDelegate(mAccessibilityDelegate);
 
         // Default case: an item in the call log.
@@ -378,12 +377,7 @@
 
         // Restore expansion state of the row on rebind.  Inflate the actions ViewStub if required,
         // and set its visibility state accordingly.
-        views.expandOrCollapseActions(
-                isExpanded(rowId),
-                mOnReportButtonClickListener,
-                mActionListener,
-                mPhoneNumberUtilsWrapper,
-                mCallLogViewsHelper);
+        views.showActions(isExpanded(rowId), mOnReportButtonClickListener);
 
         if (TextUtils.isEmpty(name)) {
             details = new PhoneCallDetails(number, numberPresentation, formattedNumber, countryIso,
@@ -409,6 +403,8 @@
                 mContactInfoHelper.isBusiness(info.sourceType));
         views.quickContactView.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
 
+        views.updateCallButton();
+
         // Listen for the first draw
         if (mViewTreeObserver == null) {
             mViewTreeObserver = views.rootView.getViewTreeObserver();
@@ -603,28 +599,13 @@
      *        of its previous state
      */
     private void handleRowExpanded(View view, boolean forceExpand) {
-        final CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+        final CallLogListItemViewHolder views = (CallLogListItemViewHolder) view.getTag();
 
         if (forceExpand && isExpanded(views.rowId)) {
             return;
         }
 
-        // Hide or show the actions view.
         boolean expanded = toggleExpansion(views.rowId);
-        expandItem(views, expanded);
-    }
-
-    /**
-     * @param views The view holder for the item to expand or collapse.
-     * @param expand {@code true} to expand the item, {@code false} otherwise.
-     */
-    public void expandItem(CallLogListItemViews views, boolean expand) {
-        // Trigger loading of the viewstub and visual expand or collapse.
-        views.expandOrCollapseActions(
-                expand,
-                mOnReportButtonClickListener,
-                mActionListener,
-                mPhoneNumberUtilsWrapper,
-                mCallLogViewsHelper);
+        views.showActions(expanded, mOnReportButtonClickListener);
     }
 }
diff --git a/src/com/android/dialer/calllog/CallLogListItemHelper.java b/src/com/android/dialer/calllog/CallLogListItemHelper.java
index 77ad333..0e94ef4 100644
--- a/src/com/android/dialer/calllog/CallLogListItemHelper.java
+++ b/src/com/android/dialer/calllog/CallLogListItemHelper.java
@@ -62,7 +62,7 @@
      * @param details the details of a phone call needed to fill in the data
      */
     public void setPhoneCallDetails(
-            Context context, CallLogListItemViews views, PhoneCallDetails details) {
+            Context context, CallLogListItemViewHolder views, PhoneCallDetails details) {
         mPhoneCallDetailsHelper.setPhoneCallDetails(views.phoneCallDetailsViews, details);
 
         // Set the accessibility text for the contact badge
@@ -81,7 +81,7 @@
      *
      * @param views The views associated with the current call log entry.
      */
-    public void setActionContentDescriptions(CallLogListItemViews views) {
+    public void setActionContentDescriptions(CallLogListItemViewHolder views) {
         if (views.nameOrNumber == null) {
             Log.e(TAG, "setActionContentDescriptions; name or number is null.");
         }
@@ -90,10 +90,6 @@
         // Although we don't expect a null name or number, it is best to protect against it.
         CharSequence nameOrNumber = views.nameOrNumber == null ? "" : views.nameOrNumber;
 
-        views.callBackButtonView.setContentDescription(
-                TextUtils.expandTemplate(
-                        mResources.getString(R.string.description_call_back_action), nameOrNumber));
-
         views.videoCallButtonView.setContentDescription(
                 TextUtils.expandTemplate(
                         mResources.getString(R.string.description_video_call_action),
diff --git a/src/com/android/dialer/calllog/CallLogListItemViews.java b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
similarity index 67%
rename from src/com/android/dialer/calllog/CallLogListItemViews.java
rename to src/com/android/dialer/calllog/CallLogListItemViewHolder.java
index 4d43436..4b208f1 100644
--- a/src/com/android/dialer/calllog/CallLogListItemViews.java
+++ b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.Intent;
 import android.net.Uri;
 import android.provider.CallLog.Calls;
 import android.support.v7.widget.CardView;
@@ -27,6 +28,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewStub;
+import android.view.ViewTreeObserver;
 import android.widget.QuickContactBadge;
 import android.widget.TextView;
 
@@ -34,19 +36,18 @@
 import com.android.contacts.common.ContactPhotoManager;
 import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
 import com.android.contacts.common.testing.NeededForTesting;
+import com.android.dialer.PhoneCallDetailsHelper;
 import com.android.dialer.PhoneCallDetailsViews;
 import com.android.dialer.R;
 
 /**
- * This is an object containing the various views within a call log entry. It contains values
- * pointing to views contained by a call log list item view, so that we can improve performance
- * by reducing the frequency with which we need to find views by IDs.
+ * This is an object containing references to views contained by the call log list item. This
+ * improves performance by reducing the frequency with which we need to find views by IDs.
  *
- * This object also contains methods for inflating action views and binding action behaviors. This
- * is a way of isolating view logic from the CallLogAdapter. We should consider moving that logic
- * if the call log list item is eventually represented as a UI component.
+ * This object also contains UI logic pertaining to the view, to isolate it from the CallLogAdapter.
  */
-public final class CallLogListItemViews extends RecyclerView.ViewHolder {
+public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder {
+
     /** The root view of the call log list item */
     public final View rootView;
     /** The quick contact badge for the contact. */
@@ -59,10 +60,10 @@
     public final TextView dayGroupHeader;
     /** The view containing the details for the call log row, including the action buttons. */
     public final CardView callLogEntryView;
+    /** The actionable view which places a call to the number corresponding to the call log row. */
+    public final View callActionView;
     /** The view containing call log item actions.  Null until the ViewStub is inflated. */
     public View actionsView;
-    /** The "call back" action button - assigned only when the action section is expanded. */
-    public TextView callBackButtonView;
     /** The "video call" action button - assigned only when the action section is expanded. */
     public TextView videoCallButtonView;
     /** The "voicemail" action button - assigned only when the action section is expanded. */
@@ -134,20 +135,31 @@
 
     private static final int VOICEMAIL_TRANSCRIPTION_MAX_LINES = 10;
 
-    private Context mContext;
-    private int mPhotoSize;
+    private final Context mContext;
+    private final View.OnClickListener mActionListener;
+    private final PhoneNumberUtilsWrapper mPhoneNumberUtilsWrapper;
+    private final CallLogListItemHelper mCallLogListItemHelper;
 
+    private final int mPhotoSize;
 
-    private CallLogListItemViews(
+    private CallLogListItemViewHolder(
             Context context,
+            View.OnClickListener actionListener,
+            PhoneNumberUtilsWrapper phoneNumberUtilsWrapper,
+            CallLogListItemHelper callLogListItemHelper,
             View rootView,
             QuickContactBadge quickContactView,
             View primaryActionView,
             PhoneCallDetailsViews phoneCallDetailsViews,
             CardView callLogEntryView,
-            TextView dayGroupHeader) {
+            TextView dayGroupHeader,
+            View callActionView) {
         super(rootView);
+
         mContext = context;
+        mActionListener = actionListener;
+        mPhoneNumberUtilsWrapper = phoneNumberUtilsWrapper;
+        mCallLogListItemHelper = callLogListItemHelper;
 
         this.rootView = rootView;
         this.quickContactView = quickContactView;
@@ -155,20 +167,39 @@
         this.phoneCallDetailsViews = phoneCallDetailsViews;
         this.callLogEntryView = callLogEntryView;
         this.dayGroupHeader = dayGroupHeader;
+        this.callActionView = callActionView;
 
         Resources resources = mContext.getResources();
         mPhotoSize = mContext.getResources().getDimensionPixelSize(R.dimen.contact_photo_size);
+
+        // Set text height to false on the TextViews so they don't have extra padding.
+        phoneCallDetailsViews.nameView.setElegantTextHeight(false);
+        phoneCallDetailsViews.callLocationAndDate.setElegantTextHeight(false);
+
+        if (callActionView != null) {
+            callActionView.setOnClickListener(mActionListener);
+        }
     }
 
-    public static CallLogListItemViews fromView(Context context, View view) {
-        return new CallLogListItemViews(
+    public static CallLogListItemViewHolder create(
+            View view,
+            Context context,
+            View.OnClickListener actionListener,
+            PhoneNumberUtilsWrapper phoneNumberUtilsWrapper,
+            CallLogListItemHelper callLogListItemHelper) {
+
+        return new CallLogListItemViewHolder(
                 context,
+                actionListener,
+                phoneNumberUtilsWrapper,
+                callLogListItemHelper,
                 view,
                 (QuickContactBadge) view.findViewById(R.id.quick_contact_photo),
                 view.findViewById(R.id.primary_action_view),
                 PhoneCallDetailsViews.fromView(view),
                 (CardView) view.findViewById(R.id.call_log_row),
-                (TextView) view.findViewById(R.id.call_log_day_group_label));
+                (TextView) view.findViewById(R.id.call_log_day_group_label),
+                view.findViewById(R.id.call_icon));
     }
 
     /**
@@ -179,19 +210,12 @@
      * @param callLogItem The call log list item view.
      */
     public void inflateActionViewStub(
-            final CallLogAdapter.OnReportButtonClickListener onReportButtonClickListener,
-            View.OnClickListener actionListener,
-            PhoneNumberUtilsWrapper phoneNumberUtilsWrapper,
-            CallLogListItemHelper callLogViewsHelper) {
+            final CallLogAdapter.OnReportButtonClickListener onReportButtonClickListener) {
         ViewStub stub = (ViewStub) rootView.findViewById(R.id.call_log_entry_actions_stub);
         if (stub != null) {
             actionsView = (ViewGroup) stub.inflate();
         }
 
-        if (callBackButtonView == null) {
-            callBackButtonView = (TextView) actionsView.findViewById(R.id.call_back_action);
-        }
-
         if (videoCallButtonView == null) {
             videoCallButtonView = (TextView) actionsView.findViewById(R.id.video_call_action);
         }
@@ -216,54 +240,54 @@
             });
         }
 
-        bindActionButtons(actionListener, phoneNumberUtilsWrapper, callLogViewsHelper);
+        bindActionButtons();
+    }
+
+    public void updateCallButton() {
+        boolean canPlaceCallToNumber =
+                PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation);
+
+        if (canPlaceCallToNumber) {
+            boolean isVoicemailNumber =
+                    mPhoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, number);
+            if (isVoicemailNumber) {
+                // Make a general call to voicemail to ensure that if there are multiple accounts
+                // it does not call the voicemail number of a specific phone account.
+                callActionView.setTag(IntentProvider.getReturnVoicemailCallIntentProvider());
+            } else {
+                callActionView.setTag(IntentProvider.getReturnCallIntentProvider(number));
+            }
+
+            if (nameOrNumber != null) {
+                callActionView.setContentDescription(TextUtils.expandTemplate(
+                        mContext.getString(R.string.description_call_action),
+                        nameOrNumber));
+            } else {
+                callActionView.setContentDescription(
+                        mContext.getString(R.string.description_call_log_call_action));
+            }
+
+            callActionView.setVisibility(View.VISIBLE);
+        } else {
+            callActionView.setTag(null);
+            callActionView.setVisibility(View.GONE);
+        }
     }
 
     /**
      * Binds text titles, click handlers and intents to the voicemail, details and callback action
      * buttons.
      */
-    private void bindActionButtons(
-            View.OnClickListener actionListener,
-            PhoneNumberUtilsWrapper phoneNumberUtilsWrapper,
-            CallLogListItemHelper callLogViewsHelper) {
+    private void bindActionButtons() {
         boolean canPlaceCallToNumber =
                 PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation);
 
-        // Set return call intent, otherwise null.
-        if (canPlaceCallToNumber) {
-            boolean isVoicemailNumber =
-                    phoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, number);
-            if (isVoicemailNumber) {
-                // Make a general call to voicemail to ensure that if there are multiple accounts
-                // it does not call the voicemail number of a specific phone account.
-                callBackButtonView.setTag(IntentProvider.getReturnVoicemailCallIntentProvider());
-            } else {
-                // Sets the primary action to call the number.
-                callBackButtonView.setTag(IntentProvider.getReturnCallIntentProvider(number));
-            }
-            callBackButtonView.setVisibility(View.VISIBLE);
-            callBackButtonView.setOnClickListener(actionListener);
-
-            final int titleId;
-            if (callType == Calls.VOICEMAIL_TYPE || callType == Calls.OUTGOING_TYPE) {
-                titleId = R.string.call_log_action_redial;
-            } else {
-                titleId = R.string.call_log_action_call_back;
-            }
-            callBackButtonView.setText(mContext.getString(titleId));
-        } else {
-            // Number is not callable, so hide button.
-            callBackButtonView.setTag(null);
-            callBackButtonView.setVisibility(View.GONE);
-        }
-
         // If one of the calls had video capabilities, show the video call button.
         if (CallUtil.isVideoEnabled(mContext) && canPlaceCallToNumber &&
                 phoneCallDetailsViews.callTypeIcons.isVideoShown()) {
             videoCallButtonView.setTag(IntentProvider.getReturnVideoCallIntentProvider(number));
             videoCallButtonView.setVisibility(View.VISIBLE);
-            videoCallButtonView.setOnClickListener(actionListener);
+            videoCallButtonView.setOnClickListener(mActionListener);
         } else {
             videoCallButtonView.setTag(null);
             videoCallButtonView.setVisibility(View.GONE);
@@ -271,7 +295,7 @@
 
         // For voicemail calls, show the "VOICEMAIL" action button; hide otherwise.
         if (callType == Calls.VOICEMAIL_TYPE) {
-            voicemailButtonView.setOnClickListener(actionListener);
+            voicemailButtonView.setOnClickListener(mActionListener);
             voicemailButtonView.setTag(
                     IntentProvider.getPlayVoicemailIntentProvider(rowId, voicemailUri));
             voicemailButtonView.setVisibility(View.VISIBLE);
@@ -281,7 +305,7 @@
             voicemailButtonView.setTag(null);
             voicemailButtonView.setVisibility(View.GONE);
 
-            detailsButtonView.setOnClickListener(actionListener);
+            detailsButtonView.setOnClickListener(mActionListener);
             detailsButtonView.setTag(
                     IntentProvider.getCallDetailIntentProvider(rowId, callIds, null));
 
@@ -292,30 +316,21 @@
             }
         }
 
-        callLogViewsHelper.setActionContentDescriptions(this);
+        mCallLogListItemHelper.setActionContentDescriptions(this);
     }
 
     /**
-     * Expands or collapses the view containing the CALLBACK/REDIAL, VOICEMAIL and DETAILS action
-     * buttons.
+     * Show or hide the action views, such as voicemail, details, and add contact.
      *
-     * TODO: Reduce number of classes which need to be passed in to inflate the action view stub.
-     *     1) Instantiate them in this class, and store local references.
-     *     2) Set them on the CallLogListItemHelper and use it for inflation.
-     *     3) Implement a parent view for a call log list item, and store references in that class.
+     * If the action views have never been shown yet for this view, inflate the view stub.
      */
-    public void expandOrCollapseActions(
-            boolean isExpanded,
-            final CallLogAdapter.OnReportButtonClickListener onReportButtonClickListener,
-            View.OnClickListener actionListener,
-            PhoneNumberUtilsWrapper phoneNumberUtilsWrapper,
-            CallLogListItemHelper callLogViewsHelper) {
-        expandVoicemailTranscriptionView(isExpanded);
+    public void showActions(boolean show,
+            final CallLogAdapter.OnReportButtonClickListener onReportButtonClickListener) {
+        expandVoicemailTranscriptionView(show);
 
-        if (isExpanded) {
+        if (show) {
             // Inflate the view stub if necessary, and wire up the event handlers.
-            inflateActionViewStub(onReportButtonClickListener, actionListener,
-                    phoneNumberUtilsWrapper, callLogViewsHelper);
+            inflateActionViewStub(onReportButtonClickListener);
 
             actionsView.setVisibility(View.VISIBLE);
             actionsView.setAlpha(1.0f);
@@ -326,6 +341,27 @@
                 actionsView.setVisibility(View.GONE);
             }
         }
+
+        if (actionsView != null) {
+            final ViewTreeObserver observer = callLogEntryView.getViewTreeObserver();
+            observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                @Override
+                public boolean onPreDraw() {
+                    if (observer.isAlive()) {
+                        observer.removeOnPreDrawListener(this);
+                    }
+
+                    // TODO: Animate, instead of immediately resizing.
+                    int currentHeight = primaryActionView.getHeight();
+                    int actionsHeight = actionsView.getVisibility() == View.VISIBLE
+                            ? actionsView.getHeight() : 0;
+                    callLogEntryView.getLayoutParams().height = currentHeight + actionsHeight;
+                    callLogEntryView.requestLayout();
+
+                    return false;
+                }
+            });
+        }
     }
 
     public void expandVoicemailTranscriptionView(boolean isExpanded) {
@@ -371,20 +407,32 @@
     }
 
     @NeededForTesting
-    public static CallLogListItemViews createForTest(Context context) {
-        CallLogListItemViews views = new CallLogListItemViews(
+    public static CallLogListItemViewHolder createForTest(Context context) {
+        Resources resources = context.getResources();
+        PhoneNumberDisplayHelper phoneNumberHelper =
+                new PhoneNumberDisplayHelper(context, resources);
+        PhoneNumberUtilsWrapper phoneNumberUtilsWrapper = new PhoneNumberUtilsWrapper(context);
+        PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
+                context, resources, phoneNumberUtilsWrapper);
+
+        CallLogListItemViewHolder viewHolder = new CallLogListItemViewHolder(
                 context,
+                null /* actionListener */,
+                phoneNumberUtilsWrapper,
+                new CallLogListItemHelper(
+                        phoneCallDetailsHelper, phoneNumberHelper, resources),
                 new View(context),
                 new QuickContactBadge(context),
                 new View(context),
                 PhoneCallDetailsViews.createForTest(context),
                 new CardView(context),
-                new TextView(context));
-        views.callBackButtonView = new TextView(context);
-        views.voicemailButtonView = new TextView(context);
-        views.detailsButtonView = new TextView(context);
-        views.reportButtonView = new TextView(context);
-        views.actionsView = new View(context);
-        return views;
+                new TextView(context),
+                new View(context));
+        viewHolder.voicemailButtonView = new TextView(context);
+        viewHolder.detailsButtonView = new TextView(context);
+        viewHolder.reportButtonView = new TextView(context);
+        viewHolder.actionsView = new View(context);
+
+        return viewHolder;
     }
 }
diff --git a/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java b/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
index bffbe5c..70d63c9 100644
--- a/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.database.MatrixCursor;
+import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.View;
@@ -45,6 +46,7 @@
 
     private MatrixCursor mCursor;
     private View mView;
+    private ViewHolder mViewHolder;
 
     @Override
     protected void setUp() throws Exception {
@@ -72,7 +74,8 @@
         mCursor.moveToFirst();
         // The views into which to store the data.
         mView = new LinearLayout(getContext());
-        mView.setTag(CallLogListItemViews.createForTest(getContext()));
+        mViewHolder = CallLogListItemViewHolder.createForTest(getContext());
+        mView.setTag(mViewHolder);
     }
 
     @Override
@@ -88,7 +91,7 @@
 
         // Bind the views of a single row.
         mAdapter.changeCursor(mCursor);
-        mAdapter.onBindViewHolder(CallLogListItemViews.fromView(getContext(), mView), 0);
+        mAdapter.onBindViewHolder(mViewHolder, 0);
 
         // There is one request for contact details.
         assertEquals(1, mAdapter.getContactInfoCache().requests.size());
@@ -107,7 +110,7 @@
 
         // Bind the views of a single row.
         mAdapter.changeCursor(mCursor);
-        mAdapter.onBindViewHolder(CallLogListItemViews.fromView(getContext(), mView), 0);
+        mAdapter.onBindViewHolder(mViewHolder, 0);
 
         // There is one request for contact details.
         assertEquals(1, mAdapter.getContactInfoCache().requests.size());
@@ -126,8 +129,7 @@
 
         // Bind the views of a single row.
         mAdapter.changeCursor(mCursor);
-        mAdapter.onBindViewHolder(
-                CallLogListItemViews.fromView(getContext(), mView), 0);
+        mAdapter.onBindViewHolder(mViewHolder, 0);
 
         // There is one request for contact details.
         assertEquals(1, mAdapter.getContactInfoCache().requests.size());
@@ -143,7 +145,7 @@
 
         // Bind the views of a single row.
         mAdapter.changeCursor(mCursor);
-        mAdapter.onBindViewHolder(CallLogListItemViews.fromView(getContext(), mView), 0);
+        mAdapter.onBindViewHolder(mViewHolder, 0);
 
         // Cache and call log are up-to-date: no need to request update.
         assertEquals(0, mAdapter.getContactInfoCache().requests.size());
@@ -159,7 +161,7 @@
 
         // Bind the views of a single row.
         mAdapter.changeCursor(mCursor);
-        mAdapter.onBindViewHolder(CallLogListItemViews.fromView(getContext(), mView), 0);
+        mAdapter.onBindViewHolder(mViewHolder, 0);
 
         // There is one request for contact details.
         assertEquals(1, mAdapter.getContactInfoCache().requests.size());
diff --git a/tests/src/com/android/dialer/calllog/CallLogFragmentTest.java b/tests/src/com/android/dialer/calllog/CallLogFragmentTest.java
index fe14f87..0c19799 100644
--- a/tests/src/com/android/dialer/calllog/CallLogFragmentTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogFragmentTest.java
@@ -30,7 +30,6 @@
 import android.provider.CallLog.Calls;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.VoicemailContract;
-import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.test.ActivityInstrumentationTestCase2;
@@ -94,10 +93,10 @@
     private Random mRnd;
 
     // An item in the call list. All the methods performing checks use it.
-    private CallLogListItemViews mItem;
+    private CallLogListItemViewHolder mItem;
 
     // The list of view holderss representing the data in the DB, in reverse order from the DB.
-    private ViewHolder[] mList;
+    private CallLogListItemViewHolder[] mList;
 
     public CallLogFragmentTest() {
         super(FragmentTestActivity.class);
@@ -136,13 +135,13 @@
     /**
      * Checks that the call icon is not visible for private and
      * unknown numbers.
-     * Use 2 passes, one where new views are created and one where
-     * half of the total views are updated and the other half created.
+     * Use 2 passes, one where new viewHolder are created and one where
+     * half of the total viewHolder are updated and the other half created.
      */
     @MediumTest
     public void testCallViewIsNotVisibleForPrivateAndUnknownNumbers() {
         final int SIZE = 100;
-        mList = new ViewHolder[SIZE];
+        mList = new CallLogListItemViewHolder[SIZE];
 
         // Insert the first batch of entries.
         mCursor.moveToFirst();
@@ -153,7 +152,7 @@
         checkCallStatus();
 
         // Append the rest of the entries. We keep the first set of
-        // views around so they get updated and not built from
+        // viewHolder around so they get updated and not built from
         // scratch, this exposes some bugs that are not there when the
         // call log is launched for the 1st time but show up when the
         // call log gets updated afterwards.
@@ -165,28 +164,31 @@
     }
 
     @MediumTest
-    public void testCallAndGroupViews_GroupView() {
+    public void testCallAndGroupviewHolder_GroupView() {
         mCursor.moveToFirst();
         insertPrivate(NOW, 0);
         insertPrivate(NOW, 0);
         insertPrivate(NOW, 0);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         mAdapter.onBindViewHolder(viewHolder, /* position */ 0);
     }
 
     @MediumTest
-    public void testCallAndGroupViews_StandAloneView() {
+    public void testCallAndGroupviewHolder_StandAloneView() {
         mCursor.moveToFirst();
         insertPrivate(NOW, 0);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
     }
 
     @MediumTest
-    public void testCallAndGroupViews_ChildView() {
+    public void testCallAndGroupviewHolder_ChildView() {
         mCursor.moveToFirst();
         insertPrivate(NOW, 0);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         mAdapter.onBindViewHolder(viewHolder, /* position */ 0);
     }
 
@@ -194,11 +196,11 @@
     public void testBindView_NumberOnlyNoCache() {
         mCursor.moveToFirst();
         insert(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
 
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
-        assertNameIs(views, TEST_NUMBER);
+        assertNameIs(viewHolder, TEST_NUMBER);
     }
 
     @MediumTest
@@ -208,11 +210,11 @@
                 Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE);
         values[CallLogQuery.CACHED_FORMATTED_NUMBER] = TEST_FORMATTED_NUMBER;
         insertValues(values);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
 
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
-        assertNameIs(views, TEST_FORMATTED_NUMBER);
+        assertNameIs(viewHolder, TEST_FORMATTED_NUMBER);
     }
 
     @MediumTest
@@ -222,12 +224,12 @@
         // {@value com.android.dialer.calllog.ContactInfo#GEOCODE_AS_LABEL}
         insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE,
                 "John Doe", Phone.TYPE_HOME, TEST_DEFAULT_CUSTOM_LABEL);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
 
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
-        assertNameIs(views, "John Doe");
-        assertLabel(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_HOME));
+        assertNameIs(viewHolder, "John Doe");
+        assertLabel(viewHolder, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_HOME));
     }
 
     @MediumTest
@@ -235,12 +237,12 @@
         mCursor.moveToFirst();
         insertWithCachedValues("sip:johndoe@gmail.com", NOW, 0, Calls.INCOMING_TYPE,
                 "John Doe", Phone.TYPE_HOME, TEST_DEFAULT_CUSTOM_LABEL);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
 
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
-        assertNameIs(views, "John Doe");
-        assertLabel(views, "sip:johndoe@gmail.com", "sip:johndoe@gmail.com");
+        assertNameIs(viewHolder, "John Doe");
+        assertLabel(viewHolder, "sip:johndoe@gmail.com", "sip:johndoe@gmail.com");
     }
 
     @MediumTest
@@ -250,12 +252,12 @@
         // {@value com.android.dialer.calllog.ContactInfo#GEOCODE_AS_LABEL}
         insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE,
                 "John Doe", Phone.TYPE_HOME, TEST_DEFAULT_CUSTOM_LABEL);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
 
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
-        assertNameIs(views, "John Doe");
-        assertLabel(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_HOME));
+        assertNameIs(viewHolder, "John Doe");
+        assertLabel(viewHolder, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_HOME));
     }
 
     @MediumTest
@@ -265,12 +267,12 @@
         // {@link com.android.dialer.calllog.ContactInfo#GEOCODE_AS_LABEL}
         insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE,
                 "John Doe", Phone.TYPE_WORK, TEST_DEFAULT_CUSTOM_LABEL);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
 
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
-        assertNameIs(views, "John Doe");
-        assertLabel(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_WORK));
+        assertNameIs(viewHolder, "John Doe");
+        assertLabel(viewHolder, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_WORK));
     }
 
     @MediumTest
@@ -279,12 +281,12 @@
         String numberLabel = "My label";
         insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE,
                 "John Doe", Phone.TYPE_CUSTOM, numberLabel);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
 
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
-        assertNameIs(views, "John Doe");
-        assertLabel(views, TEST_FORMATTED_NUMBER, numberLabel);
+        assertNameIs(viewHolder, "John Doe");
+        assertLabel(viewHolder, TEST_FORMATTED_NUMBER, numberLabel);
     }
 
     @MediumTest
@@ -292,22 +294,22 @@
         mCursor.moveToFirst();
         insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE,
                 "John Doe", Phone.TYPE_HOME, "");
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
 
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
-        assertTrue(views.quickContactView.isEnabled());
+        assertTrue(viewHolder.quickContactView.isEnabled());
     }
 
     @MediumTest
     public void testBindView_WithoutQuickContactBadge() {
         mCursor.moveToFirst();
         insert(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
 
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
-        assertFalse(views.quickContactView.isEnabled());
+        assertFalse(viewHolder.quickContactView.isEnabled());
     }
 
     @MediumTest
@@ -315,16 +317,16 @@
         mCursor.moveToFirst();
         insert(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE);
         mAdapter.changeCursor(mCursor);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
-
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
+        viewHolder.updateCallButton();
 
         // The primaryActionView tag is set in the
         // {@link com.android.dialer.calllog.CallLogAdapter#bindView} method.  If it is possible
         // to place a call to the phone number, a call intent will have been created for the
         // primaryActionView.
-        IntentProvider intentProvider = (IntentProvider) views.callBackButtonView.getTag();
+        IntentProvider intentProvider = (IntentProvider) viewHolder.callActionView.getTag();
         Intent intent = intentProvider.getIntent(mActivity);
         // Starts a call.
         assertEquals(TestConstants.CALL_INTENT_ACTION, intent.getAction());
@@ -336,11 +338,11 @@
     public void testBindView_PlayButton() {
         mCursor.moveToFirst();
         insertVoicemail(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0);
-        ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+        CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder)
+                mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
         bindViewForTest(viewHolder);
 
-        CallLogListItemViews views = (CallLogListItemViews) viewHolder;
-        IntentProvider intentProvider = (IntentProvider) views.voicemailButtonView.getTag();
+        IntentProvider intentProvider = (IntentProvider) viewHolder.voicemailButtonView.getTag();
         Intent intent = intentProvider.getIntent(mActivity);
         // Starts the call detail activity.
         assertEquals(new ComponentName(mActivity, CallDetailActivity.class),
@@ -363,10 +365,10 @@
     }
 
     //
-    // HELPERS to check conditions on the DB/views
+    // HELPERS to check conditions on the DB/viewHolder
     //
     /**
-     * Go over the views in the list and check to ensure that
+     * Go over the viewHolder in the list and check to ensure that
      * callable numbers have an associated call intent, where numbers
      * which are not callable have a null intent.
      */
@@ -375,17 +377,17 @@
             if (null == mList[i]) {
                 break;
             }
-            mItem = (CallLogListItemViews) mList[i];
+            mItem = (CallLogListItemViewHolder) mList[i];
             int presentation = getPhoneNumberPresentationForListEntry(i);
             if (presentation == Calls.PRESENTATION_RESTRICTED ||
                     presentation == Calls.PRESENTATION_UNKNOWN) {
                 //If number is not callable, the primary action view should have a null tag.
-                assertNull(mItem.callBackButtonView.getTag());
+                assertNull(mItem.callActionView.getTag());
             } else {
                 //If the number is callable, the primary action view should have a non-null tag.
-                assertNotNull(mItem.callBackButtonView.getTag());
+                assertNotNull(mItem.callActionView.getTag());
 
-                IntentProvider intentProvider = (IntentProvider)mItem.callBackButtonView.getTag();
+                IntentProvider intentProvider = (IntentProvider)mItem.callActionView.getTag();
                 Intent callIntent = intentProvider.getIntent(mActivity);
 
                 //The intent should be to make the call
@@ -412,7 +414,7 @@
     }
 
     //
-    // HELPERS to build/update the call entries (views) from the DB.
+    // HELPERS to build/update the call entries (viewHolder) from the DB.
     //
 
     /**
@@ -425,7 +427,8 @@
         mCursor.moveToLast();
         while (!mCursor.isBeforeFirst()) {
             if (null == mList[i]) {
-                mList[i] = mAdapter.onCreateViewHolder(mParentView, /* itemType */ 0);
+                mList[i] = (CallLogListItemViewHolder)
+                        mAdapter.onCreateViewHolder(mParentView, /* itemType */ 0);
             }
             // Bind to the proper position, despite iterating in reverse.
             bindViewForTest(mList[i], mCursor.getCount() - i - 1);
@@ -452,12 +455,13 @@
      * @param view The current call log row.
      * @param position The position of hte item.
      */
-    private void bindViewForTest(ViewHolder viewHolder, int position) {
+    private void bindViewForTest(CallLogListItemViewHolder viewHolder, int position) {
         mAdapter.onBindViewHolder(viewHolder, position);
-        mAdapter.expandItem((CallLogListItemViews) viewHolder, /* expand */ true);
+        viewHolder.inflateActionViewStub(null);
+        viewHolder.updateCallButton();
     }
 
-    private void bindViewForTest(ViewHolder viewHolder) {
+    private void bindViewForTest(CallLogListItemViewHolder viewHolder) {
         bindViewForTest(viewHolder, /* position */ 0);
     }
 
@@ -645,17 +649,17 @@
     }
 
     /** Asserts that the name text view is shown and contains the given text. */
-    private void assertNameIs(CallLogListItemViews views, String name) {
-        assertEquals(View.VISIBLE, views.phoneCallDetailsViews.nameView.getVisibility());
-        assertEquals(name, views.phoneCallDetailsViews.nameView.getText().toString());
+    private void assertNameIs(CallLogListItemViewHolder viewHolder, String name) {
+        assertEquals(View.VISIBLE, viewHolder.phoneCallDetailsViews.nameView.getVisibility());
+        assertEquals(name, viewHolder.phoneCallDetailsViews.nameView.getText().toString());
     }
 
     /** Asserts that the label text view contains the given text. */
-    private void assertLabel(CallLogListItemViews views, CharSequence number,
+    private void assertLabel(CallLogListItemViewHolder viewHolder, CharSequence number,
             CharSequence label) {
         if (label != null) {
-            assertTrue(views.phoneCallDetailsViews.callLocationAndDate.getText().toString()
-                    .contains(label));
+            assertTrue(viewHolder.phoneCallDetailsViews.callLocationAndDate.getText()
+                    .toString().contains(label));
         }
     }
 }
diff --git a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
index 30a84c2..0f4974b 100644
--- a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
@@ -50,7 +50,7 @@
     private CallLogListItemHelper mHelper;
 
     /** The views used in the tests. */
-    private CallLogListItemViews mViews;
+    private CallLogListItemViewHolder mViewHolder;
     private PhoneNumberDisplayHelper mPhoneNumberHelper;
     private PhoneNumberDisplayHelper mPhoneNumberDisplayHelper;
 
@@ -68,20 +68,20 @@
         mPhoneNumberDisplayHelper = new PhoneNumberDisplayHelper(context, mResources, phoneUtils);
         mHelper = new CallLogListItemHelper(phoneCallDetailsHelper, mPhoneNumberDisplayHelper,
                 mResources);
-        mViews = CallLogListItemViews.createForTest(context);
+        mViewHolder = CallLogListItemViewHolder.createForTest(getContext());
     }
 
     @Override
     protected void tearDown() throws Exception {
         mHelper = null;
-        mViews = null;
+        mViewHolder = null;
         super.tearDown();
     }
 
     public void testSetPhoneCallDetails() {
         setPhoneCallDetailsWithNumber("12125551234", Calls.PRESENTATION_ALLOWED,
                 "1-212-555-1234");
-        assertEquals(View.VISIBLE, mViews.callBackButtonView.getVisibility());
+        assertEquals(View.VISIBLE, mViewHolder.callActionView.getVisibility());
     }
 
     public void testSetPhoneCallDetails_Unknown() {
@@ -102,23 +102,23 @@
     public void testSetPhoneCallDetails_VoicemailNumber() {
         setPhoneCallDetailsWithNumber(TEST_VOICEMAIL_NUMBER,
                 Calls.PRESENTATION_ALLOWED, TEST_VOICEMAIL_NUMBER);
-        assertEquals(View.VISIBLE, mViews.voicemailButtonView.getVisibility());
+        assertEquals(View.VISIBLE, mViewHolder.voicemailButtonView.getVisibility());
     }
 
     public void testSetPhoneCallDetails_ReadVoicemail() {
         setPhoneCallDetailsWithTypes(Calls.VOICEMAIL_TYPE);
-        assertEquals(View.VISIBLE, mViews.voicemailButtonView.getVisibility());
+        assertEquals(View.VISIBLE, mViewHolder.voicemailButtonView.getVisibility());
     }
 
     public void testSetPhoneCallDetails_UnreadVoicemail() {
         setUnreadPhoneCallDetailsWithTypes(Calls.VOICEMAIL_TYPE);
-        assertEquals(View.VISIBLE, mViews.voicemailButtonView.getVisibility());
+        assertEquals(View.VISIBLE, mViewHolder.voicemailButtonView.getVisibility());
     }
 
     public void testSetPhoneCallDetails_VoicemailFromUnknown() {
         setPhoneCallDetailsWithNumberAndType("", Calls.PRESENTATION_UNKNOWN,
                 "", Calls.VOICEMAIL_TYPE);
-        assertEquals(View.VISIBLE, mViews.voicemailButtonView.getVisibility());
+        assertEquals(View.VISIBLE, mViewHolder.voicemailButtonView.getVisibility());
     }
 
     /**
@@ -335,7 +335,7 @@
 
     /** Asserts that the primary action view does not have a call intent. */
     private void assertNoCallIntent() {
-        Object intentProvider = (IntentProvider)mViews.primaryActionView.getTag();
+        Object intentProvider = (IntentProvider)mViewHolder.primaryActionView.getTag();
         // The intent provider should be null as there is no ability to make a call.
         assertNull(intentProvider);
     }
@@ -350,7 +350,7 @@
     /** Sets the details of a phone call using the specified phone number. */
     private void setPhoneCallDetailsWithNumberAndType(String number,
             int presentation, String formattedNumber, int callType) {
-        mHelper.setPhoneCallDetails(getContext(), mViews,
+        mHelper.setPhoneCallDetails(getContext(), mViewHolder,
                 new PhoneCallDetails(number, presentation, formattedNumber,
                         TEST_COUNTRY_ISO, TEST_GEOCODE,
                         new int[]{ callType }, TEST_DATE, TEST_DURATION)
@@ -359,7 +359,7 @@
 
     /** Sets the details of a phone call using the specified call type. */
     private void setPhoneCallDetailsWithTypes(int... types) {
-        mHelper.setPhoneCallDetails(getContext() ,mViews,
+        mHelper.setPhoneCallDetails(getContext() ,mViewHolder,
                 new PhoneCallDetails(TEST_NUMBER, Calls.PRESENTATION_ALLOWED,
                         TEST_FORMATTED_NUMBER, TEST_COUNTRY_ISO, TEST_GEOCODE,
                         types, TEST_DATE, TEST_DURATION)
@@ -368,7 +368,7 @@
 
     /** Sets the details of an unread phone call using the specified call type. */
     private void setUnreadPhoneCallDetailsWithTypes(int... types) {
-        mHelper.setPhoneCallDetails(getContext(), mViews,
+        mHelper.setPhoneCallDetails(getContext(), mViewHolder,
                 new PhoneCallDetails(TEST_NUMBER, Calls.PRESENTATION_ALLOWED,
                         TEST_FORMATTED_NUMBER, TEST_COUNTRY_ISO, TEST_GEOCODE,
                         types, TEST_DATE, TEST_DURATION)