Merge tag 'android-5.0.2_r1' into merge_branch

Android 5.0.2 release 1

* tag 'android-5.0.2_r1':
  Switch from CALL -> CALL_PRIVILEGED

Change-Id: I422422300dce511b261cfefdd3549d9e9bde5b94
diff --git a/Android.mk b/Android.mk
index 626a737..3687e47 100644
--- a/Android.mk
+++ b/Android.mk
@@ -28,6 +28,8 @@
     --auto-add-overlay \
     --extra-packages com.android.phone.common
 
+LOCAL_JAVA_LIBRARIES := telephony-common
+
 LOCAL_STATIC_JAVA_LIBRARIES := \
     com.android.vcard \
     guava \
diff --git a/TestCommon/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java b/TestCommon/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java
index ab2d395..d3dd722 100644
--- a/TestCommon/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java
+++ b/TestCommon/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java
@@ -66,6 +66,11 @@
     }
 
     @Override
+    public List<AccountWithDataSet> getAccounts(boolean writableOnly, int flag) {
+        return Arrays.asList(mAccounts);
+    }
+
+    @Override
     public List<AccountWithDataSet> getGroupWritableAccounts() {
         return Arrays.asList(mAccounts);
     }
diff --git a/TestCommon/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java b/TestCommon/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java
index db8f06f..3b143de 100644
--- a/TestCommon/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java
+++ b/TestCommon/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java
@@ -16,6 +16,7 @@
 
 package com.android.contacts.common.test.mocks;
 
+import android.accounts.Account;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.view.View;
@@ -29,16 +30,19 @@
  */
 public class MockContactPhotoManager extends ContactPhotoManager {
     @Override
-    public void loadThumbnail(ImageView view, long photoId, boolean darkTheme, boolean isCircular,
-            DefaultImageRequest defaultImageRequest, DefaultImageProvider defaultProvider) {
-        defaultProvider.applyDefaultImage(view, -1, darkTheme, null);
+    public void loadThumbnail(ImageView view, long photoId, Account account,
+            boolean darkTheme, boolean isCircular,
+            DefaultImageRequest defaultImageRequest,
+            DefaultImageProvider defaultProvider) {
+        defaultProvider.applyDefaultImage(view, account, -1, darkTheme, null);
     }
 
     @Override
-    public void loadPhoto(ImageView view, Uri photoUri, int requestedExtent, boolean darkTheme,
-            boolean isCircular, DefaultImageRequest defaultImageRequest,
+    public void loadPhoto(ImageView view, Uri photoUri, Account account,
+            int requestedExtent, boolean darkTheme, boolean isCircular,
+            DefaultImageRequest defaultImageRequest,
             DefaultImageProvider defaultProvider) {
-        defaultProvider.applyDefaultImage(view, requestedExtent, darkTheme, null);
+        defaultProvider.applyDefaultImage(view, account, requestedExtent, darkTheme, null);
     }
 
     @Override
@@ -69,4 +73,8 @@
     @Override
     public void preloadPhotosInBackground() {
     }
+
+    @Override
+    public void clear() {
+    }
 }
diff --git a/res/drawable-hdpi/ic_contact_picture_sim.png b/res/drawable-hdpi/ic_contact_picture_sim.png
new file mode 100755
index 0000000..7b6cc26
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contact_picture_sim_1.png b/res/drawable-hdpi/ic_contact_picture_sim_1.png
new file mode 100755
index 0000000..ec2ebcb
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim_1.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contact_picture_sim_2.png b/res/drawable-hdpi/ic_contact_picture_sim_2.png
new file mode 100755
index 0000000..3b68c68
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim_2.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contact_picture_sim_business.png b/res/drawable-hdpi/ic_contact_picture_sim_business.png
new file mode 100755
index 0000000..4df1ecd
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim_business.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contact_picture_sim_personal.png b/res/drawable-hdpi/ic_contact_picture_sim_personal.png
new file mode 100755
index 0000000..44f4b93
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim_personal.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contact_picture_sim_primary.png b/res/drawable-hdpi/ic_contact_picture_sim_primary.png
new file mode 100755
index 0000000..a5bf921
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim_primary.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_rx_videocam.png b/res/drawable-hdpi/ic_rx_videocam.png
new file mode 100644
index 0000000..ccdda67
--- /dev/null
+++ b/res/drawable-hdpi/ic_rx_videocam.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_tx_videocam.png b/res/drawable-hdpi/ic_tx_videocam.png
new file mode 100644
index 0000000..603ddc8
--- /dev/null
+++ b/res/drawable-hdpi/ic_tx_videocam.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim.png b/res/drawable-mdpi/ic_contact_picture_sim.png
new file mode 100755
index 0000000..dd63d11
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim_1.png b/res/drawable-mdpi/ic_contact_picture_sim_1.png
new file mode 100755
index 0000000..4793a07
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim_1.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim_2.png b/res/drawable-mdpi/ic_contact_picture_sim_2.png
new file mode 100755
index 0000000..665a671
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim_2.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim_business.png b/res/drawable-mdpi/ic_contact_picture_sim_business.png
new file mode 100755
index 0000000..c266e26
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim_business.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim_personal.png b/res/drawable-mdpi/ic_contact_picture_sim_personal.png
new file mode 100755
index 0000000..f1e7596
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim_personal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim_primary.png b/res/drawable-mdpi/ic_contact_picture_sim_primary.png
new file mode 100755
index 0000000..493067a
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim_primary.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_rx_videocam.png b/res/drawable-mdpi/ic_rx_videocam.png
new file mode 100755
index 0000000..1b43a07
--- /dev/null
+++ b/res/drawable-mdpi/ic_rx_videocam.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_tx_videocam.png b/res/drawable-mdpi/ic_tx_videocam.png
new file mode 100755
index 0000000..64995d1
--- /dev/null
+++ b/res/drawable-mdpi/ic_tx_videocam.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim.png b/res/drawable-xhdpi/ic_contact_picture_sim.png
new file mode 100755
index 0000000..a39b7df
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim_1.png b/res/drawable-xhdpi/ic_contact_picture_sim_1.png
new file mode 100755
index 0000000..300c028
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim_1.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim_2.png b/res/drawable-xhdpi/ic_contact_picture_sim_2.png
new file mode 100755
index 0000000..c7ce422
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim_2.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim_business.png b/res/drawable-xhdpi/ic_contact_picture_sim_business.png
new file mode 100755
index 0000000..abf631f
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim_business.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim_personal.png b/res/drawable-xhdpi/ic_contact_picture_sim_personal.png
new file mode 100755
index 0000000..e5f0cf0
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim_personal.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim_primary.png b/res/drawable-xhdpi/ic_contact_picture_sim_primary.png
new file mode 100755
index 0000000..543d6a7
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim_primary.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_rx_videocam.png b/res/drawable-xhdpi/ic_rx_videocam.png
new file mode 100755
index 0000000..43319dc
--- /dev/null
+++ b/res/drawable-xhdpi/ic_rx_videocam.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tx_videocam.png b/res/drawable-xhdpi/ic_tx_videocam.png
new file mode 100755
index 0000000..d2671ed
--- /dev/null
+++ b/res/drawable-xhdpi/ic_tx_videocam.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_rx_videocam.png b/res/drawable-xxhdpi/ic_rx_videocam.png
new file mode 100755
index 0000000..89d29b7
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_rx_videocam.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_tx_videocam.png b/res/drawable-xxhdpi/ic_tx_videocam.png
new file mode 100755
index 0000000..8d897ba
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_tx_videocam.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_rx_videocam.png b/res/drawable-xxxhdpi/ic_rx_videocam.png
new file mode 100755
index 0000000..095e090
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_rx_videocam.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_tx_videocam.png b/res/drawable-xxxhdpi/ic_tx_videocam.png
new file mode 100755
index 0000000..79ea67b
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_tx_videocam.png
Binary files differ
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 8e86c74..2c0b3bb 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -162,6 +162,7 @@
     <string name="dialog_new_contact_account" msgid="4107520273478326011">"在以下帐户中创建联系人:"</string>
     <string name="import_from_sim" msgid="4749894687871835873">"从SIM卡导入"</string>
     <string name="import_from_sim_number" msgid="1232500923375370101">"从第<xliff:g id="SIM_NUMBER">%d</xliff:g>张SIM卡导入"</string>
+    <string name="export_to_sim">"导出到 SIM 卡"</string>
     <string name="import_from_sdcard" product="default" msgid="6423964533801496764">"从存储设备导入"</string>
     <string name="cancel_import_confirmation_message" msgid="7764915400478970495">"要取消导入“<xliff:g id="FILENAME">%s</xliff:g>”吗?"</string>
     <string name="cancel_export_confirmation_message" msgid="4063783315931861656">"要取消导出“<xliff:g id="FILENAME">%s</xliff:g>”吗?"</string>
@@ -175,6 +176,7 @@
     <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="8720294715223591581">"存储设备中的 vCard 文件过多。"</string>
     <string name="fail_reason_too_many_vcard" product="default" msgid="3793454448838716962">"SD卡上的 vCard 文件过多。"</string>
     <string name="fail_reason_io_error" msgid="7736686553669161933">"I/O 错误"</string>
+    <string name="fail_reason_import_vcard">I/O 错误,无法导入 vCard <xliff:g id="name">%s</xliff:g></string>
     <string name="fail_reason_low_memory_during_import" msgid="3277485820827338116">"内存不足。该文件可能过大。"</string>
     <string name="fail_reason_vcard_parse_error" msgid="514012644716565082">"由于意外原因而无法解析 vCard。"</string>
     <string name="fail_reason_not_supported" msgid="388664373573337601">"不支持此格式。"</string>
@@ -232,6 +234,7 @@
     <string name="dialog_import_export" msgid="1125776851100740858">"导入/导出联系人"</string>
     <string name="dialog_import" msgid="5177004290082451296">"导入联系人"</string>
     <string name="share_error" msgid="665756457151793108">"无法分享此联系人。"</string>
+    <string name="share_failed">"联系人太多,分享失败。"</string>
     <string name="menu_search" msgid="7464453023659824700">"搜索"</string>
     <string name="menu_contacts_filter" msgid="586356478145511794">"要显示的联系人"</string>
     <string name="activity_title_contacts_filter" msgid="7689519428197855166">"要显示的联系人"</string>
@@ -249,6 +252,25 @@
     <string name="contact_status_update_attribution" msgid="8419168578670128134">"来源:<xliff:g id="SOURCE">%1$s</xliff:g>"</string>
     <string name="contact_status_update_attribution_with_date" msgid="7492465535645607473">"<xliff:g id="DATE">%1$s</xliff:g>,来源:<xliff:g id="SOURCE">%2$s</xliff:g>"</string>
     <string name="action_menu_back_from_search" msgid="1138551123844019647">"停止搜索"</string>
+    <string name="exporting">"正在导出"</string>
+    <string name="reading_vcard_files">读取VCARD文件</string>
+    <string name="progressdialog_cancel">取消</string>
+    <string name="export_failed">"导出失败"</string>
+    <string name="sim_card_full">"发生错误,SIM卡已满。"</string>
+    <string name="export_finished">"导出结束"</string>
+    <string name="tag_too_long">"发生错误,联系人姓名过长。"</string>
+    <string name="sim_contacts_not_load">发生错误,SIM卡联系人未完全加载</string>
+    <string name="export_cancelled">导出操作被取消,<xliff:g id="insertCount">%s</xliff:g>条成功导出</string>
+    <string name="export_no_phone_or_email">导出失败, <xliff:g id="name">%s</xliff:g>没有电话号码或者邮箱地址</string>
+    <string name="import_from_sim_select">"选择SIM卡进行导入"</string>
+    <string name="no_sdcard_title" product="nosdcard">"存储设备不存在"</string>
+    <string name="no_sdcard_title" product="default">"无 SD 卡"</string>
+    <string name="deleteConfirmation_title">"要删除联系人吗?"</string>
+    <string name="deleteConfirmation">"将会删除此联系人。"</string>
+    <string name="slot_name">"卡"</string>
+    <string name="copy_done">复制成功!</string>
+    <string name="copy_failure">复制失败!</string>
+    <string name="card_no_space">卡记录已满,部分信息未复制</string>
     <string name="description_clear_search" msgid="3893511425518852086">"清除搜索内容"</string>
     <string name="settings_contact_display_options_title" msgid="1020420603072835628">"联系人显示选项"</string>
 </resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 9866c6f..be49081 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -160,6 +160,7 @@
     <string name="listCustomView" msgid="1915154113477432033">"聯絡人自訂檢視"</string>
     <string name="listSingleContact" msgid="8525131203887307088">"單一聯絡人"</string>
     <string name="dialog_new_contact_account" msgid="4107520273478326011">"在帳戶下建立聯絡人"</string>
+    <string name="export_to_sim">"導出到 SIM 卡"</string>
     <string name="import_from_sim" msgid="4749894687871835873">"從 SIM 卡匯入"</string>
     <string name="import_from_sim_number" msgid="1232500923375370101">"從 SIM 卡 #<xliff:g id="SIM_NUMBER">%d</xliff:g> 匯入"</string>
     <string name="import_from_sdcard" product="default" msgid="6423964533801496764">"從儲存裝置匯入"</string>
@@ -175,6 +176,7 @@
     <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="8720294715223591581">"儲存裝置中的 vCard 檔案過多。"</string>
     <string name="fail_reason_too_many_vcard" product="default" msgid="3793454448838716962">"SD 卡上的 vCard 檔案過多。"</string>
     <string name="fail_reason_io_error" msgid="7736686553669161933">"I/O 錯誤"</string>
+    <string name="fail_reason_import_vcard">I/O 錯誤,無法匯入vCard <xliff:g id="name">%s</xliff:g></string>
     <string name="fail_reason_low_memory_during_import" msgid="3277485820827338116">"記憶體不足,檔案可能過大。"</string>
     <string name="fail_reason_vcard_parse_error" msgid="514012644716565082">"由於意外因素,導致無法剖析 vCard。"</string>
     <string name="fail_reason_not_supported" msgid="388664373573337601">"不支援此格式。"</string>
@@ -251,4 +253,22 @@
     <string name="action_menu_back_from_search" msgid="1138551123844019647">"停止搜尋"</string>
     <string name="description_clear_search" msgid="3893511425518852086">"清除搜尋"</string>
     <string name="settings_contact_display_options_title" msgid="1020420603072835628">"聯絡人顯示選項"</string>
+    <string name="settings_contact_display_options_description" msgid="4130259058302284077">"設定聯絡人的顯示和排序方式。"</string>
+    <string name="exporting">"正在導出"</string>
+    <string name="reading_vcard_files">讀取Vcard文件</string>
+    <string name="export_failed">"導出失敗"</string>
+    <string name="sim_card_full">"發生錯誤,SIM卡已滿。"</string>
+    <string name="export_finished">"導出結束"</string>
+    <string name="export_no_phone_or_email">導出失敗, <xliff:g id="name">%s</xliff:g>沒有電話號碼或者郵箱地址</string>
+    <string name="tag_too_long">"發生錯誤,聯絡人姓名過長。"</string>
+    <string name="import_from_sim_select">"選擇SIM卡進行導入"</string>
+    <string name="no_sdcard_title" product="nosdcard">"無存儲設備"</string>
+    <string name="no_sdcard_title" product="default">"無 SD 卡"</string>
+    <string name="deleteConfirmation_title">"要刪除聯絡人嗎?"</string>
+    <string name="ContactMultiDeleteConfirmation">"將會刪除這些聯絡人。"</string>
+    <string name="slot_name">"卡"</string>
+
+    <string name="copy_done">複制成功!</string>
+    <string name="copy_failure">複制失敗!</string>
+    <string name="card_no_space">卡記錄已滿,部分信息未複制</string>
 </resources>
diff --git a/res/values/ids.xml b/res/values/ids.xml
index 093901b..0b7d3a2 100644
--- a/res/values/ids.xml
+++ b/res/values/ids.xml
@@ -40,6 +40,8 @@
     <item type="id" name="cliv_phoneticname_textview"/>
     <item type="id" name="cliv_label_textview"/>
     <item type="id" name="cliv_data_view"/>
+    <!-- For ContactDeletionInteraction -->
+    <item type="id" name="dialog_delete_contact_confirmation"/>
     
     <!-- For tag ids used by ContactPhotoManager to tag views with contact details -->
     <item type="id" name="tag_display_name"/>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6cf20a5..89b6e7e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -418,9 +418,16 @@
 
     <string name="dialog_new_contact_account">Create contact under account</string>
 
+    <!-- Action string for managing SIM contacts -->
+    <string name="manage_sim_contacts"> Manage SIM card contacts</string>
+
+    <!-- Action that exports all contacts to SIM -->
+    <string name="export_to_sim">Export to SIM card</string>
+
     <!-- Action string for selecting SIM for importing contacts -->
     <string name="import_from_sim">Import from SIM card</string>
 
+
     <!-- Action string for selecting SIM for importing contacts, when more than one SIM card -->
     <string name="import_from_sim_number">Import from SIM card #<xliff:g id="sim_number" example="2">%d</xliff:g></string>
 
@@ -476,6 +483,9 @@
          emitted some I/O error. Exact reason will be appended by the system. [CHAR LIMIT=NONE] -->
     <string name="fail_reason_io_error">I/O error</string>
 
+    <!--The failed reason shown when importting some a vCard file -->
+    <string name="fail_reason_import_vcard">I/O error,couldn\'t import vCard <xliff:g id="name">%s</xliff:g></string>
+
     <!-- Failure reason show when Contacts app (especially vCard importer) encountered
          low memory problem and could not proceed its import procedure. [CHAR LIMIT=NONE] -->
     <string name="fail_reason_low_memory_during_import">Not enough memory. The file may be too large.</string>
@@ -687,6 +697,8 @@
     <!-- Toast indicating that sharing a contact has failed. [CHAR LIMIT=NONE]  -->
     <string name="share_error">This contact can\'t be shared.</string>
 
+    <!-- Toast indicating that sharing too many contact has failed. [CHAR LIMIT=NONE]  -->
+    <string name="share_failed">Too many contacts, share failed</string>
     <!-- Menu item to search contacts -->
     <string name="menu_search">Search</string>
 
@@ -744,6 +756,48 @@
     <!-- Attribution of a contact status update, when the time of update is known -->
     <string name="contact_status_update_attribution_with_date"><xliff:g id="date" example="3 hours ago">%1$s</xliff:g> via <xliff:g id="source" example="Google Talk">%2$s</xliff:g></string>
 
+    <string name="label_groups">Group</string>
+
+    <string name="exporting">Exporting</string>
+
+    <!-- Message while reading multiple vCard files "(current number) of (total number) files"
+          The order of "current number" and "total number" cannot be changed -->
+    <string name="reading_vcard_files"><xliff:g id="current_number">%1$s</xliff:g> of <xliff:g id="total_number">%2$s</xliff:g> files</string>
+
+    <string name="progressdialog_cancel">Cancel</string>
+
+    <string name="export_failed">Export failed</string>
+
+    <string name="sim_card_full">Error, Sim Card is full.</string>
+
+    <string name="export_finished">Export finished</string>
+
+    <string name="tag_too_long">Error, Contact name is too long.</string>
+
+    <string name="sim_contacts_not_load">Error, SIM contacts have not been loaded completely.</string>
+
+    <string name="export_cancelled">Export is canceled, <xliff:g id="insertCount">%s</xliff:g>items are exported</string>
+
+    <string name="export_no_phone_or_email">Export failed, <xliff:g id="name">%s</xliff:g>has not phone number or
+         email address</string>
+
+    <string name="import_from_sim_select">Choose card to import</string>
+
+    <!-- Dialog title shown when (USB) storage does not exist [CHAR LIMIT=25] -->
+    <string name="no_sdcard_title" product="nosdcard">Storage unavailable</string>
+    <!-- Dialog title shown when SD Card does not exist -->
+    <string name="no_sdcard_title" product="default">No SD card</string>
+        <!-- Confirmation dialog title after users selects to delete a contact. [CHAR LIMIT=25]-->
+    <string name="deleteConfirmation_title">Delete contact?</string>
+
+    <!-- Confirmation dialog contents after users selects to delete a Writable contact. -->
+    <string name="deleteConfirmation">This contact will be deleted.</string>
+        <!-- The slot common name -->
+    <string name="slot_name">SIM</string>
+
+    <string name="copy_done">Copy done!</string>
+    <string name="copy_failure">Copy Failed!</string>
+    <string name="card_no_space">Card has no space ,some record copy failed</string>
     <!-- Font family used when drawing letters for letter tile avatars.
          Do not translate. -->
     <string name="letter_tile_letter_font_family">sans-serif-light</string>
@@ -763,4 +817,11 @@
          contacts to be displayed. [CHAR LIMIT=128] -->
     <string name="settings_contact_display_options_title">Contact display options</string>
 
+    <!-- Detailed description of the preference section that allows users to configure how they
+         want their contacts to be displayed. [CHAR LIMIT=128] -->
+    <string name="settings_contact_display_options_description">Configure how your contacts are displayed and sorted.</string>
+
+    <string name="Import_All">Import Contacts From All SIMs</string>
+
+    <string name="select_sim">Select SIM</string>
 </resources>
diff --git a/src/com/android/contacts/common/CallUtil.java b/src/com/android/contacts/common/CallUtil.java
index 32bd9e1..30bbe31 100644
--- a/src/com/android/contacts/common/CallUtil.java
+++ b/src/com/android/contacts/common/CallUtil.java
@@ -27,6 +27,8 @@
 import com.android.contacts.common.util.PhoneNumberHelper;
 import com.android.phone.common.PhoneConstants;
 
+import java.util.List;
+
 /**
  * Utilities related to calls.
  */
@@ -145,15 +147,24 @@
         return Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
      }
 
+    private static boolean hasCapability(PhoneAccount phoneAccount, int capability) {
+        return (phoneAccount != null) &&
+                ((phoneAccount.getCapabilities() & capability) == capability);
+    }
+
     public static boolean isVideoEnabled(Context context) {
         TelecomManager telecommMgr = (TelecomManager)
                 context.getSystemService(Context.TELECOM_SERVICE);
         if (telecommMgr == null) {
             return false;
         }
-
-        // TODO: Check telecommManager for value instead.
-        // return telecommMgr.isVideoEnabled();
+        List<PhoneAccountHandle> phoneAccountHandles = telecommMgr.getCallCapablePhoneAccounts();
+        for (PhoneAccountHandle handle : phoneAccountHandles) {
+            final PhoneAccount phoneAccount = telecommMgr.getPhoneAccount(handle);
+            if (hasCapability(phoneAccount, PhoneAccount.CAPABILITY_VIDEO_CALLING)) {
+                return true;
+            }
+        }
         return false;
     }
 }
diff --git a/src/com/android/contacts/common/ContactPhotoManager.java b/src/com/android/contacts/common/ContactPhotoManager.java
index 12faadb..f700fd8 100644
--- a/src/com/android/contacts/common/ContactPhotoManager.java
+++ b/src/com/android/contacts/common/ContactPhotoManager.java
@@ -16,6 +16,7 @@
 
 package com.android.contacts.common;
 
+import android.accounts.Account;
 import android.app.ActivityManager;
 import android.content.ComponentCallbacks2;
 import android.content.ContentResolver;
@@ -113,19 +114,24 @@
      * draw a letter tile avatar based on the request parameters defined in the
      * {@link DefaultImageRequest}.
      */
-    public static Drawable getDefaultAvatarDrawableForContact(Resources resources, boolean hires,
+    public static Drawable getDefaultAvatarDrawableForContact(Context context, boolean hires,
             DefaultImageRequest defaultImageRequest) {
+        return getDefaultAvatarDrawableForContact(context, hires, defaultImageRequest, null);
+    }
+
+    public static Drawable getDefaultAvatarDrawableForContact(Context context, boolean hires,
+            DefaultImageRequest defaultImageRequest, Account account) {
         if (defaultImageRequest == null) {
             if (sDefaultLetterAvatar == null) {
                 // Cache and return the letter tile drawable that is created by a null request,
                 // so that it doesn't have to be recreated every time it is requested again.
                 sDefaultLetterAvatar = LetterTileDefaultImageProvider.getDefaultImageForContact(
-                        resources, null);
+                        context, null, account);
             }
             return sDefaultLetterAvatar;
         }
-        return LetterTileDefaultImageProvider.getDefaultImageForContact(resources,
-                defaultImageRequest);
+        return LetterTileDefaultImageProvider.getDefaultImageForContact(context,
+                defaultImageRequest, account);
     }
 
     /**
@@ -365,8 +371,8 @@
          * @param defaultImageRequest {@link DefaultImageRequest} object that specifies how a
          * default letter tile avatar should be drawn.
          */
-        public abstract void applyDefaultImage(ImageView view, int extent, boolean darkTheme,
-                DefaultImageRequest defaultImageRequest);
+        public abstract void applyDefaultImage(ImageView view, Account account,
+                int extent, boolean darkTheme, DefaultImageRequest defaultImageRequest);
     }
 
     /**
@@ -376,16 +382,17 @@
      */
     private static class LetterTileDefaultImageProvider extends DefaultImageProvider {
         @Override
-        public void applyDefaultImage(ImageView view, int extent, boolean darkTheme,
-                DefaultImageRequest defaultImageRequest) {
-            final Drawable drawable = getDefaultImageForContact(view.getResources(),
-                    defaultImageRequest);
+        public void applyDefaultImage(ImageView view, Account account, int extent,
+                boolean darkTheme, DefaultImageRequest defaultImageRequest) {
+            final Drawable drawable = getDefaultImageForContact(view.getContext(),
+                    defaultImageRequest, account);
             view.setImageDrawable(drawable);
         }
 
-        public static Drawable getDefaultImageForContact(Resources resources,
-                DefaultImageRequest defaultImageRequest) {
-            final LetterTileDrawable drawable = new LetterTileDrawable(resources);
+        public static Drawable getDefaultImageForContact(Context context,
+                DefaultImageRequest defaultImageRequest, Account account) {
+            final LetterTileDrawable drawable = new LetterTileDrawable(
+                    context, account);
             if (defaultImageRequest != null) {
                 // If the contact identifier is null or empty, fallback to the
                 // displayName. In that case, use {@code null} for the contact's
@@ -410,8 +417,8 @@
         private static Drawable sDrawable;
 
         @Override
-        public void applyDefaultImage(ImageView view, int extent, boolean darkTheme,
-                DefaultImageRequest defaultImageRequest) {
+        public void applyDefaultImage(ImageView view, Account account, int extent,
+                boolean darkTheme, DefaultImageRequest defaultImageRequest) {
             if (sDrawable == null) {
                 Context context = view.getContext();
                 sDrawable = new ColorDrawable(context.getResources().getColor(
@@ -440,13 +447,15 @@
         return new ContactPhotoManagerImpl(context);
     }
 
+    public abstract void clear();
+
     /**
      * Load thumbnail image into the supplied image view. If the photo is already cached,
      * it is displayed immediately.  Otherwise a request is sent to load the photo
      * from the database.
      */
-    public abstract void loadThumbnail(ImageView view, long photoId, boolean darkTheme,
-            boolean isCircular, DefaultImageRequest defaultImageRequest,
+    public abstract void loadThumbnail(ImageView view, long photoId, Account account,
+            boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest,
             DefaultImageProvider defaultProvider);
 
     /**
@@ -454,10 +463,23 @@
      * DefaultImageProvider)} using the {@link DefaultImageProvider} {@link #DEFAULT_AVATAR}.
     */
     public final void loadThumbnail(ImageView view, long photoId, boolean darkTheme,
-            boolean isCircular, DefaultImageRequest defaultImageRequest) {
-        loadThumbnail(view, photoId, darkTheme, isCircular, defaultImageRequest, DEFAULT_AVATAR);
+             boolean isCircular, DefaultImageRequest defaultImageRequest) {
+        loadThumbnail(view, photoId, null, darkTheme, isCircular,
+                defaultImageRequest, DEFAULT_AVATAR);
     }
 
+    public final void loadThumbnail(ImageView view, long photoId, Account account,
+        boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest) {
+        loadThumbnail(view, photoId, account, darkTheme, isCircular,
+                defaultImageRequest, DEFAULT_AVATAR);
+    }
+
+    public final void loadThumbnail(ImageView view, long photoId, boolean darkTheme,
+        boolean isCircular, DefaultImageRequest defaultImageRequest,
+        DefaultImageProvider defaultProvider) {
+        loadThumbnail(view, photoId, null, darkTheme, isCircular,
+                defaultImageRequest, defaultProvider);
+    }
 
     /**
      * Load photo into the supplied image view. If the photo is already cached,
@@ -476,8 +498,9 @@
      * @param defaultProvider The provider of default avatars (this is used if photoUri doesn't
      * refer to an existing image)
      */
-    public abstract void loadPhoto(ImageView view, Uri photoUri, int requestedExtent,
-            boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest,
+    public abstract void loadPhoto(ImageView view, Uri photoUri,
+            Account account, int requestedExtent, boolean darkTheme,
+            boolean isCircular, DefaultImageRequest defaultImageRequest,
             DefaultImageProvider defaultProvider);
 
     /**
@@ -488,12 +511,26 @@
      * @param defaultImageRequest {@link DefaultImageRequest} object that specifies how a default
      * letter tile avatar should be drawn.
      */
+
     public final void loadPhoto(ImageView view, Uri photoUri, int requestedExtent,
             boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest) {
-        loadPhoto(view, photoUri, requestedExtent, darkTheme, isCircular,
+        loadPhoto(view, photoUri, null, requestedExtent, darkTheme, isCircular,
                 defaultImageRequest, DEFAULT_AVATAR);
     }
 
+    public final void loadPhoto(ImageView view, Uri photoUri, Account account, int requestedExtent,
+            boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest) {
+        loadPhoto(view, photoUri, account, requestedExtent, darkTheme, isCircular,
+                defaultImageRequest, DEFAULT_AVATAR);
+    }
+
+    public final void loadPhoto(ImageView view, Uri photoUri, int requestedExtent,
+        boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest,
+        DefaultImageProvider defaultProvider) {
+        loadPhoto(view, photoUri, null, requestedExtent, darkTheme, isCircular,
+                defaultImageRequest, defaultProvider);
+    }
+
     /**
      * Calls {@link #loadPhoto(ImageView, Uri, boolean, boolean, DefaultImageRequest,
      * DefaultImageProvider)} with {@link #DEFAULT_AVATAR} and with the assumption, that
@@ -504,7 +541,15 @@
      */
     public final void loadDirectoryPhoto(ImageView view, Uri photoUri, boolean darkTheme,
             boolean isCircular, DefaultImageRequest defaultImageRequest) {
-        loadPhoto(view, photoUri, -1, darkTheme, isCircular, defaultImageRequest, DEFAULT_AVATAR);
+        loadPhoto(view, photoUri, null, -1, darkTheme, isCircular,
+                defaultImageRequest, DEFAULT_AVATAR);
+    }
+
+    public final void loadDirectoryPhoto(ImageView view, Uri photoUri,
+            Account account, boolean darkTheme, boolean isCircular,
+            DefaultImageRequest defaultImageRequest) {
+        loadPhoto(view, photoUri, account, -1, darkTheme, isCircular,
+                defaultImageRequest, DEFAULT_AVATAR);
     }
 
     /**
@@ -784,11 +829,12 @@
     }
 
     @Override
-    public void loadThumbnail(ImageView view, long photoId, boolean darkTheme, boolean isCircular,
-            DefaultImageRequest defaultImageRequest, DefaultImageProvider defaultProvider) {
+    public void loadThumbnail(ImageView view, long photoId, Account account,
+            boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest,
+            DefaultImageProvider defaultProvider) {
         if (photoId == 0) {
             // No photo is needed
-            defaultProvider.applyDefaultImage(view, -1, darkTheme, defaultImageRequest);
+            defaultProvider.applyDefaultImage(view, account, -1, darkTheme, defaultImageRequest);
             mPendingRequests.remove(view);
         } else {
             if (DEBUG) Log.d(TAG, "loadPhoto request: " + photoId);
@@ -798,19 +844,19 @@
     }
 
     @Override
-    public void loadPhoto(ImageView view, Uri photoUri, int requestedExtent, boolean darkTheme,
-            boolean isCircular, DefaultImageRequest defaultImageRequest,
+    public void loadPhoto(ImageView view, Uri photoUri, Account account, int requestedExtent,
+            boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest,
             DefaultImageProvider defaultProvider) {
         if (photoUri == null) {
             // No photo is needed
-            defaultProvider.applyDefaultImage(view, requestedExtent, darkTheme,
+            defaultProvider.applyDefaultImage(view, account, requestedExtent, darkTheme,
                     defaultImageRequest);
             mPendingRequests.remove(view);
         } else {
             if (DEBUG) Log.d(TAG, "loadPhoto request: " + photoUri);
             if (isDefaultImageUri(photoUri)) {
-                createAndApplyDefaultImageForUri(view, photoUri, requestedExtent, darkTheme,
-                        isCircular, defaultProvider);
+                createAndApplyDefaultImageForUri(view, account, photoUri, requestedExtent,
+                        darkTheme, isCircular, defaultProvider);
             } else {
                 loadPhotoByIdOrUri(view, Request.createFromUri(photoUri, requestedExtent,
                         darkTheme, isCircular, defaultProvider));
@@ -818,11 +864,12 @@
         }
     }
 
-    private void createAndApplyDefaultImageForUri(ImageView view, Uri uri, int requestedExtent,
-            boolean darkTheme, boolean isCircular, DefaultImageProvider defaultProvider) {
+    private void createAndApplyDefaultImageForUri(ImageView view,
+            Account account, Uri uri, int requestedExtent, boolean darkTheme,
+            boolean isCircular, DefaultImageProvider defaultProvider) {
         DefaultImageRequest request = getDefaultImageRequestFromUri(uri);
         request.isCircular = isCircular;
-        defaultProvider.applyDefaultImage(view, requestedExtent, darkTheme, request);
+        defaultProvider.applyDefaultImage(view, account, requestedExtent, darkTheme, request);
     }
 
     private void loadPhotoByIdOrUri(ImageView view, Request request) {
@@ -1646,7 +1693,7 @@
                         ? DefaultImageRequest.EMPTY_DEFAULT_BUSINESS_IMAGE_REQUEST
                         : DefaultImageRequest.EMPTY_DEFAULT_IMAGE_REQUEST;
             }
-            mDefaultProvider.applyDefaultImage(view, mRequestedExtent, mDarkTheme, request);
+            mDefaultProvider.applyDefaultImage(view, null, mRequestedExtent, mDarkTheme, request);
         }
     }
 }
diff --git a/src/com/android/contacts/common/ContactTileLoaderFactory.java b/src/com/android/contacts/common/ContactTileLoaderFactory.java
index f8b0c35..33d4ea6 100644
--- a/src/com/android/contacts/common/ContactTileLoaderFactory.java
+++ b/src/com/android/contacts/common/ContactTileLoaderFactory.java
@@ -23,6 +23,8 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
 
 /**
  * Used to create {@link CursorLoader}s to load different groups of
@@ -35,19 +37,22 @@
     public final static int STARRED = 2;
     public final static int PHOTO_URI = 3;
     public final static int LOOKUP_KEY = 4;
-    public final static int CONTACT_PRESENCE = 5;
-    public final static int CONTACT_STATUS = 6;
+    public final static int ACCOUNT_TYPE = 5;
+    public final static int ACCOUNT_NAME = 6;
+
+    public final static int CONTACT_PRESENCE = 7;
+    public final static int CONTACT_STATUS = 8;
 
     // Only used for StrequentPhoneOnlyLoader
-    public final static int PHONE_NUMBER = 5;
-    public final static int PHONE_NUMBER_TYPE = 6;
-    public final static int PHONE_NUMBER_LABEL = 7;
-    public final static int IS_DEFAULT_NUMBER = 8;
-    public final static int PINNED = 9;
+    public final static int PHONE_NUMBER = 7;
+    public final static int PHONE_NUMBER_TYPE = 8;
+    public final static int PHONE_NUMBER_LABEL = 9;
+    public final static int IS_DEFAULT_NUMBER = 10;
+    public final static int PINNED = 11;
     // The _ID field returned for strequent items actually contains data._id instead of
     // contacts._id because the query is performed on the data table. In order to obtain the
     // contact id for strequent items, we thus have to use Phone.contact_id instead.
-    public final static int CONTACT_ID_FOR_DATA = 10;
+    public final static int CONTACT_ID_FOR_DATA = 12;
 
     private static final String[] COLUMNS = new String[] {
         Contacts._ID, // ..........................................0
@@ -55,8 +60,10 @@
         Contacts.STARRED, // ......................................2
         Contacts.PHOTO_URI, // ....................................3
         Contacts.LOOKUP_KEY, // ...................................4
-        Contacts.CONTACT_PRESENCE, // .............................5
-        Contacts.CONTACT_STATUS, // ...............................6
+        RawContacts.ACCOUNT_TYPE, //                               5
+        RawContacts.ACCOUNT_NAME, //                               6
+        Contacts.CONTACT_PRESENCE, // .............................7
+        Contacts.CONTACT_STATUS, // ...............................8
     };
 
     /**
@@ -72,12 +79,14 @@
         Contacts.STARRED, // ......................................2
         Contacts.PHOTO_URI, // ....................................3
         Contacts.LOOKUP_KEY, // ...................................4
-        Phone.NUMBER, // ..........................................5
-        Phone.TYPE, // ............................................6
-        Phone.LABEL, // ...........................................7
-        Phone.IS_SUPER_PRIMARY, //.................................8
-        Contacts.PINNED, // .......................................9
-        Phone.CONTACT_ID //........................................10
+        RawContacts.ACCOUNT_TYPE, //                               5
+        RawContacts.ACCOUNT_NAME, //                               6
+        Phone.NUMBER, // ..........................................7
+        Phone.TYPE, // ............................................8
+        Phone.LABEL, // ............................................9
+        Phone.IS_SUPER_PRIMARY, //.................................10
+        Contacts.PINNED, // .......................................11
+        Phone.CONTACT_ID //........................................12
     };
 
     private static final String STARRED_ORDER = Contacts.DISPLAY_NAME+" COLLATE NOCASE ASC";
@@ -88,10 +97,16 @@
     }
 
     public static CursorLoader createStrequentPhoneOnlyLoader(Context context) {
-        Uri uri = Contacts.CONTENT_STREQUENT_URI.buildUpon()
-                .appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "true").build();
-
-        return new CursorLoader(context, uri, COLUMNS_PHONE_ONLY, null, null, null);
+        Uri.Builder builder = Contacts.CONTENT_STREQUENT_URI.buildUpon();
+                builder.appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "true");
+        // Do not show contacts in disabled SIM card
+        String disabledSimFilter = MoreContactUtils.getDisabledSimFilter();
+        if (!TextUtils.isEmpty(disabledSimFilter)) {
+            builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, disabledSimFilter);
+            builder.appendQueryParameter(SimContactsConstants
+                    .WITHOUT_SIM_FLAG, "true");
+        }
+        return new CursorLoader(context, builder.build(), COLUMNS_PHONE_ONLY, null, null, null);
     }
 
     public static CursorLoader createStarredLoader(Context context) {
diff --git a/src/com/android/contacts/common/MoreContactUtils.java b/src/com/android/contacts/common/MoreContactUtils.java
index 16b4e8d..4d284ab 100644
--- a/src/com/android/contacts/common/MoreContactUtils.java
+++ b/src/com/android/contacts/common/MoreContactUtils.java
@@ -16,20 +16,48 @@
 
 package com.android.contacts.common;
 
+import android.accounts.Account;
+
 import com.google.i18n.phonenumbers.NumberParseException;
 import com.google.i18n.phonenumbers.PhoneNumberUtil;
 
 import android.content.Context;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.OperationApplicationException;
+import android.database.Cursor;
 import android.graphics.Rect;
 import android.net.Uri;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.View;
 import android.widget.TextView;
 
 import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.SimAccountType;
+import com.android.internal.telephony.uicc.AdnRecord;
+import com.android.internal.telephony.uicc.IccConstants;
+import com.android.internal.telephony.IIccPhoneBook;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Shared static contact utility methods.
@@ -37,7 +65,30 @@
 public class MoreContactUtils {
 
     private static final String WAIT_SYMBOL_AS_STRING = String.valueOf(PhoneNumberUtils.WAIT);
+    private static final boolean DBG = true;
+    private static final String TAG = "MoreContactUtils";
+    public static final int MAX_LENGTH_NAME_IN_SIM = 14;
+    public static final int MAX_LENGTH_NAME_WITH_CHINESE_IN_SIM = 6;
+    public static final int MAX_LENGTH_NUMBER_IN_SIM = 20;
+    public static final int MAX_LENGTH_EMAIL_IN_SIM = 40;
+    private static final int NAME_POS = 0;
+    private static final int NUMBER_POS = 1;
+    private static final int EMAIL_POS = 2;
+    private static final int ANR_POS = 3;
+    private static final String PHONEBOOK = "simphonebook";
+    public static final String[] MULTI_SIM_NAME = { "perferred_name_sub1",
+            "perferred_name_sub2" };
 
+    public static final String PREFERRED_SIM_ICON_INDEX = "preferred_sim_icon_index";
+    public static final String[] IPCALL_PREFIX = { "ip_call_prefix_sub1",
+            "ip_call_prefix_sub2" };
+    public final static int[] IC_SIM_PICTURE = {
+        R.drawable.ic_contact_picture_sim_1,
+        R.drawable.ic_contact_picture_sim_2,
+        R.drawable.ic_contact_picture_sim_personal,
+        R.drawable.ic_contact_picture_sim_business,
+        R.drawable.ic_contact_picture_sim_primary
+   };
     /**
      * Returns true if two data with mimetypes which represent values in contact entries are
      * considered equal for collapsing in the GUI. For caller-id, use
@@ -232,4 +283,454 @@
         intent.setData(lookupUri);
         return intent;
     }
+
+    /** get disabled SIM card's name */
+    public static String getDisabledSimFilter() {
+        int count = TelephonyManager.getDefault().getPhoneCount();
+        StringBuilder simFilter = new StringBuilder("");
+
+        for (int i = 0; i < count; i++) {
+            if (TelephonyManager.SIM_STATE_UNKNOWN == TelephonyManager
+                    .getDefault().getSimState(i)) {
+                simFilter.append(getSimAccountName(i) + ',');
+            }
+        }
+
+        return simFilter.toString();
+    }
+
+    public static boolean isAPMOnAndSIMPowerDown(Context context) {
+        if (context == null) {
+            return false;
+        }
+        boolean isAirPlaneMode = Settings.System.getInt(context.getContentResolver(),
+                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
+        boolean isSIMPowerDown = SystemProperties.getInt(
+                "persist.radio.apm_sim_not_pwdn", 0) == 0;
+        return isAirPlaneMode && isSIMPowerDown;
+    }
+
+    /**
+     * Get SIM card account name
+     */
+    public static String getSimAccountName(int subscription) {
+        if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+            return SimContactsConstants.SIM_NAME + (subscription + 1);
+        } else {
+            return SimContactsConstants.SIM_NAME;
+        }
+    }
+
+    public static int getSubscription(String accountType, String accountName) {
+        int subscription = SimContactsConstants.SUB_INVALID;
+        if (accountType == null || accountName == null)
+            return subscription;
+        if (accountType.equals(SimContactsConstants.ACCOUNT_TYPE_SIM)) {
+            if (accountName.equals(SimContactsConstants.SIM_NAME)
+                    || accountName.equals(SimContactsConstants.SIM_NAME_1)) {
+                subscription = SimContactsConstants.SUB_1;
+            } else if (accountName.equals(SimContactsConstants.SIM_NAME_2)) {
+                subscription = SimContactsConstants.SUB_2;
+            }
+        }
+        return subscription;
+    }
+
+    public static int getAnrCount(int slot) {
+        int anrCount = 0;
+        long[] subId = SubscriptionManager.getSubId(slot);
+        try {
+            IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+                ServiceManager.getService("simphonebook"));
+
+            if (iccIpb != null) {
+                if (subId != null
+                        && TelephonyManager.getDefault().isMultiSimEnabled()) {
+                    anrCount = iccIpb.getAnrCountUsingSubId(subId[0]);
+                } else {
+                    anrCount = iccIpb.getAnrCount();
+                }
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return anrCount;
+    }
+
+    public static int getSpareAnrCount(int slot) {
+        int anrCount = 0;
+        long[] subId = SubscriptionManager.getSubId(slot);
+                try {
+            IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+                ServiceManager.getService("simphonebook"));
+
+            if (iccIpb != null) {
+                if (subId != null
+                        && TelephonyManager.getDefault().isMultiSimEnabled()) {
+                    anrCount = iccIpb.getSpareAnrCountUsingSubId(subId[0]);
+                } else {
+                    anrCount = iccIpb.getSpareAnrCount();
+                }
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return anrCount;
+    }
+
+    public static int getAdnCount(int slot) {
+        int adnCount = 0;
+        long[] subId = SubscriptionManager.getSubId(slot);
+                try {
+            IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+                ServiceManager.getService("simphonebook"));
+
+            if (iccIpb != null) {
+                if (subId != null
+                        && TelephonyManager.getDefault().isMultiSimEnabled()) {
+                    adnCount = iccIpb.getAdnCountUsingSubId(subId[0]);
+                } else {
+                    adnCount = iccIpb.getAdnCount();
+                }
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return adnCount;
+    }
+
+    public static int getEmailCount(int slot) {
+        int emailCount = 0;
+        long[] subId = SubscriptionManager.getSubId(slot);
+                try {
+            IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+                ServiceManager.getService("simphonebook"));
+
+            if (iccIpb != null) {
+                if (subId != null
+                        && TelephonyManager.getDefault().isMultiSimEnabled()) {
+                    emailCount = iccIpb.getEmailCountUsingSubId(subId[0]);
+                } else {
+                    emailCount = iccIpb.getEmailCount();
+                }
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return emailCount;
+    }
+
+    public static int getSpareEmailCount(int slot) {
+        int emailCount = 0;
+        long[] subId = SubscriptionManager.getSubId(slot);
+                try {
+            IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+                ServiceManager.getService("simphonebook"));
+
+            if (iccIpb != null) {
+                if (subId != null
+                        && TelephonyManager.getDefault().isMultiSimEnabled()) {
+                    emailCount = iccIpb.getSpareEmailCountUsingSubId(subId[0]);
+                } else {
+                    emailCount = iccIpb.getSpareEmailCount();
+                }
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return emailCount;
+    }
+
+    /**
+     * Returns the subscription's card can save anr or not.
+     */
+    public static boolean canSaveAnr(int slot) {
+        return getAnrCount(slot) > 0 ? true : false;
+    }
+
+    /**
+     * Returns the subscription's card can save email or not.
+     */
+    public static boolean canSaveEmail(int slot) {
+        return getEmailCount(slot) > 0 ? true : false;
+    }
+
+    public static int getOneSimAnrCount(int slot) {
+        int count = 0;
+        int anrCount = getAnrCount(slot);
+        int adnCount = getAdnCount(slot);
+        if (adnCount > 0) {
+            count = anrCount % adnCount != 0 ? (anrCount / adnCount + 1)
+                    : (anrCount / adnCount);
+        }
+        return count;
+    }
+
+    public static int getOneSimEmailCount(int slot) {
+        int count = 0;
+        int emailCount = getEmailCount(slot);
+        int adnCount = getAdnCount(slot);
+        if (adnCount > 0) {
+            count = emailCount % adnCount != 0 ? (emailCount
+                    / adnCount + 1)
+                    : (emailCount / adnCount);
+        }
+        return count;
+    }
+
+    public static boolean insertToPhone(String[] values, final ContentResolver resolver,int sub) {
+        Account account = getAcount(sub);
+        final String name = values[NAME_POS];
+        final String phoneNumber = values[NUMBER_POS];
+        final String emailAddresses = values[EMAIL_POS];
+        final String anrs = values[ANR_POS];
+
+        final String[] emailAddressArray;
+        final String[] anrArray;
+        boolean success = true;
+        if (!TextUtils.isEmpty(emailAddresses)) {
+            emailAddressArray = emailAddresses.split(",");
+        } else {
+            emailAddressArray = null;
+        }
+        if (!TextUtils.isEmpty(anrs)) {
+            anrArray = anrs.split(",");
+        } else {
+            anrArray = null;
+        }
+        if (DBG) {
+            Log.d(TAG, "insertToPhone: name= " + name + ", phoneNumber= " + phoneNumber
+                    + ", emails= " + emailAddresses + ", anrs= " + anrs + ", account= " + account);
+        }
+        final ArrayList<ContentProviderOperation> operationList =
+                new ArrayList<ContentProviderOperation>();
+        ContentProviderOperation.Builder builder = ContentProviderOperation
+                .newInsert(RawContacts.CONTENT_URI);
+        builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
+
+        if (account != null) {
+            builder.withValue(RawContacts.ACCOUNT_NAME, account.name);
+            builder.withValue(RawContacts.ACCOUNT_TYPE, account.type);
+        }
+        operationList.add(builder.build());
+
+        // do not allow empty value insert into database.
+        if (!TextUtils.isEmpty(name)) {
+            builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+            builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
+            builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+            builder.withValue(StructuredName.DISPLAY_NAME, name);
+            operationList.add(builder.build());
+        }
+
+        if (!TextUtils.isEmpty(phoneNumber)) {
+            builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+            builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
+            builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+            builder.withValue(Phone.TYPE, Phone.TYPE_MOBILE);
+            builder.withValue(Phone.NUMBER, phoneNumber);
+            builder.withValue(Data.IS_PRIMARY, 1);
+            operationList.add(builder.build());
+        }
+
+        if (anrArray != null) {
+            for (String anr : anrArray) {
+                if (!TextUtils.isEmpty(anr)) {
+                    builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+                    builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
+                    builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+                    builder.withValue(Phone.TYPE, Phone.TYPE_HOME);
+                    builder.withValue(Phone.NUMBER, anr);
+                    operationList.add(builder.build());
+                }
+            }
+        }
+
+        if (emailAddressArray != null) {
+            for (String emailAddress : emailAddressArray) {
+                if (!TextUtils.isEmpty(emailAddress)) {
+                    builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+                    builder.withValueBackReference(Email.RAW_CONTACT_ID, 0);
+                    builder.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+                    builder.withValue(Email.TYPE, Email.TYPE_MOBILE);
+                    builder.withValue(Email.ADDRESS, emailAddress);
+                    operationList.add(builder.build());
+                }
+            }
+        }
+
+        try {
+            ContentProviderResult[] results =
+                    resolver.applyBatch(ContactsContract.AUTHORITY, operationList);
+            for (ContentProviderResult result: results) {
+                if (result.uri == null) {
+                    success = false;
+                    break;
+                }
+            }
+            return success;
+        } catch (RemoteException e) {
+            Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
+            return false;
+        } catch (OperationApplicationException e) {
+            Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
+            return false;
+        }
+    }
+
+    public static Uri insertToCard(Context context, String name, String number, String emails,
+            String anrNumber, int subscription) {
+        // add the max count limit of Chinese code or not
+        if (!TextUtils.isEmpty(name)) {
+            final int maxLen = hasChinese(name) ? MAX_LENGTH_NAME_WITH_CHINESE_IN_SIM
+                    : MAX_LENGTH_NAME_IN_SIM;
+            if (name.length() > maxLen) {
+                name = name.substring(0, maxLen);
+            }
+        }
+        Uri result;
+        ContentValues mValues = new ContentValues();
+        mValues.clear();
+        mValues.put(SimContactsConstants.STR_TAG, name);
+        if (!TextUtils.isEmpty(number)) {
+            number = PhoneNumberUtils.stripSeparators(number);
+            if (number.length() > MAX_LENGTH_NUMBER_IN_SIM) {
+                number = number.substring(0, MAX_LENGTH_NUMBER_IN_SIM);
+            }
+
+            mValues.put(SimContactsConstants.STR_NUMBER, number);
+        }
+        if (!TextUtils.isEmpty(emails)) {
+            mValues.put(SimContactsConstants.STR_EMAILS, emails);
+        }
+        if (!TextUtils.isEmpty(anrNumber)) {
+            anrNumber = PhoneNumberUtils.stripSeparators(anrNumber);
+            mValues.put(SimContactsConstants.STR_ANRS, anrNumber);
+        }
+
+        SimContactsOperation mSimContactsOperation = new SimContactsOperation(context);
+        result = mSimContactsOperation.insert(mValues, subscription);
+
+        if (result != null) {
+            // we should import the contact to the sim account at the same time.
+            String[] value = new String[] {
+                    name, number, emails, anrNumber
+            };
+            insertToPhone(value, context.getContentResolver(),subscription);
+        } else {
+            Log.e(TAG, "export contact: [" + name + ", " + number + ", " + emails + "] to slot "
+                    + subscription + " failed");
+        }
+        return result;
+    }
+
+    public static Account getAcount(int sub) {
+        Account account = null;
+        if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+            if (sub == SimContactsConstants.SUB_1) {
+                account = new Account(SimContactsConstants.SIM_NAME_1,
+                        SimContactsConstants.ACCOUNT_TYPE_SIM);
+            } else if (sub == SimContactsConstants.SUB_2) {
+                account = new Account(SimContactsConstants.SIM_NAME_2,
+                        SimContactsConstants.ACCOUNT_TYPE_SIM);
+            }
+        } else {
+            if (sub == SimContactsConstants.SUB_1) {
+                account = new Account(SimContactsConstants.SIM_NAME,
+                        SimContactsConstants.ACCOUNT_TYPE_SIM);
+            }
+        }
+        if (account == null) {
+            account = new Account(SimContactsConstants.PHONE_NAME,
+                    SimContactsConstants.ACCOUNT_TYPE_PHONE);
+        }
+        return account;
+    }
+
+    public static int getEnabledSimCount() {
+        int mPhoneCount = TelephonyManager.getDefault().getPhoneCount();
+        int enabledSimCount = 0;
+        for (int i = 0; i < mPhoneCount; i++) {
+            if (TelephonyManager.SIM_STATE_READY == TelephonyManager
+                    .getDefault().getSimState(i)) {
+                enabledSimCount++;
+            }
+        }
+        return enabledSimCount;
+    }
+
+    public static int getSimFreeCount(Context context, int sub) {
+        String accountName = getAcount(sub).name;
+        int count = 0;
+
+        if (context == null) {
+            return 0;
+        }
+
+        Cursor queryCursor = context.getContentResolver().query(
+                RawContacts.CONTENT_URI,
+                new String[] {
+                    RawContacts._ID
+                },
+                RawContacts.ACCOUNT_NAME + " = '" + accountName + "' AND " + RawContacts.DELETED
+                        + " = 0", null, null);
+        if (queryCursor != null) {
+            try {
+                count = queryCursor.getCount();
+            } finally {
+                queryCursor.close();
+            }
+        }
+        return getAdnCount(sub) - count;
+    }
+
+    private static boolean hasChinese(String name) {
+        return name != null && name.getBytes().length > name.length();
+    }
+
+    /**
+     * Get SIM card aliases name, which defined in Settings
+     */
+    public static String getMultiSimAliasesName(Context context, int subscription) {
+        if (context == null || subscription < 0) {
+            return null;
+        }
+        String name = "";
+        if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+            name = Settings.System.getString(context.getContentResolver(),
+                    MULTI_SIM_NAME[subscription]);
+        }
+        if (TextUtils.isEmpty(name)) {
+            name = getSimAccountName(subscription);
+        }
+        return name;
+    }
+
+    /**
+     * Get SIM card icon index by slot
+     */
+    public static int getCurrentSimIconIndex(Context context, int slot) {
+        if (context == null || slot < SimContactsConstants.SUB_1
+                || slot >= TelephonyManager.getDefault().getPhoneCount()) {
+            return -1;
+        }
+
+        String simIconIndex = Settings.System.getString(context.getContentResolver(),
+                PREFERRED_SIM_ICON_INDEX);
+        if (TextUtils.isEmpty(simIconIndex)) {
+            return slot;
+        } else {
+            String[] indexs = simIconIndex.split(",");
+            if (slot >= indexs.length) {
+                return -1;
+            }
+            return Integer.parseInt(indexs[slot]);
+        }
+    }
+
 }
diff --git a/src/com/android/contacts/common/SimContactsConstants.java b/src/com/android/contacts/common/SimContactsConstants.java
new file mode 100644
index 0000000..759dcd9
--- /dev/null
+++ b/src/com/android/contacts/common/SimContactsConstants.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014, 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.
+
+ */
+package com.android.contacts.common;
+
+import android.telephony.SubscriptionManager;
+import com.android.internal.telephony.PhoneConstants;
+
+public interface SimContactsConstants {
+
+    public static final String SIM_NAME_1 = "SIM1";
+    public static final String SIM_NAME_2 = "SIM2";
+    public static final String SIM_NAME = "SIM";
+    public static final String PHONE_NAME = "PHONE";
+    public static final String PASSWORD = "";
+    public static final String ACCOUNT_TYPE_SIM = "com.android.sim";
+    public static final String ACCOUNT_TYPE_PHONE = "com.android.localphone";
+    public static final String SUB = PhoneConstants.SLOT_KEY;
+    public static final String ACCOUNT_TYPE = "account_type";
+    public static final String ACCOUNT_NAME = "account_name";
+    public static final String ACCOUNT_DATA = "data_set";
+    public static final String STR_TAG = "tag";
+    public static final String STR_NUMBER = "number";
+    public static final String STR_EMAILS = "emails";
+    public static final String STR_ANRS = "anrs";
+    public static final String STR_NEW_TAG = "newTag";
+    public static final String STR_NEW_NUMBER = "newNumber";
+    public static final String STR_NEW_EMAILS = "newEmails";
+    public static final String STR_NEW_ANRS = "newAnrs";
+    public static final String INTENT_EXPORT_COMPLETE =
+        "com.android.sim.INTENT_EXPORT_COMPLETE";
+    public static final String SIM_URI = "content://icc/adn";
+    public static final String SIM_SUB_URI = "content://icc/adn/subId/";
+    public static final String WITHOUT_SIM_FLAG ="no_sim";
+    public static final String IS_CONTACT = "is_contact";
+    public static final String RESULT_KEY = "result";
+    public static final String ACTION_MULTI_PICK =
+            "com.android.contacts.action.MULTI_PICK";
+    public static final String ACTION_MULTI_PICK_EMAIL =
+            "com.android.contacts.action.MULTI_PICK_EMAIL";
+    public static final String ACTION_MULTI_PICK_CALL =
+            "com.android.contacts.action.MULTI_PICK_CALL";
+    public static final String ACTION_MULTI_PICK_SIM =
+            "com.android.contacts.action.MULTI_PICK_SIM";
+    public static final int SUB_1 = PhoneConstants.SUB1;
+    public static final int SUB_2 = PhoneConstants.SUB2;
+    public static final int SUB_INVALID = SubscriptionManager.INVALID_SLOT_ID;
+
+}
+
+
diff --git a/src/com/android/contacts/common/SimContactsOperation.java b/src/com/android/contacts/common/SimContactsOperation.java
new file mode 100644
index 0000000..55c7b79
--- /dev/null
+++ b/src/com/android/contacts/common/SimContactsOperation.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2014, 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.
+
+ */
+
+package com.android.contacts.common;
+
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.ContentUris;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.CommonDataKinds;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.RawContacts;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.contacts.common.SimContactsConstants;
+
+public class SimContactsOperation {
+
+    private static final String  TAG = "SimContactsOperation";
+    private static final boolean DBG = true;
+    private static final int QUERY_TOKEN = 0;
+    private static final int INSERT_TOKEN = 1;
+    private static final int UPDATE_TOKEN = 2;
+    private static final int DELETE_TOKEN = 3;
+
+    public static final String[] ACCOUNT_PROJECTION = new String[] {
+        RawContacts._ID,
+        RawContacts.CONTACT_ID,
+        RawContacts.ACCOUNT_NAME,
+        RawContacts.ACCOUNT_TYPE,
+    };
+
+
+    private static final int ACCOUNT_COLUMN_RAW_ID = 0;
+    private static final int ACCOUNT_COLUMN_CONTACT_ID = 1;
+    private static final int ACCOUNT_COLUMN_NAME = 2;
+    private static final int ACCOUNT_COLUMN_TYPE = 3;
+    private static final int ACCOUNT_COLUMN_PHONE_NAME = 4;
+
+
+
+    private static Context mContext;
+    private ContentResolver mResolver;
+    private ContentValues mValues = new ContentValues();
+
+
+    public SimContactsOperation(Context context) {
+        this.mContext = context;
+        this.mResolver = context.getContentResolver();
+    }
+
+
+    public Uri insert(ContentValues values, int subscription) {
+
+        Uri uri = getContentUri(subscription);
+        String number = values.getAsString(SimContactsConstants.STR_NUMBER);
+        String anrs = values.getAsString(SimContactsConstants.STR_ANRS);
+        String emails = values.getAsString(SimContactsConstants.STR_EMAILS);
+        values.put(SimContactsConstants.STR_NUMBER,PhoneNumberUtils.stripSeparators(number));
+        values.put(SimContactsConstants.STR_ANRS,PhoneNumberUtils.stripSeparators(anrs));
+        values.put(SimContactsConstants.STR_EMAILS,emails);
+
+        Uri resultUri;
+        resultUri = mResolver.insert(uri,values);
+        return resultUri;
+    }
+
+    public int update(ContentValues values,int subscription) {
+        Uri uri = getContentUri(subscription);
+
+        int result;
+        String oldNumber = values.getAsString(SimContactsConstants.STR_NUMBER);
+        String newNumber = values.getAsString(SimContactsConstants.STR_NEW_NUMBER);
+        String oldAnrs = values.getAsString(SimContactsConstants.STR_ANRS);
+        String newAnrs = values.getAsString(SimContactsConstants.STR_NEW_ANRS);
+        values.put(SimContactsConstants.STR_NUMBER,PhoneNumberUtils.stripSeparators(oldNumber));
+        values.put(SimContactsConstants.STR_NEW_NUMBER,PhoneNumberUtils.stripSeparators(newNumber));
+        values.put(SimContactsConstants.STR_ANRS,PhoneNumberUtils.stripSeparators(oldAnrs));
+        values.put(SimContactsConstants.STR_NEW_ANRS,PhoneNumberUtils.stripSeparators(newAnrs));
+
+        result = mResolver.update(uri,values,null,null);
+        return result;
+
+    }
+
+    public int delete(ContentValues values, int subscription) {
+        int result;
+        StringBuilder buf = new StringBuilder();
+        String num = null;
+        String name = values.getAsString(SimContactsConstants.STR_TAG);
+        String number = values.getAsString(SimContactsConstants.STR_NUMBER);
+        String emails = values.getAsString(SimContactsConstants.STR_EMAILS);
+        String anrs = values.getAsString(SimContactsConstants.STR_ANRS);
+        if (number != null)
+            num = PhoneNumberUtils.stripSeparators(number);
+        if (anrs != null)
+            anrs = PhoneNumberUtils.stripSeparators(anrs);
+        Uri uri = getContentUri(subscription);
+
+
+        if (!TextUtils.isEmpty(name)) {
+            buf.append("tag='");
+            buf.append(name);
+            buf.append("'");
+        }
+        if (!TextUtils.isEmpty(num)) {
+            buf.append(" AND number='");
+            buf.append(num);
+            buf.append("'");
+        }
+        if (!TextUtils.isEmpty(emails)) {
+            buf.append(" AND emails='");
+            buf.append(emails);
+            buf.append("'");
+        }
+        if (!TextUtils.isEmpty(anrs)) {
+            buf.append(" AND anrs='");
+            buf.append(anrs);
+            buf.append("'");
+        }
+
+        result = mResolver.delete(uri,buf.toString(),null);
+        return result;
+
+    }
+
+    private Uri getContentUri(int subscription) {
+        Uri uri = null;
+        long[] subId = SubscriptionManager.getSubId(subscription);
+
+        if (subId != null && TelephonyManager.getDefault().isMultiSimEnabled()) {
+            uri = Uri.parse(SimContactsConstants.SIM_SUB_URI + subId[0]);
+        } else {
+            uri = Uri.parse(SimContactsConstants.SIM_URI);
+        }
+        return uri;
+    }
+
+    private static Cursor setupAccountCursor(long contactId) {
+        ContentResolver resolver = mContext.getContentResolver();
+
+        Cursor cursor = null;
+        try {
+            cursor = resolver.query(RawContacts.CONTENT_URI,
+                    ACCOUNT_PROJECTION,
+                    RawContacts.CONTACT_ID + "="
+                    + Long.toString(contactId), null, null);
+        } catch (Exception e) {
+            Log.e(TAG, e.getMessage());
+        } finally {
+            if (cursor != null && cursor.moveToFirst()) {
+                return cursor;
+            }
+            if (cursor != null) {
+                cursor.close();
+            }
+            cursor = null;
+            return null;
+        }
+    }
+
+    public static ContentValues getSimAccountValues(long contactId) {
+        ContentValues mValues = new ContentValues();
+        Cursor cursor = setupAccountCursor(contactId);
+        if (cursor == null || cursor.getCount() == 0) {
+            mValues.clear();
+            return mValues;
+        }
+        long rawContactId = cursor.getLong(cursor.getColumnIndex(RawContacts._ID));
+        String accountName = cursor.getString(cursor.getColumnIndex(RawContacts.ACCOUNT_NAME));
+        String accountType = cursor.getString(cursor.getColumnIndex(RawContacts.ACCOUNT_TYPE));
+        cursor.close();
+        if (SimContactsConstants.ACCOUNT_TYPE_SIM.equals(accountType)) {
+            mValues.clear();
+            String name = getContactItems(rawContactId,StructuredName.CONTENT_ITEM_TYPE,
+                     ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
+            mValues.put(SimContactsConstants.STR_TAG,name);
+
+            String number = getContactPhoneNumber(rawContactId,
+                Phone.CONTENT_ITEM_TYPE, String.valueOf(Phone.TYPE_MOBILE),
+                ContactsContract.CommonDataKinds.Phone.DATA);
+            mValues.put(SimContactsConstants.STR_NUMBER,number);
+
+            int sub = getSimSubscription(contactId);
+
+            if (MoreContactUtils.canSaveAnr(sub)) {
+                String anrs = getContactPhoneNumber(rawContactId,
+                        Phone.CONTENT_ITEM_TYPE, String.valueOf(Phone.TYPE_HOME),
+                        ContactsContract.CommonDataKinds.Phone.DATA);
+                mValues.put(SimContactsConstants.STR_ANRS, anrs);
+            }
+
+            if (MoreContactUtils.canSaveEmail(sub)) {
+                String emails = getContactItems(rawContactId,
+                        Email.CONTENT_ITEM_TYPE, ContactsContract.CommonDataKinds.Email.DATA);
+                mValues.put(SimContactsConstants.STR_EMAILS, emails);
+            }
+        }
+        return mValues;
+    }
+
+    public static int getSimSubscription(long contactId) {
+        int subscription = SimContactsConstants.SUB_INVALID;
+        Cursor cursor = setupAccountCursor(contactId);
+        if (cursor == null || cursor.getCount() == 0) {
+            return subscription;
+        }
+
+        String accountName = cursor.getString(cursor.getColumnIndex(RawContacts.ACCOUNT_NAME));
+        String accountType = cursor.getString(cursor.getColumnIndex(RawContacts.ACCOUNT_TYPE));
+        if (accountType == null || accountName == null) {
+            return subscription;
+        }
+        if (SimContactsConstants.ACCOUNT_TYPE_SIM.equals(accountType)) {
+            subscription = MoreContactUtils.getSubscription(accountType, accountName);
+        }
+        cursor.close();
+        return subscription;
+    }
+
+
+    private static String getContactItems(long rawContactId, String selectionArg,
+                                                String columnName) {
+        StringBuilder retval = new StringBuilder();
+        Uri baseUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
+        Uri dataUri = Uri.withAppendedPath(baseUri, RawContacts.Data.CONTENT_DIRECTORY);
+
+        Cursor c = null;
+        try {
+            c = mContext.getContentResolver().query(dataUri, null,
+                    Data.MIMETYPE + "=?", new String[] {selectionArg}, null);
+            if (c == null || c.getCount() == 0) {
+                if(c != null) {
+                    c.close();
+                }
+                return null;
+            }
+            c.moveToPosition(-1);
+
+            while (c.moveToNext()) {
+                if (!TextUtils.isEmpty(retval.toString())) {
+                    retval.append(",");
+                }
+                retval.append(c.getString(c.getColumnIndex(columnName)));
+            }
+
+        } catch (Exception e) {
+            Log.e(TAG, e.getMessage());
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+
+        return retval.toString();
+    }
+
+    private static
+    String getContactPhoneNumber(long rawContactId, String selectionArg1,
+                            String selectionArg2, String columnName) {
+        StringBuilder retval = new StringBuilder();
+        Uri baseUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
+        Uri dataUri = Uri.withAppendedPath(baseUri, RawContacts.Data.CONTENT_DIRECTORY);
+
+        Cursor c = null;
+        try {
+            c = mContext.getContentResolver().query(dataUri, null,
+                    Data.MIMETYPE + "=? AND " + Phone.TYPE + "=?",
+                    new String[] {selectionArg1,selectionArg2}, null);
+            if (c == null || c.getCount() == 0) {
+                if(c != null) {
+                    c.close();
+                }
+                return null;
+            }
+            c.moveToPosition(-1);
+
+            while (c.moveToNext()) {
+                if (!TextUtils.isEmpty(retval.toString())) {
+                    retval.append(",");
+                }
+                retval.append(c.getString(c.getColumnIndex(columnName)));
+            }
+
+        } catch (Exception e) {
+            Log.e(TAG, e.getMessage());
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+
+        return retval.toString();
+    }
+
+
+    private void log(String msg) {
+        if (DBG) Log.d(TAG,  msg);
+    }
+
+}
diff --git a/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java b/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java
index c2ebbbf..26fc771 100644
--- a/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java
+++ b/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java
@@ -65,7 +65,7 @@
         final SelectAccountDialogFragment instance = new SelectAccountDialogFragment();
         instance.setArguments(args);
         instance.setTargetFragment(targetFragment, 0);
-        instance.show(fragmentManager, null);
+        instance.show(fragmentManager, SelectAccountDialogFragment.TAG);
     }
 
     @Override
diff --git a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
index 8d87714..6b1433d 100644
--- a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
+++ b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
@@ -1,5 +1,7 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,19 +18,42 @@
 
 package com.android.contacts.common.interactions;
 
+import android.accounts.Account;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.FragmentManager;
+import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
 import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.content.DialogInterface.OnCancelListener;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.Resources;
+import android.content.OperationApplicationException;
 import android.database.Cursor;
+import android.text.TextUtils;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.Settings;
 import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -37,8 +62,13 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.SimContactsOperation;
+import com.android.contacts.common.SimContactsConstants;
 import com.android.contacts.common.R;
 import com.android.contacts.common.editor.SelectAccountDialogFragment;
+import com.android.contacts.common.list.AccountFilterActivity;
+import com.android.contacts.common.list.ContactListFilter;
 import com.android.contacts.common.model.AccountTypeManager;
 import com.android.contacts.common.model.account.AccountWithDataSet;
 import com.android.contacts.common.util.AccountSelectionUtil;
@@ -48,6 +78,8 @@
 import com.android.dialerbind.analytics.AnalyticsDialogFragment;
 
 import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
 
 /**
  * An dialog invoked to import/export contacts.
@@ -56,13 +88,71 @@
         implements SelectAccountDialogFragment.Listener {
     public static final String TAG = "ImportExportDialogFragment";
 
+    private static final String SIM_INDEX = "sim_index";
+
     private static final String KEY_RES_ID = "resourceId";
     private static final String ARG_CONTACTS_ARE_AVAILABLE = "CONTACTS_ARE_AVAILABLE";
+    private static int SIM_ID_INVALID = -1;
+    private static int mSelectedSim = SIM_ID_INVALID;
+
+    private static final boolean DEBUG = true;
+
+    // This values must be consistent with ImportExportDialogFragment.SUBACTIVITY_EXPORT_CONTACTS.
+    // This values is set 101,That is avoid to conflict with other new subactivity.
+    public static final int SUBACTIVITY_SHARE_VISILBLE_CONTACTS = 101;
+    public static final int MAX_COUNT_ALLOW_SHARE_CONTACT = 2000;
 
     private final String[] LOOKUP_PROJECTION = new String[] {
             Contacts.LOOKUP_KEY
     };
 
+    static final int PHONE_ID_COLUMN_INDEX = 0;
+    static final int PHONE_TYPE_COLUMN_INDEX = 1;
+    static final int PHONE_LABEL_COLUMN_INDEX = 2;
+    static final int PHONE_NUMBER_COLUMN_INDEX = 3;
+    static final int PHONE_DISPLAY_NAME_COLUMN_INDEX = 4;
+    static final int PHONE_CONTACT_ID_COLUMN_INDEX = 5;
+    // This value needs to start at 7. See {@link PeopleActivity}.
+    public static final int SUBACTIVITY_MULTI_PICK_CONTACT = 7;
+    //TODO: we need to refactor the export code in future release.
+    // QRD enhancement: export subscription selected by user
+    public static int mExportSub;
+    //this flag is the same as defined in MultiPickContactActivit
+    private static final String EXT_NOT_SHOW_SIM_FLAG = "not_sim_show";
+    // QRD enhancement: Toast handler for exporting concat to sim card
+    private static final int TOAST_EXPORT_FAILED = 0;
+    private static final int TOAST_EXPORT_FINISHED = 1;
+    // only for sim card is full
+    private static final int TOAST_SIM_CARD_FULL = 2;
+    // only for contact name too long
+    private static final int TOAST_CONTACT_NAME_TOO_LONG = 3;
+    // there is a case export is canceled by user
+    private static final int TOAST_EXPORT_CANCELED = 4;
+    // only for not have phone number or email address
+    private static final int TOAST_EXPORT_NO_PHONE_OR_EMAIL = 5;
+    // only for sim contacts haven't been loaded completely
+    private static final int TOAST_SIM_CARD_NOT_LOAD_COMPLETE = 6;
+    private SimContactsOperation mSimContactsOperation;
+    private ArrayAdapter<Integer> mAdapter;
+    private Activity mActivity;
+    private static boolean isExportingToSIM = false;
+    public static boolean isExportingToSIM(){
+        return isExportingToSIM;
+    }
+    private static ExportToSimThread mExportThread = null;
+    public ExportToSimThread createExportToSimThread(int subscription,
+        ArrayList<String[]> contactList, Activity mActivity){
+        if (mExportThread == null)
+            mExportThread = new ExportToSimThread(subscription, contactList,  mActivity);
+        return mExportThread;
+    }
+
+    public static void destroyExportToSimThread(){
+        mExportThread = null;
+    }
+    public void showExportToSIMProgressDialog(Activity activity){
+        mExportThread.showExportProgressDialog(activity);
+    }
     /** Preferred way to show this dialog */
     public static void show(FragmentManager fragmentManager, boolean contactsAreAvailable,
             Class callingActivity) {
@@ -83,6 +173,7 @@
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         // Wrap our context to inflate list items using the correct theme
+        mActivity = getActivity();
         final Resources res = getActivity().getResources();
         final LayoutInflater dialogInflater = (LayoutInflater)getActivity()
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -91,7 +182,7 @@
                 VCardCommonArguments.ARG_CALLING_ACTIVITY);
 
         // Adapter that shows a list of string resources
-        final ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(getActivity(),
+        mAdapter = new ArrayAdapter<Integer>(getActivity(),
                 R.layout.select_dialog_item) {
             @Override
             public View getView(int position, View convertView, ViewGroup parent) {
@@ -104,41 +195,29 @@
             }
         };
 
-        final TelephonyManager manager =
-                (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
-
-        if (manager != null && manager.hasIccCard()
-                && res.getBoolean(R.bool.config_allow_sim_import)) {
-            adapter.add(R.string.import_from_sim);
-        }
-        if (res.getBoolean(R.bool.config_allow_import_from_sdcard)) {
-            adapter.add(R.string.import_from_sdcard);
-        }
-        if (res.getBoolean(R.bool.config_allow_export_to_sdcard)) {
-            if (contactsAreAvailable) {
-                adapter.add(R.string.export_to_sdcard);
-            }
-        }
-        if (res.getBoolean(R.bool.config_allow_share_visible_contacts)) {
-            if (contactsAreAvailable) {
-                adapter.add(R.string.share_visible_contacts);
-            }
-        }
+        // Manually call notifyDataSetChanged() to refresh the list.
+        mAdapter.setNotifyOnChange(false);
+        loadData(contactsAreAvailable);
 
         final DialogInterface.OnClickListener clickListener =
                 new DialogInterface.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int which) {
-                boolean dismissDialog;
-                final int resId = adapter.getItem(which);
+                final int resId = mAdapter.getItem(which);
                 switch (resId) {
-                    case R.string.import_from_sim:
+                    case R.string.import_from_sim: {
+                        handleImportFromSimRequest(resId);
+                        break;
+                    }
                     case R.string.import_from_sdcard: {
-                        dismissDialog = handleImportRequest(resId);
+                        handleImportRequest(resId);
+                        break;
+                    }
+                    case R.string.export_to_sim: {
+                        handleExportToSimRequest(resId);
                         break;
                     }
                     case R.string.export_to_sdcard: {
-                        dismissDialog = true;
                         Intent exportIntent = new Intent(getActivity(), ExportVCardActivity.class);
                         exportIntent.putExtra(VCardCommonArguments.ARG_CALLING_ACTIVITY,
                                 callingActivity);
@@ -146,29 +225,74 @@
                         break;
                     }
                     case R.string.share_visible_contacts: {
-                        dismissDialog = true;
                         doShareVisibleContacts();
                         break;
                     }
                     default: {
-                        dismissDialog = true;
                         Log.e(TAG, "Unexpected resource: "
                                 + getActivity().getResources().getResourceEntryName(resId));
                     }
                 }
-                if (dismissDialog) {
                     dialog.dismiss();
-                }
             }
         };
         return new AlertDialog.Builder(getActivity())
                 .setTitle(contactsAreAvailable
                         ? R.string.dialog_import_export
                         : R.string.dialog_import)
-                .setSingleChoiceItems(adapter, -1, clickListener)
+                .setSingleChoiceItems(mAdapter, -1, clickListener)
                 .create();
     }
 
+    /**
+     * Loading the menu list data.
+     * @param contactsAreAvailable
+     */
+    private void loadData(boolean contactsAreAvailable) {
+        if (null == mActivity && null == mAdapter) {
+            return;
+        }
+
+        mAdapter.clear();
+        final Resources res = mActivity.getResources();
+        boolean hasIccCard = false;
+        if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+           for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+               hasIccCard = TelephonyManager.getDefault().hasIccCard(i);
+               if (hasIccCard) {
+                  break;
+               }
+           }
+        } else {
+           hasIccCard = TelephonyManager.getDefault().hasIccCard();
+        }
+
+        if (hasIccCard
+                && res.getBoolean(R.bool.config_allow_sim_import)) {
+            mAdapter.add(R.string.import_from_sim);
+        }
+        if (res.getBoolean(R.bool.config_allow_import_from_sdcard)) {
+            mAdapter.add(R.string.import_from_sdcard);
+        }
+
+        if (hasIccCard) {
+            mAdapter.add(R.string.export_to_sim);
+        }
+        if (res.getBoolean(R.bool.config_allow_export_to_sdcard)) {
+            // If contacts are available and there is at least one contact in
+            // database, show "Export to SD card" menu item. Otherwise hide it
+            // because it makes no sense.
+            if (contactsAreAvailable) {
+                mAdapter.add(R.string.export_to_sdcard);
+            }
+        }
+        if (res.getBoolean(R.bool.config_allow_share_visible_contacts)) {
+            if (contactsAreAvailable) {
+                mAdapter.add(R.string.share_visible_contacts);
+            }
+        }
+    }
+
     private void doShareVisibleContacts() {
         // TODO move the query into a loader and do this in a background thread
         final Cursor cursor = getActivity().getContentResolver().query(Contacts.CONTENT_URI,
@@ -212,7 +336,7 @@
         // - more than one accounts -> ask the user
         // - just one account -> use the account without asking the user
         // - no account -> use phone-local storage without asking the user
-        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(getActivity());
+        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mActivity);
         final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
         final int size = accountList.size();
         if (size > 1) {
@@ -220,9 +344,9 @@
             final Bundle args = new Bundle();
             args.putInt(KEY_RES_ID, resId);
             SelectAccountDialogFragment.show(
-                    getFragmentManager(), this,
+                    mActivity.getFragmentManager(), this,
                     R.string.dialog_new_contact_account,
-                    AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, args);
+                    AccountListFilter.ACCOUNTS_CONTACT_WRITABLE_WITHOUT_SIM, args);
 
             // In this case, because this DialogFragment is used as a target fragment to
             // SelectAccountDialogFragment, we can't close it yet.  We close the dialog when
@@ -230,7 +354,7 @@
             return false;
         }
 
-        AccountSelectionUtil.doImport(getActivity(), resId,
+        AccountSelectionUtil.doImport(mActivity, resId,
                 (size == 1 ? accountList.get(0) : null));
         return true; // Close the dialog.
     }
@@ -240,7 +364,7 @@
      */
     @Override
     public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
-        AccountSelectionUtil.doImport(getActivity(), extraArgs.getInt(KEY_RES_ID), account);
+        AccountSelectionUtil.doImport(mActivity, extraArgs.getInt(KEY_RES_ID), account);
 
         // At this point the dialog is still showing (which is why we can use getActivity() above)
         // So close it.
@@ -252,4 +376,450 @@
         // See onAccountChosen() -- at this point the dialog is still showing.  Close it.
         dismiss();
     }
+
+    private class ExportToSimSelectListener implements DialogInterface.OnClickListener {
+        public void onClick(DialogInterface dialog, int which) {
+            if (which >= 0) {
+                mExportSub = which;
+            } else if (which == DialogInterface.BUTTON_POSITIVE) {
+                Intent pickPhoneIntent = new Intent(
+                        SimContactsConstants.ACTION_MULTI_PICK, Contacts.CONTENT_URI);
+                // do not show the contacts in SIM card
+                pickPhoneIntent.putExtra(AccountFilterActivity.KEY_EXTRA_CONTACT_LIST_FILTER,
+                        ContactListFilter
+                                .createFilterWithType(ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS));
+                pickPhoneIntent.putExtra(EXT_NOT_SHOW_SIM_FLAG, true);
+                pickPhoneIntent.putExtra(SimContactsConstants.IS_CONTACT,true);
+                mActivity.startActivityForResult(pickPhoneIntent, SUBACTIVITY_MULTI_PICK_CONTACT);
+            }
+        }
+    }
+
+    public class ImportFromSimSelectListener implements DialogInterface.OnClickListener {
+        public void onClick(DialogInterface dialog, int which) {
+            if (which >= 0) {
+                AccountSelectionUtil.setImportSubscription(which);
+            } else if (which == DialogInterface.BUTTON_POSITIVE) {
+                handleImportRequest(R.string.import_from_sim);
+            }
+        }
+    }
+
+    /**
+     * A thread that export contacts to sim card
+     */
+    public class ExportToSimThread extends Thread {
+        private int subscription;
+        private boolean canceled;
+        private ArrayList<String[]> contactList;
+        private ProgressDialog mExportProgressDlg;
+        private ContentValues mValues = new ContentValues();
+        Activity mPeople;
+        private int freeSimCount = 0;
+
+        public ExportToSimThread(int subscription, ArrayList<String[]> contactList,
+            Activity mActivity) {
+            super();
+            this.subscription = subscription;
+            this.contactList = contactList;
+            canceled = false;
+            mPeople = mActivity;
+            showExportProgressDialog(mPeople);
+        }
+
+        @Override
+        public void run() {
+            isExportingToSIM = true;
+            Account account = MoreContactUtils.getAcount(subscription);
+            boolean isAirplaneMode = false;
+            boolean isSimCardFull = false;
+            boolean isSimCardLoaded = true;
+            // GoogleSource.createMyContactsIfNotExist(account, getActivity());
+            // in case export is stopped, record the count of inserted successfully
+            int insertCount = 0;
+            freeSimCount = MoreContactUtils.getSimFreeCount(mPeople,subscription);
+
+            mSimContactsOperation = new SimContactsOperation(mPeople);
+            Cursor cr = null;
+            // call query first, otherwise insert will fail if this insert is called
+            // without any query before
+            try{
+                long[] subId = SubscriptionManager.getSubId(subscription);
+                if (subId != null
+                        && TelephonyManager.getDefault().isMultiSimEnabled()) {
+                    cr = mPeople.getContentResolver().query(
+                            Uri.parse(SimContactsConstants.SIM_SUB_URI
+                                    + subId[0]), null, null, null, null);
+                } else {
+                    cr = mPeople.getContentResolver().query(
+                            Uri.parse(SimContactsConstants.SIM_URI), null,
+                            null, null, null);
+                }
+            } catch (NullPointerException e) {
+                Log.e(TAG, "Exception:" + e);
+            } finally {
+                if (cr != null) {
+                    cr.close();
+                }
+            }
+
+            boolean canSaveAnr = MoreContactUtils.canSaveAnr(subscription);
+            boolean canSaveEmail = MoreContactUtils.canSaveEmail(subscription);
+            int emptyAnr = MoreContactUtils.getSpareAnrCount(subscription);
+            int emptyEmail = MoreContactUtils
+                    .getSpareEmailCount(subscription);
+            int emptyNumber = freeSimCount + emptyAnr;
+
+            Log.d(TAG, "freeSimCount = " + freeSimCount);
+            String emails = null;
+                if (contactList != null) {
+                    Iterator<String[]> iterator = contactList.iterator();
+                    while (iterator.hasNext() && !canceled && !isAirplaneMode && isSimCardLoaded) {
+                        String[] contactInfo = iterator.next();
+                        String name = "";
+                        ArrayList<String> arrayNumber = new ArrayList<String>();
+                        ArrayList<String> arrayEmail = new ArrayList<String>();
+
+                        Uri dataUri = Uri.withAppendedPath(
+                                ContentUris.withAppendedId(Contacts.CONTENT_URI,
+                                        Long.parseLong(contactInfo[1])),
+                                Contacts.Data.CONTENT_DIRECTORY);
+                        final String[] projection = new String[] {
+                                Contacts._ID, Contacts.Data.MIMETYPE, Contacts.Data.DATA1,
+                        };
+                        Cursor c = mPeople.getContentResolver().query(dataUri, projection, null,
+                                null, null);
+
+                        if (c != null && c.moveToFirst()) {
+                            do {
+                                String mimeType = c.getString(1);
+                                if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                                    String number = c.getString(2);
+                                    if (!TextUtils.isEmpty(number) && emptyNumber-- >0) {
+                                        arrayNumber.add(number);
+                                    }
+                                } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                                    name = c.getString(2);
+                                }
+                                if (canSaveEmail) {
+                                    if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                                        String email = c.getString(2);
+                                        if (!TextUtils.isEmpty(email) && emptyEmail-- > 0) {
+                                            arrayEmail.add(email);
+                                        }
+                                    }
+                                }
+                            } while (c.moveToNext());
+                        }
+                        if (c != null) {
+                            c.close();
+                        }
+
+                        if (freeSimCount > 0 && 0 == arrayNumber.size()
+                                && 0 == arrayEmail.size()) {
+                            mToastHandler.sendMessage(mToastHandler.obtainMessage(
+                                    TOAST_EXPORT_NO_PHONE_OR_EMAIL, name));
+                            continue;
+                        }
+
+                        int phoneCountInOneSimContact = 1;
+                        int emailCountInOneSimContact = 0;
+                        if (canSaveAnr) {
+                            int num = MoreContactUtils.getOneSimAnrCount(subscription);
+                            phoneCountInOneSimContact = num > 1 ? (num + 1) : 2;
+                        }
+                        if (canSaveEmail) {
+                            emailCountInOneSimContact = MoreContactUtils
+                                    .getOneSimEmailCount(subscription);
+                        }
+                        int nameCount = (name != null && !name.equals("")) ? 1 : 0;
+                        int groupNumCount = (arrayNumber.size() % phoneCountInOneSimContact) != 0 ?
+                                (arrayNumber.size() / phoneCountInOneSimContact + 1)
+                                : (arrayNumber.size() / phoneCountInOneSimContact);
+                        int groupEmailCount = emailCountInOneSimContact == 0 ? 0
+                                : ((arrayEmail.size() % emailCountInOneSimContact) != 0 ? (
+                                        arrayEmail.size() / emailCountInOneSimContact + 1)
+                                        : (arrayEmail.size() / emailCountInOneSimContact));
+                        //recalute the group when spare anr is not enough
+                        if (canSaveAnr && emptyAnr <= groupNumCount) {
+                            groupNumCount = arrayNumber.size() - emptyAnr;
+                        }
+                        int groupCount = Math.max(groupEmailCount,
+                                Math.max(nameCount, groupNumCount));
+
+                        Uri result = null;
+                        if (DEBUG) {
+                            Log.d(TAG, "GroupCount = " + groupCount);
+                        }
+                        for (int i = 0; i < groupCount; i++) {
+                            if (freeSimCount > 0) {
+                                String num = arrayNumber.size() > 0 ? arrayNumber.remove(0) : null;
+                                StringBuilder anrNum = new StringBuilder();
+                                StringBuilder email = new StringBuilder();
+                                if (canSaveAnr && emptyAnr-- > 0) {
+                                    for (int j = 1; j < phoneCountInOneSimContact; j++) {
+                                        if (arrayNumber.size() > 0 && emptyAnr-- > 0 ) {
+                                            String s = arrayNumber.remove(0);
+                                            if (s.length() > MoreContactUtils
+                                                    .MAX_LENGTH_NUMBER_IN_SIM) {
+                                                s = s.substring(0,
+                                                        MoreContactUtils.MAX_LENGTH_NUMBER_IN_SIM);
+                                            }
+                                            anrNum.append(s);
+                                            anrNum.append(",");
+                                        }
+                                    }
+                                }
+                                if (canSaveEmail) {
+                                    for (int j = 0; j < emailCountInOneSimContact; j++) {
+                                        if (arrayEmail.size() > 0) {
+                                            String s = arrayEmail.remove(0);
+                                            if (s.length() > MoreContactUtils
+                                                    .MAX_LENGTH_EMAIL_IN_SIM) {
+                                                s = s.substring(0,
+                                                        MoreContactUtils.MAX_LENGTH_EMAIL_IN_SIM);
+                                            }
+                                            email.append(s);
+                                            email.append(",");
+                                        }
+                                    }
+                                }
+
+                                result = MoreContactUtils.insertToCard(mPeople, name, num,
+                                        email.toString(), anrNum.toString(), subscription);
+
+                                if (null == result) {
+                                    // add toast handler when sim card is full
+                                    if ((MoreContactUtils.getAdnCount(subscription) > 0)
+                                            && (MoreContactUtils.getSimFreeCount(mPeople,
+                                                    subscription) == 0)) {
+                                        isSimCardFull = true;
+                                        mToastHandler.sendEmptyMessage(TOAST_SIM_CARD_FULL);
+                                        break;
+                                    } else {
+                                        isAirplaneMode = MoreContactUtils
+                                                .isAPMOnAndSIMPowerDown(mPeople);
+                                        if (isAirplaneMode) {
+                                            mToastHandler.sendEmptyMessage(TOAST_EXPORT_FAILED);
+                                            break;
+                                        } else {
+                                            continue;
+                                        }
+                                    }
+                                } else {
+                                    if (DEBUG) {
+                                        Log.d(TAG, "Exported contact [" + name + ", "
+                                                + contactInfo[0] + ", " + contactInfo[1]
+                                                + "] to sub " + subscription);
+                                    }
+                                    insertCount++;
+                                    freeSimCount--;
+                                }
+                            } else {
+                                if (MoreContactUtils.getAdnCount(subscription) == 0) {
+                                    isSimCardLoaded = false;
+                                    mToastHandler.sendEmptyMessage(
+                                            TOAST_SIM_CARD_NOT_LOAD_COMPLETE);
+                                } else {
+                                    isSimCardFull = true;
+                                    mToastHandler.sendEmptyMessage(TOAST_SIM_CARD_FULL);
+                                }
+                                break;
+                            }
+                        }
+
+                        if (isSimCardFull) {
+                            break;
+                        }
+                    }
+                }
+            if (mExportProgressDlg != null) {
+                mExportProgressDlg.dismiss();
+                mExportProgressDlg = null;
+            }
+
+            if (!isAirplaneMode && !isSimCardFull) {
+                // if canceled, show toast indicating export is interrupted.
+                if (canceled) {
+                    mToastHandler.sendMessage(mToastHandler.obtainMessage(TOAST_EXPORT_CANCELED,
+                            insertCount, 0));
+                } else {
+                    mToastHandler.sendEmptyMessage(TOAST_EXPORT_FINISHED);
+                }
+            }
+            isExportingToSIM = false;
+            Intent intent = new Intent(SimContactsConstants.INTENT_EXPORT_COMPLETE);
+            mPeople.sendBroadcast(intent);
+        }
+
+        private Handler mToastHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case TOAST_EXPORT_FAILED:
+                        Toast.makeText(mPeople, R.string.export_failed, Toast.LENGTH_SHORT).show();
+                        break;
+                    case TOAST_EXPORT_FINISHED:
+                        Toast.makeText(mPeople, R.string.export_finished, Toast.LENGTH_SHORT)
+                            .show();
+                        break;
+
+                    // add toast handler when sim card is full
+                    case TOAST_SIM_CARD_FULL:
+                        Toast.makeText(mPeople, R.string.sim_card_full, Toast.LENGTH_SHORT).show();
+                        break;
+
+                    //add the max count limit of Chinese code or not
+                    case TOAST_CONTACT_NAME_TOO_LONG:
+                        Toast.makeText(mPeople, R.string.tag_too_long, Toast.LENGTH_SHORT).show();
+                        break;
+
+                     // add toast handler when export is canceled
+                    case TOAST_EXPORT_CANCELED:
+                        int exportCount = msg.arg1;
+                        Toast.makeText(mPeople,mPeople.getString(R.string.export_cancelled,
+                            String.valueOf(exportCount)), Toast.LENGTH_SHORT).show();
+                        break;
+
+                    // add toast handler when no phone or email
+                    case TOAST_EXPORT_NO_PHONE_OR_EMAIL:
+                        String name = (String) msg.obj;
+                        Toast.makeText(mPeople,
+                                mPeople.getString(R.string.export_no_phone_or_email, name),
+                                Toast.LENGTH_SHORT).show();
+                        break;
+                    case TOAST_SIM_CARD_NOT_LOAD_COMPLETE:
+                        Toast.makeText(mPeople, R.string.sim_contacts_not_load,
+                                Toast.LENGTH_SHORT).show();
+                        break;
+                }
+            }
+        };
+
+        public void showExportProgressDialog(Activity activity){
+            mPeople = activity;
+            mExportProgressDlg = new ProgressDialog(mPeople);
+            mExportProgressDlg.setTitle(R.string.export_to_sim);
+            mExportProgressDlg.setOnCancelListener(new OnCancelListener() {
+                public void onCancel(DialogInterface dialog) {
+                    Log.d(TAG, "Cancel exporting contacts");
+                    canceled = true;
+                }
+            });
+            mExportProgressDlg.setMessage(mPeople.getString(R.string.exporting));
+            mExportProgressDlg.setProgressNumberFormat(mPeople.getString(
+                R.string.reading_vcard_files));
+            mExportProgressDlg.setMax(contactList.size());
+            //mExportProgressDlg.setProgress(insertCount);
+
+            // set cancel dialog by touching outside disabled.
+            mExportProgressDlg.setCanceledOnTouchOutside(false);
+
+            // add a cancel button to let user cancel explicitly.
+            mExportProgressDlg.setButton(DialogInterface.BUTTON_NEGATIVE,
+                mPeople.getString(R.string.progressdialog_cancel),
+                    new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            if (DEBUG) {
+                                Log.d(TAG, "Cancel exporting contacts by click button");
+                            }
+                            canceled = true;
+                        }
+                    });
+
+            mExportProgressDlg.show();
+        }
+    }
+
+    public ImportFromSimSelectListener listener;
+    /**
+     * Create a {@link Dialog} that allows the user to pick from a bulk import
+     * or bulk export task across all contacts.
+     */
+    private Dialog displayImportExportDialog(int id, Bundle bundle) {
+    Dialog diag;
+        switch (id) {
+            case R.string.import_from_sim_select: {
+                    listener = new ImportFromSimSelectListener();
+                    showSimSelectDialog();
+                    break;
+            }
+            case R.string.export_to_sim: {
+                String[] items = new String[TelephonyManager.getDefault().getPhoneCount()];
+                for (int i = 0; i < items.length; i++) {
+                items[i] = getString(R.string.export_to_sim) + ": "
+                        + MoreContactUtils.getMultiSimAliasesName(mActivity, i);
+                }
+                mExportSub = SimContactsConstants.SUB_1;
+                ExportToSimSelectListener listener = new ExportToSimSelectListener();
+                return new AlertDialog.Builder(getActivity())
+                    .setTitle(R.string.export_to_sim)
+                    .setPositiveButton(android.R.string.ok, listener)
+                    .setSingleChoiceItems(items, 0, listener).create();
+            }
+        }
+        return null;
+    }
+
+    public void showSimSelectDialog() {
+        AccountSelectionUtil.setImportSubscription(SimContactsConstants.SUB_1);
+        // item is for sim account to show
+        String[] items = new String[TelephonyManager.getDefault().getPhoneCount()];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = getString(R.string.import_from_sim) + ": "
+                    + MoreContactUtils.getMultiSimAliasesName(mActivity, i);
+        }
+        new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.import_from_sim)
+                .setPositiveButton(android.R.string.ok, listener)
+                .setSingleChoiceItems(items, 0, listener).create().show();
+    }
+
+    private void handleImportFromSimRequest(int Id) {
+        if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+            if (MoreContactUtils.getEnabledSimCount() > 1) {
+                displayImportExportDialog(R.string.import_from_sim_select
+                ,null);
+            } else {
+                AccountSelectionUtil.setImportSubscription(getEnabledIccCard());
+                handleImportRequest(Id);
+            }
+        } else {
+            handleImportRequest(Id);
+        }
+    }
+
+    private void handleExportToSimRequest(int Id) {
+        if (MoreContactUtils.getEnabledSimCount() >1) {
+            //has two enalbed sim cards, prompt dialog to select one
+            displayImportExportDialog(Id, null).show();
+        } else {
+            mExportSub = getEnabledIccCard();
+            Intent pickPhoneIntent = new Intent(
+                    SimContactsConstants.ACTION_MULTI_PICK, Contacts.CONTENT_URI);
+            // do not show the contacts in SIM card
+            pickPhoneIntent.putExtra(AccountFilterActivity.KEY_EXTRA_CONTACT_LIST_FILTER,
+                    ContactListFilter
+                            .createFilterWithType(ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS));
+            pickPhoneIntent.putExtra(EXT_NOT_SHOW_SIM_FLAG, true);
+            pickPhoneIntent.putExtra(SimContactsConstants.IS_CONTACT,true);
+            mActivity.startActivityForResult(pickPhoneIntent, SUBACTIVITY_MULTI_PICK_CONTACT);
+        }
+    }
+
+    private boolean hasEnabledIccCard(int subscription) {
+        return TelephonyManager.getDefault().hasIccCard(subscription)
+                && TelephonyManager.getDefault().getSimState(subscription)
+                == TelephonyManager.SIM_STATE_READY;
+    }
+
+    private int getEnabledIccCard() {
+        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+            if (hasEnabledIccCard(i)) {
+                return i;
+            }
+        }
+        return SimContactsConstants.SUB_1;
+    }
 }
diff --git a/src/com/android/contacts/common/lettertiles/LetterTileDrawable.java b/src/com/android/contacts/common/lettertiles/LetterTileDrawable.java
index e62d421..34d3d45 100644
--- a/src/com/android/contacts/common/lettertiles/LetterTileDrawable.java
+++ b/src/com/android/contacts/common/lettertiles/LetterTileDrawable.java
@@ -16,6 +16,8 @@
 
 package com.android.contacts.common.lettertiles;
 
+import android.accounts.Account;
+import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
@@ -28,8 +30,11 @@
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.model.account.SimAccountType;
 import com.android.contacts.common.R;
 import com.android.contacts.common.util.BitmapUtil;
 
@@ -53,6 +58,9 @@
     private static Bitmap DEFAULT_PERSON_AVATAR;
     private static Bitmap DEFAULT_BUSINESS_AVATAR;
     private static Bitmap DEFAULT_VOICEMAIL_AVATAR;
+    private static Bitmap DEFAULT_SIM_PERSON_AVATAR;
+    private static Bitmap[] DEFAULT_CUSTOMIZE_SIM_PERSON_AVATAR =
+            new Bitmap[MoreContactUtils.IC_SIM_PICTURE.length];
 
     /** Reusable components to avoid new allocations */
     private static final Paint sPaint = new Paint();
@@ -71,11 +79,17 @@
     private float mScale = 1.0f;
     private float mOffset = 0.0f;
     private boolean mIsCircle = false;
+    private Account mAccount;
+    private Context mContext;
 
-    public LetterTileDrawable(final Resources res) {
+
+    public LetterTileDrawable(final Context context, final Account account) {
         mPaint = new Paint();
         mPaint.setFilterBitmap(true);
         mPaint.setDither(true);
+        mAccount = account;
+        mContext = context;
+        Resources res = context.getResources();
 
         if (sColors == null) {
             sColors = res.obtainTypedArray(R.array.letter_tile_colors);
@@ -88,6 +102,13 @@
                     R.drawable.ic_business_white_120dp);
             DEFAULT_VOICEMAIL_AVATAR = BitmapFactory.decodeResource(res,
                     R.drawable.ic_voicemail_avatar);
+            DEFAULT_SIM_PERSON_AVATAR = BitmapFactory.decodeResource(res,
+                    R.drawable.ic_contact_picture_sim);
+            for (int i = 0; i < MoreContactUtils.IC_SIM_PICTURE.length; i++) {
+                DEFAULT_CUSTOMIZE_SIM_PERSON_AVATAR[i] = BitmapFactory
+                        .decodeResource(res, MoreContactUtils.IC_SIM_PICTURE[i]);
+            }
+
             sPaint.setTypeface(Typeface.create(
                     res.getString(R.string.letter_tile_letter_font_family), Typeface.NORMAL));
             sPaint.setTextAlign(Align.CENTER);
@@ -143,7 +164,9 @@
         }
 
         // Draw letter/digit only if the first character is an english letter
-        if (mDisplayName != null && isEnglishLetter(mDisplayName.charAt(0))) {
+        if (mDisplayName != null
+                && isEnglishLetter(mDisplayName.charAt(0))
+                && (mAccount == null || (!mAccount.type.equals(SimAccountType.ACCOUNT_TYPE)))) {
             // Draw letter or digit.
             sFirstChar[0] = Character.toUpperCase(mDisplayName.charAt(0));
 
@@ -160,9 +183,9 @@
                     sPaint);
         } else {
             // Draw the default image if there is no letter/digit to be drawn
-            final Bitmap bitmap = getBitmapForContactType(mContactType);
-            drawBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(),
-                    canvas);
+            final Bitmap bitmap = getBitmapForContactType(mContactType,
+                    mAccount, mContext);
+            drawBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), canvas);
         }
     }
 
@@ -184,7 +207,21 @@
         return sColors.getColor(color, sDefaultColor);
     }
 
-    private static Bitmap getBitmapForContactType(int contactType) {
+    private static Bitmap getBitmapForContactType(int contactType,
+            Account account, Context context) {
+        if (account != null && SimAccountType.ACCOUNT_TYPE.equals(account.type)) {
+            if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+                final int sub = MoreContactUtils.getSubscription(
+                        SimAccountType.ACCOUNT_TYPE, account.name);
+                int index = MoreContactUtils.getCurrentSimIconIndex(context, sub);
+                if (index < 0) {
+                    return DEFAULT_SIM_PERSON_AVATAR;
+                }
+                return DEFAULT_CUSTOMIZE_SIM_PERSON_AVATAR[index];
+            } else {
+                return DEFAULT_SIM_PERSON_AVATAR;
+            }
+        }
         switch (contactType) {
             case TYPE_PERSON:
                 return DEFAULT_PERSON_AVATAR;
diff --git a/src/com/android/contacts/common/list/ContactEntry.java b/src/com/android/contacts/common/list/ContactEntry.java
index 43fc19d..66ae50d 100644
--- a/src/com/android/contacts/common/list/ContactEntry.java
+++ b/src/com/android/contacts/common/list/ContactEntry.java
@@ -16,6 +16,7 @@
 
 package com.android.contacts.common.list;
 
+import android.accounts.Account;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.provider.ContactsContract.PinnedPositions;
@@ -36,6 +37,7 @@
     public int pinned = PinnedPositions.UNPINNED;
     public boolean isFavorite = false;
     public boolean isDefaultNumber = false;
+    public Account account;
 
     public static final ContactEntry BLANK_ENTRY = new ContactEntry();
 }
\ No newline at end of file
diff --git a/src/com/android/contacts/common/list/ContactEntryListAdapter.java b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
index 4d7eb19..7dad437 100644
--- a/src/com/android/contacts/common/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
@@ -15,6 +15,7 @@
  */
 package com.android.contacts.common.list;
 
+import android.accounts.Account;
 import android.content.Context;
 import android.content.CursorLoader;
 import android.content.res.Resources;
@@ -710,22 +711,31 @@
      * @param contactIdColumn Index of the contact id column
      * @param lookUpKeyColumn Index of the lookup key column
      * @param displayNameColumn Index of the display name column
+     * @param accountTypeColumn Index of the account type column
+     * @param accountNameColumn Index of the account name column
      */
     protected void bindQuickContact(final ContactListItemView view, int partitionIndex,
             Cursor cursor, int photoIdColumn, int photoUriColumn, int contactIdColumn,
-            int lookUpKeyColumn, int displayNameColumn) {
+            int lookUpKeyColumn,int displayNameColumn, int accountTypeColumn,
+            int accountNameColumn) {
         long photoId = 0;
         if (!cursor.isNull(photoIdColumn)) {
             photoId = cursor.getLong(photoIdColumn);
         }
 
+        Account account = null;
+        if (!cursor.isNull(accountTypeColumn) && !cursor.isNull(accountNameColumn)) {
+            final String accountType = cursor.getString(accountTypeColumn);
+            final String accountName = cursor.getString(accountNameColumn);
+            account = new Account(accountName, accountType);
+        }
         QuickContactBadge quickContact = view.getQuickContact();
         quickContact.assignContactUri(
                 getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn));
 
         if (photoId != 0 || photoUriColumn == -1) {
-            getPhotoLoader().loadThumbnail(quickContact, photoId, mDarkTheme, mCircularPhotos,
-                    null);
+            getPhotoLoader().loadThumbnail(quickContact, photoId, account,
+                    mDarkTheme, mCircularPhotos, null);
         } else {
             final String photoUriString = cursor.getString(photoUriColumn);
             final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
@@ -734,8 +744,8 @@
                 request = getDefaultImageRequestFromCursor(cursor, displayNameColumn,
                         lookUpKeyColumn);
             }
-            getPhotoLoader().loadPhoto(quickContact, photoUri, -1, mDarkTheme, mCircularPhotos,
-                    request);
+            getPhotoLoader().loadPhoto(quickContact, photoUri, account, -1,
+                    mDarkTheme, mCircularPhotos, request);
         }
 
     }
diff --git a/src/com/android/contacts/common/list/ContactEntryListFragment.java b/src/com/android/contacts/common/list/ContactEntryListFragment.java
index 62515e2..715fade 100644
--- a/src/com/android/contacts/common/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/common/list/ContactEntryListFragment.java
@@ -19,9 +19,11 @@
 import android.app.Activity;
 import android.app.LoaderManager;
 import android.app.LoaderManager.LoaderCallbacks;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.CursorLoader;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.Loader;
 import android.content.res.Resources;
 import android.database.Cursor;
@@ -51,6 +53,7 @@
 import com.android.contacts.common.util.ContactListViewUtils;
 import com.android.contacts.common.util.SchedulingUtils;
 import com.android.dialerbind.analytics.AnalyticsFragment;
+import com.android.internal.telephony.TelephonyIntents;
 
 import java.util.Locale;
 
@@ -148,6 +151,13 @@
 
     private LoaderManager mLoaderManager;
 
+    private BroadcastReceiver mSIMStateReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context arg0, Intent arg1) {
+            reloadData();
+        }
+    };
+
     private Handler mDelayedDirectorySearchHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -254,6 +264,14 @@
         restoreSavedState(savedState);
         mAdapter = createListAdapter();
         mContactsPrefs = new ContactsPreferences(mContext);
+        restoreSavedState(savedState);
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        if (mContext != null) {
+            mContext.registerReceiver(mSIMStateReceiver, filter);
+        }
     }
 
     public void restoreSavedState(Bundle savedState) {
@@ -460,6 +478,14 @@
         mAdapter.clearPartitions();
     }
 
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mContext != null) {
+            mContext.unregisterReceiver(mSIMStateReceiver);
+        }
+    }
+
     protected void reloadData() {
         removePendingDirectorySearchRequests();
         mAdapter.onDataReload();
diff --git a/src/com/android/contacts/common/list/ContactListAdapter.java b/src/com/android/contacts/common/list/ContactListAdapter.java
index 7e9a2e9..c1c0f02 100644
--- a/src/com/android/contacts/common/list/ContactListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactListAdapter.java
@@ -15,12 +15,14 @@
  */
 package com.android.contacts.common.list;
 
+import android.accounts.Account;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.SearchSnippets;
 import android.text.TextUtils;
 import android.view.View;
@@ -49,6 +51,8 @@
             Contacts.PHOTO_THUMBNAIL_URI,           // 5
             Contacts.LOOKUP_KEY,                    // 6
             Contacts.IS_USER_PROFILE,               // 7
+            RawContacts.ACCOUNT_TYPE,               // 8
+            RawContacts.ACCOUNT_NAME,               // 9
         };
 
         private static final String[] CONTACT_PROJECTION_ALTERNATIVE = new String[] {
@@ -60,6 +64,8 @@
             Contacts.PHOTO_THUMBNAIL_URI,           // 5
             Contacts.LOOKUP_KEY,                    // 6
             Contacts.IS_USER_PROFILE,               // 7
+            RawContacts.ACCOUNT_TYPE,               // 8
+            RawContacts.ACCOUNT_NAME,               // 9
         };
 
         private static final String[] FILTER_PROJECTION_PRIMARY = new String[] {
@@ -71,7 +77,9 @@
             Contacts.PHOTO_THUMBNAIL_URI,           // 5
             Contacts.LOOKUP_KEY,                    // 6
             Contacts.IS_USER_PROFILE,               // 7
-            SearchSnippets.SNIPPET,           // 8
+            RawContacts.ACCOUNT_TYPE,               // 8
+            RawContacts.ACCOUNT_NAME,               // 9
+            SearchSnippets.SNIPPET,           // 10
         };
 
         private static final String[] FILTER_PROJECTION_ALTERNATIVE = new String[] {
@@ -83,7 +91,9 @@
             Contacts.PHOTO_THUMBNAIL_URI,           // 5
             Contacts.LOOKUP_KEY,                    // 6
             Contacts.IS_USER_PROFILE,               // 7
-            SearchSnippets.SNIPPET,           // 8
+            RawContacts.ACCOUNT_TYPE,               // 8
+            RawContacts.ACCOUNT_NAME,               // 9
+            SearchSnippets.SNIPPET,           // 10
         };
 
         public static final int CONTACT_ID               = 0;
@@ -94,7 +104,9 @@
         public static final int CONTACT_PHOTO_URI        = 5;
         public static final int CONTACT_LOOKUP_KEY       = 6;
         public static final int CONTACT_IS_USER_PROFILE  = 7;
-        public static final int CONTACT_SNIPPET          = 8;
+        public static final int CONTACT_ACCOUNT_TYPE      = 8;
+        public static final int CONTACT_ACCOUNT_NAME     = 9;
+        public static final int CONTACT_SNIPPET          = 10;
     }
 
     private CharSequence mUnknownNameText;
@@ -230,8 +242,15 @@
             photoId = cursor.getLong(ContactQuery.CONTACT_PHOTO_ID);
         }
 
+        Account account = null;
+        if (!cursor.isNull(ContactQuery.CONTACT_ACCOUNT_TYPE)
+                && !cursor.isNull(ContactQuery.CONTACT_ACCOUNT_NAME)) {
+            final String accountType = cursor.getString(ContactQuery.CONTACT_ACCOUNT_TYPE);
+            final String accountName = cursor.getString(ContactQuery.CONTACT_ACCOUNT_NAME);
+            account = new Account(accountName, accountType);
+        }
         if (photoId != 0) {
-            getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false,
+            getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, account, false,
                     getCircularPhotos(), null);
         } else {
             final String photoUriString = cursor.getString(ContactQuery.CONTACT_PHOTO_URI);
@@ -242,7 +261,7 @@
                         ContactQuery.CONTACT_DISPLAY_NAME,
                         ContactQuery.CONTACT_LOOKUP_KEY);
             }
-            getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, false,
+            getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, account, false,
                     getCircularPhotos(), request);
         }
     }
diff --git a/src/com/android/contacts/common/list/ContactTileAdapter.java b/src/com/android/contacts/common/list/ContactTileAdapter.java
index 04f415d..643c63f 100644
--- a/src/com/android/contacts/common/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/common/list/ContactTileAdapter.java
@@ -15,6 +15,7 @@
  */
 package com.android.contacts.common.list;
 
+import android.accounts.Account;
 import android.content.ContentUris;
 import android.content.Context;
 import android.content.res.Resources;
@@ -66,6 +67,8 @@
     protected int mNameIndex;
     protected int mPresenceIndex;
     protected int mStatusIndex;
+    private int mAccountTypeIndex;
+    private int mAccountNameIndex;
 
     private boolean mIsQuickContactEnabled = false;
     private final int mPaddingInPixels;
@@ -148,6 +151,8 @@
         mStarredIndex = ContactTileLoaderFactory.STARRED;
         mPresenceIndex = ContactTileLoaderFactory.CONTACT_PRESENCE;
         mStatusIndex = ContactTileLoaderFactory.CONTACT_STATUS;
+        mAccountTypeIndex = ContactTileLoaderFactory.ACCOUNT_TYPE;
+        mAccountNameIndex = ContactTileLoaderFactory.ACCOUNT_NAME;
     }
 
     private static boolean cursorIsValid(Cursor cursor) {
@@ -186,6 +191,9 @@
      * Else use {@link ContactTileLoaderFactory}
      */
     public void setContactCursor(Cursor cursor) {
+        if (cursor == null || cursor.isClosed()) {
+            return;
+        }
         mContactCursor = cursor;
         mDividerPosition = getDividerPosition(cursor);
 
@@ -270,6 +278,13 @@
         }
         contact.status = statusMessage;
 
+        if (!cursor.isNull(mAccountTypeIndex) && !cursor.isNull(mAccountTypeIndex)) {
+            final String accountType = cursor.getString(mAccountTypeIndex);
+            final String accountName = cursor.getString(mAccountNameIndex);
+            contact.account = new Account(accountName, accountType);
+        } else {
+            contact.account = null;
+        }
         return contact;
     }
 
diff --git a/src/com/android/contacts/common/list/ContactTileView.java b/src/com/android/contacts/common/list/ContactTileView.java
index 56552bb..b42ab7b 100644
--- a/src/com/android/contacts/common/list/ContactTileView.java
+++ b/src/com/android/contacts/common/list/ContactTileView.java
@@ -15,6 +15,7 @@
  */
 package com.android.contacts.common.list;
 
+import android.accounts.Account;
 import android.content.Context;
 import android.graphics.Rect;
 import android.net.Uri;
@@ -128,7 +129,8 @@
                 DefaultImageRequest request = getDefaultImageRequest(entry.name, entry.lookupKey);
                 configureViewForImage(entry.photoUri == null);
                 if (mPhoto != null) {
-                    mPhotoManager.loadPhoto(mPhoto, entry.photoUri, getApproximateImageSize(),
+                    mPhotoManager.loadPhoto(mPhoto, entry.photoUri,
+                            entry.account, getApproximateImageSize(),
                             isDarkTheme(), isContactPhotoCircular(), request);
 
                     if (mQuickContact != null) {
@@ -136,7 +138,7 @@
                     }
                 } else if (mQuickContact != null) {
                     mQuickContact.assignContactUri(mLookupUri);
-                    mPhotoManager.loadPhoto(mQuickContact, entry.photoUri,
+                    mPhotoManager.loadPhoto(mQuickContact, entry.photoUri, entry.account,
                             getApproximateImageSize(), isDarkTheme(), isContactPhotoCircular(),
                             request);
                 }
diff --git a/src/com/android/contacts/common/list/DefaultContactListAdapter.java b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
index 8774777..ed1c509 100644
--- a/src/com/android/contacts/common/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
@@ -26,11 +26,15 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.SearchSnippets;
 import android.text.TextUtils;
 import android.view.View;
 
+import com.android.contacts.common.model.account.SimAccountType;
 import com.android.contacts.common.preference.ContactsPreferences;
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.SimContactsConstants;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -47,6 +51,21 @@
         super(context);
     }
 
+    /** append Uri QueryParameter to filter contacts in SIM card */
+    private void appendUriQueryParameterWithoutSim(CursorLoader loader,
+            String key, String value) {
+        if (null == loader || null == key || null == value) {
+            return;
+        }
+
+        Uri uri = loader.getUri();
+        if (null != uri) {
+            uri = uri.buildUpon().appendQueryParameter(key, value)
+                    .appendQueryParameter(SimContactsConstants.WITHOUT_SIM_FLAG, "true").build();
+            loader.setUri(uri);
+        }
+    }
+
     @Override
     public void configureLoader(CursorLoader loader, long directoryId) {
         if (loader instanceof ProfileAndContactsLoader) {
@@ -79,6 +98,19 @@
                 loader.setUri(builder.build());
                 loader.setProjection(getProjection(true));
             }
+            boolean isAirMode = MoreContactUtils.isAPMOnAndSIMPowerDown(getContext());
+
+            if (isAirMode) {
+                appendUriQueryParameterWithoutSim(loader, RawContacts.ACCOUNT_TYPE,
+                        SimAccountType.ACCOUNT_TYPE);
+            } else {
+                // Do not show contacts when SIM card is disabled
+                String disabledSimFilter = MoreContactUtils.getDisabledSimFilter();
+                if (!TextUtils.isEmpty(disabledSimFilter)) {
+                    appendUriQueryParameterWithoutSim(
+                            loader, RawContacts.ACCOUNT_NAME, disabledSimFilter);
+                }
+            }
         } else {
             configureUri(loader, directoryId, filter);
             loader.setProjection(getProjection(false));
@@ -139,10 +171,21 @@
         StringBuilder selection = new StringBuilder();
         List<String> selectionArgs = new ArrayList<String>();
 
+        boolean isAirMode = MoreContactUtils.isAPMOnAndSIMPowerDown(getContext());
+        String disabledSimFilter = MoreContactUtils.getDisabledSimFilter();
+
         switch (filter.filterType) {
             case ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS: {
                 // We have already added directory=0 to the URI, which takes care of this
                 // filter
+                // Do not show contacts in SIM card when airplane mode is on
+                if (isAirMode) {
+                    appendUriQueryParameterWithoutSim(loader, RawContacts.ACCOUNT_TYPE,
+                            SimAccountType.ACCOUNT_TYPE);
+                } else if (!TextUtils.isEmpty(disabledSimFilter)) {
+                    appendUriQueryParameterWithoutSim(loader, RawContacts.ACCOUNT_NAME,
+                            disabledSimFilter);
+                }
                 break;
             }
             case ContactListFilter.FILTER_TYPE_SINGLE_CONTACT: {
@@ -163,6 +206,14 @@
                 if (isCustomFilterForPhoneNumbersOnly()) {
                     selection.append(" AND " + Contacts.HAS_PHONE_NUMBER + "=1");
                 }
+                // Do not show contacts in SIM card when airplane mode is on
+                if (isAirMode) {
+                    appendUriQueryParameterWithoutSim(loader, RawContacts.ACCOUNT_TYPE,
+                            SimAccountType.ACCOUNT_TYPE);
+                } else if (!TextUtils.isEmpty(disabledSimFilter)) {
+                    appendUriQueryParameterWithoutSim(loader, RawContacts.ACCOUNT_NAME,
+                            disabledSimFilter);
+                }
                 break;
             }
             case ContactListFilter.FILTER_TYPE_ACCOUNT: {
@@ -190,7 +241,8 @@
         if (isQuickContactEnabled()) {
             bindQuickContact(view, partition, cursor, ContactQuery.CONTACT_PHOTO_ID,
                     ContactQuery.CONTACT_PHOTO_URI, ContactQuery.CONTACT_ID,
-                    ContactQuery.CONTACT_LOOKUP_KEY, ContactQuery.CONTACT_DISPLAY_NAME);
+                    ContactQuery.CONTACT_LOOKUP_KEY, ContactQuery.CONTACT_DISPLAY_NAME,
+                    ContactQuery.CONTACT_ACCOUNT_TYPE, ContactQuery.CONTACT_ACCOUNT_NAME);
         } else {
             if (getDisplayPhotos()) {
                 bindPhoto(view, partition, cursor);
diff --git a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
index 8c8700c..35ff111 100644
--- a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
+++ b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
@@ -15,6 +15,7 @@
  */
 package com.android.contacts.common.list;
 
+import android.accounts.Account;
 import android.content.ContentUris;
 import android.content.Context;
 import android.content.CursorLoader;
@@ -28,6 +29,8 @@
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.util.Log;
@@ -41,6 +44,9 @@
 import com.android.contacts.common.extensions.ExtensionsFactory;
 import com.android.contacts.common.preference.ContactsPreferences;
 import com.android.contacts.common.util.Constants;
+import com.android.contacts.common.SimContactsConstants;
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.model.account.SimAccountType;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -76,6 +82,8 @@
             Phone.PHOTO_ID,                     // 6
             Phone.DISPLAY_NAME_PRIMARY,         // 7
             Phone.PHOTO_THUMBNAIL_URI,          // 8
+            RawContacts.ACCOUNT_TYPE,           // 9
+            RawContacts.ACCOUNT_NAME,           // 10
         };
 
         public static final String[] PROJECTION_ALTERNATIVE = new String[] {
@@ -88,6 +96,8 @@
             Phone.PHOTO_ID,                     // 6
             Phone.DISPLAY_NAME_ALTERNATIVE,     // 7
             Phone.PHOTO_THUMBNAIL_URI,          // 8
+            RawContacts.ACCOUNT_TYPE,           // 9
+            RawContacts.ACCOUNT_NAME,           // 10
         };
 
         public static final int PHONE_ID                = 0;
@@ -99,6 +109,8 @@
         public static final int PHOTO_ID                = 6;
         public static final int DISPLAY_NAME            = 7;
         public static final int PHOTO_URI               = 8;
+        public static final int PHONE_ACCOUNT_TYPE      = 9;
+        public static final int PHONE_ACCOUNT_NAME      = 10;
     }
 
     private static final String IGNORE_NUMBER_TOO_LONG_CLAUSE =
@@ -193,6 +205,13 @@
 
             // Remove duplicates when it is possible.
             builder.appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true");
+
+            // Do not show contacts in disabled SIM card
+            String disabledSimFilter = MoreContactUtils.getDisabledSimFilter();
+            if (!TextUtils.isEmpty(disabledSimFilter)) {
+                String disabledSimName = getDisabledSimName(disabledSimFilter);
+                loader.setSelection(RawContacts.ACCOUNT_NAME+ "<>" + disabledSimName);
+            }
             loader.setUri(builder.build());
 
             // TODO a projection that includes the search snippet
@@ -366,7 +385,8 @@
             if (isQuickContactEnabled()) {
                 bindQuickContact(view, partition, cursor, PhoneQuery.PHOTO_ID,
                         PhoneQuery.PHOTO_URI, PhoneQuery.CONTACT_ID,
-                        PhoneQuery.LOOKUP_KEY, PhoneQuery.DISPLAY_NAME);
+                        PhoneQuery.LOOKUP_KEY, PhoneQuery.DISPLAY_NAME,
+                        PhoneQuery.PHONE_ACCOUNT_TYPE, PhoneQuery.PHONE_ACCOUNT_NAME);
             } else {
                 if (getDisplayPhotos()) {
                     bindPhoto(view, partition, cursor);
@@ -436,9 +456,15 @@
         if (!cursor.isNull(PhoneQuery.PHOTO_ID)) {
             photoId = cursor.getLong(PhoneQuery.PHOTO_ID);
         }
-
+        Account account = null;
+        if (!cursor.isNull(PhoneQuery.PHONE_ACCOUNT_TYPE)
+                && !cursor.isNull(PhoneQuery.PHONE_ACCOUNT_NAME)) {
+            final String accountType = cursor.getString(PhoneQuery.PHONE_ACCOUNT_TYPE);
+            final String accountName = cursor.getString(PhoneQuery.PHONE_ACCOUNT_NAME);
+            account = new Account(accountName, accountType);
+        }
         if (photoId != 0) {
-            getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false,
+            getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, account, false,
                     getCircularPhotos(), null);
         } else {
             final String photoUriString = cursor.getString(PhoneQuery.PHOTO_URI);
@@ -450,7 +476,7 @@
                 final String lookupKey = cursor.getString(PhoneQuery.LOOKUP_KEY);
                 request = new DefaultImageRequest(displayName, lookupKey, getCircularPhotos());
             }
-            getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, false,
+            getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, account, false,
                     getCircularPhotos(), request);
         }
     }
@@ -541,4 +567,21 @@
                 .encodedFragment(cursor.getString(lookUpKeyColumn))
                 .build();
     }
+
+    private String getDisabledSimName(String disabledSimFilter){
+        String[] disabledSimArray = disabledSimFilter.split(",");//it will never be null
+        String disabledSimName = "";
+        for (int i = 0; i < disabledSimArray.length; i++) {
+            if (i < disabledSimArray.length -1) {
+                //If disabledSimArray[i] is not the last one of the array,
+                //add "or" after every member of the array.
+                disabledSimName = disabledSimName + "'" + disabledSimArray[i] + "'" + "or";
+            } else {
+                //If disabledSimArray[i] is the last one of the array,
+                //should not add anything after it.
+                disabledSimName = disabledSimName + "'" + disabledSimArray[i] + "'";
+            }
+        }
+        return disabledSimName;
+    }
 }
diff --git a/src/com/android/contacts/common/list/ShortcutIntentBuilder.java b/src/com/android/contacts/common/list/ShortcutIntentBuilder.java
index 6c97fd9..53cb857 100644
--- a/src/com/android/contacts/common/list/ShortcutIntentBuilder.java
+++ b/src/com/android/contacts/common/list/ShortcutIntentBuilder.java
@@ -15,6 +15,7 @@
  */
 package com.android.contacts.common.list;
 
+import android.accounts.Account;
 import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -38,6 +39,7 @@
 import android.provider.ContactsContract.Data;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.provider.ContactsContract.RawContacts;
 import android.telecom.PhoneAccount;
 import android.text.TextPaint;
 import android.text.TextUtils;
@@ -56,12 +58,16 @@
     private static final String[] CONTACT_COLUMNS = {
         Contacts.DISPLAY_NAME,
         Contacts.PHOTO_ID,
-        Contacts.LOOKUP_KEY
+        Contacts.LOOKUP_KEY,
+        RawContacts.ACCOUNT_TYPE,
+        RawContacts.ACCOUNT_NAME
     };
 
     private static final int CONTACT_DISPLAY_NAME_COLUMN_INDEX = 0;
     private static final int CONTACT_PHOTO_ID_COLUMN_INDEX = 1;
     private static final int CONTACT_LOOKUP_KEY_COLUMN_INDEX = 2;
+    private static final int CONTACT_ACCOUNT_TYPE_COLUMN_INDEX = 3;
+    private static final int CONTACT_ACCOUNT_NAME_COLUMN_INDEX = 4;
 
     private static final String[] PHONE_COLUMNS = {
         Phone.DISPLAY_NAME,
@@ -69,7 +75,9 @@
         Phone.NUMBER,
         Phone.TYPE,
         Phone.LABEL,
-        Phone.LOOKUP_KEY
+        Phone.LOOKUP_KEY,
+        RawContacts.ACCOUNT_TYPE,
+        RawContacts.ACCOUNT_NAME
     };
 
     private static final int PHONE_DISPLAY_NAME_COLUMN_INDEX = 0;
@@ -78,6 +86,8 @@
     private static final int PHONE_TYPE_COLUMN_INDEX = 3;
     private static final int PHONE_LABEL_COLUMN_INDEX = 4;
     private static final int PHONE_LOOKUP_KEY_COLUMN_INDEX = 5;
+    private static final int PHONE_ACCOUNT_TYPE_COLUMN_INDEX = 6;
+    private static final int PHONE_ACCOUNT_NAME_COLUMN_INDEX = 7;
 
     private static final String[] PHOTO_COLUMNS = {
         Photo.PHOTO,
@@ -187,6 +197,8 @@
     }
 
     private final class ContactLoadingAsyncTask extends LoadingAsyncTask {
+        private Account mAccount;
+
         public ContactLoadingAsyncTask(Uri uri) {
             super(uri);
         }
@@ -200,6 +212,13 @@
                     if (cursor.moveToFirst()) {
                         mDisplayName = cursor.getString(CONTACT_DISPLAY_NAME_COLUMN_INDEX);
                         mPhotoId = cursor.getLong(CONTACT_PHOTO_ID_COLUMN_INDEX);
+
+                        final String accountType = cursor
+                                .getString(CONTACT_ACCOUNT_TYPE_COLUMN_INDEX);
+                        final String accountName = cursor
+                                .getString(CONTACT_ACCOUNT_NAME_COLUMN_INDEX);
+                        mAccount = new Account(accountName, accountType);
+
                         mLookupKey = cursor.getString(CONTACT_LOOKUP_KEY_COLUMN_INDEX);
                     }
                 } finally {
@@ -209,7 +228,8 @@
         }
         @Override
         protected void onPostExecute(Void result) {
-            createContactShortcutIntent(mUri, mContentType, mDisplayName, mLookupKey, mBitmapData);
+            createContactShortcutIntent(mUri, mContentType, mDisplayName,
+                    mAccount, mLookupKey, mBitmapData);
         }
     }
 
@@ -218,6 +238,7 @@
         private String mPhoneNumber;
         private int mPhoneType;
         private String mPhoneLabel;
+        private Account mAccount;
 
         public PhoneNumberLoadingAsyncTask(Uri uri, String shortcutAction) {
             super(uri);
@@ -236,6 +257,13 @@
                         mPhoneNumber = cursor.getString(PHONE_NUMBER_COLUMN_INDEX);
                         mPhoneType = cursor.getInt(PHONE_TYPE_COLUMN_INDEX);
                         mPhoneLabel = cursor.getString(PHONE_LABEL_COLUMN_INDEX);
+
+                        final String accountType = cursor
+                                .getString(PHONE_ACCOUNT_TYPE_COLUMN_INDEX);
+                        final String accountName = cursor
+                                .getString(PHONE_ACCOUNT_NAME_COLUMN_INDEX);
+                        mAccount = new Account(accountName, accountType);
+
                         mLookupKey = cursor.getString(PHONE_LOOKUP_KEY_COLUMN_INDEX);
                     }
                 } finally {
@@ -247,23 +275,24 @@
         @Override
         protected void onPostExecute(Void result) {
             createPhoneNumberShortcutIntent(mUri, mDisplayName, mLookupKey, mBitmapData,
-                    mPhoneNumber, mPhoneType, mPhoneLabel, mShortcutAction);
+                    mPhoneNumber, mPhoneType, mPhoneLabel, mAccount, mShortcutAction);
         }
     }
 
-    private Drawable getPhotoDrawable(byte[] bitmapData, String displayName, String lookupKey) {
+    private Drawable getPhotoDrawable(byte[] bitmapData, String displayName,
+            String lookupKey, Account account) {
         if (bitmapData != null) {
             Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length, null);
             return new BitmapDrawable(mContext.getResources(), bitmap);
         } else {
-            return ContactPhotoManager.getDefaultAvatarDrawableForContact(mContext.getResources(),
-                    false, new DefaultImageRequest(displayName, lookupKey, false));
+            return ContactPhotoManager.getDefaultAvatarDrawableForContact(mContext,
+                    false, new DefaultImageRequest(displayName, lookupKey, false), account);
         }
     }
 
     private void createContactShortcutIntent(Uri contactUri, String contentType, String displayName,
-            String lookupKey, byte[] bitmapData) {
-        Drawable drawable = getPhotoDrawable(bitmapData, displayName, lookupKey);
+            Account account, String lookupKey, byte[] bitmapData) {
+        Drawable drawable = getPhotoDrawable(bitmapData, displayName, lookupKey, account);
 
         Intent shortcutIntent = new Intent(ContactsContract.QuickContact.ACTION_QUICK_CONTACT);
 
@@ -300,8 +329,8 @@
 
     private void createPhoneNumberShortcutIntent(Uri uri, String displayName, String lookupKey,
             byte[] bitmapData, String phoneNumber, int phoneType, String phoneLabel,
-            String shortcutAction) {
-        Drawable drawable = getPhotoDrawable(bitmapData, displayName, lookupKey);
+            Account account, String shortcutAction) {
+        Drawable drawable = getPhotoDrawable(bitmapData, displayName, lookupKey, account);
 
         Bitmap bitmap;
         Uri phoneUri;
diff --git a/src/com/android/contacts/common/model/AccountTypeManager.java b/src/com/android/contacts/common/model/AccountTypeManager.java
index 6efe819..ba303c4 100644
--- a/src/com/android/contacts/common/model/AccountTypeManager.java
+++ b/src/com/android/contacts/common/model/AccountTypeManager.java
@@ -38,6 +38,7 @@
 import android.os.SystemClock;
 import android.provider.ContactsContract;
 import android.text.TextUtils;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.util.TimingLogger;
 
@@ -50,7 +51,10 @@
 import com.android.contacts.common.model.account.ExternalAccountType;
 import com.android.contacts.common.model.account.FallbackAccountType;
 import com.android.contacts.common.model.account.GoogleAccountType;
+import com.android.contacts.common.model.account.PhoneAccountType;
+import com.android.contacts.common.model.account.SimAccountType;
 import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.SimContactsConstants;
 import com.android.contacts.common.testing.NeededForTesting;
 import com.android.contacts.common.util.Constants;
 import com.google.common.annotations.VisibleForTesting;
@@ -79,6 +83,13 @@
     private static final Object mInitializationLock = new Object();
     private static AccountTypeManager mAccountTypeManager;
 
+    public static final int FLAG_ALL_ACCOUNTS = 0;
+    public static final int FLAG_ALL_ACCOUNTS_WITHOUT_SIM = 1;
+    /**
+     * without sim and phone accounts
+     */
+    public static final int FLAG_ALL_ACCOUNTS_WITHOUT_LOCAL = 2;
+
     /**
      * Requests the singleton instance of {@link AccountTypeManager} with data bound from
      * the available authenticators. This method can safely be called from the UI thread.
@@ -112,6 +123,8 @@
      * contact writable accounts (if contactWritableOnly is true).
      */
     // TODO: Consider splitting this into getContactWritableAccounts() and getAllAccounts()
+    public abstract List<AccountWithDataSet> getAccounts(boolean contactWritableOnly, int flag);
+
     public abstract List<AccountWithDataSet> getAccounts(boolean contactWritableOnly);
 
     /**
@@ -418,6 +431,10 @@
                 accountType = new GoogleAccountType(mContext, auth.packageName);
             } else if (ExchangeAccountType.isExchangeType(type)) {
                 accountType = new ExchangeAccountType(mContext, auth.packageName, type);
+                } else if (SimAccountType.ACCOUNT_TYPE.equals(type)) {
+                    accountType = new SimAccountType(mContext, auth.packageName);
+                } else if (PhoneAccountType.ACCOUNT_TYPE.equals(type)) {
+                    accountType = new PhoneAccountType(mContext, auth.packageName);
             } else {
                 Log.d(TAG, "Registering external account type=" + type
                         + ", packageName=" + auth.packageName);
@@ -563,15 +580,86 @@
         return null;
     }
 
+    @Override
+    public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) {
+        return getAccounts(contactWritableOnly, FLAG_ALL_ACCOUNTS);
+    }
+
     /**
      * Return list of all known, contact writable {@link AccountWithDataSet}'s.
      */
     @Override
-    public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) {
+    public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly,
+            int flag) {
         ensureAccountsLoaded();
+        boolean isAirMode = MoreContactUtils.isAPMOnAndSIMPowerDown(mContext);
+        switch (flag) {
+            case FLAG_ALL_ACCOUNTS:
+                return trimAccountByType(
+                        contactWritableOnly ? mContactWritableAccounts : mAccounts,
+                        isAirMode ? SimAccountType.ACCOUNT_TYPE : null);
+            case FLAG_ALL_ACCOUNTS_WITHOUT_LOCAL:
+                return trimAccountByType(
+                        contactWritableOnly ? mContactWritableAccounts : mAccounts,
+                        SimAccountType.ACCOUNT_TYPE, PhoneAccountType.ACCOUNT_TYPE);
+            case FLAG_ALL_ACCOUNTS_WITHOUT_SIM:
+                return trimAccountByType(
+                        contactWritableOnly ? mContactWritableAccounts : mAccounts,
+                        SimAccountType.ACCOUNT_TYPE);
+        }
         return contactWritableOnly ? mContactWritableAccounts : mAccounts;
     }
 
+    private boolean isSimStateUnknown(Account account) {
+        int subscription = SimContactsConstants.SUB_INVALID;
+        subscription = MoreContactUtils.getSubscription(account.type, account.name);
+
+        if (subscription > SimContactsConstants.SUB_INVALID
+                && TelephonyManager.getDefault().getSimState(subscription)
+                    == TelephonyManager.SIM_STATE_UNKNOWN) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private boolean isSimAccountInvalid(Account account) {
+        if ((SimContactsConstants.ACCOUNT_TYPE_SIM).equals(account.type)) {
+            if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+                if (account.name.equals(SimContactsConstants.SIM_NAME))
+                    return true;
+            } else {
+                if (!account.name.equals(SimContactsConstants.SIM_NAME)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private List<AccountWithDataSet> trimAccountByType(final List<AccountWithDataSet> list,
+            String... trimAccountTypes) {
+        List<AccountWithDataSet> tempList = Lists.newArrayList();
+        outer: for (AccountWithDataSet accountWithDataSet : list) {
+            if (trimAccountTypes != null && trimAccountTypes.length > 0) {
+                for (String type : trimAccountTypes) {
+                    if (type != null && type.equals(accountWithDataSet.type)) {
+                        continue outer;
+                    }
+                }
+            }
+
+            if (isSimStateUnknown(accountWithDataSet)) {
+                continue outer;
+            }
+            if (isSimAccountInvalid(accountWithDataSet)) {
+                continue outer;
+            }
+            tempList.add(accountWithDataSet);
+        }
+        return tempList;
+    }
+
     /**
      * Return the list of all known, group writable {@link AccountWithDataSet}'s.
      */
diff --git a/src/com/android/contacts/common/model/RawContactDelta.java b/src/com/android/contacts/common/model/RawContactDelta.java
index 7304f02..cf5bf30 100644
--- a/src/com/android/contacts/common/model/RawContactDelta.java
+++ b/src/com/android/contacts/common/model/RawContactDelta.java
@@ -24,15 +24,20 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.BaseColumns;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 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.common.model.AccountTypeManager;
 import com.android.contacts.common.model.ValuesDelta;
 import com.android.contacts.common.model.account.AccountType;
 import com.android.contacts.common.testing.NeededForTesting;
+import com.android.contacts.common.SimContactsConstants;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
@@ -416,6 +421,139 @@
         }
     }
 
+    public ContentValues buildSimDiff() {
+        ContentValues values = new ContentValues();
+        ArrayList<ValuesDelta> names = getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
+        ArrayList<ValuesDelta> phones = getMimeEntries(Phone.CONTENT_ITEM_TYPE);
+        ArrayList<ValuesDelta> emails = getMimeEntries(Email.CONTENT_ITEM_TYPE);
+
+        ValuesDelta nameValuesDelta = null;
+        ValuesDelta emailValuesDelta = null;
+
+        if (getMimeEntriesCount(StructuredName.CONTENT_ITEM_TYPE, true) > 0) {
+            nameValuesDelta = names.get(0);
+            names.get(0).putNull(StructuredName.GIVEN_NAME);
+            names.get(0).putNull(StructuredName.FAMILY_NAME);
+            names.get(0).putNull(StructuredName.PREFIX);
+            names.get(0).putNull(StructuredName.MIDDLE_NAME);
+            names.get(0).putNull(StructuredName.SUFFIX);
+            names.get(0).put(StructuredName.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+        }
+        if (emails != null && emails.size() > 0) {
+            emailValuesDelta = emails.get(0);
+        }
+
+        String name = null;
+        String number = null;
+        String newName = null;
+        String newNumber = null;
+        StringBuilder email = new StringBuilder();
+        StringBuilder anr = new StringBuilder();
+        StringBuilder newEmail = new StringBuilder();
+        StringBuilder newAnr = new StringBuilder();
+
+        if (nameValuesDelta != null) {
+            if (isContactInsert()) {
+                name = nameValuesDelta.getAsString(StructuredName.DISPLAY_NAME);
+            } else {
+                if (nameValuesDelta.getBefore() != null) {
+                    name = nameValuesDelta.getBefore()
+                        .getAsString(StructuredName.DISPLAY_NAME);
+                }
+                if (nameValuesDelta.getAfter() != null) {
+                    newName = nameValuesDelta.getAfter()
+                        .getAsString(StructuredName.DISPLAY_NAME);
+                }
+            }
+        }
+
+        if (isContactInsert() && phones != null) {
+            for (ValuesDelta valuesDelta : phones) {
+                if (valuesDelta.getAfter() != null
+                        && valuesDelta.getAfter().size() != 0) {
+                    if (Phone.TYPE_MOBILE == valuesDelta.getAfter().getAsLong(Phone.TYPE)) {
+                        if (TextUtils.isEmpty(number)) {
+                            number = valuesDelta.getAfter().getAsString(Phone.NUMBER);
+                        } else {
+                            // don't supports to save two mobile number,so gives
+                            // invalid str here
+                            number = SimContactsConstants.STR_ANRS;
+                        }
+                    } else {
+                        anr.append(valuesDelta.getAfter().getAsString(Phone.NUMBER));
+                        anr.append(",");
+                    }
+                }
+            }
+        } else if(phones != null) {
+            for (ValuesDelta valuesDelta : phones) {
+                if (valuesDelta.getBefore() != null
+                        && valuesDelta.getBefore().size() != 0) {
+                    if (Phone.TYPE_MOBILE == valuesDelta.getBefore().getAsLong(Phone.TYPE) ) {
+                        number = valuesDelta.getBefore().getAsString(Phone.NUMBER);
+                    } else {
+                        anr.append(valuesDelta.getBefore().getAsString(Phone.NUMBER));
+                        anr.append(",");
+                    }
+                }
+                if (valuesDelta.getAfter() != null
+                        && valuesDelta.getAfter().size() != 0) {
+                    if (Phone.TYPE_MOBILE == valuesDelta.getAsLong(Phone.TYPE)) {
+                        if (TextUtils.isEmpty(newNumber)) {
+                            newNumber = valuesDelta.getAfter().getAsString(Phone.NUMBER);
+                        } else {
+                            newNumber = SimContactsConstants.STR_ANRS;
+                        }
+                    } else {
+                        newAnr.append(valuesDelta.getAfter().getAsString(Phone.NUMBER));
+                        newAnr.append(",");
+                    }
+                }
+            }
+        }
+
+        if (isContactInsert() && emails != null) {
+            for (ValuesDelta valuesDelta : emails) {
+                if (valuesDelta.getAfter() != null
+                        && valuesDelta.getAfter().size() != 0) {
+                    email.append(valuesDelta.getAfter().getAsString(Email.DATA));
+                    email.append(",");
+                }
+            }
+        } else if (emails != null) {
+            for (ValuesDelta valuesDelta : emails) {
+                if (valuesDelta.getBefore() != null
+                        && valuesDelta.getBefore().size() != 0) {
+                    email.append(valuesDelta.getBefore().getAsString(Email.DATA));
+                    email.append(",");
+                }
+                if (valuesDelta.getAfter() != null
+                        && valuesDelta.getAfter().size() != 0) {
+                        newEmail.append(valuesDelta.getAfter().getAsString(Email.DATA));
+                        newEmail.append(",");
+                }
+            }
+        }
+
+        if (isContactInsert()) {
+            if (name != null || number != null || anr != null || email != null) {
+                values.put(SimContactsConstants.STR_TAG, name);
+                values.put(SimContactsConstants.STR_NUMBER, number);
+                values.put(SimContactsConstants.STR_EMAILS, email.toString());
+                values.put(SimContactsConstants.STR_ANRS, anr.toString());
+            }
+        } else {
+            values.put(SimContactsConstants.STR_TAG, name);
+            values.put(SimContactsConstants.STR_NUMBER, number);
+            values.put(SimContactsConstants.STR_EMAILS, email.toString());
+            values.put(SimContactsConstants.STR_ANRS, anr.toString());
+            values.put(SimContactsConstants.STR_NEW_TAG, newName);
+            values.put(SimContactsConstants.STR_NEW_NUMBER, newNumber);
+            values.put(SimContactsConstants.STR_NEW_EMAILS, newEmail.toString());
+            values.put(SimContactsConstants.STR_NEW_ANRS, newAnr.toString());
+        }
+        return values;
+    }
     /**
      * Build a list of {@link ContentProviderOperation} that will transform the
      * current "before" {@link Entity} state into the modified state which this
diff --git a/src/com/android/contacts/common/model/ValuesDelta.java b/src/com/android/contacts/common/model/ValuesDelta.java
index e30cdd6..2db7e1c 100644
--- a/src/com/android/contacts/common/model/ValuesDelta.java
+++ b/src/com/android/contacts/common/model/ValuesDelta.java
@@ -23,6 +23,7 @@
 import android.os.Parcelable;
 import android.provider.BaseColumns;
 import android.provider.ContactsContract;
+import android.provider.ContactsContract.Data;
 
 import com.android.contacts.common.testing.NeededForTesting;
 import com.google.common.collect.Sets;
@@ -61,6 +62,17 @@
         final ValuesDelta entry = new ValuesDelta();
         entry.mBefore = before;
         entry.mAfter = new ContentValues();
+
+        // init data1 to mAfter map. when no operation edittext of
+        // sim phone in the UI, the mAfter init have no data1 value,
+        // it will cause the builddiff data not right.
+        if (before.containsKey(Data.DATA1)) {
+            String contactInfo = before.getAsString(Data.DATA1);
+            if (null != contactInfo && !"".equals(contactInfo)) {
+                entry.mAfter.put(Data.DATA1, contactInfo);
+            }
+        }
+
         return entry;
     }
 
@@ -83,6 +95,10 @@
         return mAfter;
     }
 
+    public ContentValues getBefore() {
+        return mBefore;
+    }
+
     public boolean containsKey(String key) {
         return ((mAfter != null && mAfter.containsKey(key)) ||
                 (mBefore != null && mBefore.containsKey(key)));
diff --git a/src/com/android/contacts/common/model/account/AccountType.java b/src/com/android/contacts/common/model/account/AccountType.java
index 53ab47d..560d33d 100644
--- a/src/com/android/contacts/common/model/account/AccountType.java
+++ b/src/com/android/contacts/common/model/account/AccountType.java
@@ -16,17 +16,22 @@
 
 package com.android.contacts.common.model.account;
 
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorDescription;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.RawContacts;
+import android.util.Log;
 import android.view.inputmethod.EditorInfo;
 import android.widget.EditText;
 
+import com.android.contacts.common.MoreContactUtils;
 import com.android.contacts.common.R;
 import com.android.contacts.common.model.dataitem.DataKind;
 import com.google.common.annotations.VisibleForTesting;
@@ -39,6 +44,7 @@
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Internal structure that represents constraints and styles for a specific data
@@ -96,6 +102,11 @@
 
     protected boolean mIsInitialized;
 
+    private Map<String, AuthenticatorDescription> mTypeToAuthDescription
+            = new HashMap<String, AuthenticatorDescription>();
+
+    private AuthenticatorDescription[] mAuthDescs;
+
     protected static class DefinitionException extends Exception {
         public DefinitionException(String message) {
             super(message);
@@ -196,12 +207,6 @@
     public String getViewGroupActivity() {
         return null;
     }
-
-    public CharSequence getDisplayLabel(Context context) {
-        // Note this resource is defined in the sync adapter package, not resourcePackageName.
-        return getResourceText(context, syncAdapterPackageName, titleRes, accountType);
-    }
-
     /**
      * @return resource ID for the "invite contact" action label, or -1 if not defined.
      */
@@ -276,16 +281,48 @@
         }
     }
 
-    public Drawable getDisplayIcon(Context context) {
-        if (this.titleRes != -1 && this.syncAdapterPackageName != null) {
-            final PackageManager pm = context.getPackageManager();
-            return pm.getDrawable(this.syncAdapterPackageName, this.iconRes, null);
-        } else if (this.titleRes != -1) {
-            return context.getResources().getDrawable(this.iconRes);
-        } else {
-            return null;
+    public void updateAuthDescriptions(Context context) {
+        mAuthDescs = AccountManager.get(context).getAuthenticatorTypes();
+        for (int i = 0; i < mAuthDescs.length; i++) {
+            mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]);
         }
     }
+    public CharSequence getDisplayLabel(Context context) {
+        CharSequence label = null;
+        updateAuthDescriptions(context);
+        if (mTypeToAuthDescription.containsKey(accountType)) {
+            try {
+                AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
+                Context authContext = context.createPackageContext(desc.packageName, 0);
+                label = authContext.getResources().getText(desc.labelId);
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.w(TAG, "No label name for account type " + accountType);
+            } catch (Resources.NotFoundException e) {
+                Log.w(TAG, "No label icon for account type " + accountType);
+            }
+        }
+        return label;
+    }
+
+    public Drawable getDisplayIcon(Context context) {
+        Drawable icon = null;
+        updateAuthDescriptions(context);
+        if (mTypeToAuthDescription.containsKey(accountType)) {
+            try {
+                AuthenticatorDescription desc = mTypeToAuthDescription
+                        .get(accountType);
+                Context authContext = context.createPackageContext(
+                        desc.packageName, 0);
+                icon = authContext.getResources().getDrawable(desc.iconId);
+            } catch (PackageManager.NameNotFoundException e) {
+            } catch (Resources.NotFoundException e) {
+            }
+        }
+        if (icon == null) {
+            icon = context.getPackageManager().getDefaultActivityIcon();
+        }
+        return icon;
+    }
 
     /**
      * Whether or not groups created under this account type have editable membership lists.
diff --git a/src/com/android/contacts/common/model/account/PhoneAccountType.java b/src/com/android/contacts/common/model/account/PhoneAccountType.java
new file mode 100644
index 0000000..f6e1f1f
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/PhoneAccountType.java
@@ -0,0 +1,99 @@
+/*
+  * Copyright (C) 2014, 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.
+*/
+
+package com.android.contacts.common.model.account;
+
+import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.os.SystemProperties;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.SimContactsConstants;
+import com.android.contacts.common.model.account.AccountType.DefinitionException;
+import com.google.android.collect.Lists;
+
+
+public class PhoneAccountType extends BaseAccountType{
+    private static final String TAG = "PhoneAccountType";
+
+    public static final String ACCOUNT_TYPE = SimContactsConstants.ACCOUNT_TYPE_PHONE;
+    public static final int FLAGS_PERSON_NAME = EditorInfo.TYPE_CLASS_TEXT
+            | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS | EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME;
+    protected static final int FLAGS_PHONE = EditorInfo.TYPE_CLASS_PHONE;
+
+    public PhoneAccountType(Context context, String resPackageName) {
+        this.accountType = ACCOUNT_TYPE;
+        this.resourcePackageName = null;
+        this.syncAdapterPackageName = resPackageName;
+
+        try {
+
+            addDataKindStructuredName(context);
+            addDataKindDisplayName(context);
+            addDataKindPhoneticName(context);
+            addDataKindNickname(context);
+            addDataKindPhone(context);
+            addDataKindEmail(context);
+            addDataKindStructuredPostal(context);
+            addDataKindIm(context);
+            addDataKindOrganization(context);
+            addDataKindPhoto(context);
+            addDataKindNote(context);
+            addDataKindWebsite(context);
+            //addDataKindGroupMembership(context);
+            if (context.getResources().getBoolean(
+                    com.android.internal.R.bool.config_built_in_sip_phone)) {
+                addDataKindSipAddress(context);
+            }
+
+            mIsInitialized = true;
+        } catch (DefinitionException e) {
+            Log.e(TAG, "Problem building account type", e);
+        }
+
+    }
+
+    @Override
+    public boolean isGroupMembershipEditable() {
+        return true;
+    }
+
+    @Override
+    public boolean areContactsWritable() {
+        return true;
+    }
+
+}
diff --git a/src/com/android/contacts/common/model/account/SimAccountType.java b/src/com/android/contacts/common/model/account/SimAccountType.java
new file mode 100644
index 0000000..6473f2b
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/SimAccountType.java
@@ -0,0 +1,123 @@
+/*
+  * Copyright (C) 2014, 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.
+*/
+
+package com.android.contacts.common.model.account;
+
+import android.content.Context;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+import android.graphics.drawable.Drawable;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.SimContactsConstants;
+import com.android.contacts.common.model.account.AccountType.DefinitionException;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.google.android.collect.Lists;
+
+public class SimAccountType extends BaseAccountType{
+    private static final String TAG = "SimContactsType";
+
+    public static final String ACCOUNT_TYPE = SimContactsConstants.ACCOUNT_TYPE_SIM;
+    public static final int FLAGS_PERSON_NAME = EditorInfo.TYPE_CLASS_TEXT
+            | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS | EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME;
+    public static final int FLAGS_PHONETIC = EditorInfo.TYPE_CLASS_TEXT
+            | EditorInfo.TYPE_TEXT_VARIATION_PHONETIC;
+    protected static final int FLAGS_PHONE = EditorInfo.TYPE_CLASS_PHONE;
+    private static Context mContext;
+
+    public SimAccountType(Context context, String resPackageName) {
+        this.accountType = ACCOUNT_TYPE;
+        this.resourcePackageName = resPackageName;
+        this.syncAdapterPackageName = resPackageName;
+
+        this.mContext = context;
+
+        try {
+            addDataKindStructuredName(context);
+            addDataKindDisplayName(context);
+            addDataKindPhone(context);
+            addDataKindEmail(context);
+            mIsInitialized = true;
+        } catch (DefinitionException e) {
+            Log.e(TAG, "Problem building account type", e);
+        }
+    }
+
+    @Override
+    protected DataKind addDataKindStructuredName(Context context) throws DefinitionException {
+        final DataKind kind = super.addDataKindStructuredName(context);
+        kind.fieldList = Lists.newArrayList();
+        kind.fieldList.add(new EditField(StructuredName.DISPLAY_NAME, R.string.nameLabelsGroup,
+                FLAGS_PERSON_NAME));
+
+        return kind;
+    }
+
+    @Override
+    protected DataKind addDataKindPhone(Context context) throws DefinitionException {
+        final DataKind kind = super.addDataKindPhone(context);
+
+        kind.iconAltRes = R.drawable.ic_text_holo_light;
+        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.typeColumn = Email.TYPE;
+        kind.fieldList = Lists.newArrayList();
+        kind.fieldList.add(new EditField(Email.ADDRESS, R.string.emailLabelsGroup, FLAGS_EMAIL));
+        return kind;
+    }
+
+
+    @Override
+    public boolean isGroupMembershipEditable() {
+        return true;
+    }
+
+    @Override
+    public boolean areContactsWritable() {
+        return true;
+    }
+
+}
diff --git a/src/com/android/contacts/common/util/AccountSelectionUtil.java b/src/com/android/contacts/common/util/AccountSelectionUtil.java
index ab32736..71e99e8 100644
--- a/src/com/android/contacts/common/util/AccountSelectionUtil.java
+++ b/src/com/android/contacts/common/util/AccountSelectionUtil.java
@@ -1,5 +1,7 @@
 /*
  * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,6 +24,7 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.net.Uri;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -31,11 +34,13 @@
 import android.widget.TextView;
 
 import com.android.contacts.common.R;
+import com.android.contacts.common.SimContactsConstants;
 import com.android.contacts.common.model.AccountTypeManager;
 import com.android.contacts.common.model.account.AccountType;
 import com.android.contacts.common.model.account.AccountWithDataSet;
 import com.android.contacts.common.vcard.ImportVCardActivity;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -46,8 +51,15 @@
     private static final String LOG_TAG = "AccountSelectionUtil";
 
     public static boolean mVCardShare = false;
+    private static int SIM_ID_INVALID = -1;
+    private static int mSelectedSim = SIM_ID_INVALID;
+    private static final String SIM_INDEX = "sim_index";
+    // Constant value to know option is import from all SIM's
+    private static int IMPORT_FROM_ALL = 8;
 
     public static Uri mPath;
+    // QRD enhancement: import subscription selected by user
+    private static int mImportSub = SimContactsConstants.SUB_INVALID;
 
     public static class AccountSelectedListener
             implements DialogInterface.OnClickListener {
@@ -55,7 +67,7 @@
         final private Context mContext;
         final private int mResId;
 
-        final protected List<AccountWithDataSet> mAccountList;
+        protected List<AccountWithDataSet> mAccountList;
 
         public AccountSelectedListener(Context context, List<AccountWithDataSet> accountList,
                 int resId) {
@@ -71,6 +83,19 @@
             dialog.dismiss();
             doImport(mContext, mResId, mAccountList.get(which));
         }
+        /**
+         * Reset the account list for this listener, to make sure the selected
+         * items reflect the displayed items.
+         *
+         * @param accountList The reset account list.
+         */
+        void setAccountList(List<AccountWithDataSet> accountList) {
+            mAccountList = accountList;
+        }
+    }
+
+    public static void setImportSubscription(int subscription) {
+        mImportSub = subscription;
     }
 
     public static Dialog getSelectAccountDialog(Context context, int resId) {
@@ -82,15 +107,28 @@
         return getSelectAccountDialog(context, resId, onClickListener, null);
     }
 
+    public static Dialog getSelectAccountDialog(Context context, int resId,
+            DialogInterface.OnClickListener onClickListener,
+            DialogInterface.OnCancelListener onCancelListener) {
+        return getSelectAccountDialog(context, resId, onClickListener,
+            onCancelListener, true);
+    }
+
     /**
      * When OnClickListener or OnCancelListener is null, uses a default listener.
      * The default OnCancelListener just closes itself with {@link Dialog#dismiss()}.
      */
     public static Dialog getSelectAccountDialog(Context context, int resId,
             DialogInterface.OnClickListener onClickListener,
-            DialogInterface.OnCancelListener onCancelListener) {
+            DialogInterface.OnCancelListener onCancelListener, boolean includeSIM) {
         final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
-        final List<AccountWithDataSet> writableAccountList = accountTypes.getAccounts(true);
+        List<AccountWithDataSet> writableAccountList = accountTypes.getAccounts(true);
+        if (includeSIM) {
+            writableAccountList = accountTypes.getAccounts(true);
+        } else {
+            writableAccountList = accountTypes.getAccounts(true,
+                AccountTypeManager.FLAG_ALL_ACCOUNTS_WITHOUT_SIM);
+        }
 
         Log.i(LOG_TAG, "The number of available accounts: " + writableAccountList.size());
 
@@ -135,6 +173,13 @@
             AccountSelectedListener accountSelectedListener =
                 new AccountSelectedListener(context, writableAccountList, resId);
             onClickListener = accountSelectedListener;
+        } else if (onClickListener instanceof AccountSelectedListener) {
+            // Because the writableAccountList is different if includeSIM or not, so
+            // should reset the account list for the AccountSelectedListener which
+            // is initialized with FLAG_ALL_ACCOUNTS.
+            // Reset the account list to make sure the selected account is contained
+            // in these display accounts.
+            ((AccountSelectedListener) onClickListener).setAccountList(writableAccountList);
         }
         if (onCancelListener == null) {
             onCancelListener = new DialogInterface.OnCancelListener() {
@@ -164,6 +209,22 @@
     }
 
     public static void doImportFromSim(Context context, AccountWithDataSet account) {
+        Intent importIntent = new Intent(SimContactsConstants.ACTION_MULTI_PICK_SIM);
+        if (account != null) {
+            importIntent.putExtra(SimContactsConstants.ACCOUNT_NAME, account.name);
+            importIntent.putExtra(SimContactsConstants.ACCOUNT_TYPE, account.type);
+            importIntent.putExtra(SimContactsConstants.ACCOUNT_DATA, account.dataSet);
+        }
+        if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+            importIntent.putExtra(SimContactsConstants.SUB, mImportSub);
+        } else {
+            importIntent.putExtra(SimContactsConstants.SUB,SimContactsConstants.SUB_1);
+        }
+        context.startActivity(importIntent);
+    }
+
+    public static void doImportFromMultiSim(Context context, AccountWithDataSet account,
+            int selectedSim) {
         Intent importIntent = new Intent(Intent.ACTION_VIEW);
         importIntent.setType("vnd.android.cursor.item/sim-contact");
         if (account != null) {
@@ -172,6 +233,7 @@
             importIntent.putExtra("data_set", account.dataSet);
         }
         importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts");
+        importIntent.putExtra(SIM_INDEX, selectedSim);
         context.startActivity(importIntent);
     }
 
@@ -191,4 +253,70 @@
         mPath = null;
         context.startActivity(importIntent);
     }
+
+    public static class SimSelectedListener
+            implements DialogInterface.OnClickListener {
+
+        final private Context mContext;
+        final private AccountWithDataSet mAccount;
+
+        public SimSelectedListener(Context context, AccountWithDataSet account) {
+            mContext = context;
+            mAccount = account;
+        }
+
+        public void onClick(DialogInterface dialog, int which) {
+            Log.d(LOG_TAG, "onClick OK: mSelectedSim = " + mSelectedSim);
+            if (mSelectedSim != SIM_ID_INVALID) {
+                doImportFromMultiSim(mContext, mAccount, mSelectedSim);
+            }
+        }
+    }
+
+    private static void displaySelectSimDialog(Context context,
+                SimSelectedListener simSelListner) {
+        Log.d(LOG_TAG, "displaySelectSimDialog");
+
+        mSelectedSim = SIM_ID_INVALID;
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(context);
+        builder.setTitle(R.string.select_sim);
+        final int numPhones = TelephonyManager.getDefault().getPhoneCount();
+        CharSequence[] subList = new CharSequence[numPhones + 1];
+        int i;
+        for (i = 1; i <= numPhones; i++) {
+            subList[i-1] = "SIM" + i;
+        }
+        subList[i-1] = context.getString(R.string.Import_All);
+        builder.setSingleChoiceItems(subList, -1, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                Log.d(LOG_TAG, "onClicked Dialog on which = " + which);
+                mSelectedSim = which;
+                if (mSelectedSim == numPhones) {
+                    mSelectedSim = IMPORT_FROM_ALL;
+                }
+            }
+        });
+
+        AlertDialog dialog = builder.create();
+        dialog.setButton(DialogInterface.BUTTON_POSITIVE,
+                context.getString(com.android.internal.R.string.ok), simSelListner);
+        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(
+                com.android.internal.R.string.cancel), new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                Log.d(LOG_TAG, "onClicked Cancel");
+            }
+        });
+
+        dialog.setOnDismissListener(new DialogInterface.OnDismissListener () {
+            @Override
+            public void onDismiss(DialogInterface dialog) {
+                Log.d(LOG_TAG, "onDismiss");
+                Log.d(LOG_TAG, "Selected SUB = " + mSelectedSim);
+            }
+        });
+        dialog.show();
+    }
 }
diff --git a/src/com/android/contacts/common/util/AccountsListAdapter.java b/src/com/android/contacts/common/util/AccountsListAdapter.java
index 84435df..575dddb 100644
--- a/src/com/android/contacts/common/util/AccountsListAdapter.java
+++ b/src/com/android/contacts/common/util/AccountsListAdapter.java
@@ -29,6 +29,8 @@
 import com.android.contacts.common.model.AccountTypeManager;
 import com.android.contacts.common.model.account.AccountType;
 import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.PhoneAccountType;
+import com.android.contacts.common.model.account.SimAccountType;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -48,7 +50,8 @@
     public enum AccountListFilter {
         ALL_ACCOUNTS,                   // All read-only and writable accounts
         ACCOUNTS_CONTACT_WRITABLE,      // Only where the account type is contact writable
-        ACCOUNTS_GROUP_WRITABLE         // Only accounts where the account type is group writable
+        ACCOUNTS_GROUP_WRITABLE,        // Only accounts where the account type is group writable
+        ACCOUNTS_CONTACT_WRITABLE_WITHOUT_SIM
     }
 
     public AccountsListAdapter(Context context, AccountListFilter accountListFilter) {
@@ -75,10 +78,22 @@
 
     private List<AccountWithDataSet> getAccounts(AccountListFilter accountListFilter) {
         if (accountListFilter == AccountListFilter.ACCOUNTS_GROUP_WRITABLE) {
-            return new ArrayList<AccountWithDataSet>(mAccountTypes.getGroupWritableAccounts());
+            return new ArrayList<AccountWithDataSet>(mAccountTypes.getAccounts(true,
+                    AccountTypeManager.FLAG_ALL_ACCOUNTS_WITHOUT_LOCAL));
         }
-        return new ArrayList<AccountWithDataSet>(mAccountTypes.getAccounts(
-                accountListFilter == AccountListFilter.ACCOUNTS_CONTACT_WRITABLE));
+        final List<AccountWithDataSet> writableAccountList = mAccountTypes
+                .getAccounts(accountListFilter == AccountListFilter.ACCOUNTS_CONTACT_WRITABLE
+                || accountListFilter == AccountListFilter.ACCOUNTS_CONTACT_WRITABLE_WITHOUT_SIM);
+        List<AccountWithDataSet> deletedList = new ArrayList<AccountWithDataSet>();
+
+        if (accountListFilter == AccountListFilter.ACCOUNTS_CONTACT_WRITABLE_WITHOUT_SIM) {
+            for (AccountWithDataSet account : writableAccountList) {
+                if (SimAccountType.ACCOUNT_TYPE.equals(account.type))
+                    deletedList.add(account);
+            }
+            writableAccountList.removeAll(deletedList);
+        }
+        return writableAccountList;
     }
 
     @Override