Fix voicemail tab items reading "speed dial" when selected.

The voicemail entries were reading "speed dial" because the focus would go
to the newly added "speed dial" tab since the tabs are all removed and
readded when the tab info changes. Change the logic so that only the
voicemail tab is changed when needed.
The voicemail entry reads "seek playback" instead of the information
about the voicemail because of custom expand logic for accessibilty.
Change it so that only the call log items are expanded when selected
(it is more important to be able to discover the overflow options).
Also change content description text because it was too long and confusing.

Bug: 25124120
Change-Id: I64c1b27d8c0db57525f7f4ada59655e9f8352245
diff --git a/res/values/strings.xml b/res/values/strings.xml
index df8d0fa..028e87b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -363,13 +363,6 @@
     -->
     <string name="description_contact_details">Contact details for <xliff:g id="nameOrNumber">%1$s</xliff:g></string>
 
-    <!-- String indicating a call log entry has an associated voicemail.
-
-    Note: AccessibilityServices use this attribute to announce what the view represents.
-          This is especially valuable for views without textual representation like ImageView.
-    -->
-    <string name="description_new_voicemail">New voicemail.</string>
-
     <!-- String indicating the number of calls to/from a caller in the call log.
 
     Note: AccessibilityServices use this attribute to announce what the view represents.
@@ -632,6 +625,16 @@
          [CHAR LIMIT=NONE] -->
     <string name="description_incoming_answered_call">Answered call from <xliff:g id="nameOrNumber" example="John Smith">^1</xliff:g>, <xliff:g id="typeOrLocation" example="Mobile">^2</xliff:g>, <xliff:g id="timeOfCall" example="2 min ago">^3</xliff:g>, <xliff:g id="phoneAccount" example="on SIM 1">^4</xliff:g>.</string>
 
+    <!-- String describing an "unread" voicemail entry in the voicemails tab.
+         Note: AccessibilityServices use this attribute to announce what the view represents.
+         [CHAR LIMIT=NONE] -->
+    <string name="description_unread_voicemail">Unread voicemail from <xliff:g id="nameOrNumber" example="John Smith">^1</xliff:g>, <xliff:g id="typeOrLocation" example="Mobile">^2</xliff:g>, <xliff:g id="timeOfCall" example="2 min ago">^3</xliff:g>, <xliff:g id="phoneAccount" example="on SIM 1">^4</xliff:g>.</string>
+
+    <!-- String describing a "read" voicemail entry in the voicemails tab.
+     Note: AccessibilityServices use this attribute to announce what the view represents.
+     [CHAR LIMIT=NONE] -->
+    <string name="description_read_voicemail">Voicemail from <xliff:g id="nameOrNumber" example="John Smith">^1</xliff:g>, <xliff:g id="typeOrLocation" example="Mobile">^2</xliff:g>, <xliff:g id="timeOfCall" example="2 min ago">^3</xliff:g>, <xliff:g id="phoneAccount" example="on SIM 1">^4</xliff:g>.</string>
+
     <!-- String describing an outgoing call entry in the call log.
          Note: AccessibilityServices uses this attribute to announce what the view represents.
          [CHAR LIMIT=NONE] -->
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 3dccf27..ce48872 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -211,7 +211,8 @@
                 // Only expand if actions are not already expanded, because triggering the expand
                 // function on clicks causes the action views to lose the focus indicator.
                 CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder) host.getTag();
-                if (mCurrentlyExpandedPosition != viewHolder.getAdapterPosition()) {
+                if (mVoicemailPlaybackPresenter == null &&
+                        mCurrentlyExpandedPosition != viewHolder.getAdapterPosition()) {
                     expandViewHolderActions((CallLogListItemViewHolder) host.getTag());
                 }
             }
diff --git a/src/com/android/dialer/calllog/CallLogListItemHelper.java b/src/com/android/dialer/calllog/CallLogListItemHelper.java
index 84d0364..57a83e6 100644
--- a/src/com/android/dialer/calllog/CallLogListItemHelper.java
+++ b/src/com/android/dialer/calllog/CallLogListItemHelper.java
@@ -164,7 +164,6 @@
      */
     public CharSequence getCallDescription(PhoneCallDetails details) {
         int lastCallType = getLastCallType(details.callTypes);
-        boolean isVoiceMail = lastCallType == Calls.VOICEMAIL_TYPE;
 
         // Get the name or number of the caller.
         final CharSequence nameOrNumber = getNameOrNumber(details);
@@ -177,11 +176,6 @@
 
         SpannableStringBuilder callDescription = new SpannableStringBuilder();
 
-        // Prepend the voicemail indication.
-        if (isVoiceMail) {
-            callDescription.append(mResources.getString(R.string.description_new_voicemail));
-        }
-
         // Add number of calls if more than one.
         if (details.callTypes.length > 1) {
             callDescription.append(mResources.getString(R.string.description_num_calls,
@@ -193,7 +187,7 @@
             callDescription.append(mResources.getString(R.string.description_video_call));
         }
 
-        int stringID = getCallDescriptionStringID(details.callTypes);
+        int stringID = getCallDescriptionStringID(details.callTypes, details.isRead);
         String accountLabel = mTelecomCallLogCache.getAccountLabel(details.accountHandle);
 
         // Use chosen string resource to build up the message.
@@ -217,15 +211,16 @@
     /**
      * Determine the appropriate string ID to describe a call for accessibility purposes.
      *
-     * @param details Call details.
+     * @param callTypes The type of call corresponding to this entry or multiple if this entry
+     * represents multiple calls grouped together.
+     * @param isRead If the entry is a voicemail, {@code true} if the voicemail is read.
      * @return String resource ID to use.
      */
-    public int getCallDescriptionStringID(int[] callTypes) {
+    public int getCallDescriptionStringID(int[] callTypes, boolean isRead) {
         int lastCallType = getLastCallType(callTypes);
         int stringID;
 
-        if (lastCallType == AppCompatConstants.CALLS_VOICEMAIL_TYPE
-                || lastCallType == AppCompatConstants.CALLS_MISSED_TYPE) {
+        if (lastCallType == AppCompatConstants.CALLS_MISSED_TYPE) {
             //Message: Missed call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>,
             //<PhoneAccount>.
             stringID = R.string.description_incoming_missed_call;
@@ -233,6 +228,11 @@
             //Message: Answered call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>,
             //<PhoneAccount>.
             stringID = R.string.description_incoming_answered_call;
+        } else if (lastCallType == AppCompatConstants.CALLS_VOICEMAIL_TYPE) {
+            //Message: (Unread) [V/v]oicemail from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>,
+            //<PhoneAccount>.
+            stringID = isRead ? R.string.description_read_voicemail
+                : R.string.description_unread_voicemail;
         } else {
             //Message: Call to <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>, <PhoneAccount>.
             stringID = R.string.description_outgoing_call;
diff --git a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
index 23c77d3..5499902 100644
--- a/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
+++ b/src/com/android/dialer/calllog/CallLogListItemViewHolder.java
@@ -398,6 +398,9 @@
             // Treat as voicemail list item; show play button if not expanded.
             if (!isExpanded) {
                 primaryActionButtonView.setImageResource(R.drawable.ic_play_arrow_24dp);
+                primaryActionButtonView.setContentDescription(TextUtils.expandTemplate(
+                        mContext.getString(R.string.description_voicemail_action),
+                        nameOrNumber));
                 primaryActionButtonView.setVisibility(View.VISIBLE);
             } else {
                 primaryActionButtonView.setVisibility(View.GONE);
diff --git a/src/com/android/dialer/list/ListsFragment.java b/src/com/android/dialer/list/ListsFragment.java
index c80ab42..934792c 100644
--- a/src/com/android/dialer/list/ListsFragment.java
+++ b/src/com/android/dialer/list/ListsFragment.java
@@ -313,7 +313,7 @@
         if (hasActiveVoicemailProvider != mHasActiveVoicemailProvider) {
             mHasActiveVoicemailProvider = hasActiveVoicemailProvider;
             mViewPagerAdapter.notifyDataSetChanged();
-            mViewPagerTabs.setViewPager(mViewPager);
+            mViewPagerTabs.updateTab(TAB_INDEX_VOICEMAIL);
 
             mPrefs.edit()
                   .putBoolean(PREF_KEY_HAS_ACTIVE_VOICEMAIL_PROVIDER, hasActiveVoicemailProvider)
@@ -344,7 +344,7 @@
         }
 
         mViewPagerTabs.setUnreadCount(count, TAB_INDEX_VOICEMAIL);
-        mViewPagerTabs.setViewPager(mViewPager);
+        mViewPagerTabs.updateTab(TAB_INDEX_VOICEMAIL);
     }
 
     @Override
diff --git a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
index 12f32ce..c9d8264 100644
--- a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
@@ -129,27 +129,18 @@
      * Test getCallDescriptionID method used to get the accessibility description for calls.
      */
     public void testGetCallDescriptionID_Answered() {
-        int[] callTypes = new int[]{ AppCompatConstants.CALLS_INCOMING_TYPE };
+        int[] callTypes = new int[] {AppCompatConstants.CALLS_INCOMING_TYPE};
         assertEquals(R.string.description_incoming_answered_call,
-                mHelper.getCallDescriptionStringID(callTypes));
+                mHelper.getCallDescriptionStringID(callTypes, true));
     }
 
     /**
      * Test getCallDescriptionID method used to get the accessibility description for calls.
      */
     public void testGetCallDescriptionID_Missed() {
-        int[] callTypes = new int[]{ AppCompatConstants.CALLS_MISSED_TYPE };
+        int[] callTypes = new int[] {AppCompatConstants.CALLS_MISSED_TYPE};
         assertEquals(R.string.description_incoming_missed_call,
-                mHelper.getCallDescriptionStringID(callTypes));
-    }
-
-    /**
-     * Test getCallDescriptionID method used to get the accessibility description for calls.
-     */
-    public void testGetCallDescriptionID_Voicemail() {
-        int[] callTypes = new int[]{ AppCompatConstants.CALLS_VOICEMAIL_TYPE };
-        assertEquals(R.string.description_incoming_missed_call,
-                mHelper.getCallDescriptionStringID(callTypes));
+                mHelper.getCallDescriptionStringID(callTypes, true));
     }
 
     /**
@@ -158,9 +149,9 @@
      * only a single call for this caller.
      */
     public void testGetCallDescriptionID_OutgoingSingle() {
-        int[] callTypes = new int[]{ AppCompatConstants.CALLS_OUTGOING_TYPE };
+        int[] callTypes = new int[] {AppCompatConstants.CALLS_OUTGOING_TYPE};
         assertEquals(R.string.description_outgoing_call,
-                mHelper.getCallDescriptionStringID(callTypes));
+                mHelper.getCallDescriptionStringID(callTypes, true));
     }
 
     /**
@@ -169,60 +160,32 @@
      * many calls for this caller.
      */
     public void testGetCallDescriptionID_OutgoingMultiple() {
-        int[] callTypes = new int[]{
+        int[] callTypes = new int[] {
             AppCompatConstants.CALLS_OUTGOING_TYPE,
             AppCompatConstants.CALLS_OUTGOING_TYPE
         };
         assertEquals(R.string.description_outgoing_call,
-                mHelper.getCallDescriptionStringID(callTypes));
+                mHelper.getCallDescriptionStringID(callTypes, true));
     }
 
     /**
      * Test getCallDescription method used to get the accessibility description for calls.
-     * For outgoing calls, we should NOT have "New Voicemail" in the description.
+     * For read voicemail calls, we should have "Voicemail" in the description.
      */
-    public void testGetCallDescription_NoVoicemailOutgoing() {
-        PhoneCallDetails details = getPhoneCallDetailsWithTypes(
-                AppCompatConstants.CALLS_OUTGOING_TYPE, AppCompatConstants.CALLS_OUTGOING_TYPE);
-        CharSequence description = mHelper.getCallDescription(details);
-        assertFalse(description.toString()
-                .contains(this.mResources.getString(R.string.description_new_voicemail)));
+    public void testGetCallDescriptionID_Voicemail() {
+        int[] callTypes = new int[] {AppCompatConstants.CALLS_VOICEMAIL_TYPE};
+        assertEquals(R.string.description_read_voicemail,
+                mHelper.getCallDescriptionStringID(callTypes, true));
     }
 
     /**
      * Test getCallDescription method used to get the accessibility description for calls.
-     * For regular incoming calls, we should NOT have "New Voicemail" in the description.
+     * For unread voicemail calls, we should have "Unread voicemail" in the description.
      */
-    public void testGetCallDescription_NoVoicemailIncoming() {
-        PhoneCallDetails details = getPhoneCallDetailsWithTypes(
-                AppCompatConstants.CALLS_INCOMING_TYPE, AppCompatConstants.CALLS_OUTGOING_TYPE);
-        CharSequence description = mHelper.getCallDescription(details);
-        assertFalse(description.toString()
-                .contains(this.mResources.getString(R.string.description_new_voicemail)));
-    }
-
-    /**
-     * Test getCallDescription method used to get the accessibility description for calls.
-     * For regular missed calls, we should NOT have "New Voicemail" in the description.
-     */
-    public void testGetCallDescription_NoVoicemailMissed() {
-        PhoneCallDetails details = getPhoneCallDetailsWithTypes(
-                AppCompatConstants.CALLS_MISSED_TYPE, AppCompatConstants.CALLS_OUTGOING_TYPE);
-        CharSequence description = mHelper.getCallDescription(details);
-        assertFalse(description.toString()
-                .contains(this.mResources.getString(R.string.description_new_voicemail)));
-    }
-
-    /**
-     * Test getCallDescription method used to get the accessibility description for calls.
-     * For voicemail calls, we should have "New Voicemail" in the description.
-     */
-    public void testGetCallDescription_Voicemail() {
-        PhoneCallDetails details = getPhoneCallDetailsWithTypes(
-                AppCompatConstants.CALLS_VOICEMAIL_TYPE, AppCompatConstants.CALLS_OUTGOING_TYPE);
-        CharSequence description = mHelper.getCallDescription(details);
-        assertTrue(description.toString()
-                .contains(this.mResources.getString(R.string.description_new_voicemail)));
+    public void testGetCallDescriptionID_UnreadVoicemail() {
+        int[] callTypes = new int[] {AppCompatConstants.CALLS_VOICEMAIL_TYPE};
+        assertEquals(R.string.description_unread_voicemail,
+                mHelper.getCallDescriptionStringID(callTypes, false));
     }
 
     /**
@@ -292,7 +255,7 @@
             int presentation, String formattedNumber, int callType) {
         PhoneCallDetails details = getPhoneCallDetails(
                 number, presentation, formattedNumber);
-        details.callTypes = new int[]{ callType };
+        details.callTypes = new int[] {callType};
         mHelper.setPhoneCallDetails(mViewHolder, details);
     }
 
@@ -322,7 +285,7 @@
     }
 
     private void setDefaultDetails(PhoneCallDetails details) {
-        details.callTypes = new int[]{ Calls.INCOMING_TYPE };
+        details.callTypes = new int[] {Calls.INCOMING_TYPE};
         details.countryIso = TEST_COUNTRY_ISO;
         details.date = TEST_DATE;
         details.duration = TEST_DURATION;