diff options
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | res/values/cm_strings.xml | 56 | ||||
-rw-r--r-- | res/values/ids.xml | 8 | ||||
-rw-r--r-- | res/values/strings.xml | 2 | ||||
-rw-r--r-- | src/com/android/contacts/common/MoreContactUtils.java | 423 | ||||
-rw-r--r-- | src/com/android/contacts/common/SimContactsConstants.java | 1 | ||||
-rw-r--r-- | src/com/android/contacts/common/interactions/ImportExportDialogFragment.java | 935 | ||||
-rw-r--r-- | src/com/android/contacts/common/util/AccountSelectionUtil.java | 54 |
8 files changed, 1384 insertions, 96 deletions
@@ -20,6 +20,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, res) +LOCAL_JAVA_LIBRARIES := telephony-common LOCAL_STATIC_JAVA_LIBRARIES := \ com.android.phone.shared \ com.android.vcard \ diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index e79cadc5..c890ee58 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -37,4 +37,60 @@ <string name="fail_reason_import_vcard">I/O error,couldn\'t import vCard <xliff:g id="name">%s</xliff:g></string> <string name="label_groups">Group</string> + + <!-- Toast indicating that sharing too many contact has failed. [CHAR LIMIT=NONE] --> + <string name="share_failed">Too many contacts, share failed</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="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> + + <!-- Warning dialog contents after users selects to delete a contact. --> + <string name="readOnlyContactDeleteConfirmation">This contact contains information from multiple + accounts. Information from read-only accounts will be hidden in your contacts lists, + not deleted.</string> + + <!-- Warning dialog contents after users selects to delete a ReadOnly contact--> + <string name="readOnlyContactWarning">You can\'t delete contacts from read-only accounts, + but you can hide them in your contacts lists.</string> + + <!-- Warning dialog contents after users selects to delete a contact with multiple Writable sources. --> + <string name="multipleContactDeleteConfirmation">Deleting this contact will delete information + from multiple accounts.</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> </resources> diff --git a/res/values/ids.xml b/res/values/ids.xml index 093901ba..d106c0e9 100644 --- a/res/values/ids.xml +++ b/res/values/ids.xml @@ -45,4 +45,12 @@ <item type="id" name="tag_display_name"/> <item type="id" name="tag_identifier"/> <item type="id" name="tag_contact_type"/> + + <!-- For ContactDeletionInteraction --> + <item type="id" name="dialog_delete_contact_confirmation"/> + + <!-- For ContactsListActivity --> + <item type="id" name="dialog_readonly_contact_hide_confirmation"/> + <item type="id" name="dialog_readonly_contact_delete_confirmation"/> + <item type="id" name="dialog_multiple_contact_delete_confirmation"/> </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index c6b6c059..c63fb33d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -416,9 +416,7 @@ a ren't members of any other group. [CHAR LIMIT=25] --> <string name="dialog_new_contact_account">Create contact under account</string> <!-- Action string for selecting SIM for importing contacts --> - <!-- <string name="import_from_sim">Import from SIM card</string> - --> <!-- Action string for selecting (USB) storage for importing contacts [CHAR LIMIT=30] --> <string name="import_from_sdcard" product="default">Import from storage</string> diff --git a/src/com/android/contacts/common/MoreContactUtils.java b/src/com/android/contacts/common/MoreContactUtils.java index ef014f39..c310e287 100644 --- a/src/com/android/contacts/common/MoreContactUtils.java +++ b/src/com/android/contacts/common/MoreContactUtils.java @@ -16,20 +16,41 @@ package com.android.contacts.common; +import android.accounts.Account; import com.android.i18n.phonenumbers.NumberParseException; import com.android.i18n.phonenumbers.PhoneNumberUtil; import android.content.Context; +import android.content.ContentProviderOperation; +import android.content.ContentResolver; +import android.content.ContentValues; 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.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.telephony.MSimTelephonyManager; 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.IIccPhoneBook; +import com.android.internal.telephony.msim.IIccPhoneBookMSim; + +import java.util.ArrayList; /** * Shared static contact utility methods. @@ -37,7 +58,21 @@ import com.android.contacts.common.model.account.AccountType; 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"; + private static final int MAX_LENGTH_NAME_IN_SIM = 14; + private static final int MAX_LENGTH_NAME_WITH_CHINESE_IN_SIM = 6; + private static final int MAX_LENGTH_NUMBER_IN_SIM = 20; + private 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_MSIM = "simphonebook_msim"; + private static final String PHONEBOOK = "simphonebook"; + public static final String[] MULTI_SIM_NAME = { + "perferred_name_sub1", "preferred_name_sub2" + }; /** * 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 @@ -231,4 +266,390 @@ public class MoreContactUtils { return subscription; } + public static void 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; + 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 { + resolver.applyBatch(ContactsContract.AUTHORITY, operationList); + } catch (RemoteException e) { + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } catch (OperationApplicationException e) { + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } + } + + 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 = number.replaceAll("[^0123456789PWN\\,\\;\\*\\#\\+]", ""); + 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)) { + if (emails.length() > MAX_LENGTH_EMAIL_IN_SIM) { + emails = emails.substring(0, MAX_LENGTH_EMAIL_IN_SIM); + } + mValues.put(SimContactsConstants.STR_EMAILS, emails); + } + if (!TextUtils.isEmpty(anrNumber)) { + anrNumber = anrNumber.replaceAll("[^0123456789PWN\\,\\;\\*\\#\\+]", ""); + if (anrNumber.length() > MAX_LENGTH_NUMBER_IN_SIM) { + anrNumber = anrNumber.substring(0, MAX_LENGTH_NUMBER_IN_SIM); + } + + 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 (MSimTelephonyManager.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 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 getAnrCount(int sub) { + int anrCount = 0; + if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { + try { + IIccPhoneBookMSim iccIpb = IIccPhoneBookMSim.Stub.asInterface(ServiceManager + .getService(PHONEBOOK_MSIM)); + if (iccIpb != null) { + anrCount = iccIpb.getAnrCount(sub); + } + } catch (RemoteException ex) { + // ignore it + } catch (SecurityException ex) { + Log.i(TAG, ex.toString()); + } catch (Exception ex) { + } + } else { + try { + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(ServiceManager + .getService(PHONEBOOK)); + if (iccIpb != null) { + anrCount = iccIpb.getAnrCount(); + } + } catch (RemoteException ex) { + // ignore it + } catch (SecurityException ex) { + Log.i(TAG, ex.toString()); + } catch (Exception ex) { + } + } + if (DBG) { + Log.d(TAG, "getAnrCount(" + sub + ") = " + anrCount); + } + return anrCount; + } + + public static int getEmailCount(int sub) { + int emailCount = 0; + if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { + try { + IIccPhoneBookMSim iccIpb = IIccPhoneBookMSim.Stub.asInterface(ServiceManager + .getService(PHONEBOOK_MSIM)); + if (iccIpb != null) { + emailCount = iccIpb.getEmailCount(sub); + } + } catch (RemoteException ex) { + // ignore it + } catch (SecurityException ex) { + Log.i(TAG, ex.toString()); + } catch (Exception ex) { + } + } else { + try { + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(ServiceManager + .getService(PHONEBOOK)); + if (iccIpb != null) { + emailCount = iccIpb.getEmailCount(); + } + } catch (RemoteException ex) { + // ignore it + } catch (SecurityException ex) { + Log.i(TAG, ex.toString()); + } catch (Exception ex) { + } + } + if (DBG) { + Log.d(TAG, "getEmailCount(" + sub + ") = " + emailCount); + } + return emailCount; + } + + public static int getSpareAnrCount(int sub) { + int anrCount = 0; + if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { + try { + IIccPhoneBookMSim iccIpb = IIccPhoneBookMSim.Stub.asInterface(ServiceManager + .getService(PHONEBOOK_MSIM)); + if (iccIpb != null) { + anrCount = iccIpb.getSpareAnrCount(sub); + } + } catch (RemoteException ex) { + // ignore it + } catch (SecurityException ex) { + Log.i(TAG, ex.toString()); + } catch (Exception ex) { + } + } else { + try { + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(ServiceManager + .getService(PHONEBOOK)); + if (iccIpb != null) { + anrCount = iccIpb.getSpareAnrCount(); + } + } 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; + if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { + try { + IIccPhoneBookMSim iccIpb = IIccPhoneBookMSim.Stub.asInterface(ServiceManager + .getService(PHONEBOOK_MSIM)); + if (iccIpb != null) { + emailCount = iccIpb.getSpareEmailCount(sub); + } + } catch (RemoteException ex) { + // ignore it + } catch (SecurityException ex) { + Log.i(TAG, ex.toString()); + } catch (Exception ex) { + } + } else { + try { + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(ServiceManager + .getService(PHONEBOOK)); + if (iccIpb != null) { + 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(); + } + + public static int getAdnCount(int sub) { + int adnCount = 0; + if (sub == -1) { + return Integer.MAX_VALUE; + } + if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { + try { + IIccPhoneBookMSim iccIpb = IIccPhoneBookMSim.Stub.asInterface(ServiceManager + .getService(PHONEBOOK_MSIM)); + if (iccIpb != null) { + adnCount = iccIpb.getAdnCount(sub); + } + } catch (RemoteException ex) { + // ignore it + } catch (SecurityException ex) { + Log.i(TAG, ex.toString()); + } catch (Exception ex) { + } + } else { + try { + IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(ServiceManager + .getService(PHONEBOOK)); + if (iccIpb != null) { + adnCount = iccIpb.getAdnCount(); + } + } catch (RemoteException ex) { + // ignore it + } catch (SecurityException ex) { + Log.i(TAG, ex.toString(), (new Exception())); + } catch (Exception ex) { + } + } + if (DBG) { + Log.d(TAG, "getAdnCount(" + sub + ") = " + adnCount); + } + return adnCount; + } + + /** + * Returns the subscription's card can save anr or not. + */ + public static boolean canSaveAnr(int subscription) { + return getAnrCount(subscription) > 0 ? true : false; + } + + /** + * Returns the subscription's card can save email or not. + */ + public static boolean canSaveEmail(int subscription) { + return getEmailCount(subscription) > 0 ? true : false; + } + } diff --git a/src/com/android/contacts/common/SimContactsConstants.java b/src/com/android/contacts/common/SimContactsConstants.java index 16fcfe41..f7214dd8 100644 --- a/src/com/android/contacts/common/SimContactsConstants.java +++ b/src/com/android/contacts/common/SimContactsConstants.java @@ -43,6 +43,7 @@ public interface SimContactsConstants { public static final String SUB = MSimConstants.SUBSCRIPTION_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"; diff --git a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java index dc71b962..13f829e7 100644 --- a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java +++ b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java @@ -18,19 +18,44 @@ 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.telephony.PhoneNumberUtils; +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.QuickContact; +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.provider.Settings.System; import android.telephony.MSimTelephonyManager; import android.telephony.TelephonyManager; import android.util.Log; @@ -41,8 +66,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; @@ -51,6 +81,8 @@ import com.android.contacts.common.vcard.ExportVCardActivity; import com.android.contacts.common.vcard.VCardCommonArguments; import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; /** * An dialog invoked to import/export contacts. @@ -62,27 +94,97 @@ public class ImportExportDialogFragment extends DialogFragment 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 int mSelectedSim = SimContactsConstants.SUB_INVALID; 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; + + //decide whether pick phone or contacts + private static final String IS_CONTACT = "IS_CONTACT"; + + // multi-pick contacts which contains email address + private static final String ACTION_MULTI_PICK_EMAIL = + "com.android.contacts.action.MULTI_PICK_EMAIL"; + + // multi-pick contacts + private static final String ACTION_MULTI_PICK = + "com.android.contacts.action.MULTI_PICK"; + + //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"; + // the max count limit of Chinese code or not + private static final int CONTACT_NAME_MAX_LENGTH_NOT_CHN = 14; + private static final int CONTACT_NAME_MAX_LENGTH_CHN = 6; + + // 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; + private static final boolean DEBUG = false; + private static boolean isMenuItemClicked = false; + private SimContactsOperation mSimContactsOperation; + private ArrayAdapter<Integer> mAdapter; + private Activity mActiv; + private static boolean isExportingToSIM = false; + public static boolean isExportingToSIM(){ + return isExportingToSIM; + } + private static ExportToSimThread mExportThread = null; + public ExportToSimThread createExportToSimThread(int type, int subscription, + ArrayList<String[]> contactList, Activity mAactivity){ + if (mExportThread == null) + mExportThread = new ExportToSimThread(type, subscription, contactList, mAactivity); + 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) { + public static void show(FragmentManager fragmentManager, + boolean contactsAreAvailable, Class callingActivity) { final ImportExportDialogFragment fragment = new ImportExportDialogFragment(); Bundle args = new Bundle(); args.putBoolean(ARG_CONTACTS_ARE_AVAILABLE, contactsAreAvailable); args.putString(VCardCommonArguments.ARG_CALLING_ACTIVITY, callingActivity.getName()); fragment.setArguments(args); fragment.show(fragmentManager, ImportExportDialogFragment.TAG); + isMenuItemClicked = false; } + private String getMultiSimName(int subscription) { + return Settings.System.getString(getActivity().getContentResolver(), + MoreContactUtils.MULTI_SIM_NAME[subscription]); + } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // Wrap our context to inflate list items using the correct theme + mActiv = getActivity(); final Resources res = getActivity().getResources(); final LayoutInflater dialogInflater = (LayoutInflater)getActivity() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -91,7 +193,7 @@ public class ImportExportDialogFragment extends DialogFragment 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,48 +206,37 @@ public class ImportExportDialogFragment extends DialogFragment } }; - boolean hasIccCard = false; - - if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { - for (int i = 0; i < MSimTelephonyManager.getDefault().getPhoneCount(); i++) { - hasIccCard = MSimTelephonyManager.getDefault().hasIccCard(i); - if (hasIccCard) { - break; - } - } - } else { - hasIccCard = TelephonyManager.getDefault().hasIccCard(); - } - - if (hasIccCard - && res.getBoolean(R.bool.config_allow_sim_import)) { - adapter.add(R.string.manage_sim_contacts); - adapter.add(R.string.export_to_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) { + isMenuItemClicked = true; boolean dismissDialog; - final int resId = adapter.getItem(which); + final int resId = mAdapter.getItem(which); switch (resId) { - case R.string.manage_sim_contacts: + case R.string.import_from_sim: { + + // after click import from sim,we set this value to true. + // it indicate that at the end of this method this dialog should dismiss. + dismissDialog = true; + handleImportFromSimRequest(resId); + break; + } case R.string.import_from_sdcard: { - dismissDialog = handleImportRequest(resId); + + // After click import from sdcard,we set this value to true. + // it indicate that at the end of this method this dialog should dismiss. + dismissDialog = true; + handleImportRequest(resId); + break; + } + case R.string.export_to_sim: { + dismissDialog = true; + handleExportToSimRequest(resId); break; } case R.string.export_to_sdcard: { @@ -161,18 +252,6 @@ public class ImportExportDialogFragment extends DialogFragment doShareVisibleContacts(); break; } - case R.string.export_to_sim: { - dismissDialog = true; - if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { - displaySIMSelection(); - } else { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setClassName("com.android.phone", - "com.android.phone.ExportContactsToSim"); - startActivity(intent); - } - break; - } default: { dismissDialog = true; Log.e(TAG, "Unexpected resource: " @@ -188,10 +267,79 @@ public class ImportExportDialogFragment extends DialogFragment .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 == mActiv && null == mAdapter) { + return; + } + + mAdapter.clear(); + final Resources res = mActiv.getResources(); + boolean hasIccCard = false; + if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { + for (int i = 0; i < MSimTelephonyManager.getDefault().getPhoneCount(); i++) { + hasIccCard = MSimTelephonyManager.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); + } + + boolean hasContact = hasContacts(); + + if (hasIccCard && hasContact) { + 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 && hasContact) { + 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); + } + } + } + + // Judge if there is contacts in database, if has return true, otherwise + // return false. + private boolean hasContacts() { + boolean hasContacts = false; + if (null != mActiv) { + Cursor cursor = mActiv.getContentResolver().query(Contacts.CONTENT_URI, new String[] { + Contacts._ID }, null, null, null); + if (null != cursor) { + try { + hasContacts = cursor.getCount() > 0; + } finally { + cursor.close(); + } + } + } + return hasContacts; + } + 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, @@ -234,15 +382,24 @@ public class ImportExportDialogFragment extends DialogFragment // There are two possibilities: // - one or more than one accounts -> ask the user (user can select phone-local also) // - no account -> use phone-local storage without asking the user - final AccountTypeManager accountTypes = AccountTypeManager.getInstance(getActivity()); + final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mActiv); final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true); final int size = accountList.size(); if (size > 0) { // Send over to the account selector final Bundle args = new Bundle(); args.putInt(KEY_RES_ID, resId); + switch (resId) { + case R.string.import_from_sim: + case R.string.import_from_sdcard: + SelectAccountDialogFragment.show( + mActiv.getFragmentManager(), this, + R.string.dialog_new_contact_account, + AccountListFilter.ACCOUNTS_CONTACT_WRITABLE_WITHOUT_SIM, args); + return false; + } SelectAccountDialogFragment.show( - getFragmentManager(), this, + mActiv.getFragmentManager(), this, R.string.dialog_new_contact_account, AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, args); @@ -252,7 +409,8 @@ public class ImportExportDialogFragment extends DialogFragment return false; } - AccountSelectionUtil.doImport(getActivity(), resId, null); + AccountSelectionUtil.doImport(mActiv, resId, + (size == 1 ? accountList.get(0) : null)); return true; // Close the dialog. } @@ -261,7 +419,7 @@ public class ImportExportDialogFragment extends DialogFragment */ @Override public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) { - AccountSelectionUtil.doImport(getActivity(), extraArgs.getInt(KEY_RES_ID), account); + AccountSelectionUtil.doImport(mActiv, 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. @@ -275,24 +433,22 @@ public class ImportExportDialogFragment extends DialogFragment } private void displaySIMSelection() { - Log.d(TAG, "displayMyDialog"); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(R.string.select_sim); - mSelectedSim = SIM_ID_INVALID; - int numPhones = MSimTelephonyManager.getDefault().getPhoneCount(); - CharSequence[] subList = new CharSequence[numPhones]; - int i; - for (i = 1; i <= numPhones; i++) { - subList[i-1] = "SIM" + i; + mSelectedSim = SimContactsConstants.SUB_INVALID; + final int numPhones = MSimTelephonyManager.getDefault().getPhoneCount(); + CharSequence[] sub_list = new CharSequence[numPhones]; + for (int i = 1; i <= numPhones; i++) { + sub_list[i - 1] = "SIM" + i; } - builder.setSingleChoiceItems(subList, -1, + builder.setSingleChoiceItems(sub_list, -1, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface arg0, int arg1) { - Log.d(TAG, "onClicked Dialog on arg1 = " + arg1); - mSelectedSim = arg1; - } - }); + @Override + public void onClick(DialogInterface arg0, int arg1) { + Log.d(TAG, "onClicked Dialog on arg1 = " + arg1); + mSelectedSim = arg1; + } + }); AlertDialog dialog = builder.create(); dialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.ok), @@ -304,7 +460,7 @@ public class ImportExportDialogFragment extends DialogFragment intent.setClassName("com.android.phone", "com.android.phone.ExportContactsToSim"); intent.putExtra(SIM_INDEX, mSelectedSim); - if (mSelectedSim != SIM_ID_INVALID) { + if (mSelectedSim != SimContactsConstants.SUB_INVALID) { ((AlertDialog)dialog).getContext().startActivity(intent); } } @@ -326,4 +482,641 @@ public class ImportExportDialogFragment extends DialogFragment }); dialog.show(); } + + 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(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(IS_CONTACT,true); + mActiv.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); + } + } + } + + private String getAccountNameBy(int subscription) { + String accountName = null; + if (!MSimTelephonyManager.getDefault().isMultiSimEnabled()) { + accountName = SimContactsConstants.SIM_NAME; + } else { + if (subscription == SimContactsConstants.SUB_1) { + accountName = SimContactsConstants.SIM_NAME_1; + } + else if (subscription == SimContactsConstants.SUB_2) { + accountName = SimContactsConstants.SIM_NAME_2; + } + } + return accountName; + } + + private void actuallyImportOneSimContact ( + final ContentValues values, final ContentResolver resolver, int subscription) { + + ContentValues sEmptyContentValues = new ContentValues(); + final String name = values.getAsString(SimContactsConstants.STR_TAG); + final String phoneNumber = values.getAsString(SimContactsConstants.STR_NUMBER); + final String emailAddresses = values.getAsString(SimContactsConstants.STR_EMAILS); + final String anrs = values.getAsString(SimContactsConstants.STR_ANRS); + final String[] emailAddressArray; + final String[] anrArray; + if (!TextUtils.isEmpty(emailAddresses)) { + emailAddressArray = emailAddresses.split(","); + } else { + emailAddressArray = null; + } + if (!TextUtils.isEmpty(anrs)) { + anrArray = anrs.split(","); + } else { + anrArray = null; + } + Log.d(TAG," actuallyImportOneSimContact: name= " + name + + ", phoneNumber= " + phoneNumber +", emails= "+ emailAddresses + +", anrs= "+ anrs + ", sub " + subscription); + + String accountName = getAccountNameBy(subscription); + String accountType = SimContactsConstants.ACCOUNT_TYPE_SIM; + + final ArrayList<ContentProviderOperation> operationList = + new ArrayList<ContentProviderOperation>(); + ContentProviderOperation.Builder builder = + ContentProviderOperation.newInsert(RawContacts.CONTENT_URI); + builder.withValue(RawContacts.ACCOUNT_NAME, accountName); + builder.withValue(RawContacts.ACCOUNT_TYPE, accountType); + builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED); + operationList.add(builder.build()); + + 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()); + + 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) { + 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 (emailAddresses != null) { + for (String emailAddress : emailAddressArray) { + 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 { + resolver.applyBatch(ContactsContract.AUTHORITY, operationList); + } catch (RemoteException e) { + Log.e(TAG,String.format("%s: %s", e.toString(), e.getMessage())); + } catch (OperationApplicationException e) { + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } + } + + /** + * A thread that export contacts to sim card + */ + public class ExportToSimThread extends Thread { + public static final int TYPE_SELECT = 2; + private int subscription; + private int type; + private boolean canceled; + private ArrayList<String[]> contactList; + private ProgressDialog mExportProgressDlg; + private ContentValues mValues = new ContentValues(); + Activity mPeople; + private int freeSimCount = 0; + + public ExportToSimThread(int type, int subscription, ArrayList<String[]> contactList, + Activity mAactivity) { + super(); + this.type = type; + this.subscription = subscription; + this.contactList = contactList; + canceled = false; + mPeople = mAactivity; + setExportProgress(contactList.size()); + } + + @Override + public void run() { + isExportingToSIM = true; + String accountName = getAccountNameBy(subscription); + String accountType = SimContactsConstants.ACCOUNT_TYPE_SIM; + Account account = new Account(accountName,accountType); + boolean isAirplaneMode = false; + boolean isSimCardFull = false; + // 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{ + if (subscription == SimContactsConstants.SUB_1) { + cr = mPeople.getContentResolver().query(Uri.parse("content://iccmsim/adn"), + null, null, null, null); + } else if (subscription == SimContactsConstants.SUB_2) { + cr = mPeople.getContentResolver().query( + Uri.parse("content://iccmsim/adn_sub2"), null, null, null, null); + } else { + cr = mPeople.getContentResolver().query(Uri.parse("content://icc/adn"), 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); + + String emails = null; + if (type == TYPE_SELECT) { + if (contactList != null) { + Iterator<String[]> iterator = contactList.iterator(); + while (iterator.hasNext() && !canceled && !isAirplaneMode) { + 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)) { + 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)) { + arrayEmail.add(email); + } + } + } + } while (c.moveToNext()); + } + if (c != null) { + c.close(); + } + + if (0 == arrayNumber.size() && 0 == arrayEmail.size()) { + mToastHandler.sendMessage(mToastHandler.obtainMessage( + TOAST_EXPORT_NO_PHONE_OR_EMAIL, name)); + continue; + } + + int phoneCountInOneSimContact = 1; + if (canSaveAnr) { + phoneCountInOneSimContact = 2; + } + int nameCount = (name != null && !name.equals("")) ? 1 : 0; + int groupNumCount = (arrayNumber.size() % phoneCountInOneSimContact) != 0 ? + (arrayNumber.size() / phoneCountInOneSimContact + 1) + : (arrayNumber.size() / phoneCountInOneSimContact); + int groupEmailCount = arrayEmail.size(); + + 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; + String anrNum = null; + String email = null; + if (canSaveAnr) { + anrNum = arrayNumber.size() > 0 ? arrayNumber.remove(0) : null; + } + if (canSaveEmail) { + email = arrayEmail.size() > 0 ? arrayEmail.remove(0) : null; + } + + result = MoreContactUtils.insertToCard(mPeople, name, num, email, + anrNum, 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 = (System.getInt(mPeople.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) != 0); + 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 { + 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 void setExportProgress(int size){ + 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(size); + mExportProgressDlg.setProgress(0); + + // 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(); + } + + 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; + } + } + }; + + 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(); + } + + } + + Uri mSelectedContactUri; + private class DeleteClickListener implements DialogInterface.OnClickListener { + public void onClick(DialogInterface dialog, int which) { + // TODO: need to consider USIM + if (mSelectedContactUri != null) { + long id = ContentUris.parseId(mSelectedContactUri); + int sub = mSimContactsOperation.getSimSubscription(id); + if (sub != SimContactsConstants.SUB_INVALID) { + ContentValues values = + mSimContactsOperation.getSimAccountValues(id); + if (mSimContactsOperation.delete(values, sub) == 1) { + getActivity().getContentResolver().delete(mSelectedContactUri, null, null); + } + } else { + getActivity().getContentResolver().delete(mSelectedContactUri, null, null); + } + } + } + } + + private int activeSubCount() { + int count = 0; + for (int i = 0; i < MSimTelephonyManager.getDefault().getPhoneCount(); i++) { + if (TelephonyManager.SIM_STATE_ABSENT != MSimTelephonyManager.getDefault() + .getSimState(i)) + count++; + } + return count; + } + + 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: + case R.string.import_from_sim_select: { + if (activeSubCount() == 2) { + listener = new ImportFromSimSelectListener(); + showSimSelectDialog(); + } else if (activeSubCount() == 1) { + AccountSelectionUtil.setImportSubscription(MSimTelephonyManager + .getDefault().getPreferredVoiceSubscription()); + handleImportRequest(R.string.import_from_sim); + } + break; + } + case R.string.import_from_sdcard: { + return AccountSelectionUtil.getSelectAccountDialog(getActivity(), id); + } + case R.string.export_to_sim: { + String[] items = new String[MSimTelephonyManager.getDefault().getPhoneCount()]; + for (int i = 0; i < items.length; i++) { + items[i] = getString(R.string.export_to_sim) + ": " + getMultiSimName(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(); + } + case R.id.dialog_sdcard_not_found: { + return new AlertDialog.Builder(getActivity()) + .setTitle(R.string.no_sdcard_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(R.string.no_sdcard_message) + .setPositiveButton(android.R.string.ok, null).create(); + } + case R.id.dialog_delete_contact_confirmation: { + return new AlertDialog.Builder(getActivity()) + .setTitle(R.string.deleteConfirmation_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(R.string.deleteConfirmation) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(android.R.string.ok, + new DeleteClickListener()).create(); + } + case R.id.dialog_readonly_contact_hide_confirmation: { + return new AlertDialog.Builder(getActivity()) + .setTitle(R.string.deleteConfirmation_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(R.string.readOnlyContactWarning) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(android.R.string.ok, + new DeleteClickListener()).create(); + } + case R.id.dialog_readonly_contact_delete_confirmation: { + return new AlertDialog.Builder(getActivity()) + .setTitle(R.string.deleteConfirmation_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(R.string.readOnlyContactDeleteConfirmation) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(android.R.string.ok, + new DeleteClickListener()).create(); + } + case R.id.dialog_multiple_contact_delete_confirmation: { + return new AlertDialog.Builder(getActivity()) + .setTitle(R.string.deleteConfirmation_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(R.string.multipleContactDeleteConfirmation) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(android.R.string.ok, + new DeleteClickListener()).create(); + } + } + return null; + } + + public void showSimSelectDialog() { + AccountSelectionUtil.setImportSubscription(SimContactsConstants.SUB_1); + // item is for sim account to show + String[] items = new String[MSimTelephonyManager.getDefault().getPhoneCount()]; + for (int i = 0; i < items.length; i++) { + items[i] = getString(R.string.import_from_sim) + ": " + getMultiSimName(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 (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { + if (hasMultiEnabledIccCard()) { + displayImportExportDialog(R.string.import_from_sim_select + ,null); + } else { + AccountSelectionUtil.setImportSubscription(getEnabledIccCard()); + handleImportRequest(Id); + } + } else { + handleImportRequest(Id); + } + } + + private void handleExportToSimRequest(int Id) { + if (hasMultiEnabledIccCard()) { + //has two enalbed sim cards, prompt dialog to select one + displayImportExportDialog(Id, null).show(); + } else { + mExportSub = getEnabledIccCard(); + Intent pickPhoneIntent = new Intent(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(IS_CONTACT,true); + mActiv.startActivityForResult(pickPhoneIntent, SUBACTIVITY_MULTI_PICK_CONTACT); + } + } + + private boolean hasEnabledIccCard(int subscription) { + return MSimTelephonyManager.getDefault().hasIccCard(subscription) && + MSimTelephonyManager.getDefault().getSimState(subscription) + == TelephonyManager.SIM_STATE_READY; + } + + private boolean hasMultiEnabledIccCard() { + int count = 0; + for (int i = 0; i < MSimTelephonyManager.getDefault().getPhoneCount(); i++) { + if (hasEnabledIccCard(i)) { + count++; + } + } + return count > 1; + } + + private int getEnabledIccCard() { + for (int i = 0; i < MSimTelephonyManager.getDefault().getPhoneCount(); i++) { + if (hasEnabledIccCard(i)) { + return i; + } + } + return SimContactsConstants.SUB_1; + } + + /** + * refer to the code of hasChinese() in ContactSaveService. + */ + private boolean hasChinese(String name) { + return name != null && name.getBytes().length > name.length(); + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + } + + public static boolean isMenuItemClicked() { + return isMenuItemClicked; + } } diff --git a/src/com/android/contacts/common/util/AccountSelectionUtil.java b/src/com/android/contacts/common/util/AccountSelectionUtil.java index 4d19396f..4140fa75 100644 --- a/src/com/android/contacts/common/util/AccountSelectionUtil.java +++ b/src/com/android/contacts/common/util/AccountSelectionUtil.java @@ -34,11 +34,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 static com.android.internal.telephony.MSimConstants.SUBSCRIPTION_KEY; +import java.util.ArrayList; import java.util.List; /** @@ -54,8 +57,13 @@ public class AccountSelectionUtil { 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; + // multi pick sim contacts action + private static final String ACTION_MULTI_PICK_SIM = + "com.android.contacts.action.MULTI_PICK_SIM"; 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 { @@ -90,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); } @@ -189,13 +201,8 @@ public class AccountSelectionUtil { public static void doImport(Context context, int resId, AccountWithDataSet account) { switch (resId) { - case R.string.manage_sim_contacts: { - if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { - SimSelectedListener simSelListner = new SimSelectedListener(context, account); - displaySelectSimDialog(context, simSelListner); - } else { + case R.string.import_from_sim: { doImportFromSim(context, account); - } break; } case R.string.import_from_sdcard: { @@ -206,14 +213,17 @@ public class AccountSelectionUtil { } public static void doImportFromSim(Context context, AccountWithDataSet account) { - Intent importIntent = new Intent(Intent.ACTION_VIEW); - importIntent.setType("vnd.android.cursor.item/sim-contact"); + Intent importIntent = new Intent(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 (MSimTelephonyManager.getDefault().isMultiSimEnabled()) { + importIntent.putExtra(SUBSCRIPTION_KEY,mImportSub); + } else { + importIntent.putExtra(SUBSCRIPTION_KEY,SimContactsConstants.SUB_1); } - importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts"); context.startActivity(importIntent); } @@ -234,9 +244,14 @@ public class AccountSelectionUtil { public static void doImportFromSdCard(Context context, AccountWithDataSet account) { Intent importIntent = new Intent(context, ImportVCardActivity.class); 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); + } + + // put import subscription if we have set it. + if (mImportSub != SimContactsConstants.SUB_INVALID) { + importIntent.putExtra(SUBSCRIPTION_KEY, mImportSub); } if (mVCardShare) { @@ -276,20 +291,15 @@ public class AccountSelectionUtil { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.select_sim); final int numPhones = MSimTelephonyManager.getDefault().getPhoneCount(); - CharSequence[] sub_list = new CharSequence[numPhones + 1]; - int i; - for (i = 1; i <= numPhones; i++) { + CharSequence[] sub_list = new CharSequence[numPhones]; + for (int i = 1; i <= numPhones; i++) { sub_list[i-1] = "SIM" + i; } - sub_list[i-1] = context.getString(R.string.Import_All); builder.setSingleChoiceItems(sub_list, -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; - } } }); |