Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3c3ce5ea authored by Jeremy Goldman's avatar Jeremy Goldman Committed by Android (Google) Code Review
Browse files

Merge "Return mapping of subscription id to unique display name."

parents 79c21c07 2fb7e1bb
Loading
Loading
Loading
Loading
+92 −0
Original line number Diff line number Diff line
@@ -28,19 +28,25 @@ import android.telephony.SubscriptionInfo;
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 @@ public class SubscriptionUtil {
        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) {
+132 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.network;

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 org.mockito.MockitoAnnotations;

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
@@ -125,6 +132,131 @@ public class SubscriptionUtilTest {
        assertThat(subs).hasSize(2);
    }

    @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();