Merge "Add via number to CallLog Account entry" into nyc-dev
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index 469e72a..660bca3 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -125,6 +125,7 @@
                         android:id="@+id/call_account_label"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
+                        android:layout_marginTop="@dimen/call_log_call_account_margin_bottom"
                         android:layout_marginEnd="@dimen/call_log_icon_margin"
                         android:textColor="?attr/call_log_secondary_text_color"
                         android:textSize="@dimen/call_log_detail_text_size"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a9f2702..371a1c6 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -34,6 +34,7 @@
     <dimen name="call_log_start_margin">8dp</dimen>
     <dimen name="call_log_indent_margin">24dp</dimen>
     <dimen name="call_log_name_margin_bottom">2dp</dimen>
+    <dimen name="call_log_call_account_margin_bottom">2dp</dimen>
     <dimen name="call_log_vertical_padding">12dp</dimen>
     <dimen name="call_log_list_item_height">56dp</dimen>
     <dimen name="call_log_list_item_info_margin_start">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ee9418a..cb85684 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -731,6 +731,26 @@
          [CHAR LIMIT=NONE] -->
     <string name="description_phone_account">on <xliff:g id="phoneAccount" example="SIM 1">^1</xliff:g></string>
 
+    <!-- String describing the secondary line number the call was received via.
+         Note: AccessibilityServices use this attribute to announce what the view represents.
+         [CHAR LIMIT=NONE]-->
+    <string name="description_via_number">via <xliff:g id="number" example="(555) 555-5555">%1$s</xliff:g></string>
+
+    <!-- TextView text item showing the secondary line number the call was received via.
+         [CHAR LIMIT=NONE]-->
+    <string name="call_log_via_number">via <xliff:g id="number" example="(555) 555-5555">%1$s</xliff:g></string>
+
+    <!-- String describing the PhoneAccount and via number that a call was received on, if both are
+         visible.
+         Note: AccessibilityServices use this attribute to announce what the view represents.
+         [CHAR LIMIT=NONE]-->
+    <string name="description_via_number_phone_account">on <xliff:g id="phoneAccount" example="SIM 1">%1$s</xliff:g>, via <xliff:g id="number" example="(555) 555-5555">%2$s</xliff:g></string>
+
+    <!-- The order of the PhoneAccount and via number that a call was received on,
+         if both are visible.
+         [CHAR LIMIT=NONE]-->
+    <string name="call_log_via_number_phone_account"><xliff:g id="phoneAccount" example="SIM 1">%1$s</xliff:g> via <xliff:g id="number" example="(555) 555-5555">%2$s</xliff:g></string>
+
     <!-- 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>
diff --git a/src-N/com/android/dialer/compat/CallsSdkCompat.java b/src-N/com/android/dialer/compat/CallsSdkCompat.java
index 3d72e35..a428ca3 100644
--- a/src-N/com/android/dialer/compat/CallsSdkCompat.java
+++ b/src-N/com/android/dialer/compat/CallsSdkCompat.java
@@ -21,4 +21,5 @@
 public class CallsSdkCompat {
 
     public static final String POST_DIAL_DIGITS = CallLog.Calls.POST_DIAL_DIGITS;
+    public static final String VIA_NUMBER  = CallLog.Calls.VIA_NUMBER;
 }
diff --git a/src-pre-N/com/android/dialer/compat/CallsSdkCompat.java b/src-pre-N/com/android/dialer/compat/CallsSdkCompat.java
index 836f091..60d3ca1 100644
--- a/src-pre-N/com/android/dialer/compat/CallsSdkCompat.java
+++ b/src-pre-N/com/android/dialer/compat/CallsSdkCompat.java
@@ -21,4 +21,5 @@
 public class CallsSdkCompat {
 
     @Nullable public static final String POST_DIAL_DIGITS = null;
+    @Nullable public static final String VIA_NUMBER = null;
 }
diff --git a/src/com/android/dialer/CallDetailActivity.java b/src/com/android/dialer/CallDetailActivity.java
index 42bee1e..94c2f00 100644
--- a/src/com/android/dialer/CallDetailActivity.java
+++ b/src/com/android/dialer/CallDetailActivity.java
@@ -142,10 +142,23 @@
                 }
             }
 
-            String accountLabel =
-                    PhoneAccountUtils.getAccountLabel(mContext, mDetails.accountHandle);
+            CharSequence accountLabel = PhoneAccountUtils.getAccountLabel(mContext,
+                    mDetails.accountHandle);
+            CharSequence accountContentDescription =
+                    PhoneCallDetails.createAccountLabelDescription(mResources, mDetails.viaNumber,
+                            accountLabel);
+            if (!TextUtils.isEmpty(mDetails.viaNumber)) {
+                if (!TextUtils.isEmpty(accountLabel)) {
+                    accountLabel = mResources.getString(R.string.call_log_via_number_phone_account,
+                            accountLabel, mDetails.viaNumber);
+                } else {
+                    accountLabel = mResources.getString(R.string.call_log_via_number,
+                            mDetails.viaNumber);
+                }
+            }
             if (!TextUtils.isEmpty(accountLabel)) {
                 mAccountLabel.setText(accountLabel);
+                mAccountLabel.setContentDescription(accountContentDescription);
                 mAccountLabel.setVisibility(View.VISIBLE);
             } else {
                 mAccountLabel.setVisibility(View.GONE);
diff --git a/src/com/android/dialer/PhoneCallDetails.java b/src/com/android/dialer/PhoneCallDetails.java
index b332b43..17f1c2b 100644
--- a/src/com/android/dialer/PhoneCallDetails.java
+++ b/src/com/android/dialer/PhoneCallDetails.java
@@ -18,11 +18,14 @@
 
 import com.android.contacts.common.ContactsUtils.UserType;
 import com.android.contacts.common.preference.ContactsPreferences;
+import com.android.contacts.common.util.ContactDisplayUtils;
 import com.android.dialer.calllog.PhoneNumberDisplayUtil;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.net.Uri;
 import android.provider.CallLog.Calls;
+import android.support.annotation.Nullable;
 import android.telecom.PhoneAccountHandle;
 import android.text.TextUtils;
 
@@ -34,6 +37,8 @@
     public CharSequence number;
     // Post-dial digits associated with the outgoing call.
     public String postDialDigits;
+    // The secondary line number the call was received via.
+    public String viaNumber;
     // The number presenting rules set by the network, e.g., {@link Calls#PRESENTATION_ALLOWED}
     public int numberPresentation;
     // The formatted version of {@link #number}.
@@ -149,4 +154,31 @@
         }
         return nameAlternative;
     }
+
+    /**
+     * Construct the "on {accountLabel} via {viaNumber}" accessibility description for the account
+     * list item, depending on the existence of the accountLabel and viaNumber.
+     * @param viaNumber The number that this call is being placed via.
+     * @param accountLabel The {@link PhoneAccount} label that this call is being placed with.
+     * @return The description of the account that this call has been placed on.
+     */
+    public static CharSequence createAccountLabelDescription(Resources resources,
+            @Nullable String viaNumber, @Nullable CharSequence accountLabel) {
+
+        if((!TextUtils.isEmpty(viaNumber)) && !TextUtils.isEmpty(accountLabel)) {
+            String msg = resources.getString(R.string.description_via_number_phone_account,
+                    accountLabel, viaNumber);
+            CharSequence accountNumberLabel = ContactDisplayUtils.getTelephoneTtsSpannable(msg,
+                    viaNumber);
+            return (accountNumberLabel == null) ? msg : accountNumberLabel;
+        } else if (!TextUtils.isEmpty(viaNumber)) {
+            CharSequence viaNumberLabel = ContactDisplayUtils.getTtsSpannedPhoneNumber(resources,
+                    R.string.description_via_number, viaNumber);
+            return (viaNumberLabel == null) ? viaNumber : viaNumberLabel;
+        } else if (!TextUtils.isEmpty(accountLabel)) {
+            return TextUtils.expandTemplate(
+                    resources.getString(R.string.description_phone_account), accountLabel);
+        }
+        return "";
+    }
 }
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 165594e..3958611 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -490,15 +490,17 @@
         int count = getGroupSize(position);
 
         final String number = c.getString(CallLogQuery.NUMBER);
+        final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
         final String postDialDigits = CompatUtils.isNCompatible()
                 && mActivityType != ACTIVITY_TYPE_ARCHIVE ?
                 c.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
-
+        final String viaNumber = CompatUtils.isNCompatible()
+                && mActivityType != ACTIVITY_TYPE_ARCHIVE ?
+                c.getString(CallLogQuery.VIA_NUMBER) : "";
         final int numberPresentation = c.getInt(CallLogQuery.NUMBER_PRESENTATION);
         final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount(
                 c.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME),
                 c.getString(CallLogQuery.ACCOUNT_ID));
-        final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
         final ContactInfo cachedContactInfo = ContactInfoHelper.getContactInfo(c);
         final boolean isVoicemailNumber =
                 mCallLogCache.isVoicemailNumber(accountHandle, number);
@@ -518,6 +520,7 @@
         final PhoneCallDetails details = new PhoneCallDetails(
                 mContext, number, numberPresentation, formattedNumber,
                 postDialDigits, isVoicemailNumber);
+        details.viaNumber = viaNumber;
         details.accountHandle = accountHandle;
         details.countryIso = countryIso;
         details.date = c.getLong(CallLogQuery.DATE);
diff --git a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
index 7cb35f5..34b2f0e 100644
--- a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
+++ b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
@@ -28,6 +28,7 @@
 import android.provider.CallLog;
 import android.provider.VoicemailContract.Voicemails;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -44,6 +45,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Locale;
 
 public class CallLogAsyncTaskUtil {
     private static String TAG = CallLogAsyncTaskUtil.class.getSimpleName();
@@ -90,12 +92,14 @@
         static final int DATA_USAGE = 10;
         static final int TRANSCRIPTION_COLUMN_INDEX = 11;
         static final int POST_DIAL_DIGITS = 12;
+        static final int VIA_NUMBER = 13;
 
         static {
             ArrayList<String> projectionList = new ArrayList<>();
             projectionList.addAll(Arrays.asList(CALL_LOG_PROJECTION_INTERNAL));
             if (CompatUtils.isNCompatible()) {
                 projectionList.add(CallsSdkCompat.POST_DIAL_DIGITS);
+                projectionList.add(CallsSdkCompat.VIA_NUMBER);
             }
             projectionList.trimToSize();
             CALL_LOG_PROJECTION = projectionList.toArray(new String[projectionList.size()]);
@@ -187,6 +191,8 @@
             final String number = cursor.getString(CallDetailQuery.NUMBER_COLUMN_INDEX);
             final String postDialDigits = CompatUtils.isNCompatible()
                     ? cursor.getString(CallDetailQuery.POST_DIAL_DIGITS) : "";
+            final String viaNumber = CompatUtils.isNCompatible() ?
+                    cursor.getString(CallDetailQuery.VIA_NUMBER) : "";
             final int numberPresentation =
                     cursor.getInt(CallDetailQuery.NUMBER_PRESENTATION_COLUMN_INDEX);
 
@@ -211,6 +217,7 @@
                     context, number, numberPresentation, info.formattedNumber,
                     postDialDigits, isVoicemail);
 
+            details.viaNumber = viaNumber;
             details.accountHandle = accountHandle;
             details.contactUri = info.lookupUri;
             details.namePrimary = info.name;
diff --git a/src/com/android/dialer/calllog/CallLogGroupBuilder.java b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
index 0931e06..aa45029 100644
--- a/src/com/android/dialer/calllog/CallLogGroupBuilder.java
+++ b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
@@ -125,6 +125,8 @@
         String groupNumber = cursor.getString(CallLogQuery.NUMBER);
         String groupPostDialDigits = CompatUtils.isNCompatible()
                 ? cursor.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
+        String groupViaNumbers = CompatUtils.isNCompatible()
+                ? cursor.getString(CallLogQuery.VIA_NUMBER) : "";
         int groupCallType = cursor.getInt(CallLogQuery.CALL_TYPE);
         String groupAccountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
         String groupAccountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
@@ -132,6 +134,7 @@
 
         String number;
         String numberPostDialDigits;
+        String numberViaNumbers;
         int callType;
         String accountComponentName;
         String accountId;
@@ -141,18 +144,21 @@
             number = cursor.getString(CallLogQuery.NUMBER);
             numberPostDialDigits = CompatUtils.isNCompatible()
                     ? cursor.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
+            numberViaNumbers = CompatUtils.isNCompatible()
+                    ? cursor.getString(CallLogQuery.VIA_NUMBER) : "";
             callType = cursor.getInt(CallLogQuery.CALL_TYPE);
             accountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
             accountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
 
             final boolean isSameNumber = equalNumbers(groupNumber, number);
             final boolean isSamePostDialDigits = groupPostDialDigits.equals(numberPostDialDigits);
+            final boolean isSameViaNumbers = groupViaNumbers.equals(numberViaNumbers);
             final boolean isSameAccount = isSameAccount(
                     groupAccountComponentName, accountComponentName, groupAccountId, accountId);
 
             // Group with the same number and account. Never group voicemails. Only group blocked
             // calls with other blocked calls.
-            if (isSameNumber && isSameAccount && isSamePostDialDigits
+            if (isSameNumber && isSameAccount && isSamePostDialDigits && isSameViaNumbers
                     && areBothNotVoicemail(callType, groupCallType)
                     && (areBothNotBlocked(callType, groupCallType)
                             || areBothBlocked(callType, groupCallType))) {
@@ -174,6 +180,7 @@
                 // Update the group values to those of the current call.
                 groupNumber = number;
                 groupPostDialDigits = numberPostDialDigits;
+                groupViaNumbers = numberViaNumbers;
                 groupCallType = callType;
                 groupAccountComponentName = accountComponentName;
                 groupAccountId = accountId;
diff --git a/src/com/android/dialer/calllog/CallLogListItemHelper.java b/src/com/android/dialer/calllog/CallLogListItemHelper.java
index 5d2bc85..07e2bb4 100644
--- a/src/com/android/dialer/calllog/CallLogListItemHelper.java
+++ b/src/com/android/dialer/calllog/CallLogListItemHelper.java
@@ -188,20 +188,15 @@
             callDescription.append(mResources.getString(R.string.description_video_call));
         }
 
-        int stringID = getCallDescriptionStringID(details.callTypes, details.isRead);
         String accountLabel = mCallLogCache.getAccountLabel(details.accountHandle);
+        CharSequence onAccountLabel = PhoneCallDetails.createAccountLabelDescription(mResources,
+                details.viaNumber, accountLabel);
 
-        // Use chosen string resource to build up the message.
-        CharSequence onAccountLabel = accountLabel == null
-                ? ""
-                : TextUtils.expandTemplate(
-                        mResources.getString(R.string.description_phone_account),
-                        accountLabel);
+        int stringID = getCallDescriptionStringID(details.callTypes, details.isRead);
         callDescription.append(
                 TextUtils.expandTemplate(
                         mResources.getString(stringID),
                         nameOrNumber,
-                        // If no type or location can be determined, sub in empty string.
                         typeOrLocation == null ? "" : typeOrLocation,
                         timeOfCall,
                         onAccountLabel));
diff --git a/src/com/android/dialer/calllog/CallLogQuery.java b/src/com/android/dialer/calllog/CallLogQuery.java
index 4900354..e1a4119 100644
--- a/src/com/android/dialer/calllog/CallLogQuery.java
+++ b/src/com/android/dialer/calllog/CallLogQuery.java
@@ -93,6 +93,7 @@
      * Call {@link CompatUtils#isNCompatible()} prior to use
      */
     public static int POST_DIAL_DIGITS = -1;
+    public static int VIA_NUMBER = -1;
 
     public static final String[] _PROJECTION;
 
@@ -105,6 +106,8 @@
         if (CompatUtils.isNCompatible()) {
             projectionList.add(CallsSdkCompat.POST_DIAL_DIGITS);
             POST_DIAL_DIGITS = projectionList.size() - 1;
+            projectionList.add(CallsSdkCompat.VIA_NUMBER);
+            VIA_NUMBER = projectionList.size() - 1;
         }
         _PROJECTION = projectionList.toArray(new String[projectionList.size()]);
     }
diff --git a/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java b/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java
index 7b149e2..4f1c455 100644
--- a/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java
+++ b/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java
@@ -116,8 +116,16 @@
 
         // Set the account label if it exists.
         String accountLabel = mCallLogCache.getAccountLabel(details.accountHandle);
-
-        if (accountLabel != null) {
+        if (!TextUtils.isEmpty(details.viaNumber)) {
+            if (!TextUtils.isEmpty(accountLabel)) {
+                accountLabel = mResources.getString(R.string.call_log_via_number_phone_account,
+                        accountLabel, details.viaNumber);
+            } else {
+                accountLabel = mResources.getString(R.string.call_log_via_number,
+                        details.viaNumber);
+            }
+        }
+        if (!TextUtils.isEmpty(accountLabel)) {
             views.callAccountLabel.setVisibility(View.VISIBLE);
             views.callAccountLabel.setText(accountLabel);
             int color = mCallLogCache.getAccountColor(details.accountHandle);
diff --git a/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java b/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
index f6ef7ef..3b1dd2c 100644
--- a/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
@@ -21,11 +21,13 @@
 import android.content.ContentUris;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.database.MatrixCursor;
 import android.net.Uri;
 import android.provider.CallLog.Calls;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.VoicemailContract;
+import android.telephony.PhoneNumberUtils;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.text.TextUtils;
@@ -37,6 +39,7 @@
 import com.android.dialer.database.VoicemailArchiveContract;
 import com.android.dialer.util.AppCompatConstants;
 import com.android.dialer.util.TestConstants;
+import com.android.dialer.R;
 
 import java.util.Date;
 import java.util.List;
@@ -63,26 +66,30 @@
     private static final String TEST_COUNTRY_ISO = "US";
     private static final String TEST_DEFAULT_CUSTOM_LABEL = "myLabel";
     private static final Uri TEST_LOOKUP_URI = Uri.parse("content://contacts/2");
+    private static final String TEST_ACCOUNT_ID_LABEL = "label";
 
     private static final String TEST_NUMBER = "12125551000";
     private static final String TEST_NUMBER_1 = "12345678";
     private static final String TEST_NUMBER_2 = "87654321";
     private static final String TEST_NUMBER_3 = "18273645";
     private static final String TEST_POST_DIAL_DIGITS = ";12345";
+    private static final String TEST_VIA_NUMBER = "+16505551234";
     private static final String TEST_FORMATTED_NUMBER = "1 212-555-1000";
 
     // The object under test.
     private TestCallLogAdapter mAdapter;
 
     private MatrixCursor mCursor;
+    private Resources mResources;
 
-    private View mView;
     private CallLogListItemViewHolder mViewHolder;
     private final Random mRandom = new Random();
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        mContext = getContext();
+        mResources = mContext.getResources();
 
         // Use a call fetcher that does not do anything.
         CallLogAdapter.CallFetcher fakeCallFetcher = new CallLogAdapter.CallFetcher() {
@@ -281,6 +288,36 @@
     }
 
     @MediumTest
+    public void testBindView_CallLogWithViaNumber() {
+        createCallLogEntry(TEST_NUMBER, EMPTY_STRING, TEST_VIA_NUMBER, NO_VALUE_SET, NO_VALUE_SET);
+
+        mAdapter.changeCursor(mCursor);
+        mAdapter.onBindViewHolder(mViewHolder, 0);
+
+        // Copy format of Resource String
+        String formattedNumber = mResources.getString(R.string.description_via_number,
+                TEST_VIA_NUMBER);
+
+        if (CompatUtils.isNCompatible()) {
+            assertEquals(formattedNumber,
+                    mViewHolder.phoneCallDetailsViews.callAccountLabel.getText());
+        }
+    }
+
+    @MediumTest
+    public void testBindView_CallLogWithoutViaNumber() {
+        createCallLogEntry(TEST_NUMBER, EMPTY_STRING, EMPTY_STRING, NO_VALUE_SET, NO_VALUE_SET);
+
+        mAdapter.changeCursor(mCursor);
+        mAdapter.onBindViewHolder(mViewHolder, 0);
+
+        if (CompatUtils.isNCompatible()) {
+            assertEquals(View.GONE,
+                    mViewHolder.phoneCallDetailsViews.callAccountLabel.getVisibility());
+        }
+    }
+
+    @MediumTest
     public void testPresentationAfterRebindingViewHolders() {
         final int increment = 10;
         final int size = increment * 4;
@@ -589,11 +626,18 @@
         createCallLogEntry(TEST_NUMBER, EMPTY_STRING, NO_VALUE_SET, ARCHIVE_TYPE);
     }
 
-    private void createCallLogEntry(String number, String postDialDigits, int presentation, int type) {
+    private void createCallLogEntry(String number, String postDialDigits, int presentation,
+            int type) {
         Object[] values = getValues(number, postDialDigits, presentation, type);
         mCursor.addRow(values);
     }
 
+    private void createCallLogEntry(String number, String postDialDigits, String viaNumber,
+            int presentation, int type) {
+        Object[] values = getValues(number, postDialDigits, viaNumber, presentation, type);
+        mCursor.addRow(values);
+    }
+
     private void createCallLogEntryWithCachedValues(boolean inject) {
         createCallLogEntryWithCachedValues(
                 TEST_NUMBER,
@@ -665,6 +709,23 @@
             String postDialDigits,
             int presentation,
             int type) {
+        return getValues(number, postDialDigits, "", presentation, type);
+    }
+
+    /**
+     * @param number The phone number.
+     * @param postDialDigits The post dial digits dialed (if any)
+     * @param viaNumber The secondary number that the call was placed via
+     * @param presentation Number representing display rules for "allowed",
+     *               "payphone", "restricted", or "unknown".
+     * @param type The type of the call (outgoing/ingoing)
+     */
+    private Object[] getValues(
+            String number,
+            String postDialDigits,
+            String viaNumber,
+            int presentation,
+            int type) {
         Object[] values = CallLogQueryTestUtils.createTestValues();
 
         values[CallLogQuery.ID] = mCursor.getCount();
@@ -678,6 +739,9 @@
         if (!TextUtils.isEmpty(postDialDigits) && CompatUtils.isNCompatible()) {
             values[CallLogQuery.POST_DIAL_DIGITS] = postDialDigits;
         }
+        if (!TextUtils.isEmpty(viaNumber) && CompatUtils.isNCompatible()) {
+            values[CallLogQuery.VIA_NUMBER] = viaNumber;
+        }
         if (presentation != NO_VALUE_SET) {
             values[CallLogQuery.NUMBER_PRESENTATION] = presentation;
         }
diff --git a/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java b/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
index 107cf75..beb83b1 100644
--- a/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
@@ -109,6 +109,26 @@
         }
     }
 
+    public void testAddGroups_WithViaNumberMatching() {
+        addCallLogEntryWithViaNumber(TEST_NUMBER1, TEST_NUMBER2,
+                AppCompatConstants.CALLS_OUTGOING_TYPE);
+        addCallLogEntryWithViaNumber(TEST_NUMBER1, TEST_NUMBER2,
+                AppCompatConstants.CALLS_OUTGOING_TYPE);
+        addCallLogEntryWithViaNumber(TEST_NUMBER1, "",
+                AppCompatConstants.CALLS_OUTGOING_TYPE);
+
+        mBuilder.addGroups(mCursor);
+
+        if (CompatUtils.isNCompatible()) {
+            assertEquals(2, mFakeGroupCreator.groups.size());
+            assertGroupIs(0, 2, mFakeGroupCreator.groups.get(0));
+            assertGroupIs(2, 1, mFakeGroupCreator.groups.get(1));
+        } else {
+            assertEquals(1, mFakeGroupCreator.groups.size());
+            assertGroupIs(0, 3, mFakeGroupCreator.groups.get(0));
+        }
+    }
+
     public void testAddGroups_MatchingIncomingAndOutgoing() {
         addCallLogEntry(TEST_NUMBER1, AppCompatConstants.CALLS_INCOMING_TYPE);
         addCallLogEntry(TEST_NUMBER1, AppCompatConstants.CALLS_OUTGOING_TYPE);
@@ -387,6 +407,19 @@
         mCursor.addRow(values);
     }
 
+    /** Adds a call log entry with the given number, post-dial digits, and type to the cursor. */
+    private void addCallLogEntryWithViaNumber(String number, String viaNumber, int type) {
+        mCursor.moveToNext();
+        Object[] values = CallLogQueryTestUtils.createTestValues();
+        values[CallLogQuery.ID] = mCursor.getPosition();
+        values[CallLogQuery.NUMBER] = number;
+        values[CallLogQuery.CALL_TYPE] = type;
+        if (CompatUtils.isNCompatible()) {
+            values[CallLogQuery.VIA_NUMBER] = viaNumber;
+        }
+        mCursor.addRow(values);
+    }
+
     /** Adds a call log entry with a header to the cursor. */
     private void addCallLogHeader(int section) {
         mCursor.moveToNext();
diff --git a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
index 28caed4..daba428 100644
--- a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
@@ -64,7 +64,7 @@
         mContext = getContext();
         mResources = mContext.getResources();
         final TestTelecomCallLogCache phoneUtils =
-                new TestTelecomCallLogCache(mContext, TEST_VOICEMAIL_NUMBER);
+                new TestTelecomCallLogCache(mContext, TEST_VOICEMAIL_NUMBER, "");
         PhoneCallDetailsHelper phoneCallDetailsHelper =
                 new PhoneCallDetailsHelper(mContext, mResources, phoneUtils);
         mHelper = new CallLogListItemHelper(phoneCallDetailsHelper, mResources, phoneUtils);
diff --git a/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java b/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
index f1b1a9a..c2cfedb 100644
--- a/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
+++ b/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
@@ -32,7 +32,7 @@
             values = new Object[]{
                     0L, "", 0L, 0L, Calls.INCOMING_TYPE, "", "", "", null, 0, null, null, null,
                     null, 0L, null, 0, Calls.PRESENTATION_ALLOWED, null, null, 0, null, null,
-                    null, ""
+                    null, "", ""
             };
         } else {
             values = new Object[]{
diff --git a/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java b/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java
index c0d1203..0c57fde 100644
--- a/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java
+++ b/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java
@@ -16,9 +16,11 @@
 
 package com.android.dialer.calllog;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
 import android.provider.CallLog.Calls;
+import android.telecom.PhoneAccountHandle;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.text.Html;
@@ -63,6 +65,10 @@
     private static final String EMPTY_GEOCODE = "";
     /** Empty post-dial digits label */
     private static final String EMPTY_POSTDIAL = "";
+    /** The number that the call was received via */
+    private static final String TEST_VIA_NUMBER = "+16505551234";
+    /** The Phone Account name that the Call was received on */
+    private static final String TEST_ACCOUNT_LABEL = "T-Stationary";
 
     /** The object under test. */
     private PhoneCallDetailsHelper mHelper;
@@ -79,10 +85,9 @@
         super.setUp();
         mContext = getContext();
         Resources resources = mContext.getResources();
-        mPhoneUtils = new TestTelecomCallLogCache(mContext, TEST_VOICEMAIL_NUMBER);
-        final TestTelecomCallLogCache phoneUtils = new TestTelecomCallLogCache(
-                mContext, TEST_VOICEMAIL_NUMBER);
-        mHelper = new PhoneCallDetailsHelper(mContext, resources, phoneUtils);
+        mPhoneUtils = new TestTelecomCallLogCache(mContext, TEST_VOICEMAIL_NUMBER,
+                TEST_ACCOUNT_LABEL);
+        mHelper = new PhoneCallDetailsHelper(mContext, resources, mPhoneUtils);
         mHelper.setCurrentTimeForTest(INJECTED_CURRENT_DATE);
         mViews = PhoneCallDetailsViews.createForTest(mContext);
         mNameView = new TextView(mContext);
@@ -120,6 +125,26 @@
         assertNameEqualsResource(R.string.voicemail);
     }
 
+    public void testSetPhoneCallDetails_ViaNumber() {
+        setPhoneCallDetailsWithViaNumber(TEST_VIA_NUMBER);
+        assertViaNumberEquals(TEST_VIA_NUMBER);
+    }
+
+    public void testSetPhoneCallDetails_NoViaNumber() {
+        setDefaultPhoneCallDetailsNoViaNumber();
+        assertCallAccountInvisible();
+    }
+
+    public void testSetPhoneCallDetails_AccountLabel() {
+        setPhoneCallDetailsWithAccountHandle();
+        assertAccountLabelEquals(TEST_ACCOUNT_LABEL);
+    }
+
+    public void testSetPhoneCallDetails_AccountHandleViaNumber() {
+        setPhoneCallDetailsWithAccountLabelViaNumber(TEST_VIA_NUMBER);
+        assertAccountLabelEquals(TEST_VIA_NUMBER, TEST_ACCOUNT_LABEL);
+    }
+
     // Voicemail date string has 3 different formats depending on how long ago the call was placed
     public void testSetVoicemailPhoneCallDetails_Today() {
         setVoicemailPhoneCallDetailsWithDate(System.currentTimeMillis());
@@ -368,6 +393,30 @@
         assertEquals(text, mViews.callLocationAndDate.getText());
     }
 
+    /** Asserts that the via number is correct. */
+    private void assertViaNumberEquals(String text) {
+        final String callAccountText =
+                mContext.getResources().getString(R.string.description_via_number, text);
+        assertEquals(callAccountText, mViews.callAccountLabel.getText());
+    }
+
+    /** Asserts that the account label is correct. */
+    private void assertAccountLabelEquals(String text) {
+        assertEquals(text, mViews.callAccountLabel.getText());
+    }
+
+    /** Asserts that the account label is correct when also showing the via number. */
+    private void assertAccountLabelEquals(String viaNumber, String accountLabel) {
+        final String viaNumberText =
+                mContext.getResources().getString(R.string.description_via_number, viaNumber);
+        assertEquals(accountLabel + " " + viaNumberText, mViews.callAccountLabel.getText());
+    }
+
+    /** Asserts that the call account label is invisible. */
+    private void assertCallAccountInvisible() {
+        assertEquals(mViews.callAccountLabel.getVisibility(), View.GONE);
+    }
+
     /** Asserts that the duration is exactly as included in the location and date text field. */
     private void assertDurationExactEquals(String text) {
         Matcher matcher = Pattern.compile("(.*) (\\u2022) (\\d{2}:\\d{2})").matcher(
@@ -414,6 +463,36 @@
         mHelper.setPhoneCallDetails(mViews, details);
     }
 
+    /** Sets the phone call details with default values and the given via number. */
+    private void setPhoneCallDetailsWithViaNumber(String viaNumber) {
+        PhoneCallDetails details = getPhoneCallDetails();
+        mPhoneUtils.setAccountLabel("");
+        details.viaNumber = viaNumber;
+        mHelper.setPhoneCallDetails(mViews, details);
+    }
+
+    /** Sets the phone call details with an account handle. */
+    private void setPhoneCallDetailsWithAccountHandle() {
+        PhoneCallDetails details = getPhoneCallDetails();
+        details.accountHandle = new PhoneAccountHandle(new ComponentName("",""), "");
+        mHelper.setPhoneCallDetails(mViews, details);
+    }
+
+    /** Sets the phone call details with an account handle and via number */
+    private void setPhoneCallDetailsWithAccountLabelViaNumber(String viaNumber) {
+        PhoneCallDetails details = getPhoneCallDetails();
+        details.viaNumber = viaNumber;
+        details.accountHandle = new PhoneAccountHandle(new ComponentName("",""), "");
+        mHelper.setPhoneCallDetails(mViews, details);
+    }
+
+    /** Populates the phone call details with the Defaults. */
+    private void setDefaultPhoneCallDetailsNoViaNumber() {
+        PhoneCallDetails details = getPhoneCallDetails();
+        mPhoneUtils.setAccountLabel("");
+        mHelper.setPhoneCallDetails(mViews, details);
+    }
+
     /** Sets the phone call details with default values and the given number. */
     private void setPhoneCallDetailsWithNumberAndGeocode(
             String number, String formattedNumber, String geocodedLocation) {
diff --git a/tests/src/com/android/dialer/calllog/PhoneCallDetailsTest.java b/tests/src/com/android/dialer/calllog/PhoneCallDetailsTest.java
new file mode 100644
index 0000000..5c500d8
--- /dev/null
+++ b/tests/src/com/android/dialer/calllog/PhoneCallDetailsTest.java
@@ -0,0 +1,63 @@
+package com.android.dialer.calllog;
+
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.TtsSpan;
+
+import com.android.dialer.PhoneCallDetails;
+import com.android.dialer.R;
+import com.android.contacts.common.util.ContactDisplayUtils;
+
+/**
+ * Unit tests for {@link PhoneCallDetails}.
+ */
+public class PhoneCallDetailsTest extends AndroidTestCase {
+    private static final String VIA_NUMBER = "+16505551212";
+    private static final String PHONE_ACCOUNT_LABEL = "TEST";
+
+    private Resources mResources;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResources = mContext.getResources();
+    }
+
+    @SmallTest
+    public void testCreateAccountLabelDescription_NoViaNumberNoAccountLabel() {
+        CharSequence result = PhoneCallDetails.createAccountLabelDescription(mResources, "","");
+        assertEquals("", result);
+    }
+
+    @SmallTest
+    public void testCreateAccountLabelDescription_ViaNumberAccountLabel() {
+        String msg = mResources.getString(R.string.description_via_number_phone_account,
+                PHONE_ACCOUNT_LABEL, VIA_NUMBER);
+        CharSequence accountNumberLabel = ContactDisplayUtils.getTelephoneTtsSpannable(msg,
+                VIA_NUMBER);
+        CharSequence result = PhoneCallDetails.createAccountLabelDescription(mResources, VIA_NUMBER,
+                PHONE_ACCOUNT_LABEL);
+        assertEquals(accountNumberLabel.toString(), result.toString());
+    }
+
+    @SmallTest
+    public void testCreateAccountLabelDescription_ViaNumber() {
+        CharSequence viaNumberLabel = ContactDisplayUtils.getTtsSpannedPhoneNumber(mResources,
+                R.string.description_via_number, VIA_NUMBER);
+        CharSequence result = PhoneCallDetails.createAccountLabelDescription(mResources, VIA_NUMBER,
+                "");
+        assertEquals(viaNumberLabel.toString(), result.toString());
+    }
+
+    @SmallTest
+    public void testCreateAccountLabelDescription_AccountLabel() {
+        CharSequence accountLabel = TextUtils.expandTemplate(
+                mResources.getString(R.string.description_phone_account), PHONE_ACCOUNT_LABEL);
+        CharSequence result = PhoneCallDetails.createAccountLabelDescription(mResources, "",
+                PHONE_ACCOUNT_LABEL);
+        assertEquals(accountLabel, result);
+    }
+}
diff --git a/tests/src/com/android/dialer/calllog/calllogcache/TestTelecomCallLogCache.java b/tests/src/com/android/dialer/calllog/calllogcache/TestTelecomCallLogCache.java
index 077a498..270019a 100644
--- a/tests/src/com/android/dialer/calllog/calllogcache/TestTelecomCallLogCache.java
+++ b/tests/src/com/android/dialer/calllog/calllogcache/TestTelecomCallLogCache.java
@@ -28,12 +28,15 @@
  * but...
  * TODO: write tests to test multi-SIM functionality in TelecomCallLogCache.
  */
-public final class TestTelecomCallLogCache extends CallLogCache {
+public class TestTelecomCallLogCache extends CallLogCache {
     private CharSequence mVoicemailNumber;
+    private String mAccountLabel;
 
-    public TestTelecomCallLogCache(Context context, CharSequence voicemailNumber) {
+    public TestTelecomCallLogCache(Context context, CharSequence voicemailNumber,
+            String accountLabel) {
         super(context);
         mVoicemailNumber = voicemailNumber;
+        mAccountLabel = accountLabel;
     }
 
     @Override
@@ -43,7 +46,11 @@
 
     @Override
     public String getAccountLabel(PhoneAccountHandle accountHandle) {
-        return null;
+        return mAccountLabel;
+    }
+
+    public void setAccountLabel(String accountLabel) {
+        mAccountLabel = accountLabel;
     }
 
     @Override
diff --git a/tests/src/com/android/dialer/database/DatabaseTestUtils.java b/tests/src/com/android/dialer/database/DatabaseTestUtils.java
index 03b4938..19fff7f 100644
--- a/tests/src/com/android/dialer/database/DatabaseTestUtils.java
+++ b/tests/src/com/android/dialer/database/DatabaseTestUtils.java
@@ -47,20 +47,21 @@
                     Contacts.STARRED,                   // 10
                     Data.IS_SUPER_PRIMARY,              // 11
                     Contacts.IN_VISIBLE_GROUP,          // 12
-                    Data.IS_PRIMARY});                  // 13
+                    Data.IS_PRIMARY,                    // 13
+                    Data.CARRIER_PRESENCE});            // 14
         return cursor;
     }
 
     public static ContactNumber constructNewContactWithDummyIds(MatrixCursor contactCursor,
             MatrixCursor nameCursor, String number, int id, String displayName) {
         return constructNewContact(contactCursor, nameCursor, id, number, id, String.valueOf(id),
-                displayName, 0, 0, 0, 0, 0, 0, 0);
+                displayName, 0, 0, 0, 0, 0, 0, 0, 0);
     }
 
     public static ContactNumber constructNewContact(MatrixCursor contactCursor,
             MatrixCursor nameCursor, int id, String number, int contactId, String lookupKey,
             String displayName, int photoId, int lastTimeUsed, int timesUsed, int starred,
-            int isSuperPrimary, int inVisibleGroup, int isPrimary) {
+            int isSuperPrimary, int inVisibleGroup, int isPrimary, int carrierPresence) {
         if (contactCursor == null || nameCursor == null) {
             throw new IllegalArgumentException("Provided MatrixCursors cannot be null");
         }
@@ -73,7 +74,7 @@
 
         contactCursor.addRow(new Object[]{id, "", "", number, contactId, lookupKey, displayName,
                 photoId, lastTimeUsed, timesUsed, starred, isSuperPrimary, inVisibleGroup,
-                isPrimary});
+                isPrimary, carrierPresence});
         nameCursor.addRow(new Object[]{displayName, contactId});
 
         return new ContactNumber(contactId, id, displayName, number, lookupKey, 0, 0);