Merge "Add method to check if Google account exists." into ub-contactsdialer-h-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 461fafe..20e0a65 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,8 +16,8 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.contacts"
-    android:versionCode="10606"
-    android:versionName="1.6.6">
+    android:versionCode="10607"
+    android:versionName="1.6.7">
 
     <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="25" />
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 13d2f61..0efa091 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1376,11 +1376,17 @@
     <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> - <xliff:g id="sim_number">^2</xliff:g></string>
+    <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>
+
     <!-- 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>
 
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 7c04626..b26a52f 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -445,6 +445,11 @@
     }
 
     @Override
+    public void onMultiWindowModeChanged(boolean entering) {
+        initializeHomeVisibility();
+    }
+
+    @Override
     protected void onResume() {
         super.onResume();
 
@@ -464,6 +469,7 @@
             onSyncStateUpdated();
         }
         initializeFabVisibility();
+        initializeHomeVisibility();
 
         mSaveServiceListener = new SaveServiceListener();
         LocalBroadcastManager.getInstance(this).registerReceiver(mSaveServiceListener,
@@ -483,6 +489,15 @@
         wasLastFabAnimationScaleIn = !shouldHideFab();
     }
 
+    private void initializeHomeVisibility() {
+        // Remove the navigation icon if we return to the fragment in a search or select state
+        if (getToolbar() != null && (isAllFragmentInSelectionMode()
+                || isAllFragmentInSearchMode() || isGroupsFragmentInSelectionMode()
+                || isGroupsFragmentInSearchMode())) {
+            getToolbar().setNavigationIcon(null);
+        }
+    }
+
     private boolean shouldHideFab() {
         if (mAllFragment != null && mAllFragment.getActionBarAdapter() == null
                 || isInSecondLevel()) {
@@ -698,15 +713,25 @@
     }
 
     private boolean isAllFragmentInSelectionMode() {
-        return mAllFragment.getActionBarAdapter() != null
+        return mAllFragment != null && mAllFragment.getActionBarAdapter() != null
                 && mAllFragment.getActionBarAdapter().isSelectionMode();
     }
 
     private boolean isAllFragmentInSearchMode() {
-        return mAllFragment.getActionBarAdapter() != null
+        return mAllFragment != null && mAllFragment.getActionBarAdapter() != null
                 && mAllFragment.getActionBarAdapter().isSearchMode();
     }
 
+    private boolean isGroupsFragmentInSelectionMode() {
+        return mMembersFragment != null && mMembersFragment.getActionBarAdapter() != null
+                && mMembersFragment.getActionBarAdapter().isSelectionMode();
+    }
+
+    private boolean isGroupsFragmentInSearchMode() {
+        return mMembersFragment != null && mMembersFragment.getActionBarAdapter() != null
+                && mMembersFragment.getActionBarAdapter().isSearchMode();
+    }
+
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
@@ -790,9 +815,7 @@
         final FragmentManager fragmentManager =  getFragmentManager();
         final FragmentTransaction transaction = fragmentManager.beginTransaction();
         if (isGroupView()) {
-            if (mMembersFragment == null) {
-                mMembersFragment = GroupMembersFragment.newInstance(mGroupUri);
-            }
+            mMembersFragment = GroupMembersFragment.newInstance(mGroupUri);
             transaction.replace(
                     R.id.contacts_list_container, mMembersFragment, TAG_GROUP_VIEW);
         } else if(isAssistantView()) {
diff --git a/src/com/android/contacts/common/database/SimContactDao.java b/src/com/android/contacts/common/database/SimContactDao.java
index 5f22287..8d7855f 100644
--- a/src/com/android/contacts/common/database/SimContactDao.java
+++ b/src/com/android/contacts/common/database/SimContactDao.java
@@ -20,6 +20,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.OperationApplicationException;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -32,10 +33,12 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.ArraySet;
+import android.util.Log;
 
 import com.android.contacts.common.Experiments;
 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;
@@ -50,6 +53,8 @@
  * SIM contacts to a CP2 account.
  */
 public class SimContactDao {
+    private static final String TAG = "SimContactDao";
+
     @VisibleForTesting
     public static final Uri ICC_CONTENT_URI = Uri.parse("content://icc/adn");
 
@@ -88,9 +93,20 @@
     }
 
     public boolean shouldLoad() {
-        final Set<String> simIds = getSimCardIds();
-        return !Sets.difference(simIds, SharedPreferenceUtil.getImportedSims(mContext)).isEmpty()
-                && getSimState() != TelephonyManager.SIM_STATE_ABSENT;
+        final Set<String> simIds = hasTelephony() && hasPermissions() ? getSimCardIds() :
+                Collections.<String>emptySet();
+
+        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));
+        }
+        return hasTelephony() && hasPermissions() &&
+                getSimState() != TelephonyManager.SIM_STATE_ABSENT &&
+                !Sets.difference(simIds, SharedPreferenceUtil.getImportedSims(mContext))
+                        .isEmpty();
     }
 
     public Set<String> getSimCardIds() {
@@ -190,4 +206,13 @@
             SharedPreferenceUtil.addImportedSim(mContext, id);
         }
     }
+
+    private boolean hasTelephony() {
+        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+    }
+
+    private boolean hasPermissions() {
+        return PermissionsUtil.hasContactsPermissions(mContext) &&
+                PermissionsUtil.hasPhonePermissions(mContext);
+    }
 }
diff --git a/src/com/android/contacts/common/interactions/ImportDialogFragment.java b/src/com/android/contacts/common/interactions/ImportDialogFragment.java
index 991a9c2..30c6603 100644
--- a/src/com/android/contacts/common/interactions/ImportDialogFragment.java
+++ b/src/com/android/contacts/common/interactions/ImportDialogFragment.java
@@ -24,8 +24,11 @@
 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;
@@ -45,10 +48,11 @@
 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.common.vcard.VCardCommonArguments;
 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.
@@ -60,6 +64,9 @@
     private static final String KEY_RES_ID = "resourceId";
     private static final String KEY_SUBSCRIPTION_ID = "subscriptionId";
 
+    public static final String EXTRA_SIM_ONLY = "extraSimOnly";
+
+    private boolean mSimOnly = false;
 
     private final String[] LOOKUP_PROJECTION = new String[] {
             Contacts.LOOKUP_KEY
@@ -68,15 +75,31 @@
     private SubscriptionManager mSubscriptionManager;
 
     /** Preferred way to show this dialog */
-    public static void show(FragmentManager fragmentManager, Class callingActivity) {
+    public static void show(FragmentManager fragmentManager) {
+        final ImportDialogFragment fragment = new ImportDialogFragment();
+        fragment.show(fragmentManager, TAG);
+    }
+
+    /**
+     * Create an instance that will only have items for the SIM cards (VCF will not be included).
+     */
+    public static void showForSimOnly(FragmentManager fragmentManager) {
         final ImportDialogFragment fragment = new ImportDialogFragment();
         Bundle args = new Bundle();
-        args.putString(VCardCommonArguments.ARG_CALLING_ACTIVITY, callingActivity.getName());
+        args.putBoolean(EXTRA_SIM_ONLY, true);
         fragment.setArguments(args);
         fragment.show(fragmentManager, TAG);
     }
 
     @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Bundle args = getArguments();
+        mSimOnly = args != null && args.getBoolean(EXTRA_SIM_ONLY, false);
+    }
+
+    @Override
     public Context getContext() {
         return getActivity();
     }
@@ -92,8 +115,6 @@
         final Resources res = getActivity().getResources();
         final LayoutInflater dialogInflater = (LayoutInflater)getActivity()
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        final String callingActivity = getArguments().getString(
-                VCardCommonArguments.ARG_CALLING_ACTIVITY);
 
         // Adapter that shows a list of string resources
         final ArrayAdapter<AdapterEntry> adapter = new ArrayAdapter<AdapterEntry>(getActivity(),
@@ -110,7 +131,7 @@
 
         final TelephonyManager manager =
                 (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
-        if (res.getBoolean(R.bool.config_allow_import_from_vcf_file)) {
+        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));
         }
@@ -129,6 +150,11 @@
                     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),
@@ -234,18 +260,62 @@
         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;
+            }
+        }
+        return true;
+    }
+
     private CharSequence getSubDescription(SubscriptionInfo record) {
-        CharSequence name = record.getDisplayName();
-        if (TextUtils.isEmpty(record.getNumber())) {
-            // Don't include the phone number in the description, since we don't know the number.
+        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 TextUtils.expandTemplate(
-                getString(R.string.import_from_sim_summary),
-                name,
-                PhoneNumberUtilsCompat.createTtsSpannable(record.getNumber()));
+
+        return TextUtils.expandTemplate(getString(R.string.import_from_sim_summary), name, 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;
diff --git a/src/com/android/contacts/common/preference/DisplayOptionsPreferenceFragment.java b/src/com/android/contacts/common/preference/DisplayOptionsPreferenceFragment.java
index a6881ed..1b9818f 100644
--- a/src/com/android/contacts/common/preference/DisplayOptionsPreferenceFragment.java
+++ b/src/com/android/contacts/common/preference/DisplayOptionsPreferenceFragment.java
@@ -324,7 +324,7 @@
             ((ContactsPreferenceActivity) getActivity()).showAboutFragment();
             return true;
         } else if (KEY_IMPORT.equals(prefKey)) {
-            ImportDialogFragment.show(getFragmentManager(), ContactsPreferenceActivity.class);
+            ImportDialogFragment.show(getFragmentManager());
             return true;
         } else if (KEY_EXPORT.equals(prefKey)) {
             ExportDialogFragment.show(getFragmentManager(), ContactsPreferenceActivity.class,
diff --git a/src/com/android/contacts/common/util/AccountFilterUtil.java b/src/com/android/contacts/common/util/AccountFilterUtil.java
index b89e8b9..96c5113 100644
--- a/src/com/android/contacts/common/util/AccountFilterUtil.java
+++ b/src/com/android/contacts/common/util/AccountFilterUtil.java
@@ -219,7 +219,8 @@
     public static String getActionBarTitleForFilter(Context context, ContactListFilter filter) {
         if (filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
             return context.getString(R.string.account_phone);
-        } else if (!TextUtils.isEmpty(filter.accountName)) {
+        } else if (filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT &&
+                !TextUtils.isEmpty(filter.accountName)) {
             return getActionBarTitleForAccount(context, filter);
         }
         return context.getString(R.string.contactsList);
diff --git a/src/com/android/contacts/list/ContactsUnavailableFragment.java b/src/com/android/contacts/list/ContactsUnavailableFragment.java
index 518447c..72e6718 100644
--- a/src/com/android/contacts/list/ContactsUnavailableFragment.java
+++ b/src/com/android/contacts/list/ContactsUnavailableFragment.java
@@ -148,7 +148,7 @@
                 ImplicitIntentsUtil.startActivityOutsideApp(getActivity(), intent);
                 break;
             case R.id.import_contacts_button:
-                ImportDialogFragment.show(getFragmentManager(), getActivity().getClass());
+                ImportDialogFragment.show(getFragmentManager());
                 break;
         }
     }
diff --git a/src/com/android/contacts/list/GroupMemberPickerFragment.java b/src/com/android/contacts/list/GroupMemberPickerFragment.java
index c6f7493..a7e37d7 100644
--- a/src/com/android/contacts/list/GroupMemberPickerFragment.java
+++ b/src/com/android/contacts/list/GroupMemberPickerFragment.java
@@ -278,12 +278,13 @@
     @Override
     public void onPrepareOptionsMenu(Menu menu) {
         final ContactSelectionActivity activity = getContactSelectionActivity();
+        final boolean hasContacts = mContactIds == null ? false : mContactIds.size() > 0;
         final boolean isSearchMode = activity == null ? false : activity.isSearchMode();
         final boolean isSelectionMode = activity == null ? false : activity.isSelectionMode();
 
         // Added in ContactSelectionActivity but we must account for selection mode
         setVisible(menu, R.id.menu_search, !isSearchMode && !isSelectionMode);
-        setVisible(menu, R.id.menu_select, !isSearchMode && !isSelectionMode);
+        setVisible(menu, R.id.menu_select, hasContacts && !isSearchMode && !isSelectionMode);
     }
 
     private ContactSelectionActivity getContactSelectionActivity() {
diff --git a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
index 9152956..ec08a76 100644
--- a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
@@ -107,33 +107,33 @@
     }
 
     public void testSingleWritableRawContact() {
-        expectQuery().returnRow(1, WRITABLE_ACCOUNT_TYPE, null, 13, "foo", "baz");
+        expectQuery().returnRow(1, WRITABLE_ACCOUNT_TYPE, null, 13, "foo", "baz", "bazAlt");
         assertWithMessageId(R.string.deleteConfirmation);
     }
 
     public void testReadOnlyRawContacts() {
-        expectQuery().returnRow(1, READONLY_ACCOUNT_TYPE, null, 13, "foo", "baz");
+        expectQuery().returnRow(1, READONLY_ACCOUNT_TYPE, null, 13, "foo", "baz", "bazAlt");
         assertWithMessageId(R.string.readOnlyContactWarning);
     }
 
     public void testMixOfWritableAndReadOnlyRawContacts() {
         expectQuery()
-                .returnRow(1, WRITABLE_ACCOUNT_TYPE, null, 13, "foo", "baz")
-                .returnRow(2, READONLY_ACCOUNT_TYPE, null, 13, "foo", "baz");
+                .returnRow(1, WRITABLE_ACCOUNT_TYPE, null, 13, "foo", "baz", "bazAlt")
+                .returnRow(2, READONLY_ACCOUNT_TYPE, null, 13, "foo", "baz", "bazAlt");
         assertWithMessageId(R.string.readOnlyContactDeleteConfirmation);
     }
 
     public void testMultipleWritableRawContacts() {
         expectQuery()
-                .returnRow(1, WRITABLE_ACCOUNT_TYPE, null, 13, "foo", "baz")
-                .returnRow(2, WRITABLE_ACCOUNT_TYPE, null, 13, "foo", "baz");
+                .returnRow(1, WRITABLE_ACCOUNT_TYPE, null, 13, "foo", "baz", "bazAlt")
+                .returnRow(2, WRITABLE_ACCOUNT_TYPE, null, 13, "foo", "baz", "bazAlt");
         assertWithMessageId(R.string.multipleContactDeleteConfirmation);
     }
 
     private Query expectQuery() {
         return mContactsProvider.expectQuery(ENTITY_URI).withProjection(
                 Entity.RAW_CONTACT_ID, Entity.ACCOUNT_TYPE, Entity.DATA_SET, Entity.CONTACT_ID,
-                Entity.LOOKUP_KEY, Entity.DISPLAY_NAME);
+                Entity.LOOKUP_KEY, Entity.DISPLAY_NAME, Entity.DISPLAY_NAME_ALTERNATIVE);
     }
 
     private void assertWithMessageId(int messageId) {