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

Commit 966a88e0 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic 'contacts-multisim' into ub-contactsdialer-h-dev

* changes:
  Use SimCard class in ImportDialogFragment
  Add better support for importing from multiple SIMs
parents 9b63029f 216e297d
Loading
Loading
Loading
Loading
+1 −10
Original line number Diff line number Diff line
@@ -1376,16 +1376,7 @@
    <string name="import_from_sim">Import from SIM card</string>

    <!-- Action string for selecting a SIM subscription for importing contacts -->
    <string name="import_from_sim_summary">Import from SIM <xliff:g id="sim_name">^1</xliff:g>\n<xliff:g id="sim_number">^2</xliff:g></string>

    <!-- Action string for selecting a SIM subscription for importing contacts, without a phone number -->
    <string name="import_from_sim_summary_no_number">Import from SIM <xliff:g id="sim_name">%1$s</xliff:g></string>

    <!-- Action string for selecting a SIM subscription for importing contacts -->
    <string name="import_from_sim_summary_by_carrier">Import from <xliff:g id="carrier_name">^1</xliff:g> SIM\n<xliff:g id="sim_number">^2</xliff:g></string>

    <!-- Action string for selecting a SIM subscription for importing contacts -->
    <string name="import_from_sim_summary_by_carrier_no_number">Import from <xliff:g id="carrier_name">%1$s</xliff:g> SIM</string>
    <string name="import_from_sim_summary_fmt">Import from SIM <xliff:g id="sim_name">%1$s</xliff:g></string>

    <!-- Action string for selecting a .vcf file to import contacts from [CHAR LIMIT=30] -->
    <string name="import_from_vcf_file" product="default">Import from .vcf file</string>
+11 −5
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.Profile;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.RawContactsEntity;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.os.ResultReceiver;
import android.text.TextUtils;
@@ -150,6 +152,7 @@ public class ContactSaveService extends IntentService {

    public static final String BROADCAST_GROUP_DELETED = "groupDeleted";
    public static final String BROADCAST_SIM_IMPORT_COMPLETE = "simImportComplete";
    public static final String EXTRA_CALLBACK_DATA = "extraCallbackData";

    public static final String EXTRA_RESULT_CODE = "resultCode";
    public static final String EXTRA_RESULT_COUNT = "count";
@@ -208,7 +211,7 @@ public class ContactSaveService extends IntentService {
    public void onCreate() {
        super.onCreate();
        mGroupsDao = new GroupsDaoImpl(this);
        mSimContactDao = new SimContactDao(this);
        mSimContactDao = SimContactDao.create(this);
    }

    public static void registerListener(Listener listener) {
@@ -1685,12 +1688,14 @@ public class ContactSaveService extends IntentService {
        operations.add(builder.build());
    }

    public static Intent createImportFromSimIntent(Context context,
            ArrayList<SimContact> contacts, AccountWithDataSet targetAccount) {
    public static Intent createImportFromSimIntent(@NonNull Context context,
            @NonNull ArrayList<SimContact> contacts, @NonNull AccountWithDataSet targetAccount,
            @Nullable  Bundle callbackData) {
        return new Intent(context, ContactSaveService.class)
                .setAction(ACTION_IMPORT_FROM_SIM)
                .putExtra(EXTRA_SIM_CONTACTS, contacts)
                .putExtra(EXTRA_ACCOUNT, targetAccount);
                .putExtra(EXTRA_ACCOUNT, targetAccount)
                .putExtra(EXTRA_CALLBACK_DATA, callbackData);
    }

    private void importFromSim(Intent intent) {
@@ -1704,7 +1709,8 @@ public class ContactSaveService extends IntentService {
            // notify success
            LocalBroadcastManager.getInstance(this).sendBroadcast(result
                    .putExtra(EXTRA_RESULT_COUNT, contacts.size())
                    .putExtra(EXTRA_RESULT_CODE, RESULT_SUCCESS));
                    .putExtra(EXTRA_RESULT_CODE, RESULT_SUCCESS)
                    .putExtra(EXTRA_CALLBACK_DATA, intent.getBundleExtra(EXTRA_CALLBACK_DATA)));
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "importFromSim completed successfully");
            }
+10 −6
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.contacts.common.list.ContactListAdapter;
import com.android.contacts.common.list.ContactListItemView;
import com.android.contacts.common.list.MultiSelectEntryContactListAdapter;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.SimCard;
import com.android.contacts.common.model.SimContact;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.preference.ContactsPreferences;
@@ -59,7 +60,8 @@ public class SimImportFragment extends DialogFragment

    private static final String KEY_SELECTED_IDS = "selectedIds";
    private static final String ARG_SUBSCRIPTION_ID = "subscriptionId";
    public static final int NO_SUBSCRIPTION_ID = -1;

    public static final String CALLBACK_KEY_SUBSCRIPTION_ID = "simSubscriptionId";

    private ContactsPreferences mPreferences;
    private AccountTypeManager mAccountTypeManager;
@@ -88,8 +90,8 @@ public class SimImportFragment extends DialogFragment
        mAdapter.setHasHeader(0, false);

        final Bundle args = getArguments();
        mSubscriptionId = args == null ? NO_SUBSCRIPTION_ID : args.getInt(ARG_SUBSCRIPTION_ID,
                NO_SUBSCRIPTION_ID);
        mSubscriptionId = args == null ? SimCard.NO_SUBSCRIPTION_ID :
                args.getInt(ARG_SUBSCRIPTION_ID, SimCard.NO_SUBSCRIPTION_ID);

        if (savedInstanceState == null) return;
        mSelectedContacts = savedInstanceState.getLongArray(KEY_SELECTED_IDS);
@@ -198,9 +200,11 @@ public class SimImportFragment extends DialogFragment
    }

    private void importCurrentSelections() {
        final Bundle callbackData = new Bundle();
        callbackData.putInt(CALLBACK_KEY_SUBSCRIPTION_ID, mSubscriptionId);
        ContactSaveService.startService(getContext(), ContactSaveService
                .createImportFromSimIntent(getContext(), mAdapter.getSelectedContacts(),
                mAccountHeaderPresenter.getCurrentAccount()));
                mAccountHeaderPresenter.getCurrentAccount(), callbackData));
    }

    @Override
@@ -321,7 +325,7 @@ public class SimImportFragment extends DialogFragment

        public SimContactLoader(Context context, int subscriptionId) {
            super(context);
            mDao = new SimContactDao(context);
            mDao = SimContactDao.create(context);
            mSubscriptionId = subscriptionId;
        }

@@ -342,7 +346,7 @@ public class SimImportFragment extends DialogFragment

        @Override
        public ArrayList<SimContact> loadInBackground() {
            if (mSubscriptionId != NO_SUBSCRIPTION_ID) {
            if (mSubscriptionId != SimCard.NO_SUBSCRIPTION_ID) {
                return mDao.loadSimContacts(mSubscriptionId);
            } else {
                return mDao.loadSimContacts();
+131 −56
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.contacts.common.database;

import android.annotation.TargetApi;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
@@ -28,25 +29,25 @@ import android.os.Build;
import android.os.RemoteException;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;

import com.android.contacts.common.Experiments;
import com.android.contacts.common.compat.CompatUtils;
import com.android.contacts.common.model.SimCard;
import com.android.contacts.common.model.SimContact;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.util.PermissionsUtil;
import com.android.contacts.util.SharedPreferenceUtil;
import com.android.contactsbind.experiments.Flags;
import com.google.common.collect.Sets;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * Provides data access methods for loading contacts from a SIM card and and migrating these
@@ -55,6 +56,10 @@ import java.util.Set;
public class SimContactDao {
    private static final String TAG = "SimContactDao";

    // Set to true for manual testing on an emulator or phone without a SIM card
    // DO NOT SUBMIT if set to true
    private static final boolean USE_FAKE_INSTANCE = false;

    @VisibleForTesting
    public static final Uri ICC_CONTENT_URI = Uri.parse("content://icc/adn");

@@ -76,65 +81,50 @@ public class SimContactDao {
    public void warmupSimQueryIfNeeded() {
        // Not needed if we don't have an Assistant section
        if (!Flags.getInstance().getBoolean(Experiments.ASSISTANT) ||
                !shouldLoad()) return;
                !canReadSimContacts()) return;

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                for (SimCard card : getSimCards()) {
                    // We don't actually have to do any caching ourselves. Some other layer must do
                // caching of the data (OS or framework) because subsequent queries are very fast.
                final Cursor cursor = mResolver.query(ICC_CONTENT_URI, null, null, null, null);
                if (cursor != null) {
                    cursor.close();
                    // caching of the data (OS or framework) because subsequent queries are very
                    // fast.
                    card.loadContacts(SimContactDao.this);
                }
                return null;
            }
        }.execute();
    }

    public boolean shouldLoad() {
        final Set<String> simIds = hasTelephony() && hasPermissions() ? getSimCardIds() :
                Collections.<String>emptySet();
    public boolean canReadSimContacts() {
        return hasTelephony() && hasPermissions() &&
                mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_ABSENT;
    }

        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "shouldLoad: hasTelephony? " + hasTelephony() +
                    " hasPermissions? " + hasPermissions() +
                    " SIM absent? " + (getSimState() != TelephonyManager.SIM_STATE_ABSENT) +
                    " SIM ids=" + simIds +
                    " imported=" + SharedPreferenceUtil.getImportedSims(mContext));
    public List<SimCard> getSimCards() {
        if (!canReadSimContacts()) {
            return Collections.emptyList();
        }
        return hasTelephony() && hasPermissions() &&
                getSimState() != TelephonyManager.SIM_STATE_ABSENT &&
                !Sets.difference(simIds, SharedPreferenceUtil.getImportedSims(mContext))
                        .isEmpty();
        final List<SimCard> sims = CompatUtils.isMSIMCompatible() ?
                getSimCardsFromSubscriptions() :
                Collections.singletonList(SimCard.create(mTelephonyManager));
        return SharedPreferenceUtil.restoreSimStates(mContext, sims);
    }

    public Set<String> getSimCardIds() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            final SubscriptionManager subscriptionManager = SubscriptionManager.from(mContext);
    @NonNull
    @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
    private List<SimCard> getSimCardsFromSubscriptions() {
        final SubscriptionManager subscriptionManager = (SubscriptionManager)
                mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
        final List<SubscriptionInfo> subscriptions = subscriptionManager
                .getActiveSubscriptionInfoList();
            if (subscriptions == null) {
                return Collections.emptySet();
            }
            final ArraySet<String> result = new ArraySet<>(
                    subscriptionManager.getActiveSubscriptionInfoCount());

            for (SubscriptionInfo info : subscriptions) {
                result.add(info.getIccId());
        final ArrayList<SimCard> result = new ArrayList<>();
        for (SubscriptionInfo subscriptionInfo : subscriptions) {
            result.add(SimCard.create(subscriptionInfo));
        }
        return result;
    }
        return Collections.singleton(getSimSerialNumber());
    }

    public int getSimState() {
        return mTelephonyManager.getSimState();
    }

    public String getSimSerialNumber() {
        return mTelephonyManager.getSimSerialNumber();
    }

    public ArrayList<SimContact> loadSimContacts(int subscriptionId) {
        return loadFrom(ICC_CONTENT_URI.buildUpon()
@@ -147,6 +137,10 @@ public class SimContactDao {
        return loadFrom(ICC_CONTENT_URI);
    }

    public Context getContext() {
        return mContext;
    }

    private ArrayList<SimContact> loadFrom(Uri uri) {
        final Cursor cursor = mResolver.query(uri, null, null, null, null);

@@ -185,6 +179,31 @@ public class SimContactDao {
        return mResolver.applyBatch(ContactsContract.AUTHORITY, ops);
    }

    public void persistSimState(SimCard sim) {
        SharedPreferenceUtil.persistSimStates(mContext, Collections.singletonList(sim));
    }

    public void persistSimStates(List<SimCard> simCards) {
        SharedPreferenceUtil.persistSimStates(mContext, simCards);
    }

    public SimCard getFirstSimCard() {
        return getSimBySubscriptionId(SimCard.NO_SUBSCRIPTION_ID);
    }

    public SimCard getSimBySubscriptionId(int subscriptionId) {
        final List<SimCard> sims = getSimCards();
        if (subscriptionId == SimCard.NO_SUBSCRIPTION_ID && !sims.isEmpty()) {
            return sims.get(0);
        }
        for (SimCard sim : getSimCards()) {
            if (sim.getSubscriptionId() == subscriptionId) {
                return sim;
            }
        }
        return null;
    }

    private ArrayList<ContentProviderOperation> createImportOperations(List<SimContact> contacts,
            AccountWithDataSet targetAccount) {
        final ArrayList<ContentProviderOperation> ops = new ArrayList<>();
@@ -198,15 +217,6 @@ public class SimContactDao {
        return emails != null ? emails.split(",") : null;
    }

    public void persistImportSuccess() {
        // TODO: either need to have an assistant card per SIM card or show contacts from all
        // SIMs in the import view.
        final Set<String> simIds = getSimCardIds();
        for (String id : simIds) {
            SharedPreferenceUtil.addImportedSim(mContext, id);
        }
    }

    private boolean hasTelephony() {
        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
    }
@@ -215,4 +225,69 @@ public class SimContactDao {
        return PermissionsUtil.hasContactsPermissions(mContext) &&
                PermissionsUtil.hasPhonePermissions(mContext);
    }

    public static SimContactDao create(Context context) {
        if (USE_FAKE_INSTANCE) {
            return new DebugImpl(context)
                    .addSimCard(new SimCard("fake-sim-id1", 1, "Fake Carrier", "Card 1",
                            "15095550101", "us").withContacts(
                            new SimContact(1, "Sim One", "15095550111", null),
                            new SimContact(2, "Sim Two", "15095550112", null),
                            new SimContact(3, "Sim Three", "15095550113", null),
                            new SimContact(4, "Sim Four", "15095550114", null),
                            new SimContact(5, "411 & more", "411", null)
                    ))
                    .addSimCard(new SimCard("fake-sim-id2", 2, "Carrier Two", "Card 2",
                            "15095550102", "us").withContacts(
                            new SimContact(1, "John Sim", "15095550121", null),
                            new SimContact(2, "Bob Sim", "15095550122", null),
                            new SimContact(3, "Mary Sim", "15095550123", null),
                            new SimContact(4, "Alice Sim", "15095550124", null)
                    ));
        }

        return new SimContactDao(context);
    }

    // TODO remove this class and the USE_FAKE_INSTANCE flag once this code is not under
    // active development or anytime after 3/1/2017
    private static class DebugImpl extends SimContactDao {

        private List<SimCard> mSimCards = new ArrayList<>();
        private SparseArray<SimCard> mCardsBySubscription = new SparseArray<>();

        public DebugImpl(Context context) {
            super(context);
        }

        public DebugImpl addSimCard(SimCard sim) {
            mSimCards.add(sim);
            mCardsBySubscription.put(sim.getSubscriptionId(), sim);
            return this;
        }

        @Override
        public void warmupSimQueryIfNeeded() {
        }

        @Override
        public List<SimCard> getSimCards() {
            return SharedPreferenceUtil.restoreSimStates(getContext(), mSimCards);
        }

        @Override
        public ArrayList<SimContact> loadSimContacts() {
            return new ArrayList<>(mSimCards.get(0).getContacts());
        }

        @Override
        public ArrayList<SimContact> loadSimContacts(int subscriptionId) {
            return new ArrayList<>(mCardsBySubscription.get(subscriptionId).getContacts());
        }

        @Override
        public boolean canReadSimContacts() {
            return true;
        }
    }
}
+36 −100
Original line number Diff line number Diff line
@@ -24,14 +24,10 @@ import android.app.FragmentManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.provider.ContactsContract.Contacts;
import android.support.annotation.RequiresApi;
import android.support.v4.util.ArraySet;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -44,15 +40,15 @@ import com.android.contacts.SimImportFragment;
import com.android.contacts.common.R;
import com.android.contacts.common.compat.CompatUtils;
import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
import com.android.contacts.common.database.SimContactDao;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.SimCard;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.util.AccountSelectionUtil;
import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.editor.SelectAccountDialogFragment;

import java.util.List;
import java.util.Locale;
import java.util.Set;

/**
 * An dialog invoked to import/export contacts.
@@ -67,6 +63,7 @@ public class ImportDialogFragment extends DialogFragment
    public static final String EXTRA_SIM_ONLY = "extraSimOnly";

    private boolean mSimOnly = false;
    private SimContactDao mSimDao;

    private final String[] LOOKUP_PROJECTION = new String[] {
            Contacts.LOOKUP_KEY
@@ -97,6 +94,7 @@ public class ImportDialogFragment extends DialogFragment

        final Bundle args = getArguments();
        mSimOnly = args != null && args.getBoolean(EXTRA_SIM_ONLY, false);
        mSimDao = SimContactDao.create(getContext());
    }

    @Override
@@ -112,7 +110,6 @@ public class ImportDialogFragment extends DialogFragment
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Wrap our context to inflate list items using the correct theme
        final Resources res = getActivity().getResources();
        final LayoutInflater dialogInflater = (LayoutInflater)getActivity()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

@@ -129,48 +126,7 @@ public class ImportDialogFragment extends DialogFragment
            }
        };

        final TelephonyManager manager =
                (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
        if (res.getBoolean(R.bool.config_allow_import_from_vcf_file) && !mSimOnly) {
            adapter.add(new AdapterEntry(getString(R.string.import_from_vcf_file),
                    R.string.import_from_vcf_file));
        }

        if (CompatUtils.isMSIMCompatible()) {
            mSubscriptionManager = SubscriptionManager.from(getActivity());
            if (manager != null && res.getBoolean(R.bool.config_allow_sim_import)) {
                List<SubscriptionInfo> subInfoRecords = null;
                try {
                    subInfoRecords =  mSubscriptionManager.getActiveSubscriptionInfoList();
                } catch (SecurityException e) {
                    Log.w(TAG, "SecurityException thrown, lack permission for"
                            + " getActiveSubscriptionInfoList", e);
                }
                if (subInfoRecords != null) {
                    if (subInfoRecords.size() == 1) {
                        adapter.add(new AdapterEntry(getString(R.string.import_from_sim),
                                R.string.import_from_sim, subInfoRecords.get(0).getSubscriptionId()));
                    } else if (hasUniqueNonNullCarrierNames(subInfoRecords)) {
                        for (SubscriptionInfo record : subInfoRecords) {
                            adapter.add(new AdapterEntry(getSubDescriptionForCarrier(record),
                                    R.string.import_from_sim, record.getSubscriptionId()));
                        }
                    } else {
                        for (SubscriptionInfo record : subInfoRecords) {
                            adapter.add(new AdapterEntry(getSubDescription(record),
                                    R.string.import_from_sim, record.getSubscriptionId()));
                        }
                    }
                }
            }
        } else {
            if (manager != null && manager.hasIccCard()
                    && res.getBoolean(R.bool.config_allow_sim_import)) {
                adapter.add(new AdapterEntry(getString(R.string.import_from_sim),
                        R.string.import_from_sim, -1));
            }
        }

        addItems(adapter);

        final DialogInterface.OnClickListener clickListener =
                new DialogInterface.OnClickListener() {
@@ -201,6 +157,25 @@ public class ImportDialogFragment extends DialogFragment
                .create();
    }

    private void addItems(ArrayAdapter<AdapterEntry> adapter) {
        final Resources res = getActivity().getResources();
        if (res.getBoolean(R.bool.config_allow_import_from_vcf_file) && !mSimOnly) {
            adapter.add(new AdapterEntry(getString(R.string.import_from_vcf_file),
                    R.string.import_from_vcf_file));
        }
        final List<SimCard> sims = mSimDao.getSimCards();

        if (sims.size() == 1) {
            adapter.add(new AdapterEntry(getString(R.string.import_from_sim),
                    R.string.import_from_sim, SimCard.NO_SUBSCRIPTION_ID));
            return;
        }
        for (SimCard sim : sims) {
            adapter.add(new AdapterEntry(getSimDescription(sim), R.string.import_from_sim,
                    sim.getSubscriptionId()));
        }
    }

    private boolean handleSimImportRequest(int subscriptionId) {
        SimImportFragment.newInstance(subscriptionId).show(getFragmentManager(), "SimImport");
        return true;
@@ -260,62 +235,23 @@ public class ImportDialogFragment extends DialogFragment
        dismiss();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
    private boolean hasUniqueNonNullCarrierNames(List<SubscriptionInfo> subscriptions) {
        final Set<CharSequence> names = new ArraySet<>();
        for (SubscriptionInfo subscription : subscriptions) {
            final CharSequence name = subscription.getCarrierName();
            if (name == null) {
                return false;
            }
            if (!names.add(name)) {
                return false;
    private CharSequence getSimDescription(SimCard sim) {
        final CharSequence name = sim.getDisplayName();
        CharSequence number = sim.getFormattedPhone();
        // If formatting fails use the raw phone number
        if (number == null) {
            number = sim.getPhone();
        }
        if (number != null) {
            number = PhoneNumberUtilsCompat.createTtsSpannable(number);
        }
        return true;
    }

    private CharSequence getSubDescription(SubscriptionInfo record) {
        final CharSequence name = record.getDisplayName();
        final CharSequence number = getFormattedNumber(record);

        if (TextUtils.isEmpty(number)) {
            return getString(R.string.import_from_sim_summary_no_number, name);
            return getString(R.string.import_from_sim_summary_fmt, name);
        }

        return TextUtils.expandTemplate(getString(R.string.import_from_sim_summary), name, number);
        return new SpannableStringBuilder(getString(R.string.import_from_sim_summary_fmt, name))
                .append('\n').append(number);
    }

    private CharSequence getSubDescriptionForCarrier(SubscriptionInfo record) {
        final CharSequence carrierName = record.getCarrierName();
        final CharSequence number = getFormattedNumber(record);

        if (TextUtils.isEmpty(number)) {
            return getString(R.string.import_from_sim_summary_by_carrier_no_number, carrierName);
        }

        return TextUtils.expandTemplate(
                getString(R.string.import_from_sim_summary_by_carrier), carrierName, number);
    }

    private CharSequence getFormattedNumber(SubscriptionInfo subscription) {
        final String rawNumber = subscription.getNumber();
        if (rawNumber == null) {
            return null;
        }
        final String country = subscription.getCountryIso();
        final String number;
        if (country != null) {
            number = PhoneNumberUtilsCompat.formatNumber(rawNumber, null,
                    country.toUpperCase(Locale.US));
        } else {
            number = rawNumber;
        }
        return PhoneNumberUtilsCompat.createTtsSpannable(number);
    }



    private static class AdapterEntry {
        public final CharSequence mLabel;
        public final int mChoiceResourceId;
Loading