am e94ad7cc: am faed3374: Switch from CALL -> CALL_PRIVILEGED

* commit 'e94ad7cc098ed77f4a69130a0393abdad835c9b9':
  Switch from CALL -> CALL_PRIVILEGED
diff --git a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
index 99b8df5..0de0be3 100644
--- a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
+++ b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
+import android.app.DialogFragment;
 import android.app.FragmentManager;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -28,7 +29,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.ContactsContract.Contacts;
-import android.telephony.SubInfoRecord;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -48,7 +49,7 @@
 import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
 import com.android.contacts.common.vcard.ExportVCardActivity;
 import com.android.contacts.common.vcard.VCardCommonArguments;
-import com.android.dialerbind.analytics.AnalyticsDialogFragment;
+import com.android.contacts.commonbind.analytics.AnalyticsUtil;
 
 import java.util.Collections;
 import java.util.List;
@@ -56,7 +57,7 @@
 /**
  * An dialog invoked to import/export contacts.
  */
-public class ImportExportDialogFragment extends AnalyticsDialogFragment
+public class ImportExportDialogFragment extends DialogFragment
         implements SelectAccountDialogFragment.Listener {
     public static final String TAG = "ImportExportDialogFragment";
 
@@ -82,7 +83,7 @@
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
-        sendScreenView();
+        AnalyticsUtil.sendScreenView(this);
     }
 
     @Override
@@ -116,14 +117,14 @@
                     R.string.import_from_sdcard));
         }
         if (manager != null && res.getBoolean(R.bool.config_allow_sim_import)) {
-            final List<SubInfoRecord> subInfoRecords = getAllSubInfoList();
+            final List<SubscriptionInfo> subInfoRecords = getAllSubInfoList();
             if (subInfoRecords.size() == 1) {
                 adapter.add(new AdapterEntry(getString(R.string.import_from_sim),
-                        R.string.import_from_sim, subInfoRecords.get(0).subId));
+                        R.string.import_from_sim, subInfoRecords.get(0).getSubscriptionId()));
             } else {
-                for (SubInfoRecord record : subInfoRecords) {
+                for (SubscriptionInfo record : subInfoRecords) {
                     adapter.add(new AdapterEntry(getSubDescription(record),
-                            R.string.import_from_sim, record.subId));
+                            R.string.import_from_sim, record.getSubscriptionId()));
                 }
             }
         }
@@ -272,13 +273,13 @@
     }
 
     /**
-     * Return the same values as {@link SubscriptionManager#getAllSubInfoList()} without relying
+     * Return the same values as {@link SubscriptionManager#getAllSubscriptionInfoList()} without relying
      * on any hidden methods.
      */
     // TODO: replace with a method that doesn't make assumptions about the number of SIM slots
-    private static List<SubInfoRecord> getAllSubInfoList() {
-        final List<SubInfoRecord> subInfoRecords0 = SubscriptionManager.getSubInfoUsingSlotId(0);
-        final List<SubInfoRecord> subInfoRecords1 = SubscriptionManager.getSubInfoUsingSlotId(1);
+    private static List<SubscriptionInfo> getAllSubInfoList() {
+        final List<SubscriptionInfo> subInfoRecords0 = SubscriptionManager.getSubscriptionInfoUsingSlotId(0);
+        final List<SubscriptionInfo> subInfoRecords1 = SubscriptionManager.getSubscriptionInfoUsingSlotId(1);
         if (subInfoRecords0 == null && subInfoRecords1 != null) {
             return subInfoRecords1;
         }
@@ -292,23 +293,24 @@
         return subInfoRecords0;
     }
 
-    private String getSubDescription(SubInfoRecord record) {
-        if (TextUtils.isEmpty(record.number)) {
+    private String 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.
-            return getString(R.string.import_from_sim_summary_no_number, record.displayName);
+            return getString(R.string.import_from_sim_summary_no_number, name);
         }
-        return getString(R.string.import_from_sim_summary, record.displayName, record.number);
+        return getString(R.string.import_from_sim_summary, name, record.getNumber());
     }
 
     private static class AdapterEntry {
         public final String mLabel;
         public final int mChoiceResourceId;
-        public final long mSubscriptionId;
+        public final int mSubscriptionId;
 
-        public AdapterEntry(String label, int resId, long subscriptionId) {
+        public AdapterEntry(String label, int resId, int subId) {
             mLabel = label;
             mChoiceResourceId = resId;
-            mSubscriptionId = subscriptionId;
+            mSubscriptionId = subId;
         }
 
         public AdapterEntry(String label, int resId) {
diff --git a/src/com/android/contacts/common/list/ContactEntryListFragment.java b/src/com/android/contacts/common/list/ContactEntryListFragment.java
index 62515e2..c38e969 100644
--- a/src/com/android/contacts/common/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/common/list/ContactEntryListFragment.java
@@ -17,13 +17,13 @@
 package com.android.contacts.common.list;
 
 import android.app.Activity;
+import android.app.Fragment;
 import android.app.LoaderManager;
 import android.app.LoaderManager.LoaderCallbacks;
 import android.content.Context;
 import android.content.CursorLoader;
 import android.content.Intent;
 import android.content.Loader;
-import android.content.res.Resources;
 import android.database.Cursor;
 import android.os.Bundle;
 import android.os.Handler;
@@ -45,12 +45,9 @@
 import android.widget.ListView;
 
 import com.android.common.widget.CompositeCursorAdapter.Partition;
-import com.android.contacts.common.R;
 import com.android.contacts.common.ContactPhotoManager;
 import com.android.contacts.common.preference.ContactsPreferences;
 import com.android.contacts.common.util.ContactListViewUtils;
-import com.android.contacts.common.util.SchedulingUtils;
-import com.android.dialerbind.analytics.AnalyticsFragment;
 
 import java.util.Locale;
 
@@ -58,7 +55,7 @@
  * Common base class for various contact-related list fragments.
  */
 public abstract class ContactEntryListFragment<T extends ContactEntryListAdapter>
-        extends AnalyticsFragment
+        extends Fragment
         implements OnItemClickListener, OnScrollListener, OnFocusChangeListener, OnTouchListener,
                 LoaderCallbacks<Cursor> {
     private static final String TAG = "ContactEntryListFragment";
diff --git a/src/com/android/contacts/common/list/ContactListItemView.java b/src/com/android/contacts/common/list/ContactListItemView.java
index e5de1f4..4c561df 100644
--- a/src/com/android/contacts/common/list/ContactListItemView.java
+++ b/src/com/android/contacts/common/list/ContactListItemView.java
@@ -49,6 +49,7 @@
 import com.android.contacts.common.ContactStatusUtil;
 import com.android.contacts.common.R;
 import com.android.contacts.common.format.TextHighlighter;
+import com.android.contacts.common.util.ContactDisplayUtils;
 import com.android.contacts.common.util.SearchUtil;
 import com.android.contacts.common.util.ViewUtil;
 
@@ -894,6 +895,7 @@
             mPhoneticNameTextView.setSingleLine(true);
             mPhoneticNameTextView.setEllipsize(getTextEllipsis());
             mPhoneticNameTextView.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
+            mPhoneticNameTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
             mPhoneticNameTextView.setTypeface(mPhoneticNameTextView.getTypeface(), Typeface.BOLD);
             mPhoneticNameTextView.setActivated(isActivated());
             mPhoneticNameTextView.setId(R.id.cliv_phoneticname_textview);
@@ -1019,6 +1021,7 @@
             mDataView.setSingleLine(true);
             mDataView.setEllipsize(getTextEllipsis());
             mDataView.setTextAppearance(getContext(), R.style.TextAppearanceSmall);
+            mDataView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
             mDataView.setActivated(isActivated());
             mDataView.setId(R.id.cliv_data_view);
             mDataView.setElegantTextHeight(false);
@@ -1038,6 +1041,13 @@
         } else {
             mTextHighlighter.setPrefixText(getSnippetView(), text, mHighlightedPrefix);
             mSnippetView.setVisibility(VISIBLE);
+            if (ContactDisplayUtils.isPossiblePhoneNumber(text)) {
+                // Give the text-to-speech engine a hint that it's a phone number
+                mSnippetView.setContentDescription(
+                        ContactDisplayUtils.getTelephoneTtsSpannable(text));
+            } else {
+                mSnippetView.setContentDescription(null);
+            }
         }
     }
 
@@ -1050,6 +1060,7 @@
             mSnippetView.setSingleLine(true);
             mSnippetView.setEllipsize(getTextEllipsis());
             mSnippetView.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
+            mSnippetView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
             mSnippetView.setActivated(isActivated());
             addView(mSnippetView);
         }
@@ -1149,6 +1160,14 @@
             name = mUnknownNameText;
         }
         setMarqueeText(getNameTextView(), name);
+
+        if (ContactDisplayUtils.isPossiblePhoneNumber(name)) {
+            // Give the text-to-speech engine a hint that it's a phone number
+            mNameTextView.setContentDescription(
+                    ContactDisplayUtils.getTelephoneTtsSpannable(name.toString()));
+        } else {
+            mNameTextView.setContentDescription(null);
+        }
     }
 
     public void hideDisplayName() {
diff --git a/src/com/android/contacts/common/list/ContactTileAdapter.java b/src/com/android/contacts/common/list/ContactTileAdapter.java
index 04f415d..789ca02 100644
--- a/src/com/android/contacts/common/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/common/list/ContactTileAdapter.java
@@ -562,7 +562,8 @@
 
             // Just line up children horizontally.
             for (int i = 0; i < count; i++) {
-                final View child = getChildAt(i);
+                final int rtlAdjustedIndex = isLayoutRtl() ? count - i - 1 : i;
+                final View child = getChildAt(rtlAdjustedIndex);
 
                 // Note MeasuredWidth includes the padding.
                 final int childWidth = child.getMeasuredWidth();
diff --git a/src/com/android/contacts/common/list/PhoneNumberPickerFragment.java b/src/com/android/contacts/common/list/PhoneNumberPickerFragment.java
index 47cce8b..968f8db 100644
--- a/src/com/android/contacts/common/list/PhoneNumberPickerFragment.java
+++ b/src/com/android/contacts/common/list/PhoneNumberPickerFragment.java
@@ -15,7 +15,6 @@
  */
 package com.android.contacts.common.list;
 
-import android.content.CursorLoader;
 import android.content.Intent;
 import android.content.Loader;
 import android.database.Cursor;
diff --git a/src/com/android/contacts/common/list/ViewPagerTabs.java b/src/com/android/contacts/common/list/ViewPagerTabs.java
index ec95de6..006d632 100644
--- a/src/com/android/contacts/common/list/ViewPagerTabs.java
+++ b/src/com/android/contacts/common/list/ViewPagerTabs.java
@@ -198,7 +198,12 @@
     @Override
     public void onPageSelected(int position) {
         position = getRtlPosition(position);
-        if (mPrevSelected >= 0) {
+        int tabStripChildCount = mTabStrip.getChildCount();
+        if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+            return;
+        }
+
+        if (mPrevSelected >= 0 && mPrevSelected < tabStripChildCount) {
             mTabStrip.getChildAt(mPrevSelected).setSelected(false);
         }
         final View selectedChild = mTabStrip.getChildAt(position);
diff --git a/src/com/android/contacts/common/location/UpdateCountryService.java b/src/com/android/contacts/common/location/UpdateCountryService.java
index e339306..9403187 100644
--- a/src/com/android/contacts/common/location/UpdateCountryService.java
+++ b/src/com/android/contacts/common/location/UpdateCountryService.java
@@ -38,6 +38,10 @@
 
     @Override
     protected void onHandleIntent(Intent intent) {
+        if (intent == null) {
+            Log.d(TAG, "onHandleIntent: could not handle null intent");
+            return;
+        }
         if (ACTION_UPDATE_COUNTRY.equals(intent.getAction())) {
             final Location location = (Location) intent.getParcelableExtra(KEY_INTENT_LOCATION);
             final String country = getCountryFromLocation(getApplicationContext(), location);
diff --git a/src/com/android/contacts/common/model/account/BaseAccountType.java b/src/com/android/contacts/common/model/account/BaseAccountType.java
index 984cb78..648a6dc 100644
--- a/src/com/android/contacts/common/model/account/BaseAccountType.java
+++ b/src/com/android/contacts/common/model/account/BaseAccountType.java
@@ -99,20 +99,20 @@
         static final String TYPE = "type";
     }
 
-    private interface Weight {
+    protected interface Weight {
         static final int NONE = -1;
-        static final int ORGANIZATION = 5;
         static final int PHONE = 10;
         static final int EMAIL = 15;
-        static final int IM = 20;
         static final int STRUCTURED_POSTAL = 25;
-        static final int NOTE = 110;
-        static final int NICKNAME = 115;
-        static final int WEBSITE = 120;
-        static final int SIP_ADDRESS = 130;
-        static final int EVENT = 150;
-        static final int RELATIONSHIP = 160;
-        static final int GROUP_MEMBERSHIP = 999;
+        static final int NICKNAME = 111;
+        static final int EVENT = 120;
+        static final int ORGANIZATION = 125;
+        static final int NOTE = 130;
+        static final int IM = 140;
+        static final int SIP_ADDRESS = 145;
+        static final int GROUP_MEMBERSHIP = 150;
+        static final int WEBSITE = 160;
+        static final int RELATIONSHIP = 999;
     }
 
     public BaseAccountType() {
@@ -148,7 +148,7 @@
 
     protected DataKind addDataKindStructuredName(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(StructuredName.CONTENT_ITEM_TYPE,
-                R.string.nameLabelsGroup, -1, true));
+                R.string.nameLabelsGroup, Weight.NONE, true));
         kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
         kind.actionBody = new SimpleInflater(Nickname.NAME);
         kind.typeOverallMax = 1;
@@ -178,7 +178,7 @@
 
     protected DataKind addDataKindDisplayName(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME,
-                R.string.nameLabelsGroup, -1, true));
+                R.string.nameLabelsGroup, Weight.NONE, true));
         kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
         kind.actionBody = new SimpleInflater(Nickname.NAME);
         kind.typeOverallMax = 1;
@@ -219,7 +219,7 @@
 
     protected DataKind addDataKindPhoneticName(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME,
-                R.string.name_phonetic, -1, true));
+                R.string.name_phonetic, Weight.NONE, true));
         kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
         kind.actionBody = new SimpleInflater(Nickname.NAME);
         kind.typeOverallMax = 1;
@@ -239,7 +239,7 @@
 
     protected DataKind addDataKindNickname(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(Nickname.CONTENT_ITEM_TYPE,
-                    R.string.nicknameLabelsGroup, 115, true));
+                    R.string.nicknameLabelsGroup, Weight.NICKNAME, true));
         kind.typeOverallMax = 1;
         kind.actionHeader = new SimpleInflater(R.string.nicknameLabelsGroup);
         kind.actionBody = new SimpleInflater(Nickname.NAME);
@@ -255,7 +255,7 @@
 
     protected DataKind addDataKindPhone(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(Phone.CONTENT_ITEM_TYPE, R.string.phoneLabelsGroup,
-                10, true));
+                Weight.PHONE, true));
         kind.iconAltRes = R.drawable.ic_text_holo_light;
         kind.iconAltDescriptionRes = R.string.sms;
         kind.actionHeader = new PhoneActionInflater();
@@ -294,7 +294,7 @@
 
     protected DataKind addDataKindEmail(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(Email.CONTENT_ITEM_TYPE, R.string.emailLabelsGroup,
-                15, true));
+                Weight.EMAIL, true));
         kind.actionHeader = new EmailActionInflater();
         kind.actionBody = new SimpleInflater(Email.DATA);
         kind.typeColumn = Email.TYPE;
@@ -314,7 +314,7 @@
 
     protected DataKind addDataKindStructuredPostal(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(StructuredPostal.CONTENT_ITEM_TYPE,
-                R.string.postalLabelsGroup, 25, true));
+                R.string.postalLabelsGroup, Weight.STRUCTURED_POSTAL, true));
         kind.actionHeader = new PostalActionInflater();
         kind.actionBody = new SimpleInflater(StructuredPostal.FORMATTED_ADDRESS);
         kind.typeColumn = StructuredPostal.TYPE;
@@ -336,8 +336,8 @@
     }
 
     protected DataKind addDataKindIm(Context context) throws DefinitionException {
-        DataKind kind = addKind(new DataKind(Im.CONTENT_ITEM_TYPE, R.string.imLabelsGroup, 20,
-                true));
+        DataKind kind = addKind(new DataKind(Im.CONTENT_ITEM_TYPE, R.string.imLabelsGroup,
+                Weight.IM, true));
         kind.actionHeader = new ImActionInflater();
         kind.actionBody = new SimpleInflater(Im.DATA);
 
@@ -368,7 +368,7 @@
 
     protected DataKind addDataKindOrganization(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(Organization.CONTENT_ITEM_TYPE,
-                    R.string.organizationLabelsGroup, 5, true));
+                    R.string.organizationLabelsGroup, Weight.ORGANIZATION, true));
         kind.actionHeader = new SimpleInflater(R.string.organizationLabelsGroup);
         kind.actionBody = ORGANIZATION_BODY_INFLATER;
         kind.typeOverallMax = 1;
@@ -383,7 +383,7 @@
     }
 
     protected DataKind addDataKindPhoto(Context context) throws DefinitionException {
-        DataKind kind = addKind(new DataKind(Photo.CONTENT_ITEM_TYPE, -1, -1, true));
+        DataKind kind = addKind(new DataKind(Photo.CONTENT_ITEM_TYPE, -1, Weight.NONE, true));
         kind.typeOverallMax = 1;
         kind.fieldList = Lists.newArrayList();
         kind.fieldList.add(new EditField(Photo.PHOTO, -1, -1));
@@ -391,8 +391,8 @@
     }
 
     protected DataKind addDataKindNote(Context context) throws DefinitionException {
-        DataKind kind = addKind(new DataKind(Note.CONTENT_ITEM_TYPE, R.string.label_notes, 110,
-                true));
+        DataKind kind = addKind(new DataKind(Note.CONTENT_ITEM_TYPE, R.string.label_notes,
+                Weight.NOTE, true));
         kind.typeOverallMax = 1;
         kind.actionHeader = new SimpleInflater(R.string.label_notes);
         kind.actionBody = new SimpleInflater(Note.NOTE);
@@ -406,7 +406,7 @@
 
     protected DataKind addDataKindWebsite(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(Website.CONTENT_ITEM_TYPE,
-                R.string.websiteLabelsGroup, 120, true));
+                R.string.websiteLabelsGroup, Weight.WEBSITE, true));
         kind.actionHeader = new SimpleInflater(R.string.websiteLabelsGroup);
         kind.actionBody = new SimpleInflater(Website.URL);
         kind.defaultValues = new ContentValues();
@@ -420,7 +420,7 @@
 
     protected DataKind addDataKindSipAddress(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(SipAddress.CONTENT_ITEM_TYPE,
-                    R.string.label_sip_address, 130, true));
+                    R.string.label_sip_address, Weight.SIP_ADDRESS, true));
 
         kind.typeOverallMax = 1;
         kind.actionHeader = new SimpleInflater(R.string.label_sip_address);
@@ -434,7 +434,7 @@
 
     protected DataKind addDataKindGroupMembership(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(GroupMembership.CONTENT_ITEM_TYPE,
-                R.string.groupsLabel, 999, true));
+                R.string.groupsLabel, Weight.GROUP_MEMBERSHIP, true));
 
         kind.typeOverallMax = 1;
         kind.fieldList = Lists.newArrayList();
diff --git a/src/com/android/contacts/common/model/account/ExchangeAccountType.java b/src/com/android/contacts/common/model/account/ExchangeAccountType.java
index 04b5263..7020836 100644
--- a/src/com/android/contacts/common/model/account/ExchangeAccountType.java
+++ b/src/com/android/contacts/common/model/account/ExchangeAccountType.java
@@ -80,7 +80,7 @@
     @Override
     protected DataKind addDataKindStructuredName(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(StructuredName.CONTENT_ITEM_TYPE,
-                R.string.nameLabelsGroup, -1, true));
+                R.string.nameLabelsGroup, Weight.NONE, true));
         kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
         kind.actionBody = new SimpleInflater(Nickname.NAME);
 
@@ -109,7 +109,7 @@
     @Override
     protected DataKind addDataKindDisplayName(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME,
-                R.string.nameLabelsGroup, -1, true));
+                R.string.nameLabelsGroup, Weight.NONE, true));
 
         boolean displayOrderPrimary =
                 context.getResources().getBoolean(R.bool.config_editor_field_order_primary);
@@ -142,7 +142,7 @@
     @Override
     protected DataKind addDataKindPhoneticName(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME,
-                R.string.name_phonetic, -1, true));
+                R.string.name_phonetic, Weight.NONE, true));
         kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
         kind.actionBody = new SimpleInflater(Nickname.NAME);
 
@@ -307,7 +307,7 @@
 
     protected DataKind addDataKindEvent(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(Event.CONTENT_ITEM_TYPE, R.string.eventLabelsGroup,
-                150, true));
+                Weight.EVENT, true));
         kind.actionHeader = new EventActionInflater();
         kind.actionBody = new SimpleInflater(Event.START_DATE);
 
diff --git a/src/com/android/contacts/common/model/account/GoogleAccountType.java b/src/com/android/contacts/common/model/account/GoogleAccountType.java
index 8705ae3..6877187 100644
--- a/src/com/android/contacts/common/model/account/GoogleAccountType.java
+++ b/src/com/android/contacts/common/model/account/GoogleAccountType.java
@@ -122,7 +122,7 @@
 
     private DataKind addDataKindRelation(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(Relation.CONTENT_ITEM_TYPE,
-                R.string.relationLabelsGroup, 160, true));
+                R.string.relationLabelsGroup, Weight.RELATIONSHIP, true));
         kind.actionHeader = new RelationActionInflater();
         kind.actionBody = new SimpleInflater(Relation.NAME);
 
@@ -157,7 +157,7 @@
 
     private DataKind addDataKindEvent(Context context) throws DefinitionException {
         DataKind kind = addKind(new DataKind(Event.CONTENT_ITEM_TYPE,
-                    R.string.eventLabelsGroup, 150, true));
+                    R.string.eventLabelsGroup, Weight.EVENT, true));
         kind.actionHeader = new EventActionInflater();
         kind.actionBody = new SimpleInflater(Event.START_DATE);
 
diff --git a/src/com/android/contacts/common/model/dataitem/EventDataItem.java b/src/com/android/contacts/common/model/dataitem/EventDataItem.java
index aae00e9..5096fea 100644
--- a/src/com/android/contacts/common/model/dataitem/EventDataItem.java
+++ b/src/com/android/contacts/common/model/dataitem/EventDataItem.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.text.TextUtils;
 
 /**
  * Represents an event data item, wrapping the columns in
@@ -46,12 +47,14 @@
         }
         final EventDataItem that = (EventDataItem) t;
         // Events can be different (anniversary, birthday) but have the same start date
-        if (!getStartDate().equals(that.getStartDate())) {
+        if (!TextUtils.equals(getStartDate(), that.getStartDate())) {
             return false;
+        } else if (!hasKindTypeColumn(mKind) || !that.hasKindTypeColumn(that.getDataKind())) {
+            return hasKindTypeColumn(mKind) == that.hasKindTypeColumn(that.getDataKind());
         } else if (getKindTypeColumn(mKind) != that.getKindTypeColumn(that.getDataKind())) {
             return false;
         } else if (getKindTypeColumn(mKind) == Event.TYPE_CUSTOM &&
-                !getLabel().equals(that.getLabel())) {
+                !TextUtils.equals(getLabel(), that.getLabel())) {
             // Check if custom types are not the same
             return false;
         }
diff --git a/src/com/android/contacts/common/model/dataitem/ImDataItem.java b/src/com/android/contacts/common/model/dataitem/ImDataItem.java
index d1af246..f89e5c6 100644
--- a/src/com/android/contacts/common/model/dataitem/ImDataItem.java
+++ b/src/com/android/contacts/common/model/dataitem/ImDataItem.java
@@ -21,6 +21,7 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.text.TextUtils;
 
 /**
  * Represents an IM data item, wrapping the columns in
@@ -91,21 +92,21 @@
         // IM can have the same data put different protocol. These should not collapse.
         if (!getData().equals(that.getData())) {
             return false;
-        } else if (isProtocolValid() && that.isProtocolValid() &&
-                getProtocol() != that.getProtocol()) {
+        } else if (!isProtocolValid() || !that.isProtocolValid()) {
+            // Deal with invalid protocol as if it was custom. If either has a non valid
+            // protocol, check to see if the other has a valid that is not custom
+            if (isProtocolValid()) {
+                return getProtocol() == Im.PROTOCOL_CUSTOM;
+            } else if (that.isProtocolValid()) {
+                return that.getProtocol() == Im.PROTOCOL_CUSTOM;
+            }
+            return true;
+        } else if (getProtocol() != that.getProtocol()) {
             return false;
-        } else if (isProtocolValid() && that.isProtocolValid() &&
-                getProtocol() == Im.PROTOCOL_CUSTOM &&
-                !getCustomProtocol().equals(that.getCustomProtocol())) {
+        } else if (getProtocol() == Im.PROTOCOL_CUSTOM &&
+                !TextUtils.equals(getCustomProtocol(), that.getCustomProtocol())) {
             // Check if custom protocols are not the same
             return false;
-        } else if ((isProtocolValid() && !that.isProtocolValid() &&
-                getProtocol() != Im.PROTOCOL_CUSTOM) ||
-                (that.isProtocolValid() && !isProtocolValid() &&
-                        that.getProtocol() != Im.PROTOCOL_CUSTOM)) {
-            // Deal with invalid protocol as if it was custom. If either has a non valid protocol,
-            // check to see if the other has a valid that is not custom
-            return false;
         }
         return true;
     }
diff --git a/src/com/android/contacts/common/model/dataitem/RelationDataItem.java b/src/com/android/contacts/common/model/dataitem/RelationDataItem.java
index 1ba3fcf..9e883fe 100644
--- a/src/com/android/contacts/common/model/dataitem/RelationDataItem.java
+++ b/src/com/android/contacts/common/model/dataitem/RelationDataItem.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Relation;
+import android.text.TextUtils;
 
 /**
  * Represents a relation data item, wrapping the columns in
@@ -46,12 +47,14 @@
         }
         final RelationDataItem that = (RelationDataItem) t;
         // Relations can have different types (assistant, father) but have the same name
-        if (!getName().equals(that.getName())) {
+        if (!TextUtils.equals(getName(), that.getName())) {
             return false;
+        } else if (!hasKindTypeColumn(mKind) || !that.hasKindTypeColumn(that.getDataKind())) {
+            return hasKindTypeColumn(mKind) == that.hasKindTypeColumn(that.getDataKind());
         } else if (getKindTypeColumn(mKind) != that.getKindTypeColumn(that.getDataKind())) {
             return false;
         } else if (getKindTypeColumn(mKind) == Relation.TYPE_CUSTOM &&
-                !getLabel().equals(that.getLabel())) {
+                !TextUtils.equals(getLabel(), that.getLabel())) {
             // Check if custom types are not the same
             return false;
         }
diff --git a/src/com/android/contacts/common/util/AccountSelectionUtil.java b/src/com/android/contacts/common/util/AccountSelectionUtil.java
index 68217b9..da30e89 100644
--- a/src/com/android/contacts/common/util/AccountSelectionUtil.java
+++ b/src/com/android/contacts/common/util/AccountSelectionUtil.java
@@ -55,12 +55,12 @@
 
         final private Context mContext;
         final private int mResId;
-        final private long mSubscriptionId;
+        final private int mSubscriptionId;
 
         final protected List<AccountWithDataSet> mAccountList;
 
         public AccountSelectedListener(Context context, List<AccountWithDataSet> accountList,
-                int resId, long subscriptionId) {
+                int resId, int subscriptionId) {
             if (accountList == null || accountList.size() == 0) {
                 Log.e(LOG_TAG, "The size of Account list is 0.");
             }
diff --git a/src/com/android/contacts/common/util/BitmapUtil.java b/src/com/android/contacts/common/util/BitmapUtil.java
index a70831e..66ab00f 100644
--- a/src/com/android/contacts/common/util/BitmapUtil.java
+++ b/src/com/android/contacts/common/util/BitmapUtil.java
@@ -19,6 +19,11 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.BitmapDrawable;
 
@@ -107,4 +112,51 @@
 
         return new BitmapDrawable(resources,rotated);
     }
+
+    /**
+     * Given an input bitmap, scales it to the given width/height and makes it round.
+     *
+     * @param input {@link Bitmap} to scale and crop
+     * @param targetWidth desired output width
+     * @param targetHeight desired output height
+     * @return output bitmap scaled to the target width/height and cropped to an oval. The
+     *         cropping algorithm will try to fit as much of the input into the output as possible,
+     *         while preserving the target width/height ratio.
+     */
+    public static Bitmap getRoundedBitmap(Bitmap input, int targetWidth, int targetHeight) {
+        if (input == null) {
+            return null;
+        }
+        final Bitmap result = Bitmap.createBitmap(targetWidth, targetHeight, input.getConfig());
+        final Canvas canvas = new Canvas(result);
+        final Paint paint = new Paint();
+        canvas.drawARGB(0, 0, 0, 0);
+        paint.setAntiAlias(true);
+        canvas.drawOval(0, 0, targetWidth, targetHeight, paint);
+
+        // Specifies that only pixels present in the destination (i.e. the drawn oval) should
+        // be overwritten with pixels from the input bitmap.
+        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
+
+        final int inputWidth = input.getWidth();
+        final int inputHeight = input.getHeight();
+
+        // Choose the largest scale factor that will fit inside the dimensions of the
+        // input bitmap.
+        final float scaleBy = Math.min((float) inputWidth / targetWidth,
+            (float) inputHeight / targetHeight);
+
+        final int xCropAmountHalved = (int) (scaleBy * targetWidth / 2);
+        final int yCropAmountHalved = (int) (scaleBy * targetHeight / 2);
+
+        final Rect src = new Rect(
+                inputWidth / 2 - xCropAmountHalved,
+                inputHeight / 2 - yCropAmountHalved,
+                inputWidth / 2 + xCropAmountHalved,
+                inputHeight / 2 + yCropAmountHalved);
+
+        final RectF dst = new RectF(0, 0, targetWidth, targetHeight);
+        canvas.drawBitmap(input, src, dst, paint);
+        return result;
+    }
 }
diff --git a/src/com/android/contacts/common/util/ContactDisplayUtils.java b/src/com/android/contacts/common/util/ContactDisplayUtils.java
index 7ec751a..bb91b53 100644
--- a/src/com/android/contacts/common/util/ContactDisplayUtils.java
+++ b/src/com/android/contacts/common/util/ContactDisplayUtils.java
@@ -19,10 +19,18 @@
 import static android.provider.ContactsContract.CommonDataKinds.Phone;
 
 import android.content.Context;
+import android.telephony.PhoneNumberUtils;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.TtsSpan;
 import android.util.Log;
+import android.util.Patterns;
 
 import com.android.contacts.common.R;
 
+import com.android.i18n.phonenumbers.NumberParseException;
+import com.android.i18n.phonenumbers.PhoneNumberUtil;
+import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
 import com.google.common.base.Preconditions;
 
 /**
@@ -187,4 +195,80 @@
         }
     }
 
+    /**
+     * Whether the given text could be a phone number.
+     *
+     * Note this will miss many things that are legitimate phone numbers, for example,
+     * phone numbers with letters.
+     */
+    public static boolean isPossiblePhoneNumber(CharSequence text) {
+        return text == null ? false : Patterns.PHONE.matcher(text.toString()).matches();
+    }
+
+    /**
+     * Returns a Spannable for the given phone number with a telephone {@link TtsSpan} set over
+     * the entire length of the given phone number.
+     */
+    public static Spannable getTelephoneTtsSpannable(String phoneNumber) {
+        if (phoneNumber == null) {
+            return null;
+        }
+        final Spannable spannable = new SpannableString(phoneNumber);
+        final TtsSpan ttsSpan = getTelephoneTtsSpan(phoneNumber);
+        spannable.setSpan(ttsSpan, 0, phoneNumber.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        return spannable;
+    }
+
+    /**
+     * Returns a Spannable for the given message with a telephone {@link TtsSpan} set for
+     * the given phone number text wherever it is found within the message.
+     */
+    public static Spannable getTelephoneTtsSpannable(String message, String phoneNumber) {
+        if (message == null) {
+            return null;
+        }
+        final Spannable spannable = new SpannableString(message);
+        int start = phoneNumber == null ? -1 : message.indexOf(phoneNumber);
+        while (start >= 0) {
+            final int end = start + phoneNumber.length();
+            final TtsSpan ttsSpan = getTelephoneTtsSpan(phoneNumber);
+            spannable.setSpan(ttsSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+            start = message.indexOf(phoneNumber, end);
+        }
+        return spannable;
+    }
+
+    /**
+     * Returns a telephone {@link TtsSpan} for the given phone number.
+     */
+    public static TtsSpan getTelephoneTtsSpan(String phoneNumberString) {
+        if (phoneNumberString == null) {
+            throw new NullPointerException();
+        }
+
+        // Parse the phone number
+        final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
+        PhoneNumber phoneNumber = null;
+        try {
+            // Don't supply a defaultRegion so this fails for non-international numbers because
+            // we don't want to TalkBalk to read a country code (e.g. +1) if it is not already
+            // present
+            phoneNumber = phoneNumberUtil.parse(phoneNumberString, /* defaultRegion */ null);
+        } catch (NumberParseException ignored) {
+        }
+
+        // Build a telephone tts span
+        final TtsSpan.TelephoneBuilder builder = new TtsSpan.TelephoneBuilder();
+        if (phoneNumber == null) {
+            // Strip separators otherwise TalkBack will be silent
+            // (this behavior was observed with TalkBalk 4.0.2 from their alpha channel)
+            builder.setNumberParts(PhoneNumberUtils.stripSeparators(phoneNumberString));
+        } else {
+            if (phoneNumber.hasCountryCode()) {
+                builder.setCountryCode(Integer.toString(phoneNumber.getCountryCode()));
+            }
+            builder.setNumberParts(Long.toString(phoneNumber.getNationalNumber()));
+        }
+        return builder.build();
+    }
 }
diff --git a/src/com/android/contacts/common/util/MaterialColorMapUtils.java b/src/com/android/contacts/common/util/MaterialColorMapUtils.java
index 9c8862c..1e44643 100644
--- a/src/com/android/contacts/common/util/MaterialColorMapUtils.java
+++ b/src/com/android/contacts/common/util/MaterialColorMapUtils.java
@@ -23,7 +23,6 @@
 import android.os.Trace;
 
 public class MaterialColorMapUtils {
-
     private final TypedArray sPrimaryColors;
     private final TypedArray sSecondaryColors;
 
@@ -41,6 +40,36 @@
         }
         public final int mPrimaryColor;
         public final int mSecondaryColor;
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            MaterialPalette other = (MaterialPalette) obj;
+            if (mPrimaryColor != other.mPrimaryColor) {
+                return false;
+            }
+            if (mSecondaryColor != other.mSecondaryColor) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + mPrimaryColor;
+            result = prime * result + mSecondaryColor;
+            return result;
+        }
     }
 
     /**
diff --git a/src/com/android/contacts/common/vcard/ExportVCardActivity.java b/src/com/android/contacts/common/vcard/ExportVCardActivity.java
index 3d6f602..b86845e 100644
--- a/src/com/android/contacts/common/vcard/ExportVCardActivity.java
+++ b/src/com/android/contacts/common/vcard/ExportVCardActivity.java
@@ -30,6 +30,8 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Messenger;
+import android.text.BidiFormatter;
+import android.text.TextDirectionHeuristics;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -111,6 +113,7 @@
 
     private VCardService mService;
     private final Messenger mIncomingMessenger = new Messenger(new IncomingHandler());
+    private static final BidiFormatter mBidiFormatter = BidiFormatter.getInstance();
 
     // Used temporarily when asking users to confirm the file name
     private String mTargetFileName;
@@ -208,13 +211,25 @@
         }
     }
 
+    /**
+     * Returns the name of the target path with additional formatting characters to improve its
+     * appearance in bidirectional text.
+     */
+    private String getTargetFileForDisplay() {
+        if (mTargetFileName == null) {
+            return null;
+        }
+        return mBidiFormatter.unicodeWrap(mTargetFileName, TextDirectionHeuristics.LTR);
+    }
+
     @Override
     protected Dialog onCreateDialog(int id, Bundle bundle) {
         switch (id) {
             case R.id.dialog_export_confirmation: {
                 return new AlertDialog.Builder(this)
                         .setTitle(R.string.confirm_export_title)
-                        .setMessage(getString(R.string.confirm_export_message, mTargetFileName))
+                        .setMessage(getString(R.string.confirm_export_message,
+                                getTargetFileForDisplay()))
                         .setPositiveButton(android.R.string.ok,
                                 new ExportConfirmationListener(mTargetFileName))
                         .setNegativeButton(android.R.string.cancel, this)
@@ -258,7 +273,7 @@
             ((AlertDialog)dialog).setMessage(mErrorReason);
         } else if (id == R.id.dialog_export_confirmation) {
             ((AlertDialog)dialog).setMessage(
-                    getString(R.string.confirm_export_message, mTargetFileName));
+                    getString(R.string.confirm_export_message, getTargetFileForDisplay()));
         } else {
             super.onPrepareDialog(id, dialog, args);
         }
diff --git a/src/com/android/contacts/common/vcard/ImportProcessor.java b/src/com/android/contacts/common/vcard/ImportProcessor.java
index 3712875..219ec14 100644
--- a/src/com/android/contacts/common/vcard/ImportProcessor.java
+++ b/src/com/android/contacts/common/vcard/ImportProcessor.java
@@ -194,14 +194,14 @@
                 Log.i(LOG_TAG, "Successfully finished importing one vCard file: " + uri);
                 List<Uri> uris = committer.getCreatedUris();
                 if (mListener != null) {
-                    if (uris != null && uris.size() > 0) {
-                        // TODO: construct intent showing a list of imported contact list.
+                    if (uris != null && uris.size() == 1) {
                         mListener.onImportFinished(mImportRequest, mJobId, uris.get(0));
                     } else {
-                        // Not critical, but suspicious.
-                        Log.w(LOG_TAG,
-                                "Created Uris is null or 0 length " +
-                                "though the creation itself is successful.");
+                        if (uris == null || uris.size() == 0) {
+                            // Not critical, but suspicious.
+                            Log.w(LOG_TAG,  "Created Uris is null or 0 length " +
+                                    "though the creation itself is successful.");
+                        }
                         mListener.onImportFinished(mImportRequest, mJobId, null);
                     }
                 }
diff --git a/src/com/android/contacts/common/vcard/NotificationImportExportListener.java b/src/com/android/contacts/common/vcard/NotificationImportExportListener.java
index f873e31..a85825f 100644
--- a/src/com/android/contacts/common/vcard/NotificationImportExportListener.java
+++ b/src/com/android/contacts/common/vcard/NotificationImportExportListener.java
@@ -26,12 +26,15 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
+import android.provider.ContactsContract;
 import android.provider.ContactsContract.RawContacts;
 import android.widget.Toast;
 
 import com.android.contacts.common.R;
 import com.android.vcard.VCardEntry;
 
+import java.text.NumberFormat;
+
 public class NotificationImportExportListener implements VCardImportExportListener,
         Handler.Callback {
     /** The tag used by vCard-related notifications. */
@@ -123,7 +126,8 @@
                             RawContacts.CONTENT_URI, rawContactId));
             intent = new Intent(Intent.ACTION_VIEW, contactUri);
         } else {
-            intent = null;
+            intent = new Intent(Intent.ACTION_VIEW);
+            intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
         }
         final Notification notification =
                 NotificationImportExportListener.constructFinishNotification(mContext,
@@ -218,13 +222,15 @@
                 .setProgress(totalCount, currentCount, totalCount == - 1)
                 .setTicker(tickerText)
                 .setContentTitle(description)
+                .setColor(context.getResources().getColor(R.color.dialtacts_theme_color))
                 .setSmallIcon(type == VCardService.TYPE_IMPORT
                         ? android.R.drawable.stat_sys_download
                         : android.R.drawable.stat_sys_upload)
                 .setContentIntent(PendingIntent.getActivity(context, 0, intent, 0));
         if (totalCount > 0) {
-            builder.setContentText(context.getString(R.string.percentage,
-                    String.valueOf(currentCount * 100 / totalCount)));
+            String percentage =
+                    NumberFormat.getPercentInstance().format((double) currentCount / totalCount);
+            builder.setContentText(percentage);
         }
         return builder.getNotification();
     }
@@ -240,6 +246,7 @@
         return new Notification.Builder(context)
                 .setAutoCancel(true)
                 .setSmallIcon(android.R.drawable.stat_notify_error)
+                .setColor(context.getResources().getColor(R.color.dialtacts_theme_color))
                 .setContentTitle(description)
                 .setContentText(description)
                 .setContentIntent(PendingIntent.getActivity(context, 0, new Intent(), 0))
@@ -257,6 +264,7 @@
             Context context, String title, String description, Intent intent) {
         return new Notification.Builder(context)
                 .setAutoCancel(true)
+                .setColor(context.getResources().getColor(R.color.dialtacts_theme_color))
                 .setSmallIcon(android.R.drawable.stat_sys_download_done)
                 .setContentTitle(title)
                 .setContentText(description)
@@ -275,6 +283,7 @@
             Context context, String reason) {
         return new Notification.Builder(context)
                 .setAutoCancel(true)
+                .setColor(context.getResources().getColor(R.color.dialtacts_theme_color))
                 .setSmallIcon(android.R.drawable.stat_notify_error)
                 .setContentTitle(context.getString(R.string.vcard_import_failed))
                 .setContentText(reason)
diff --git a/src/com/android/contacts/common/vcard/VCardService.java b/src/com/android/contacts/common/vcard/VCardService.java
index e2adbbd..0a50bec 100644
--- a/src/com/android/contacts/common/vcard/VCardService.java
+++ b/src/com/android/contacts/common/vcard/VCardService.java
@@ -37,6 +37,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -472,7 +473,8 @@
          * This method increments "index" part from 1 to maximum, and checks whether any file name
          * following naming rule is available. If there's no file named /mnt/sdcard/00001.vcf, the
          * name will be returned to a caller. If there are 00001.vcf 00002.vcf, 00003.vcf is
-         * returned.
+         * returned. We format these numbers in the US locale to ensure we they appear as
+         * english numerals.
          *
          * There may not be any appropriate file name. If there are 99999 vCard files in the
          * storage, for example, there's no appropriate name, so this method returns
@@ -495,7 +497,7 @@
 
         if (!ALLOW_LONG_FILE_NAME) {
             final String possibleBody =
-                    String.format(bodyFormat, mFileNamePrefix, 1, mFileNameSuffix);
+                    String.format(Locale.US, bodyFormat, mFileNamePrefix, 1, mFileNameSuffix);
             if (possibleBody.length() > 8 || mFileNameExtension.length() > 3) {
                 Log.e(LOG_TAG, "This code does not allow any long file name.");
                 mErrorReason = getString(R.string.fail_reason_too_long_filename,
@@ -507,7 +509,8 @@
 
         for (int i = mFileIndexMinimum; i <= mFileIndexMaximum; i++) {
             boolean numberIsAvailable = true;
-            final String body = String.format(bodyFormat, mFileNamePrefix, i, mFileNameSuffix);
+            final String body
+                    = String.format(Locale.US, bodyFormat, mFileNamePrefix, i, mFileNameSuffix);
             // Make sure that none of the extensions of mExtensionsToConsider matches. If this
             // number is free, we'll go ahead with mFileNameExtension (which is included in
             // mExtensionsToConsider)
diff --git a/src/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java b/src/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
index 0dbe70a..86db174 100644
--- a/src/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
+++ b/src/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
@@ -26,6 +26,7 @@
 import android.content.DialogInterface;
 import android.os.Bundle;
 import android.telecom.TelecomManager;
+import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -46,6 +47,7 @@
  * the choice to set the phone account as default.
  */
 public class SelectPhoneAccountDialogFragment extends DialogFragment {
+    private int mTitleResId;
     private boolean mCanSetDefault;
     private List<PhoneAccountHandle> mAccountHandles;
     private boolean mIsSelected;
@@ -59,17 +61,39 @@
      *
      * @param fragmentManager The fragment manager.
      * @param accountHandles The {@code PhoneAccountHandle}s available to select from.
+     * @param listener The listener for the results of the account selection.
      */
-    public static void showAccountDialog(FragmentManager fragmentManager, boolean canSetDefault,
+    public static void showAccountDialog(FragmentManager fragmentManager,
             List<PhoneAccountHandle> accountHandles, SelectPhoneAccountListener listener) {
+        showAccountDialog(fragmentManager, R.string.select_account_dialog_title, false,
+                accountHandles, listener);
+    }
+
+    /**
+     * Shows the account selection dialog.
+     * This is the preferred way to show this dialog.
+     * This method also allows specifying a custom title and "set default" checkbox.
+     *
+     * @param fragmentManager The fragment manager.
+     * @param titleResId The resource ID for the string to use in the title of the dialog.
+     * @param canSetDefault {@code true} if the dialog should include an option to set the selection
+     * as the default. False otherwise.
+     * @param accountHandles The {@code PhoneAccountHandle}s available to select from.
+     * @param listener The listener for the results of the account selection.
+     */
+    public static void showAccountDialog(FragmentManager fragmentManager, int titleResId,
+            boolean canSetDefault, List<PhoneAccountHandle> accountHandles,
+            SelectPhoneAccountListener listener) {
         SelectPhoneAccountDialogFragment fragment =
-                new SelectPhoneAccountDialogFragment(canSetDefault, accountHandles, listener);
+                new SelectPhoneAccountDialogFragment(
+                        titleResId, canSetDefault, accountHandles, listener);
         fragment.show(fragmentManager, "selectAccount");
     }
 
-    public SelectPhoneAccountDialogFragment(boolean canSetDefault,
+    public SelectPhoneAccountDialogFragment(int titleResId, boolean canSetDefault,
             List<PhoneAccountHandle> accountHandles, SelectPhoneAccountListener listener) {
         super();
+        mTitleResId = titleResId;
         mCanSetDefault = canSetDefault;
         mAccountHandles = accountHandles;
         mListener = listener;
@@ -111,7 +135,7 @@
                 R.layout.select_account_list_item,
                 mAccountHandles);
 
-        AlertDialog dialog = builder.setTitle(R.string.select_account_dialog_title)
+        AlertDialog dialog = builder.setTitle(mTitleResId)
                 .setAdapter(selectAccountListAdapter, selectionListener)
                 .create();
 
@@ -132,20 +156,18 @@
     }
 
     private class SelectAccountListAdapter extends ArrayAdapter<PhoneAccountHandle> {
-        private Context mContext;
         private int mResId;
 
         public SelectAccountListAdapter(
                 Context context, int resource, List<PhoneAccountHandle> accountHandles) {
             super(context, resource, accountHandles);
-            mContext = context;
             mResId = resource;
         }
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             LayoutInflater inflater = (LayoutInflater)
-                    mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+                    getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
             View rowView;
             final ViewHolder holder;
@@ -154,7 +176,8 @@
                 // Cache views for faster scrolling
                 rowView = inflater.inflate(mResId, null);
                 holder = new ViewHolder();
-                holder.textView = (TextView) rowView.findViewById(R.id.text);
+                holder.labelTextView = (TextView) rowView.findViewById(R.id.label);
+                holder.numberTextView = (TextView) rowView.findViewById(R.id.number);
                 holder.imageView = (ImageView) rowView.findViewById(R.id.icon);
                 rowView.setTag(holder);
             }
@@ -165,13 +188,21 @@
 
             PhoneAccountHandle accountHandle = getItem(position);
             PhoneAccount account = mTelecomManager.getPhoneAccount(accountHandle);
-            holder.textView.setText(account.getLabel());
-            holder.imageView.setImageDrawable(account.getIcon(mContext));
+            holder.labelTextView.setText(account.getLabel());
+            if (account.getAddress() == null ||
+                    TextUtils.isEmpty(account.getAddress().getSchemeSpecificPart())) {
+                holder.numberTextView.setVisibility(View.GONE);
+            } else {
+                holder.numberTextView.setVisibility(View.VISIBLE);
+                holder.numberTextView.setText(account.getAddress().getSchemeSpecificPart());
+            }
+            holder.imageView.setImageDrawable(account.createIconDrawable(getContext()));
             return rowView;
         }
 
         private class ViewHolder {
-            TextView textView;
+            TextView labelTextView;
+            TextView numberTextView;
             ImageView imageView;
         }
     }
@@ -183,4 +214,4 @@
         }
         super.onPause();
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/contacts/commonbind/analytics/AnalyticsUtil.java b/src/com/android/contacts/commonbind/analytics/AnalyticsUtil.java
new file mode 100644
index 0000000..59650aa
--- /dev/null
+++ b/src/com/android/contacts/commonbind/analytics/AnalyticsUtil.java
@@ -0,0 +1,25 @@
+package com.android.contacts.commonbind.analytics;
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Fragment;
+import android.text.TextUtils;
+
+public class AnalyticsUtil {
+
+    /**
+     * Initialize this class and setup automatic activity tracking.
+     */
+    public static void initialize(Application application) { }
+
+    /**
+     * Log a screen view for {@param fragment}.
+     */
+    public static void sendScreenView(Fragment fragment) {}
+
+    public static void sendScreenView(Fragment fragment, Activity activity) {}
+
+    public static void sendScreenView(Fragment fragment, Activity activity, String tag) {}
+
+    public static void sendScreenView(String fragmentName, Activity activity, String tag) {}
+}
\ No newline at end of file