Utility to compute a single subscription's unique display name.

Bug: 150370656
Bug: 148303118
Test: atest -c SubscriptionUtilTest
Change-Id: Id4600dbf038117129c62331f9e00b7035af1c0fd
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index a63658a..054e3d9 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -306,6 +306,24 @@
                 info -> info.uniqueName));
     }
 
+    /**
+     * Return the display name for a subscription id, which is guaranteed to be unique.
+     * The logic to create this name has the following order of operations:
+     * 1) If the original display name is not unique, the last four digits of the phone number
+     *    will be appended.
+     * 2) If the phone number is not visible or the last four digits are shared with another
+     *    subscription, the subscription id will be appended to the original display name.
+     * More details can be found at go/unique-sub-display-names.
+     *
+     * @return map of active subscription ids to diaplay names.
+     */
+    @VisibleForTesting
+    public static CharSequence getUniqueSubscriptionDisplayName(
+            Integer subscriptionId, Context context) {
+        final Map<Integer, CharSequence> displayNames = getUniqueSubscriptionDisplayNames(context);
+        return displayNames.getOrDefault(subscriptionId, "");
+    }
+
     public static String getDisplayName(SubscriptionInfo info) {
         final CharSequence name = info.getDisplayName();
         if (name != null) {
diff --git a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
index 90564fa..85ac011 100644
--- a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
+++ b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
@@ -27,6 +28,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -258,6 +260,107 @@
     }
 
     @Test
+    public void getUniqueDisplayName_onlyOneSubscription_correctNameReturned() {
+        // Each subscription's default display name is unique.
+        final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+        when(info1.getSubscriptionId()).thenReturn(SUBID_1);
+        when(info1.getDisplayName()).thenReturn(CARRIER_1);
+        when(mSubMgr.getActiveSubscriptionInfoList()).thenReturn(
+                Arrays.asList(info1));
+
+        TelephonyManager sub1Telmgr = mock(TelephonyManager.class);
+        when(sub1Telmgr.getLine1Number()).thenReturn("1112223333");
+        when(mTelMgr.createForSubscriptionId(SUBID_1)).thenReturn(sub1Telmgr);
+
+        final CharSequence name =
+                SubscriptionUtil.getUniqueSubscriptionDisplayName(SUBID_1, mContext);
+
+        assertThat(name).isNotNull();
+        assertEquals(CARRIER_1, name);
+    }
+
+    @Test
+    public void getUniqueDisplayName_identicalCarriers_correctNameReturned() {
+        // Each subscription's default display name is unique.
+        final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+        final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
+        when(info1.getSubscriptionId()).thenReturn(SUBID_1);
+        when(info2.getSubscriptionId()).thenReturn(SUBID_2);
+        when(info1.getDisplayName()).thenReturn(CARRIER_1);
+        when(info2.getDisplayName()).thenReturn(CARRIER_1);
+        when(mSubMgr.getActiveSubscriptionInfoList()).thenReturn(
+                Arrays.asList(info1, info2));
+
+        // Each subscription has a unique last 4 digits of the phone number.
+        TelephonyManager sub1Telmgr = mock(TelephonyManager.class);
+        TelephonyManager sub2Telmgr = mock(TelephonyManager.class);
+        when(sub1Telmgr.getLine1Number()).thenReturn("1112223333");
+        when(sub2Telmgr.getLine1Number()).thenReturn("2223334444");
+        when(mTelMgr.createForSubscriptionId(SUBID_1)).thenReturn(sub1Telmgr);
+        when(mTelMgr.createForSubscriptionId(SUBID_2)).thenReturn(sub2Telmgr);
+
+        final CharSequence name1 =
+                SubscriptionUtil.getUniqueSubscriptionDisplayName(SUBID_1, mContext);
+        assertThat(name1).isNotNull();
+        assertEquals(CARRIER_1 + " 3333", name1);
+        final CharSequence name2 =
+                SubscriptionUtil.getUniqueSubscriptionDisplayName(SUBID_2, mContext);
+        assertThat(name2).isNotNull();
+        assertEquals(CARRIER_1 + " 4444", name2);
+    }
+
+    @Test
+    public void getUniqueDisplayName_phoneNumberIdentical_correctNameReturned() {
+        // Each subscription's default display name is unique.
+        final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+        final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
+        when(info1.getSubscriptionId()).thenReturn(SUBID_1);
+        when(info2.getSubscriptionId()).thenReturn(SUBID_2);
+        when(info1.getDisplayName()).thenReturn(CARRIER_1);
+        when(info2.getDisplayName()).thenReturn(CARRIER_1);
+        when(mSubMgr.getActiveSubscriptionInfoList()).thenReturn(
+                Arrays.asList(info1, info2));
+
+        // Both subscriptions have a the same 4 digits of the phone number.
+        TelephonyManager sub1Telmgr = mock(TelephonyManager.class);
+        TelephonyManager sub2Telmgr = mock(TelephonyManager.class);
+        when(sub1Telmgr.getLine1Number()).thenReturn("1112224444");
+        when(sub2Telmgr.getLine1Number()).thenReturn("2223334444");
+        when(mTelMgr.createForSubscriptionId(SUBID_1)).thenReturn(sub1Telmgr);
+        when(mTelMgr.createForSubscriptionId(SUBID_2)).thenReturn(sub2Telmgr);
+
+        final CharSequence name1 =
+                SubscriptionUtil.getUniqueSubscriptionDisplayName(SUBID_1, mContext);
+        assertThat(name1).isNotNull();
+        assertEquals(CARRIER_1 + " 1", name1);
+        final CharSequence name2 =
+                SubscriptionUtil.getUniqueSubscriptionDisplayName(SUBID_2, mContext);
+        assertThat(name2).isNotNull();
+        assertEquals(CARRIER_1 + " 2", name2);
+    }
+
+    @Test
+    public void getUniqueDisplayName_subscriptionNotActive_emptyString() {
+        // Each subscription's default display name is unique.
+        final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+        when(info1.getSubscriptionId()).thenReturn(SUBID_1);
+        when(info1.getDisplayName()).thenReturn(CARRIER_1);
+        when(mSubMgr.getActiveSubscriptionInfoList()).thenReturn(
+                Arrays.asList(info1));
+
+        TelephonyManager sub1Telmgr = mock(TelephonyManager.class);
+        when(sub1Telmgr.getLine1Number()).thenReturn("1112223333");
+        when(mTelMgr.createForSubscriptionId(SUBID_1)).thenReturn(sub1Telmgr);
+
+        // Subscription id is different than the one returned by the subscription manager.
+        final CharSequence name =
+                SubscriptionUtil.getUniqueSubscriptionDisplayName(SUBID_2, mContext);
+
+        assertThat(name).isNotNull();
+        assertTrue(TextUtils.isEmpty(name));
+    }
+
+    @Test
     public void isInactiveInsertedPSim_nullSubInfo_doesNotCrash() {
         assertThat(SubscriptionUtil.isInactiveInsertedPSim(null)).isFalse();
     }