Merge QP1A.190418.001

Change-Id: I4d7ef67e84b04aa407e31a4d9371bfc7ec77ed96
diff --git a/Android.mk b/Android.mk
index 2a3a485..9e5552f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -29,6 +29,8 @@
     guava \
     libphonenumber
 
+LOCAL_JAVA_LIBRARIES := voip-common
+
 LOCAL_USE_AAPT2 := true
 
 LOCAL_AAPT_FLAGS := \
@@ -43,7 +45,8 @@
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
-LOCAL_SDK_VERSION := current
+LOCAL_PRIVATE_PLATFORM_APIS := true
+#LOCAL_SDK_VERSION := current
 LOCAL_MIN_SDK_VERSION := 21
 
 include $(BUILD_PACKAGE)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b0783d4..1395823 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -514,7 +514,6 @@
             android:label="@string/sim_import_title"
             android:theme="@style/PeopleThemeAppCompat.FullScreenDialog.SimImportActivity"/>
 
-
         <service
             android:name=".vcard.VCardService"
             android:exported="false"/>
diff --git a/res/menu/people_options.xml b/res/menu/people_options.xml
index 5fb0f2e..18707e3 100644
--- a/res/menu/people_options.xml
+++ b/res/menu/people_options.xml
@@ -45,4 +45,9 @@
         android:title="@string/menu_joinAggregate"
         contacts:showAsAction="ifRoom"/>
 
+    <item
+        android:id="@+id/menu_select_all"
+        android:title="@string/menu_select_all"
+        contacts:showAsAction="never"/>
+
 </menu>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index e5007f0..2948e96 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -92,6 +92,7 @@
     <string name="multipleContactDeleteConfirmation" msgid="5235324124905653550">"删除此联系人也将删除多个帐号中的相关详细信息。"</string>
     <string name="deleteConfirmation" msgid="3512271779086656043">"要删除此联系人吗?"</string>
     <string name="deleteConfirmation_positive_button" msgid="7857888845028586365">"删除"</string>
+    <string name="delete_contacts_title">删除联系人</string>
     <string name="invalidContactMessage" msgid="8215051456181842274">"该联系人不存在。"</string>
     <string name="createContactShortcutSuccessful_NoName" msgid="8831303345367275472">"已将该联系人添加到主屏幕。"</string>
     <string name="createContactShortcutSuccessful" msgid="953651153238790069">"已将<xliff:g id="NAME">%s</xliff:g>添加到主屏幕。"</string>
@@ -135,6 +136,7 @@
     <string name="missing_app" msgid="1466111003546611387">"未找到可处理此操作的应用。"</string>
     <string name="menu_share" msgid="943789700636542260">"分享"</string>
     <string name="menu_add_contact" msgid="3198704337220892684">"添加到通讯录"</string>
+    <string name="menu_select_all">全选</string>
     <string name="menu_add_contacts" msgid="4465646512002163011">"添加"</string>
     <plurals name="title_share_via" formatted="false" msgid="5886112726191455415">
       <item quantity="other">通过以下应用分享联系人</item>
@@ -163,6 +165,7 @@
     <string name="contact_directory_description" msgid="683398073603909119">"目录类型:<xliff:g id="TYPE">%1$s</xliff:g>"</string>
     <string name="activity_title_settings" msgid="5464130076132770781">"设置"</string>
     <string name="menu_settings" msgid="377929915873428211">"设置"</string>
+    <string name="menu_sim_contacts">"SIM卡联系人"</string>
     <string name="menu_help" msgid="1680178646764069976">"帮助和反馈"</string>
     <string name="organization_company_and_title" msgid="6718207751363732025">"<xliff:g id="COMPANY_0">%2$s</xliff:g>,<xliff:g id="COMPANY_1">%1$s</xliff:g>"</string>
     <string name="non_phone_caption" msgid="1541655052330027380">"电话号码"</string>
diff --git a/res/values/ids.xml b/res/values/ids.xml
index a4b8b4b..751d667 100644
--- a/res/values/ids.xml
+++ b/res/values/ids.xml
@@ -25,6 +25,9 @@
     <!-- For ContactMultiDeletionInteraction -->
     <item type="id" name="dialog_delete_multiple_contact_loader_id" />
 
+    <!-- For ContactMultiShareInteraction -->
+    <item type="id" name="dialog_share_multiple_contact_loader_id" />
+
     <!-- For PhoneNumberInteraction -->
     <item type="id" name="dialog_phone_number_call_disambiguation"/>
 
@@ -71,6 +74,9 @@
     <!-- Menu ID for Settings menu -->
     <item type="id" name="nav_settings" />
 
+    <!-- Menu ID for SIM contacts menu -->
+    <item type="id" name="nav_sim_contacts" />
+
     <!-- Menu ID for help & feedback  menu -->
     <item type="id" name="nav_help" />
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 56c4aaa..96a5731 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -232,6 +232,9 @@
     <!-- Positive button text of confirmation dialog contents after users selects to delete a Writable contact. [CHAR LIMIT=30] -->
     <string name="deleteConfirmation_positive_button">Delete</string>
 
+    <!-- Deleting dialog, shown after users selects to delete multiple contacts writable contacts. [CHAR LIMIT=NONE]  -->
+    <string name="delete_contacts_title">Deleting contacts</string>
+
     <!-- Message displayed in a toast when you try to view the details of a contact that
          for some reason doesn't exist anymore. [CHAR LIMIT=NONE]-->
     <string name="invalidContactMessage">The contact doesn\'t exist.</string>
@@ -366,6 +369,9 @@
     <!-- The menu item to share the currently viewed contact [CHAR LIMIT=30] -->
     <string name="menu_share">Share</string>
 
+    <!-- The menu item to select all contacts -->
+    <string name="menu_select_all">Select all</string>
+
     <!-- The menu item to add the the currently viewed contact to your contacts [CHAR LIMIT=30] -->
     <string name="menu_add_contact">Add to contacts</string>
 
@@ -449,6 +455,9 @@
     <!-- Menu item for the settings activity [CHAR LIMIT=64] -->
     <string name="menu_settings" msgid="377929915873428211">Settings</string>
 
+    <!-- Menu item for the sim contacts-->
+    <string name="menu_sim_contacts">SIM contacts</string>
+
     <!-- Menu item for invoking contextual Help & Feedback [CHAR LIMIT=64] -->
     <string name="menu_help">Help &amp; feedback</string>
 
@@ -1533,4 +1542,4 @@
     <!-- Text of Negative Button in dialog -->
     <string name="no_button">No</string>
 
-</resources>
\ No newline at end of file
+</resources>
diff --git a/src/com/android/contacts/ContactPhotoManager.java b/src/com/android/contacts/ContactPhotoManager.java
index e5f808d..4e1afaa 100644
--- a/src/com/android/contacts/ContactPhotoManager.java
+++ b/src/com/android/contacts/ContactPhotoManager.java
@@ -473,7 +473,6 @@
         loadThumbnail(view, photoId, darkTheme, isCircular, defaultImageRequest, DEFAULT_AVATAR);
     }
 
-
     /**
      * Load photo into the supplied image view. If the photo is already cached,
      * it is displayed immediately. Otherwise a request is sent to load the photo
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
old mode 100755
new mode 100644
index 9f25726..4372488
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -166,6 +166,9 @@
     public static final int RESULT_UNKNOWN = 0;
     public static final int RESULT_SUCCESS = 1;
     public static final int RESULT_FAILURE = 2;
+    public static final int CONTACTS_DELETE_STARTED = 0;
+    public static final int CONTACTS_DELETE_INCREMENT = 1;
+    public static final int CONTACTS_DELETE_COMPLETE = 2;
 
     private static final HashSet<String> ALLOWED_DATA_COLUMNS = Sets.newHashSet(
         Data.MIMETYPE,
@@ -561,7 +564,7 @@
                     // removed if all information was removed, we need to do a special query to
                     // get the lookup URI for the profile contact (if it still exists).
                     Cursor c = resolver.query(Profile.CONTENT_URI,
-                            new String[] {Contacts._ID, Contacts.LOOKUP_KEY},
+                            new String[]{Contacts._ID, Contacts.LOOKUP_KEY},
                             null, null, null);
                     if (c == null) {
                         continue;
@@ -577,7 +580,7 @@
                     }
                 } else {
                     final Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI,
-                                    rawContactId);
+                            rawContactId);
                     lookupUri = RawContacts.getContactLookupUri(resolver, rawContactUri);
                 }
                 if (lookupUri != null && Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1183,10 +1186,19 @@
      */
     public static Intent createDeleteMultipleContactsIntent(Context context,
             long[] contactIds, final String[] names) {
+        return createDeleteMultipleContactsIntent(context, contactIds, names, /* receiver = */null);
+    }
+
+    /**
+     * Creates an intent that can be sent to this service to delete multiple contacts.
+     */
+    public static Intent createDeleteMultipleContactsIntent(Context context,
+            long[] contactIds, final String[] names, ResultReceiver receiver) {
         Intent serviceIntent = new Intent(context, ContactSaveService.class);
         serviceIntent.setAction(ContactSaveService.ACTION_DELETE_MULTIPLE_CONTACTS);
         serviceIntent.putExtra(ContactSaveService.EXTRA_CONTACT_IDS, contactIds);
         serviceIntent.putExtra(ContactSaveService.EXTRA_DISPLAY_NAME_ARRAY, names);
+        serviceIntent.putExtra(ContactSaveService.EXTRA_RESULT_RECEIVER, receiver);
         return serviceIntent;
     }
 
@@ -1206,9 +1218,13 @@
             Log.e(TAG, "Invalid arguments for deleteMultipleContacts request");
             return;
         }
+        final ResultReceiver receiver = intent.getParcelableExtra(
+                ContactSaveService.EXTRA_RESULT_RECEIVER);
+        notifyActionProgress(CONTACTS_DELETE_STARTED, receiver);
         for (long contactId : contactIds) {
             final Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
             getContentResolver().delete(contactUri, null, null);
+            notifyActionProgress(CONTACTS_DELETE_INCREMENT, receiver);
         }
         final String[] names = intent.getStringArrayExtra(
                 ContactSaveService.EXTRA_DISPLAY_NAME_ARRAY);
@@ -1227,6 +1243,7 @@
                     R.string.contacts_deleted_many_named_toast, (Object[]) names);
         }
 
+        notifyActionProgress(CONTACTS_DELETE_COMPLETE, receiver);
         mMainHandler.post(new Runnable() {
             @Override
             public void run() {
@@ -1236,6 +1253,12 @@
         });
     }
 
+    private void notifyActionProgress(int state, ResultReceiver receiver){
+        if (receiver != null) {
+            receiver.send(state, new Bundle());
+        }
+    }
+
     /**
      * Creates an intent that can be sent to this service to split a contact into it's constituent
      * pieces. This will set the raw contact ids to {@link AggregationExceptions#TYPE_AUTOMATIC} so
diff --git a/src/com/android/contacts/ShortcutIntentBuilder.java b/src/com/android/contacts/ShortcutIntentBuilder.java
index 5ea6b7e..22d0f9c 100644
--- a/src/com/android/contacts/ShortcutIntentBuilder.java
+++ b/src/com/android/contacts/ShortcutIntentBuilder.java
@@ -157,7 +157,6 @@
         protected String mLookupKey;
         protected byte[] mBitmapData;
         protected long mPhotoId;
-
         public LoadingAsyncTask(Uri uri) {
             mUri = uri;
         }
@@ -193,6 +192,7 @@
     }
 
     private final class ContactLoadingAsyncTask extends LoadingAsyncTask {
+
         public ContactLoadingAsyncTask(Uri uri) {
             super(uri);
         }
diff --git a/src/com/android/contacts/SimImportFragment.java b/src/com/android/contacts/SimImportFragment.java
index 6042939..c7faabb 100644
--- a/src/com/android/contacts/SimImportFragment.java
+++ b/src/com/android/contacts/SimImportFragment.java
@@ -437,6 +437,8 @@
                 return contact.getPhone();
             } else if (contact.hasEmails()) {
                 return contact.getEmails()[0];
+            } else if(contact.hasAnrs()) {
+                return contact.getAnrs()[0];
             } else {
                 // This isn't really possible because we skip empty SIM contacts during loading
                 return "";
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 243ec00..84924ae 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -736,7 +736,7 @@
             fragment.updateStatus(mProviderStatus);
         }
         if (!transaction.isEmpty()) {
-            transaction.commit();
+            transaction.commitAllowingStateLoss();
             fragmentManager.executePendingTransactions();
         }
 
@@ -1195,6 +1195,16 @@
     }
 
     @Override
+    public void onLaunchSimContactsManagement() {
+        new Handler().postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                startActivity(ImplicitIntentsUtil.getIntentForSimContactsManagement());
+            }
+        }, DRAWER_CLOSE_DELAY);
+    }
+
+    @Override
     public void onGroupViewSelected(GroupListItem groupListItem) {
         onGroupMenuItemClicked(groupListItem.getGroupId());
     }
diff --git a/src/com/android/contacts/database/SimContactDaoImpl.java b/src/com/android/contacts/database/SimContactDaoImpl.java
index 5ba6bd5..36ad9f2 100644
--- a/src/com/android/contacts/database/SimContactDaoImpl.java
+++ b/src/com/android/contacts/database/SimContactDaoImpl.java
@@ -82,6 +82,7 @@
     public static String NAME = "name";
     public static String NUMBER = "number";
     public static String EMAILS = "emails";
+    public static String ANRS = "anrs";
 
     private final Context mContext;
     private final ContentResolver mResolver;
@@ -292,7 +293,7 @@
         final int colName = cursor.getColumnIndex(NAME);
         final int colNumber = cursor.getColumnIndex(NUMBER);
         final int colEmails = cursor.getColumnIndex(EMAILS);
-
+        final int colAnrs = cursor.getColumnIndex(ANRS);
         final ArrayList<SimContact> result = new ArrayList<>();
 
         while (cursor.moveToNext()) {
@@ -300,10 +301,14 @@
             final String name = cursor.getString(colName);
             final String number = cursor.getString(colNumber);
             final String emails = cursor.getString(colEmails);
-
-            final SimContact contact = new SimContact(id, name, number, parseEmails(emails));
+            String anrs = "";
+            if (colAnrs >=0 )
+                anrs = cursor.getString(colAnrs);
+            final SimContact contact = new SimContact(id, name, number, parseEmails(emails),
+                    parseAnrs(anrs));
             // Only include contact if it has some useful data
-            if (contact.hasName() || contact.hasPhone() || contact.hasEmails()) {
+            if (contact.hasName() || contact.hasPhone() || contact.hasEmails()
+                    || contact.hasAnrs()) {
                 result.add(contact);
             }
         }
@@ -396,6 +401,10 @@
         return !TextUtils.isEmpty(emails) ? emails.split(",") : null;
     }
 
+    private String[] parseAnrs(String anrs) {
+        return !TextUtils.isEmpty(anrs) ? anrs.split(":") : null;
+    }
+
     private boolean hasTelephony() {
         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
     }
diff --git a/src/com/android/contacts/drawer/DrawerAdapter.java b/src/com/android/contacts/drawer/DrawerAdapter.java
index 0c8423a..00ecce4 100644
--- a/src/com/android/contacts/drawer/DrawerAdapter.java
+++ b/src/com/android/contacts/drawer/DrawerAdapter.java
@@ -33,6 +33,7 @@
 import com.android.contacts.model.account.AccountDisplayInfo;
 import com.android.contacts.model.account.AccountDisplayInfoFactory;
 import com.android.contacts.util.SharedPreferenceUtil;
+import com.android.contacts.util.ImplicitIntentsUtil;
 import com.android.contactsbind.HelpUtils;
 import com.android.contactsbind.ObjectFactory;
 
@@ -115,6 +116,11 @@
         mMiscItems.add(new DividerItem());
         mMiscItems.add(new MiscItem(R.id.nav_settings, R.string.menu_settings,
                 R.drawable.quantum_ic_settings_vd_theme_24));
+        if (ImplicitIntentsUtil.checkIntentIfExists(mActivity,
+                ImplicitIntentsUtil.getIntentForSimContactsManagement())) {
+            mMiscItems.add(new MiscItem(R.id.nav_sim_contacts, R.string.menu_sim_contacts,
+                    R.drawable.quantum_ic_sim_card_vd_theme_24));
+        }
         if (HelpUtils.isHelpAndFeedbackAvailable()) {
             mMiscItems.add(new MiscItem(R.id.nav_help, R.string.menu_help,
                     R.drawable.quantum_ic_help_vd_theme_24));
@@ -272,7 +278,6 @@
         }
         final ContactListFilter account = item.account;
         final TextView textView = ((TextView) result.findViewById(R.id.title));
-        textView.setText(account.accountName);
         final boolean activated = account.equals(mSelectedAccount)
                 && mSelectedView == ContactsView.ACCOUNT_VIEW;
         textView.setTextAppearance(mActivity, activated
@@ -283,6 +288,11 @@
                 mAccountDisplayFactory.getAccountDisplayInfoFor(item.account);
         icon.setScaleType(ImageView.ScaleType.FIT_CENTER);
         icon.setImageDrawable(displayableAccount.getIcon());
+        if (account.accountName != null) {
+            textView.setText(account.accountName);
+        }else {
+            textView.setText(displayableAccount.getNameLabel());
+        }
 
         result.setTag(account);
         result.setActivated(activated);
diff --git a/src/com/android/contacts/drawer/DrawerFragment.java b/src/com/android/contacts/drawer/DrawerFragment.java
index 485513a..bcd1856 100644
--- a/src/com/android/contacts/drawer/DrawerFragment.java
+++ b/src/com/android/contacts/drawer/DrawerFragment.java
@@ -256,6 +256,8 @@
                 mListener.onCreateLabelButtonClicked();
             } else if (viewId == R.id.nav_settings) {
                 mListener.onOpenSettings();
+            } else if (viewId ==  R.id.nav_sim_contacts) {
+                mListener.onLaunchSimContactsManagement();
             } else if (viewId == R.id.nav_help) {
                 mListener.onLaunchHelpFeedback();
             } else {
@@ -313,6 +315,7 @@
         void onCreateLabelButtonClicked();
         void onOpenSettings();
         void onLaunchHelpFeedback();
+        void onLaunchSimContactsManagement();
     }
 
     private class WindowInsetsListener implements View.OnApplyWindowInsetsListener {
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
old mode 100755
new mode 100644
diff --git a/src/com/android/contacts/interactions/ContactMultiDeletionInteraction.java b/src/com/android/contacts/interactions/ContactMultiDeletionInteraction.java
index 47b76a5..605e0fb 100644
--- a/src/com/android/contacts/interactions/ContactMultiDeletionInteraction.java
+++ b/src/com/android/contacts/interactions/ContactMultiDeletionInteraction.java
@@ -18,9 +18,12 @@
 
 import android.app.Activity;
 import android.app.AlertDialog;
+import android.app.ProgressDialog;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.LoaderManager.LoaderCallbacks;
+import android.os.Handler;
+import android.support.v4.os.ResultReceiver;
 import android.content.Context;
 import android.content.CursorLoader;
 import android.content.DialogInterface;
@@ -82,6 +85,7 @@
     private TreeSet<Long> mContactIds;
     private Context mContext;
     private AlertDialog mDialog;
+    private ProgressDialog mProgressDialog;
     private MultiContactDeleteListener mListener;
 
     /**
@@ -165,19 +169,17 @@
     public Loader<Cursor> onCreateLoader(int id, Bundle args) {
         final TreeSet<Long> contactIds = (TreeSet<Long>) args.getSerializable(ARG_CONTACT_IDS);
         final Object[] parameterObject = contactIds.toArray();
-        final String[] parameters = new String[contactIds.size()];
 
-        final StringBuilder builder = new StringBuilder();
+        final StringBuilder builder = new StringBuilder(RawContacts.CONTACT_ID + " in (");
         for (int i = 0; i < contactIds.size(); i++) {
-            parameters[i] = String.valueOf(parameterObject[i]);
-            builder.append(RawContacts.CONTACT_ID + " =?");
-            if (i == contactIds.size() -1) {
-                break;
+            if (i > 0){
+                builder.append(",");
             }
-            builder.append(" OR ");
+            builder.append(String.valueOf(parameterObject[i]));
         }
+        builder.append(")");
         return new CursorLoader(mContext, RawContacts.CONTENT_URI, RAW_CONTACT_PROJECTION,
-                builder.toString(), parameters, null);
+                builder.toString(), null, null);
     }
 
     @Override
@@ -310,9 +312,44 @@
         }
     }
 
+    private void showProgressDialog(){
+        CharSequence title = getString(R.string.delete_contacts_title);
+
+        mProgressDialog = new ProgressDialog(mContext);
+        mProgressDialog.setTitle(title);
+        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+        mProgressDialog.setProgress(0);
+        mProgressDialog.setMax(mContactIds.size());
+        mProgressDialog.setCancelable(false);
+        mProgressDialog.show();
+    }
+
     protected void doDeleteContact(long[] contactIds, final String[] names) {
+        ResultReceiver receiver = new ResultReceiver(new Handler()){
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                super.onReceiveResult(resultCode, resultData);
+                switch (resultCode){
+                    case ContactSaveService.CONTACTS_DELETE_STARTED:
+                        showProgressDialog();
+                        break;
+                    case ContactSaveService.CONTACTS_DELETE_INCREMENT:
+                        if (mProgressDialog != null){
+                            mProgressDialog.incrementProgressBy(1);
+                        }
+                        break;
+                    case ContactSaveService.CONTACTS_DELETE_COMPLETE:
+                        if (mProgressDialog != null){
+                            mProgressDialog.dismiss();
+                            mProgressDialog = null;
+                        }
+                        break;
+                }
+            }
+        };
+
         mContext.startService(ContactSaveService.createDeleteMultipleContactsIntent(mContext,
-                contactIds, names));
+                contactIds, names, receiver));
         mListener.onDeletionFinished();
     }
 
diff --git a/src/com/android/contacts/interactions/ContactMultiShareInteraction.java b/src/com/android/contacts/interactions/ContactMultiShareInteraction.java
new file mode 100644
index 0000000..8d34b9e
--- /dev/null
+++ b/src/com/android/contacts/interactions/ContactMultiShareInteraction.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+     * Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above
+       copyright notice, this list of conditions and the following
+       disclaimer in the documentation and/or other materials provided
+       with the distribution.
+     * Neither the name of The Linux Foundation nor the names of its
+       contributors may be used to endorse or promote products derived
+       from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.interactions;
+
+import android.content.Intent;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.provider.ContactsContract;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.ContentUris;
+import android.content.AsyncTaskLoader;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Loader;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.contacts.ContactSaveService;
+import com.android.contacts.R;
+
+import java.util.List;
+import java.util.TreeSet;
+/**
+ * An interaction invoked to share multiple contacts.
+ */
+public class ContactMultiShareInteraction extends Fragment
+        implements LoaderCallbacks<String> {
+
+    private static final int ACTIVITY_REQUEST_CODE_SHARE = 0;
+
+    private static final String FRAGMENT_TAG = "shareMultipleContacts";
+    private static final String TAG = "ContactMultiShare";
+    private static final String KEY_ACTIVE = "active";
+    private static final String KEY_CONTACTS_IDS = "contactIds";
+    public static final String ARG_CONTACT_IDS = "contactIds";
+
+    private boolean mIsLoaderActive;
+    private TreeSet<Long> mContactIds;
+    private Context mContext;
+    private static ProgressDialog mProgressDialog;
+
+    /**
+     * Starts the interaction.
+     *
+     * @param hostFragment the fragment within which to start the interaction
+     * @param contactIds the IDs of contacts to be shared
+     * @return the newly created interaction
+     */
+    public static ContactMultiShareInteraction start(
+            Fragment hostFragment, TreeSet<Long> contactIds) {
+        if (contactIds == null) {
+            return null;
+        }
+
+        final FragmentManager fragmentManager = hostFragment.getFragmentManager();
+        ContactMultiShareInteraction fragment =
+                (ContactMultiShareInteraction) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
+        if (fragment == null) {
+            fragment = new ContactMultiShareInteraction();
+            fragment.setContactIds(contactIds);
+            fragmentManager.beginTransaction().add(fragment, FRAGMENT_TAG)
+                    .commitAllowingStateLoss();
+        } else {
+            fragment.setContactIds(contactIds);
+        }
+        return fragment;
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        mContext = activity;
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        if (mProgressDialog != null && mProgressDialog.isShowing()) {
+            mProgressDialog.setOnDismissListener(null);
+            mProgressDialog.dismiss();
+            mProgressDialog = null;
+        }
+    }
+
+    public void setContactIds(TreeSet<Long> contactIds) {
+        mContactIds = contactIds;
+        mIsLoaderActive = true;
+        if (isStarted()) {
+            Bundle args = new Bundle();
+            args.putSerializable(ARG_CONTACT_IDS, mContactIds);
+            getLoaderManager().restartLoader(R.id.dialog_share_multiple_contact_loader_id,
+                    args, this);
+            showDialog();
+        }
+    }
+
+    private boolean isStarted() {
+        return isAdded();
+    }
+
+    @Override
+    public void onStart() {
+        if (mIsLoaderActive) {
+            Bundle args = new Bundle();
+            args.putSerializable(ARG_CONTACT_IDS, mContactIds);
+            getLoaderManager().initLoader(
+                    R.id.dialog_share_multiple_contact_loader_id, args, this);
+            showDialog();
+        }
+        super.onStart();
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        if (mProgressDialog != null){
+            mProgressDialog.dismiss();
+        }
+    }
+
+    @Override
+    public Loader<String> onCreateLoader(int id, Bundle args) {
+        final TreeSet<Long> contactIds = (TreeSet<Long>) args.getSerializable(ARG_CONTACT_IDS);
+        return new ShareContactsLoader(mContext, contactIds);
+    }
+
+    @Override
+    public void onLoadFinished(Loader<String> loader, String uriList) {
+        if (mProgressDialog != null){
+            mProgressDialog.dismiss();
+            mProgressDialog = null;
+        }
+
+        if (!mIsLoaderActive) {
+            return;
+        }
+
+        if (TextUtils.isEmpty(uriList)) {
+            Log.e(TAG, "Failed to load contacts");
+            return;
+        }
+
+        final Uri uri = Uri.withAppendedPath(
+                ContactsContract.Contacts.CONTENT_MULTI_VCARD_URI,
+                Uri.encode(uriList));
+        final Intent intent = new Intent(Intent.ACTION_SEND);
+        intent.setType(ContactsContract.Contacts.CONTENT_VCARD_TYPE);
+        intent.putExtra(Intent.EXTRA_STREAM, uri);
+        try {
+            startActivityForResult(Intent.createChooser(intent, mContext.getResources().getQuantityString(
+                    R.plurals.title_share_via,/* quantity */ mContactIds.size()))
+                    , ACTIVITY_REQUEST_CODE_SHARE);
+        } catch (final ActivityNotFoundException ex) {
+            Toast.makeText(getContext(), R.string.share_error, Toast.LENGTH_SHORT).show();
+        }
+
+        // We don't want onLoadFinished() calls any more, which may come when the database is
+        // updating.
+        getLoaderManager().destroyLoader(R.id.dialog_share_multiple_contact_loader_id);
+    }
+
+    @Override
+    public void onLoaderReset(Loader<String> loader) {
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(KEY_ACTIVE, mIsLoaderActive);
+        outState.putSerializable(KEY_CONTACTS_IDS, mContactIds);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        if (savedInstanceState != null) {
+            mIsLoaderActive = savedInstanceState.getBoolean(KEY_ACTIVE);
+            mContactIds = (TreeSet<Long>) savedInstanceState.getSerializable(KEY_CONTACTS_IDS);
+        }
+    }
+
+    private void cancelLoad(){
+        Loader loader = getLoaderManager().getLoader(R.id.dialog_share_multiple_contact_loader_id);
+        if (loader != null){
+            loader.cancelLoad();
+        }
+    }
+
+    private void showDialog(){
+        CharSequence title = getString(R.string.exporting_contact_list_title);
+
+        mProgressDialog = new ProgressDialog(mContext);
+        mProgressDialog.setTitle(title);
+        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+        mProgressDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
+                getString(android.R.string.cancel), (OnClickListener)null);
+        mProgressDialog.setProgress(0);
+        mProgressDialog.setMax(mContactIds.size());
+        mProgressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+            @Override
+            public void onDismiss(DialogInterface dialog) {
+                cancelLoad();
+                mIsLoaderActive = false;
+                mProgressDialog = null;
+            }
+        });
+
+        mProgressDialog.show();
+    }
+
+    private static class ShareContactsLoader extends AsyncTaskLoader<String>{
+        private TreeSet<Long> mSelectedContactIds;
+
+        public ShareContactsLoader(Context context, TreeSet<Long> contactIds){
+            super(context);
+            mSelectedContactIds = contactIds;
+        }
+
+        @Override
+        protected void onStartLoading() {
+            forceLoad();
+        }
+
+        @Override
+        public String loadInBackground() {
+            final StringBuilder uriListBuilder = new StringBuilder();
+            for (Long contactId : mSelectedContactIds) {
+                if (!isLoadInBackgroundCanceled()) {
+                    final Uri contactUri = ContentUris.withAppendedId(
+                            ContactsContract.Contacts.CONTENT_URI, contactId);
+                    final Uri lookupUri = ContactsContract.Contacts.getLookupUri(
+                            getContext().getContentResolver(), contactUri);
+                    if (lookupUri == null) {
+                        continue;
+                    }
+                    final List<String> pathSegments = lookupUri.getPathSegments();
+                    if (pathSegments.size() < 2) {
+                        continue;
+                    }
+                    final String lookupKey = pathSegments.get(pathSegments.size() - 2);
+                    if (uriListBuilder.length() > 0) {
+                        uriListBuilder.append(':');
+                    }
+                    uriListBuilder.append(Uri.encode(lookupKey));
+                    if (mProgressDialog != null) {
+                        mProgressDialog.incrementProgressBy(1);
+                    }
+                }
+
+            }
+            return uriListBuilder.toString();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/interactions/ExportDialogFragment.java b/src/com/android/contacts/interactions/ExportDialogFragment.java
index c7ce072..ac391f9 100644
--- a/src/com/android/contacts/interactions/ExportDialogFragment.java
+++ b/src/com/android/contacts/interactions/ExportDialogFragment.java
@@ -41,6 +41,7 @@
 import com.android.contacts.R;
 import com.android.contacts.util.ImplicitIntentsUtil;
 import com.android.contacts.vcard.ExportVCardActivity;
+import com.android.contacts.model.SimCard;
 import com.android.contacts.vcard.ShareVCardActivity;
 import com.android.contacts.vcard.VCardCommonArguments;
 
@@ -61,7 +62,6 @@
     };
 
     private SubscriptionManager mSubscriptionManager;
-
     /** Preferred way to show this dialog */
     public static void show(FragmentManager fragmentManager, Class callingActivity,
             int exportMode) {
@@ -91,7 +91,6 @@
                 .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(),
                 R.layout.select_dialog_item) {
@@ -217,18 +216,18 @@
     private static class AdapterEntry {
         public final CharSequence mLabel;
         public final int mChoiceResourceId;
-        public final int mSubscriptionId;
+        public final SimCard mSim;
 
-        public AdapterEntry(CharSequence label, int resId, int subId) {
+        public AdapterEntry(CharSequence label, int resId, SimCard sim) {
             mLabel = label;
             mChoiceResourceId = resId;
-            mSubscriptionId = subId;
+            mSim = sim;
         }
 
         public AdapterEntry(String label, int resId) {
             // Store a nonsense value for mSubscriptionId. If this constructor is used,
             // the mSubscriptionId value should not be read later.
-            this(label, resId, /* subId = */ -1);
+            this(label, resId, /* subId = */ null);
         }
     }
 }
diff --git a/src/com/android/contacts/interactions/ImportDialogFragment.java b/src/com/android/contacts/interactions/ImportDialogFragment.java
index 41b1c71..6e05f08 100644
--- a/src/com/android/contacts/interactions/ImportDialogFragment.java
+++ b/src/com/android/contacts/interactions/ImportDialogFragment.java
@@ -35,6 +35,7 @@
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import com.android.contacts.R;
 import com.android.contacts.activities.SimImportActivity;
@@ -48,6 +49,7 @@
 import com.android.contacts.model.account.AccountInfo;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.util.AccountSelectionUtil;
+import com.android.contacts.util.ImplicitIntentsUtil;
 import com.google.common.util.concurrent.Futures;
 
 import java.util.List;
@@ -237,16 +239,20 @@
             adapter.add(new AdapterEntry(getString(R.string.import_from_vcf_file),
                     R.string.import_from_vcf_file));
         }
-        final List<SimCard> sims = mSimDao.getSimCards();
+        if (!ImplicitIntentsUtil.checkIntentIfExists(getActivity(),
+                ImplicitIntentsUtil.getIntentForSimContactsManagement())) {
+            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, sims.get(0)));
-            return;
-        }
-        for (int i = 0; i < sims.size(); i++) {
-            final SimCard sim = sims.get(i);
-            adapter.add(new AdapterEntry(getSimDescription(sim, i), R.string.import_from_sim, sim));
+            if (sims.size() == 1) {
+                adapter.add(new AdapterEntry(getString(R.string.import_from_sim),
+                        R.string.import_from_sim, sims.get(0)));
+                return;
+            }
+            for (int i = 0; i < sims.size(); i++) {
+                final SimCard sim = sims.get(i);
+                adapter.add(new AdapterEntry(getSimDescription(sim, i),
+                        R.string.import_from_sim, sim));
+            }
         }
     }
 
@@ -259,6 +265,11 @@
      * Handle "import from SD".
      */
     private void handleImportRequest(int resId, int subscriptionId) {
+        //if the accounts is not initial complete, give a toast here.
+        if (mAccountsFuture == null) {
+            Toast.makeText(getActivity(), R.string.vcard_import_failed, Toast.LENGTH_SHORT).show();
+            return;
+        }
         // Get the accounts. Because this only happens after a user action this should pretty
         // much never block since it will usually be at least several seconds before the user
         // interacts with the view
diff --git a/src/com/android/contacts/lettertiles/LetterTileDrawable.java b/src/com/android/contacts/lettertiles/LetterTileDrawable.java
index b80fd4f..55df967 100644
--- a/src/com/android/contacts/lettertiles/LetterTileDrawable.java
+++ b/src/com/android/contacts/lettertiles/LetterTileDrawable.java
@@ -16,6 +16,8 @@
 
 package com.android.contacts.lettertiles;
 
+import android.accounts.Account;
+import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
diff --git a/src/com/android/contacts/list/ContactEntryListAdapter.java b/src/com/android/contacts/list/ContactEntryListAdapter.java
index b508dda..5d46fa4 100644
--- a/src/com/android/contacts/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/list/ContactEntryListAdapter.java
@@ -710,7 +710,6 @@
         if (!cursor.isNull(photoIdColumn)) {
             photoId = cursor.getLong(photoIdColumn);
         }
-
         QuickContactBadge quickContact = view.getQuickContact();
         quickContact.assignContactUri(
                 getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn));
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index cb63f53..95ce6fe 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -50,7 +50,7 @@
             Contacts.PHOTO_THUMBNAIL_URI,           // 5
             Contacts.LOOKUP_KEY,                    // 6
             Contacts.PHONETIC_NAME,                 // 7
-            Contacts.STARRED,                       // 9
+            Contacts.STARRED,                       // 8
         };
 
         private static final String[] CONTACT_PROJECTION_ALTERNATIVE = new String[] {
@@ -252,7 +252,6 @@
         if (!cursor.isNull(ContactQuery.CONTACT_PHOTO_ID)) {
             photoId = cursor.getLong(ContactQuery.CONTACT_PHOTO_ID);
         }
-
         if (photoId != 0) {
             getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false,
                     getCircularPhotos(), null);
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index 9851d2b..b4f748c 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -62,6 +62,7 @@
 import com.android.contacts.activities.ActionBarAdapter;
 import com.android.contacts.activities.PeopleActivity;
 import com.android.contacts.compat.CompatUtils;
+import com.android.contacts.interactions.ContactMultiShareInteraction;
 import com.android.contacts.interactions.ContactDeletionInteraction;
 import com.android.contacts.interactions.ContactMultiDeletionInteraction;
 import com.android.contacts.interactions.ContactMultiDeletionInteraction.MultiContactDeleteListener;
@@ -1015,8 +1016,10 @@
                 && getSelectedContactIds().size() != 0;
         makeMenuItemVisible(menu, R.id.menu_share, showSelectedContactOptions);
         makeMenuItemVisible(menu, R.id.menu_delete, showSelectedContactOptions);
+        makeMenuItemVisible(menu, R.id.menu_select_all, !isSearchOrSelectionMode);
         final boolean showLinkContactsOptions = mActionBarAdapter.isSelectionMode()
-                && getSelectedContactIds().size() > 1;
+                && getSelectedContactIds().size() > 1
+                && getSelectedContactIds().size() <= 9;
         makeMenuItemVisible(menu, R.id.menu_join, showLinkContactsOptions);
 
         // Debug options need to be visible even in search mode.
@@ -1085,6 +1088,10 @@
             intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
             ImplicitIntentsUtil.startActivityOutsideApp(getContext(), intent);
             return true;
+        } else if (id == R.id.menu_select_all){
+            mActionBarAdapter.setSelectionMode(true);
+            mActivity.invalidateOptionsMenu();
+            setSelectedAll();
         }
         return super.onOptionsItemSelected(item);
     }
@@ -1094,41 +1101,9 @@
      * handling large numbers of contacts. I don't expect this to be a problem.
      */
     private void shareSelectedContacts() {
-        final StringBuilder uriListBuilder = new StringBuilder();
-        for (Long contactId : getSelectedContactIds()) {
-            final Uri contactUri = ContentUris.withAppendedId(
-                    ContactsContract.Contacts.CONTENT_URI, contactId);
-            final Uri lookupUri = ContactsContract.Contacts.getLookupUri(
-                    getContext().getContentResolver(), contactUri);
-            if (lookupUri == null) {
-                continue;
-            }
-            final List<String> pathSegments = lookupUri.getPathSegments();
-            if (pathSegments.size() < 2) {
-                continue;
-            }
-            final String lookupKey = pathSegments.get(pathSegments.size() - 2);
-            if (uriListBuilder.length() > 0) {
-                uriListBuilder.append(':');
-            }
-            uriListBuilder.append(Uri.encode(lookupKey));
-        }
-        if (uriListBuilder.length() == 0) {
-            return;
-        }
-        final Uri uri = Uri.withAppendedPath(
-                ContactsContract.Contacts.CONTENT_MULTI_VCARD_URI,
-                Uri.encode(uriListBuilder.toString()));
-        final Intent intent = new Intent(Intent.ACTION_SEND);
-        intent.setType(ContactsContract.Contacts.CONTENT_VCARD_TYPE);
-        intent.putExtra(Intent.EXTRA_STREAM, uri);
-        try {
-            startActivityForResult(Intent.createChooser(intent, getResources().getQuantityString(
-                    R.plurals.title_share_via,/* quantity */ getSelectedContactIds().size()))
-                    , ACTIVITY_REQUEST_CODE_SHARE);
-        } catch (final ActivityNotFoundException ex) {
-            Toast.makeText(getContext(), R.string.share_error, Toast.LENGTH_SHORT).show();
-        }
+        final ContactMultiShareInteraction multiShareInteraction =
+                ContactMultiShareInteraction.start(this, getSelectedContactIds());
+        mActionBarAdapter.setSelectionMode(false);
     }
 
     private void joinSelectedContacts() {
diff --git a/src/com/android/contacts/list/DefaultContactListAdapter.java b/src/com/android/contacts/list/DefaultContactListAdapter.java
index 20c1a8f..40a8e76 100644
--- a/src/com/android/contacts/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/list/DefaultContactListAdapter.java
@@ -89,12 +89,7 @@
         } else {
             final ContactListFilter filter = getFilter();
             configureUri(loader, directoryId, filter);
-            if (filter != null
-                    && filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
-                loader.setProjection(getDataProjectionForContacts(false));
-            } else {
-                loader.setProjection(getProjection(false));
-            }
+            loader.setProjection(getProjection(false));
             configureSelection(loader, directoryId, filter);
         }
 
@@ -140,8 +135,6 @@
                 } else {
                     uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, getSelectedContactId());
                 }
-            } else if (filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
-                uri = Data.CONTENT_URI;
             }
         }
 
diff --git a/src/com/android/contacts/list/JoinContactListAdapter.java b/src/com/android/contacts/list/JoinContactListAdapter.java
index 82da6f7..1903a73 100644
--- a/src/com/android/contacts/list/JoinContactListAdapter.java
+++ b/src/com/android/contacts/list/JoinContactListAdapter.java
@@ -97,7 +97,6 @@
                 .build();
         }
         loader.setUri(allContactsUri);
-        loader.setSelection(Contacts._ID + "!=?");
         loader.setSelectionArgs(new String[]{ String.valueOf(mTargetContactId) });
         if (getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY) {
             loader.setSortOrder(Contacts.SORT_KEY_PRIMARY);
diff --git a/src/com/android/contacts/list/MultiSelectContactsListFragment.java b/src/com/android/contacts/list/MultiSelectContactsListFragment.java
index 5e7f9e8..1d6b900 100644
--- a/src/com/android/contacts/list/MultiSelectContactsListFragment.java
+++ b/src/com/android/contacts/list/MultiSelectContactsListFragment.java
@@ -189,6 +189,23 @@
         }
     }
 
+    /**
+     * @param selected all contacts
+     */
+    public void setSelectedAll() {
+        TreeSet<Long> allContactIds = new TreeSet<Long>();
+        for (int i = 0; i < getAdapter().getCount(); i++) {
+            final long contactId = getContactId(i);
+            if (contactId < 0) {
+                return;
+            }
+            allContactIds.add(contactId);
+        }
+        if (getAdapter().isDisplayingCheckBoxes()) {
+            getAdapter().setSelectedContactIds(allContactIds);
+        }
+    }
+
     private long getContactId(int position) {
         final int contactIdColumnIndex = getAdapter().getContactColumnIdIndex();
 
diff --git a/src/com/android/contacts/list/MultiSelectEntryContactListAdapter.java b/src/com/android/contacts/list/MultiSelectEntryContactListAdapter.java
index a0b4f3c..32cfff1 100644
--- a/src/com/android/contacts/list/MultiSelectEntryContactListAdapter.java
+++ b/src/com/android/contacts/list/MultiSelectEntryContactListAdapter.java
@@ -165,7 +165,7 @@
       * @param displayNameColumn Index of the display name column
       */
     protected void bindPhoto(final ContactListItemView view, final Cursor cursor,
-           final int photoIdColumn, final int lookUpKeyColumn, final int displayNameColumn) {
+            final int photoIdColumn, final int lookUpKeyColumn, final int displayNameColumn) {
         final long photoId = cursor.isNull(photoIdColumn)
             ? 0 : cursor.getLong(photoIdColumn);
         final ContactPhotoManager.DefaultImageRequest imageRequest = photoId == 0
diff --git a/src/com/android/contacts/list/PhoneNumberListAdapter.java b/src/com/android/contacts/list/PhoneNumberListAdapter.java
index d459d47..4d17aeb 100644
--- a/src/com/android/contacts/list/PhoneNumberListAdapter.java
+++ b/src/com/android/contacts/list/PhoneNumberListAdapter.java
@@ -540,7 +540,6 @@
         if (!cursor.isNull(PhoneQuery.PHOTO_ID)) {
             photoId = cursor.getLong(PhoneQuery.PHOTO_ID);
         }
-
         if (photoId != 0) {
             getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false,
                     getCircularPhotos(), null);
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index f67f074..03f1b76 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -99,7 +99,7 @@
             public boolean apply(@Nullable AccountInfo input) {
                 return input != null && input.getType().isGroupMembershipEditable();
             }
-        };
+        },
     }
 
     /**
diff --git a/src/com/android/contacts/model/RawContactDelta.java b/src/com/android/contacts/model/RawContactDelta.java
index 6ee31ba..0666517 100644
--- a/src/com/android/contacts/model/RawContactDelta.java
+++ b/src/com/android/contacts/model/RawContactDelta.java
@@ -27,12 +27,12 @@
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.Profile;
 import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.contacts.compat.CompatUtils;
 import com.android.contacts.model.account.AccountType;
 import com.android.contacts.model.account.AccountWithDataSet;
-
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
diff --git a/src/com/android/contacts/model/RawContactModifier.java b/src/com/android/contacts/model/RawContactModifier.java
old mode 100644
new mode 100755
index 789bd10..171a810
--- a/src/com/android/contacts/model/RawContactModifier.java
+++ b/src/com/android/contacts/model/RawContactModifier.java
@@ -1038,10 +1038,30 @@
             return;
         }
 
+        boolean supportPrefix = false;
+        boolean supportFamilyName = false;
+        boolean supportMiddleName = false;
+        boolean supportGivenName = false;
+        boolean supportSuffix = false;
         boolean supportPhoneticFamilyName = false;
         boolean supportPhoneticMiddleName = false;
         boolean supportPhoneticGivenName = false;
         for (EditField editField : newDataKind.fieldList) {
+            if (StructuredName.PREFIX.equals(editField.column)) {
+                supportPrefix = true;
+            }
+            if (StructuredName.FAMILY_NAME.equals(editField.column)) {
+                supportFamilyName = true;
+            }
+            if (StructuredName.MIDDLE_NAME.equals(editField.column)) {
+                supportMiddleName = true;
+            }
+            if (StructuredName.GIVEN_NAME.equals(editField.column)) {
+                supportGivenName = true;
+            }
+            if (StructuredName.SUFFIX.equals(editField.column)) {
+                supportSuffix = true;
+            }
             if (StructuredName.PHONETIC_FAMILY_NAME.equals(editField.column)) {
                 supportPhoneticFamilyName = true;
             }
@@ -1053,6 +1073,21 @@
             }
         }
 
+        if (!supportPrefix) {
+            values.remove(StructuredName.PREFIX);
+        }
+        if (!supportFamilyName) {
+            values.remove(StructuredName.FAMILY_NAME);
+        }
+        if (!supportMiddleName) {
+            values.remove(StructuredName.MIDDLE_NAME);
+        }
+        if (!supportGivenName) {
+            values.remove(StructuredName.GIVEN_NAME);
+        }
+        if (!supportSuffix) {
+            values.remove(StructuredName.SUFFIX);
+        }
         if (!supportPhoneticFamilyName) {
             values.remove(StructuredName.PHONETIC_FAMILY_NAME);
         }
diff --git a/src/com/android/contacts/model/SimContact.java b/src/com/android/contacts/model/SimContact.java
index 7babe27..d6cc13e 100644
--- a/src/com/android/contacts/model/SimContact.java
+++ b/src/com/android/contacts/model/SimContact.java
@@ -47,20 +47,26 @@
     private final String mName;
     private final String mPhone;
     private final String[] mEmails;
+    private final String[] mAnrs;
 
     public SimContact(long id, String name, String phone) {
         this(id, name, phone, null);
     }
 
     public SimContact(long id, String name, String phone, String[] emails) {
+        this(id, name, phone, emails, null);
+    }
+
+    public SimContact(long id, String name, String phone, String[] emails, String[] anrs) {
         mId = id;
         mName = name;
         mPhone = phone == null ? "" : phone.trim();
         mEmails = emails;
+        mAnrs = anrs;
     }
 
     public SimContact(SimContact other) {
-        this(other.mId, other.mName, other.mPhone, other.mEmails);
+        this(other.mId, other.mName, other.mPhone, other.mEmails, other.mAnrs);
     }
 
     public long getId() {
@@ -79,10 +85,14 @@
         return mEmails;
     }
 
+    public String[] getAnrs() {
+        return mAnrs;
+    }
+
     public void appendCreateContactOperations(List<ContentProviderOperation> ops,
             AccountWithDataSet targetAccount) {
         // There is nothing to save so skip it.
-        if (!hasName() && !hasPhone() && !hasEmails()) return;
+        if (!hasName() && !hasPhone() && !hasEmails() && !hasAnrs()) return;
 
         final int rawContactOpIndex = ops.size();
         ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
@@ -105,6 +115,12 @@
                         Email.ADDRESS, email));
             }
         }
+        if (mAnrs != null) {
+            for (String anr : mAnrs) {
+                ops.add(createInsertOp(rawContactOpIndex, Phone.CONTENT_ITEM_TYPE,
+                        Phone.NUMBER, anr));
+            }
+        }
     }
 
     private ContentProviderOperation createInsertOp(int rawContactOpIndex, String mimeType,
@@ -134,6 +150,10 @@
         return mEmails != null && mEmails.length > 0;
     }
 
+    public boolean hasAnrs() {
+        return mAnrs != null && mAnrs.length > 0;
+    }
+
     /**
      * Generate a "fake" lookup key. This is needed because
      * {@link ContactPhotoManager} will only generate a letter avatar
@@ -167,7 +187,8 @@
         final SimContact that = (SimContact) o;
 
         return mId == that.mId && Objects.equals(mName, that.mName) &&
-                Objects.equals(mPhone, that.mPhone) && Arrays.equals(mEmails, that.mEmails);
+                Objects.equals(mPhone, that.mPhone) && Arrays.equals(mEmails, that.mEmails)
+                && Arrays.equals(mAnrs, that.mAnrs);
     }
 
     @Override
@@ -176,6 +197,7 @@
         result = 31 * result + (mName != null ? mName.hashCode() : 0);
         result = 31 * result + (mPhone != null ? mPhone.hashCode() : 0);
         result = 31 * result + Arrays.hashCode(mEmails);
+        result = 31 * result + Arrays.hashCode(mAnrs);
         return result;
     }
 
@@ -190,6 +212,7 @@
         dest.writeString(mName);
         dest.writeString(mPhone);
         dest.writeStringArray(mEmails);
+        dest.writeStringArray(mAnrs);
     }
 
     public static final Creator<SimContact> CREATOR = new Creator<SimContact>() {
@@ -199,7 +222,8 @@
             final String name = source.readString();
             final String phone = source.readString();
             final String[] emails = source.createStringArray();
-            return new SimContact(id, name, phone, emails);
+            final String[] anrs = source.createStringArray();
+            return new SimContact(id, name, phone, emails, anrs);
         }
 
         @Override
diff --git a/src/com/android/contacts/model/account/SimAccountType.java b/src/com/android/contacts/model/account/SimAccountType.java
index 360e944..b0efef4 100644
--- a/src/com/android/contacts/model/account/SimAccountType.java
+++ b/src/com/android/contacts/model/account/SimAccountType.java
@@ -17,6 +17,8 @@
 
 import android.accounts.AuthenticatorDescription;
 import android.content.Context;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.Nickname;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 
@@ -32,19 +34,22 @@
  */
 public class SimAccountType extends BaseAccountType {
 
+    public static final String ACCOUNT_TYPE = "com.android.sim";
+
     public SimAccountType(Context context) {
-        this.titleRes = R.string.account_sim;
-        this.iconRes = R.drawable.quantum_ic_sim_card_vd_theme_24;
+        this(context, null);
+    }
+
+    public SimAccountType(Context context, String resPackageName) {
+        this.accountType = ACCOUNT_TYPE;
+        this.resourcePackageName = resPackageName;
+        this.syncAdapterPackageName = resPackageName;
 
         try {
             addDataKindStructuredName(context);
             addDataKindName(context);
-            final DataKind phoneKind = addDataKindPhone(context);
-            phoneKind.typeOverallMax = 1;
-            // SIM card contacts don't necessarily support separate types (based on data exposed
-            // in Samsung and LG Contacts Apps.
-            phoneKind.typeList = Collections.emptyList();
-
+            addDataKindPhone(context);
+            addDataKindEmail(context);
             mIsInitialized = true;
         } catch (DefinitionException e) {
             // Just fail fast. Because we're explicitly adding the fields in this class this
@@ -66,6 +71,7 @@
     @Override
     public void initializeFieldsFromAuthenticator(AuthenticatorDescription authenticator) {
         // Do nothing. We want to use our local icon and title
+        super.initializeFieldsFromAuthenticator(authenticator);
     }
 
     @Override
@@ -75,14 +81,9 @@
         kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
         kind.actionBody = new SimpleInflater(Nickname.NAME);
         kind.typeOverallMax = 1;
-
-
         kind.fieldList = Lists.newArrayList();
-        kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
+        kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.nameLabelsGroup,
                 FLAGS_PERSON_NAME));
-        kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
-                FLAGS_PERSON_NAME));
-
         return kind;
     }
 
@@ -98,18 +99,33 @@
                 context.getResources().getBoolean(R.bool.config_editor_field_order_primary);
 
         kind.fieldList = Lists.newArrayList();
-        if (!displayOrderPrimary) {
-            kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
-                    FLAGS_PERSON_NAME));
-            kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
-                    FLAGS_PERSON_NAME));
-        } else {
-            kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
-                    FLAGS_PERSON_NAME));
-            kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
-                    FLAGS_PERSON_NAME));
-        }
+        kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME,
+                R.string.nameLabelsGroup, FLAGS_PERSON_NAME));
+        return kind;
+    }
 
+    @Override
+    protected DataKind addDataKindPhone(Context context) throws DefinitionException {
+        final DataKind kind = super.addDataKindPhone(context);
+        kind.typeOverallMax = 2;
+        kind.typeColumn = Phone.TYPE;
+        kind.typeList = Lists.newArrayList();
+        kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
+        kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));// This is used to save ANR records
+        kind.fieldList = Lists.newArrayList();
+        kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
+
+        return kind;
+    }
+
+    @Override
+    protected DataKind addDataKindEmail(Context context) throws DefinitionException {
+        final DataKind kind = super.addDataKindEmail(context);
+
+        kind.typeOverallMax = 1;
+        kind.typeList =  Collections.emptyList();
+        kind.fieldList = Lists.newArrayList();
+        kind.fieldList.add(new EditField(Email.ADDRESS, R.string.emailLabelsGroup, FLAGS_EMAIL));
         return kind;
     }
 
@@ -118,7 +134,7 @@
         // Use the "SIM" type label for the name as well because on OEM phones the "name" is
         // not always user-friendly
         return new AccountInfo(
-                new AccountDisplayInfo(account, getDisplayLabel(context), getDisplayLabel(context),
+                new AccountDisplayInfo(account, account.name, getDisplayLabel(context),
                         getDisplayIcon(context), true), this);
     }
 }
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index fcbfba9..a7db5ac 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -2311,7 +2311,6 @@
             ContactDisplayUtils.configureStarredMenuItem(starredMenuItem,
                     mContactData.isDirectoryEntry(), mContactData.isUserProfile(),
                     mContactData.getStarred());
-
             // Configure edit MenuItem
             final MenuItem editMenuItem = menu.findItem(R.id.menu_edit);
             editMenuItem.setVisible(true);
diff --git a/src/com/android/contacts/util/ImageViewDrawableSetter.java b/src/com/android/contacts/util/ImageViewDrawableSetter.java
index b90cf1f..a197a32 100644
--- a/src/com/android/contacts/util/ImageViewDrawableSetter.java
+++ b/src/com/android/contacts/util/ImageViewDrawableSetter.java
@@ -30,7 +30,6 @@
 import com.android.contacts.ContactPhotoManager.DefaultImageRequest;
 import com.android.contacts.lettertiles.LetterTileDrawable;
 import com.android.contacts.model.Contact;
-
 import java.util.Arrays;
 
 /**
diff --git a/src/com/android/contacts/util/ImplicitIntentsUtil.java b/src/com/android/contacts/util/ImplicitIntentsUtil.java
index 0d00519..a7b503c 100644
--- a/src/com/android/contacts/util/ImplicitIntentsUtil.java
+++ b/src/com/android/contacts/util/ImplicitIntentsUtil.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.ComponentName;
 import android.net.Uri;
 import android.os.Build;
 import android.provider.ContactsContract;
@@ -175,6 +176,18 @@
         return intent;
     }
 
+    /**
+     * Returns an Intent to manage SIM contacts.
+     */
+    public static Intent getIntentForSimContactsManagement() {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        ComponentName cn = new ComponentName("com.qualcomm.qti.simcontacts",
+                "com.qualcomm.qti.simcontacts.activities.SimCardsSelectionActivity");
+        intent.setComponent(cn);
+        return intent;
+    }
+
     public static Intent getIntentForQuickContactLauncherShortcut(Context context, Uri contactUri) {
         final Intent intent = composeQuickContactIntent(context, contactUri,
                 QuickContact.MODE_LARGE, ScreenType.UNKNOWN);
@@ -197,6 +210,12 @@
         return intent;
     }
 
+    public static boolean checkIntentIfExists(Context context, Intent intent){
+        List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(intent,
+                PackageManager.GET_ACTIVITIES);
+        return list != null && list.size() > 0;
+    }
+
     /**
      * Returns a copy of {@param intent} with a class name set, if a class inside this app
      * has a corresponding intent filter.