diff options
author | xjiang <xjiang@codeaurora.org> | 2015-08-20 17:36:39 +0800 |
---|---|---|
committer | blong <blong@codeaurora.org> | 2015-09-09 09:45:04 +0800 |
commit | b1a1a5cd3d7053be3f01d0fb39ea59a832f76931 (patch) | |
tree | ebba7b621c25a42b1bcae990dc3329136b4edc9b | |
parent | 131c336b838153492bf71fdf20072550979e28ca (diff) | |
download | android_packages_apps_ContactsCommon-b1a1a5cd3d7053be3f01d0fb39ea59a832f76931.tar.gz android_packages_apps_ContactsCommon-b1a1a5cd3d7053be3f01d0fb39ea59a832f76931.tar.bz2 android_packages_apps_ContactsCommon-b1a1a5cd3d7053be3f01d0fb39ea59a832f76931.zip |
Add import/export contacts from/to SIM card
- Support import or export contacts from/to SIM card
- Support auto split contacts according email and number count
when export to SIM card
- Add the interface to get anr and email count
- Add the interface to copy contacts between SIM card and Phone
Change-Id: Iba56d1ca38d9fdb32469a961bf0a370daeac4bff
-rw-r--r-- | Android.mk | 2 | ||||
-rw-r--r-- | res/values-zh-rCN/strings.xml | 4 | ||||
-rw-r--r-- | res/values-zh-rTW/strings.xml | 20 | ||||
-rw-r--r-- | res/values/strings.xml | 4 | ||||
-rw-r--r-- | src/com/android/contacts/common/MoreContactUtils.java | 406 | ||||
-rw-r--r-- | src/com/android/contacts/common/editor/SelectAccountDialogFragment.java | 2 | ||||
-rw-r--r-- | src/com/android/contacts/common/interactions/ImportExportDialogFragment.java | 718 | ||||
-rw-r--r-- | src/com/android/contacts/common/util/AccountSelectionUtil.java | 40 | ||||
-rw-r--r-- | src/com/android/contacts/common/vcard/SelectAccountActivity.java | 5 |
9 files changed, 1087 insertions, 114 deletions
@@ -23,7 +23,7 @@ res_dirs := res $(phone_common_dir)/res LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs)) LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs)) - +LOCAL_JAVA_LIBRARIES := telephony-common LOCAL_AAPT_FLAGS := \ --auto-add-overlay \ --extra-packages com.android.phone.common diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index b67f9309..bc9d5383 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- +<!-- ~ Copyright (C) 2012 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); @@ -161,6 +161,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_summary" msgid="2306434118233541675">"从 SIM 卡“<xliff:g id="SIM_NAME">^1</xliff:g>” - <xliff:g id="SIM_NUMBER">^2</xliff:g> 导入"</string> <string name="import_from_sim_summary_no_number" msgid="8498561004799710237">"从 SIM 卡“<xliff:g id="SIM_NAME">%1$s</xliff:g>”导入"</string> @@ -179,6 +180,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> diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 3dc3cfd1..3e5ef1ab 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -161,6 +161,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_summary" msgid="2306434118233541675">"從 SIM 卡 <xliff:g id="SIM_NAME">^1</xliff:g> - <xliff:g id="SIM_NUMBER">^2</xliff:g> 匯入"</string> <string name="import_from_sim_summary_no_number" msgid="8498561004799710237">"從 SIM 卡 <xliff:g id="SIM_NAME">%1$s</xliff:g> 匯入"</string> @@ -178,6 +179,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> @@ -247,6 +249,24 @@ <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_to_sim_failed">"導出失敗,<xliff:g id="insertCount">%d</xliff:g>條成功導出"</string> + <string name="export_sim_card_full">"SIM卡已滿,<xliff:g id="insertCount">%d</xliff:g>條成功導出"</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> <string name="select_account_dialog_title" msgid="5509088895267310568">"帳戶"</string> <string name="set_default_account" msgid="3865970860434642695">"一律使用這張 SIM 卡通話"</string> <string name="select_phone_account_for_calls" msgid="933905607702811164">"選擇通話帳戶"</string> diff --git a/res/values/strings.xml b/res/values/strings.xml index f5973e0b..d471f4e9 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -764,6 +764,10 @@ a ren't members of any other group. [CHAR LIMIT=25] --> <string name="export_sim_card_full">Sim Card is full, <xliff:g id="insertCount">%d</xliff:g> items are exported</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> diff --git a/src/com/android/contacts/common/MoreContactUtils.java b/src/com/android/contacts/common/MoreContactUtils.java index c6dd3329..520efd8a 100644 --- a/src/com/android/contacts/common/MoreContactUtils.java +++ b/src/com/android/contacts/common/MoreContactUtils.java @@ -22,21 +22,44 @@ 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.ComponentName; +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.TelephonyManager; import android.telephony.PhoneNumberUtils; 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.internal.telephony.PhoneConstants; +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. @@ -44,6 +67,19 @@ import com.android.internal.telephony.PhoneConstants; 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" }; /** * Returns true if two data with mimetypes which represent values in contact entries are @@ -254,9 +290,6 @@ public class MoreContactUtils { StringBuilder simFilter = new StringBuilder(""); for (int i = 0; i < count; i++) { - if (!TelephonyManager.getDefault().hasIccCard(i)) { - continue; - } if (TelephonyManager.SIM_STATE_UNKNOWN == TelephonyManager .getDefault().getSimState(i)) { simFilter.append(getSimAccountName(i) + ','); @@ -303,42 +336,385 @@ public class MoreContactUtils { return subscription; } + public static int getAnrCount(int slot) { + int anrCount = 0; + /*int[] 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 getAdnCount(int slot) { + int adnCount = 250; + /*int[] 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; + /*int[] 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; + } + /** * Returns the subscription's card can save anr or not. */ - public static boolean canSaveAnr(int subscription) { - return false; - //return getAnrCount(subscription) > 0 ? true : false; + 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 subscription) { - return false; - //return getEmailCount(subscription) > 0 ? true : false; + return getEmailCount(subscription) > 0 ? true : false; } public static int getOneSimAnrCount(int sub) { int count = 0; - /*int anrCount = getAnrCount(sub); + int anrCount = getAnrCount(sub); int adnCount = getAdnCount(sub); if (adnCount > 0) { count = anrCount % adnCount != 0 ? (anrCount / adnCount + 1) : (anrCount / adnCount); - }*/ + } return count; } public static int getOneSimEmailCount(int sub) { int count = 0; - /*int emailCount = getEmailCount(sub); + int emailCount = getEmailCount(sub); int adnCount = getAdnCount(sub); if (adnCount > 0) { - count = emailCount % adnCount != 0 ? (emailCount - / adnCount + 1) + 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(SimContactsConstants.ANR_SEP); + } 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 = anrNumber.replaceAll("[^0123456789PWN\\,\\;\\*\\#\\+\\:]", ""); + 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 == PhoneConstants.SUB1) { + account = new Account(SimContactsConstants.SIM_NAME_1, + SimContactsConstants.ACCOUNT_TYPE_SIM); + } else if (sub == PhoneConstants.SUB2) { + account = new Account(SimContactsConstants.SIM_NAME_2, + SimContactsConstants.ACCOUNT_TYPE_SIM); + } + } else { + if (sub == PhoneConstants.SUB1) { + 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; + } + + public static int getSpareAnrCount(int sub) { + int anrCount = 0; + /*int[] subId=SubscriptionManager.getSubId(sub); + try { + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(ServiceManager + .getService(PHONEBOOK)); + if (iccIpb != null) { + if (subId != null + && TelephonyManager.getDefault().isMultiSimEnabled()) { + anrCount = iccIpb.getSpareEmailCountUsingSubId(subId[0]); + } else { + anrCount = iccIpb.getSpareEmailCount(); + } + } + } catch (RemoteException ex) { + // ignore it + } catch (SecurityException ex) { + Log.i(TAG, ex.toString()); + } catch (Exception ex) { + } + if (DBG) { + Log.d(TAG, "getSpareAnrCount(" + sub + ") = " + anrCount); + }*/ + return anrCount; + } + + public static int getSpareEmailCount(int sub) { + int emailCount = 0; + /*int[] subId=SubscriptionManager.getSubId(sub); + try { + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(ServiceManager + .getService(PHONEBOOK)); + if (iccIpb != null) { + if (subId != null + && TelephonyManager.getDefault().isMultiSimEnabled()) { + emailCount = iccIpb.getSpareEmailCountUsingSubId(subId[0]); + } else { + emailCount = iccIpb.getSpareEmailCount(); + } + } + } catch (RemoteException ex) { + // ignore it + } catch (SecurityException ex) { + Log.i(TAG, ex.toString()); + } catch (Exception ex) { + } + if (DBG) { + Log.d(TAG, "getSpareEmailCount(" + sub + ") = " + emailCount); + }*/ + return emailCount; + } + + 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; + } } diff --git a/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java b/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java index c2ebbbfa..26fc7712 100644 --- a/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java +++ b/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java @@ -65,7 +65,7 @@ public final class SelectAccountDialogFragment extends DialogFragment { 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 6553627f..67edac02 100644 --- a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java +++ b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java @@ -16,20 +16,41 @@ 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.DialogFragment; 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.PhoneNumberUtils; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -43,8 +64,13 @@ import android.widget.ArrayAdapter; 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; @@ -53,8 +79,11 @@ import com.android.contacts.common.util.ImplicitIntentsUtil; import com.android.contacts.common.vcard.ExportVCardActivity; import com.android.contacts.common.vcard.VCardCommonArguments; import com.android.contacts.commonbind.analytics.AnalyticsUtil; +import com.android.internal.telephony.PhoneConstants; import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; /** * An dialog invoked to import/export contacts. @@ -67,10 +96,67 @@ public class ImportExportDialogFragment extends DialogFragment private static final String KEY_SUBSCRIPTION_ID = "subscriptionId"; private static final String ARG_CONTACTS_ARE_AVAILABLE = "CONTACTS_ARE_AVAILABLE"; + private static final boolean DEBUG = true; + + public static final int SUBACTIVITY_EXPORT_CONTACTS = 100; + + // 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<AdapterEntry> 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); + } + private SubscriptionManager mSubscriptionManager; /** Preferred way to show this dialog */ @@ -93,6 +179,7 @@ public class ImportExportDialogFragment extends DialogFragment @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); @@ -101,7 +188,7 @@ public class ImportExportDialogFragment extends DialogFragment VCardCommonArguments.ARG_CALLING_ACTIVITY); // Adapter that shows a list of string resources - final ArrayAdapter<AdapterEntry> adapter = new ArrayAdapter<AdapterEntry>(getActivity(), + mAdapter = new ArrayAdapter<AdapterEntry>(getActivity(), R.layout.select_dialog_item) { @Override public View getView(int position, View convertView, ViewGroup parent) { @@ -113,69 +200,29 @@ public class ImportExportDialogFragment extends DialogFragment } }; - final TelephonyManager manager = - (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE); - - mSubscriptionManager = SubscriptionManager.from(getActivity()); - - if (res.getBoolean(R.bool.config_allow_import_from_vcf_file)) { - adapter.add(new AdapterEntry(getString(R.string.import_from_vcf_file), - R.string.import_from_vcf_file)); - } - if (manager != null && res.getBoolean(R.bool.config_allow_sim_import)) { - List<SubscriptionInfo> subInfoRecords = null; - try { - subInfoRecords = mSubscriptionManager.getActiveSubscriptionInfoList(); - } catch (SecurityException e) { - Log.w(TAG, "SecurityException thrown, lack permission for" - + " getActiveSubscriptionInfoList", e); - } - if (subInfoRecords != null) { - if (subInfoRecords.size() == 1) { - adapter.add(new AdapterEntry(getString(R.string.manage_sim_contacts), - R.string.manage_sim_contacts, - subInfoRecords.get(0).getSubscriptionId())); - adapter.add(new AdapterEntry(getString(R.string.export_to_sim), - R.string.export_to_sim, - subInfoRecords.get(0).getSubscriptionId())); - } else { - for (SubscriptionInfo record : subInfoRecords) { - adapter.add(new AdapterEntry(getSubDescription(record, true), - R.string.manage_sim_contacts, record.getSubscriptionId())); - adapter.add(new AdapterEntry(getSubDescription(record, false), - R.string.export_to_sim, record.getSubscriptionId())); - } - } - } - } - if (res.getBoolean(R.bool.config_allow_export)) { - if (contactsAreAvailable) { - adapter.add(new AdapterEntry(getString(R.string.export_to_vcf_file), - R.string.export_to_vcf_file)); - } - } - if (res.getBoolean(R.bool.config_allow_share_visible_contacts)) { - if (contactsAreAvailable) { - adapter.add(new AdapterEntry(getString(R.string.share_visible_contacts), - 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).mChoiceResourceId; + final int resId = mAdapter.getItem(which).mChoiceResourceId; switch (resId) { - case R.string.manage_sim_contacts: + case R.string.import_from_sim: { + handleImportFromSimRequest(resId); + break; + } case R.string.import_from_vcf_file: { - dismissDialog = handleImportRequest(resId, - adapter.getItem(which).mSubscriptionId); + handleImportRequest(resId); + break; + } + case R.string.export_to_sim: { + handleExportToSimRequest(resId); break; } case R.string.export_to_vcf_file: { - dismissDialog = true; Intent exportIntent = new Intent(getActivity(), ExportVCardActivity.class); exportIntent.putExtra(VCardCommonArguments.ARG_CALLING_ACTIVITY, callingActivity); @@ -183,38 +230,79 @@ public class ImportExportDialogFragment extends DialogFragment break; } case R.string.share_visible_contacts: { - dismissDialog = true; doShareVisibleContacts(); break; } - case R.string.export_to_sim: { - dismissDialog = true; - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setClassName("com.android.phone", - "com.android.phone.ExportContactsToSim"); - intent.putExtra("subscription_id", adapter.getItem(which).mSubscriptionId); - startActivity(intent); - break; - } default: { - dismissDialog = true; Log.e(TAG, "Unexpected resource: " + getActivity().getResources().getResourceEntryName(resId)); } } - if (dismissDialog) { - dialog.dismiss(); - } + 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(new AdapterEntry(getString(R.string.import_from_sim), + R.string.import_from_sim)); + } + if (res.getBoolean(R.bool.config_allow_import_from_vcf_file)) { + mAdapter.add(new AdapterEntry(getString(R.string.import_from_vcf_file), + R.string.import_from_vcf_file)); + } + + if (hasIccCard) { + mAdapter.add(new AdapterEntry(getString(R.string.export_to_sim), + R.string.export_to_sim)); + } + if (res.getBoolean(R.bool.config_allow_export)) { + // 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(new AdapterEntry(getString(R.string.export_to_vcf_file), + R.string.export_to_vcf_file)); + } + } + if (res.getBoolean(R.bool.config_allow_share_visible_contacts)) { + if (contactsAreAvailable) { + mAdapter.add(new AdapterEntry(getString(R.string.share_visible_contacts), + R.string.share_visible_contacts)); + } + } + } + private void doShareVisibleContacts() { try { // TODO move the query into a loader and do this in a background thread @@ -260,23 +348,22 @@ public class ImportExportDialogFragment extends DialogFragment * * @return {@code true} if the dialog show be closed. {@code false} otherwise. */ - private boolean handleImportRequest(int resId, int subscriptionId) { + private boolean handleImportRequest(int resId) { // There are three possibilities: // - 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) { // Send over to the account selector final Bundle args = new Bundle(); args.putInt(KEY_RES_ID, resId); - args.putInt(KEY_SUBSCRIPTION_ID, subscriptionId); - SelectAccountDialogFragment.show( - getFragmentManager(), this, - R.string.dialog_new_contact_account, - AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, args); + SelectAccountDialogFragment.show(mActivity.getFragmentManager(), + this, R.string.dialog_new_contact_account, + 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 @@ -284,8 +371,8 @@ public class ImportExportDialogFragment extends DialogFragment return false; } - AccountSelectionUtil.doImport(getActivity(), resId, - (size == 1 ? accountList.get(0) : null), subscriptionId); + AccountSelectionUtil.doImport(mActivity, resId, + (size == 1 ? accountList.get(0) : null)); return true; // Close the dialog. } @@ -294,8 +381,7 @@ public class ImportExportDialogFragment extends DialogFragment */ @Override public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) { - AccountSelectionUtil.doImport(getActivity(), extraArgs.getInt(KEY_RES_ID), - account, extraArgs.getInt(KEY_SUBSCRIPTION_ID)); + 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. @@ -308,6 +394,478 @@ public class ImportExportDialogFragment extends DialogFragment 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; + + mSimContactsOperation = new SimContactsOperation(mPeople); + Cursor cr = null; + // call query first, otherwise insert will fail if this insert is called + // without any query before + try{ + int[] 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(); + } + } + freeSimCount = MoreContactUtils.getSimFreeCount(mPeople,subscription); + 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(); + //contacts name has been existed in contactInfo,so no need query it again + String name = contactInfo[4]; + 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); + } + } + 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 >=0 && 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) { + 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(SimContactsConstants.ANR_SEP); + } + } + } + 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(SimContactsConstants.EMAIL_SEP); + } + } + } + + 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.sendMessage(mToastHandler.obtainMessage( + TOAST_SIM_CARD_FULL, insertCount, 0)); + break; + } else { + isAirplaneMode = MoreContactUtils + .isAPMOnAndSIMPowerDown(mPeople); + if (isAirplaneMode) { + mToastHandler.sendMessage(mToastHandler.obtainMessage( + TOAST_EXPORT_FAILED, insertCount, 0)); + break; + } else { + // Failed to insert to SIM card + int anrNumber = 0; + if (!TextUtils.isEmpty(anrNum)) { + anrNumber += anrNum.toString().split( + SimContactsConstants.ANR_SEP).length; + } + // reset emptyNumber and emptyAnr to the value before + // the insert operation + emptyAnr += anrNumber; + emptyNumber += anrNumber; + if (!TextUtils.isEmpty(num)) { + emptyNumber++; + } + + if (!TextUtils.isEmpty(email)) { + // reset emptyEmail to the value before the insert + // operation + emptyEmail += email.toString().split( + SimContactsConstants.EMAIL_SEP).length; + } + 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.sendMessage(mToastHandler.obtainMessage( + TOAST_SIM_CARD_FULL, insertCount, 0)); + } + 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) { + int exportCount = 0; + switch (msg.what) { + case TOAST_EXPORT_FAILED: + exportCount = msg.arg1; + Toast.makeText(mPeople, mPeople.getString(R.string.export_to_sim_failed, + exportCount), 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: + exportCount = msg.arg1; + Toast.makeText(mPeople, mPeople.getString(R.string.export_sim_card_full, + exportCount), 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: + 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 = PhoneConstants.SUB1; + 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(PhoneConstants.SUB1); + // 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 PhoneConstants.SUB1; + } + private CharSequence getSubDescription(SubscriptionInfo record, boolean isImport) { CharSequence name = record.getDisplayName(); if (TextUtils.isEmpty(record.getNumber())) { diff --git a/src/com/android/contacts/common/util/AccountSelectionUtil.java b/src/com/android/contacts/common/util/AccountSelectionUtil.java index ff8397ae..79eb44a8 100644 --- a/src/com/android/contacts/common/util/AccountSelectionUtil.java +++ b/src/com/android/contacts/common/util/AccountSelectionUtil.java @@ -22,6 +22,8 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.util.Log; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; @@ -31,11 +33,14 @@ import android.widget.ArrayAdapter; 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 com.android.internal.telephony.PhoneConstants; +import java.util.ArrayList; import java.util.List; /** @@ -48,6 +53,8 @@ public class AccountSelectionUtil { public static boolean mVCardShare = false; public static Uri mPath; + // QRD enhancement: import subscription selected by user + private static int mImportSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID; public static class AccountSelectedListener implements DialogInterface.OnClickListener { @@ -78,7 +85,7 @@ public class AccountSelectionUtil { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); - doImport(mContext, mResId, mAccountList.get(which), mSubscriptionId); + doImport(mContext, mResId, mAccountList.get(which)); } /** * Reset the account list for this listener, to make sure the selected @@ -91,6 +98,10 @@ public class AccountSelectionUtil { } } + public static void setImportSubscription(int subscription) { + mImportSub = subscription; + } + public static Dialog getSelectAccountDialog(Context context, int resId) { return getSelectAccountDialog(context, resId, null, null); } @@ -188,11 +199,11 @@ public class AccountSelectionUtil { .create(); } - public static void doImport(Context context, int resId, AccountWithDataSet account, - int subscriptionId) { + public static void doImport(Context context, int resId, + AccountWithDataSet account) { switch (resId) { - case R.string.manage_sim_contacts: { - doImportFromSim(context, account, subscriptionId); + case R.string.import_from_sim: { + doImportFromSim(context, account); break; } case R.string.import_from_vcf_file: { @@ -202,17 +213,18 @@ public class AccountSelectionUtil { } } - public static void doImportFromSim(Context context, AccountWithDataSet account, - int subscriptionId) { - Intent importIntent = new Intent(Intent.ACTION_VIEW); - importIntent.setType("vnd.android.cursor.item/sim-contact"); + public static void doImportFromSim(Context context, AccountWithDataSet account) { + Intent importIntent = new Intent(SimContactsConstants.ACTION_MULTI_PICK_SIM); if (account != null) { - importIntent.putExtra("account_name", account.name); - importIntent.putExtra("account_type", account.type); - importIntent.putExtra("data_set", account.dataSet); + 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(PhoneConstants.SLOT_KEY, mImportSub); + } else { + importIntent.putExtra(PhoneConstants.SLOT_KEY,PhoneConstants.SUB1); } - importIntent.putExtra("subscription_id", (Integer) subscriptionId); - importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts"); context.startActivity(importIntent); } diff --git a/src/com/android/contacts/common/vcard/SelectAccountActivity.java b/src/com/android/contacts/common/vcard/SelectAccountActivity.java index 66bfbca1..d8596378 100644 --- a/src/com/android/contacts/common/vcard/SelectAccountActivity.java +++ b/src/com/android/contacts/common/vcard/SelectAccountActivity.java @@ -58,7 +58,8 @@ public class SelectAccountActivity extends Activity { // - no account -> use phone-local storage without asking the user final int resId = R.string.import_from_vcf_file; final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this); - final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true); + final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true, + AccountTypeManager.FLAG_ALL_ACCOUNTS_WITHOUT_SIM); if (accountList.size() == 0) { Log.w(LOG_TAG, "Account does not exist"); finish(); @@ -106,7 +107,7 @@ public class SelectAccountActivity extends Activity { } return AccountSelectionUtil.getSelectAccountDialog(this, resId, mAccountSelectionListener, - new CancelListener()); + new CancelListener(), false); } } return super.onCreateDialog(resId, bundle); |