Merge "Return mapping of subscription id to unique display name."
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index cff8f55..a63658a 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -28,19 +28,25 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.UiccSlotInfo;
+import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.settings.network.telephony.DeleteEuiccSubscriptionDialogActivity;
import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity;
+import com.android.settingslib.DeviceInfoUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
public class SubscriptionUtil {
private static final String TAG = "SubscriptionUtil";
@@ -214,6 +220,92 @@
return null;
}
+ /**
+ * Return a mapping of active subscription ids to diaplay names. Each display name is
+ * guaranteed to be unique in the following manner:
+ * 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 Map<Integer, CharSequence> getUniqueSubscriptionDisplayNames(Context context) {
+ class DisplayInfo {
+ public SubscriptionInfo subscriptionInfo;
+ public CharSequence originalName;
+ public CharSequence uniqueName;
+ }
+
+ final SubscriptionManager subscriptionManager =
+ context.getSystemService(SubscriptionManager.class);
+ // Map of SubscriptionId to DisplayName
+ final Supplier<Stream<DisplayInfo>> originalInfos =
+ () -> getActiveSubscriptions(subscriptionManager)
+ .stream()
+ .map(i -> {
+ DisplayInfo info = new DisplayInfo();
+ info.subscriptionInfo = i;
+ info.originalName = i.getDisplayName();
+ return info;
+ });
+
+ // TODO(goldmanj) consider using a map of DisplayName to SubscriptionInfos.
+ // A Unique set of display names
+ Set<CharSequence> uniqueNames = new HashSet<>();
+ // Return the set of duplicate names
+ final Set<CharSequence> duplicateOriginalNames = originalInfos.get()
+ .filter(info -> !uniqueNames.add(info.originalName))
+ .map(info -> info.originalName)
+ .collect(Collectors.toSet());
+
+ // If a display name is duplicate, append the final 4 digits of the phone number.
+ // Creates a mapping of Subscription id to original display name + phone number display name
+ final Supplier<Stream<DisplayInfo>> uniqueInfos = () -> originalInfos.get().map(info -> {
+ if (duplicateOriginalNames.contains(info.originalName)) {
+ // This may return null, if the user cannot view the phone number itself.
+ final String phoneNumber = DeviceInfoUtils.getBidiFormattedPhoneNumber(context,
+ info.subscriptionInfo);
+ String lastFourDigits = "";
+ if (phoneNumber != null) {
+ lastFourDigits = (phoneNumber.length() > 4)
+ ? phoneNumber.substring(phoneNumber.length() - 4) : phoneNumber;
+ }
+
+ if (TextUtils.isEmpty(lastFourDigits)) {
+ info.uniqueName = info.originalName;
+ } else {
+ info.uniqueName = info.originalName + " " + lastFourDigits;
+ }
+
+ } else {
+ info.uniqueName = info.originalName;
+ }
+ return info;
+ });
+
+ // Check uniqueness a second time.
+ // We might not have had permission to view the phone numbers.
+ // There might also be multiple phone numbers whose last 4 digits the same.
+ uniqueNames.clear();
+ final Set<CharSequence> duplicatePhoneNames = uniqueInfos.get()
+ .filter(info -> !uniqueNames.add(info.uniqueName))
+ .map(info -> info.uniqueName)
+ .collect(Collectors.toSet());
+
+ return uniqueInfos.get().map(info -> {
+ if (duplicatePhoneNames.contains(info.uniqueName)) {
+ info.uniqueName = info.originalName + " "
+ + info.subscriptionInfo.getSubscriptionId();
+ }
+ return info;
+ }).collect(Collectors.toMap(
+ info -> info.subscriptionInfo.getSubscriptionId(),
+ info -> info.uniqueName));
+ }
+
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 9e319fb..90564fa 100644
--- a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
+++ b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -38,9 +39,15 @@
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
@RunWith(AndroidJUnit4.class)
public class SubscriptionUtilTest {
+ private static final int SUBID_1 = 1;
+ private static final int SUBID_2 = 2;
+ private static final int SUBID_3 = 3;
+ private static final CharSequence CARRIER_1 = "carrier1";
+ private static final CharSequence CARRIER_2 = "carrier2";
private Context mContext;
@Mock
@@ -126,6 +133,131 @@
}
@Test
+ public void getUniqueDisplayNames_uniqueCarriers_originalUsed() {
+ // 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_2);
+ 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 Map<Integer, CharSequence> idNames =
+ SubscriptionUtil.getUniqueSubscriptionDisplayNames(mContext);
+
+ assertThat(idNames).isNotNull();
+ assertThat(idNames).hasSize(2);
+ assertEquals(CARRIER_1, idNames.get(SUBID_1));
+ assertEquals(CARRIER_2, idNames.get(SUBID_2));
+ }
+
+ @Test
+ public void getUniqueDisplayNames_identicalCarriers_fourDigitsUsed() {
+ // Both subscriptoins have the same display name.
+ 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 Map<Integer, CharSequence> idNames =
+ SubscriptionUtil.getUniqueSubscriptionDisplayNames(mContext);
+
+ assertThat(idNames).isNotNull();
+ assertThat(idNames).hasSize(2);
+ assertEquals(CARRIER_1 + " 3333", idNames.get(SUBID_1));
+ assertEquals(CARRIER_1 + " 4444", idNames.get(SUBID_2));
+ }
+
+ @Test
+ public void getUniqueDisplayNames_phoneNumberBlocked_subscriptoinIdFallback() {
+ // Both subscriptoins have the same display name.
+ 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));
+
+ // The subscriptions' phone numbers cannot be revealed to the user.
+ TelephonyManager sub1Telmgr = mock(TelephonyManager.class);
+ TelephonyManager sub2Telmgr = mock(TelephonyManager.class);
+ when(sub1Telmgr.getLine1Number()).thenReturn("");
+ when(sub2Telmgr.getLine1Number()).thenReturn("");
+ when(mTelMgr.createForSubscriptionId(SUBID_1)).thenReturn(sub1Telmgr);
+ when(mTelMgr.createForSubscriptionId(SUBID_2)).thenReturn(sub2Telmgr);
+
+ final Map<Integer, CharSequence> idNames =
+ SubscriptionUtil.getUniqueSubscriptionDisplayNames(mContext);
+
+ assertThat(idNames).isNotNull();
+ assertThat(idNames).hasSize(2);
+ assertEquals(CARRIER_1 + " 1", idNames.get(SUBID_1));
+ assertEquals(CARRIER_1 + " 2", idNames.get(SUBID_2));
+ }
+
+ @Test
+ public void getUniqueDisplayNames_phoneNumberIdentical_subscriptoinIdFallback() {
+ // TODO have three here from the same carrier
+ // Both subscriptoins have the same display name.
+ final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+ final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
+ final SubscriptionInfo info3 = mock(SubscriptionInfo.class);
+ when(info1.getSubscriptionId()).thenReturn(SUBID_1);
+ when(info2.getSubscriptionId()).thenReturn(SUBID_2);
+ when(info3.getSubscriptionId()).thenReturn(SUBID_3);
+ when(info1.getDisplayName()).thenReturn(CARRIER_1);
+ when(info2.getDisplayName()).thenReturn(CARRIER_1);
+ when(info3.getDisplayName()).thenReturn(CARRIER_1);
+ when(mSubMgr.getActiveSubscriptionInfoList()).thenReturn(
+ Arrays.asList(info1, info2, info3));
+
+ // Subscription 1 has a unique phone number, but subscriptions 2 and 3 share the same
+ // last four digits.
+ TelephonyManager sub1Telmgr = mock(TelephonyManager.class);
+ TelephonyManager sub2Telmgr = mock(TelephonyManager.class);
+ TelephonyManager sub3Telmgr = mock(TelephonyManager.class);
+ when(sub1Telmgr.getLine1Number()).thenReturn("1112223333");
+ when(sub2Telmgr.getLine1Number()).thenReturn("2223334444");
+ when(sub3Telmgr.getLine1Number()).thenReturn("5556664444");
+ when(mTelMgr.createForSubscriptionId(SUBID_1)).thenReturn(sub1Telmgr);
+ when(mTelMgr.createForSubscriptionId(SUBID_2)).thenReturn(sub2Telmgr);
+ when(mTelMgr.createForSubscriptionId(SUBID_3)).thenReturn(sub3Telmgr);
+
+ final Map<Integer, CharSequence> idNames =
+ SubscriptionUtil.getUniqueSubscriptionDisplayNames(mContext);
+
+ assertThat(idNames).isNotNull();
+ assertThat(idNames).hasSize(3);
+ assertEquals(CARRIER_1 + " 3333", idNames.get(SUBID_1));
+ assertEquals(CARRIER_1 + " 2", idNames.get(SUBID_2));
+ assertEquals(CARRIER_1 + " 3", idNames.get(SUBID_3));
+ }
+
+ @Test
public void isInactiveInsertedPSim_nullSubInfo_doesNotCrash() {
assertThat(SubscriptionUtil.isInactiveInsertedPSim(null)).isFalse();
}