详细介绍Android通讯录的导出和导入
通讯录导出到SD卡时,会在SD卡中生成一个vcf文件,用于保存联系人姓名,手机号码。vCard 规范容许公开交换个人数据交换 (Personal Data Interchange PDI)信息,在传统纸质商业名片可找到这些信息。规范定义电子名片(或叫vCard)的格式。
而在Android上使用vcard就要借助第三方包:我已经上传,看后面的链接地址
下载后里面会有2个Example {ReadExample.java / WriteExample.java} 。
但是凭借这两个Example,不足以让你更好的完成其他信息的备份和恢复,于是你要看下源码。
其中比较的2个类的源码如下.
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package a_vcard.android.syncml.pim.vcard;
//import android.content.AbstractSyncableContentProvider;
//import android.content.ContentResolver;
//import android.content.ContentUris;
//import android.content.ContentValues;
//import android.net.Uri;
import a_vcard.android.provider.Contacts;
import a_vcard.android.provider.Contacts.ContactMethods;
//import android.provider.Contacts.Extensions;
//import android.provider.Contacts.GroupMembership;
//import android.provider.Contacts.Organizations;
//import android.provider.Contacts.People;
import a_vcard.android.provider.Contacts.Phones;
//import android.provider.Contacts.Photos;
import a_vcard.android.syncml.pim.PropertyNode;
import a_vcard.android.syncml.pim.VNode;
import a_vcard.android.telephony.PhoneNumberUtils;
import a_vcard.android.text.TextUtils;
import a_vcard.android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
/**
* The parameter class of VCardComposer.
* This class standy by the person-contact in
* Android system, we must use this class instance as parameter to transmit to
* VCardComposer so that create vCard string.
*/
// TODO: rename the class name, next step
public class ContactStruct {
private static final String LOG_TAG = "ContactStruct";
// Note: phonetic name probably should be "LAST FIRST MIDDLE" for European languages, and
// space should be added between each element while it should not be in Japanese.
// But unfortunately, we currently do not have the data and are not sure whether we should
// support European version of name ordering.
//
// TODO: Implement the logic described above if we really need European version of
// phonetic name handling. Also, adding the appropriate test case of vCard would be
// highly appreciated.
public static final int NAME_ORDER_TYPE_ENGLISH = 0;
public static final int NAME_ORDER_TYPE_JAPANESE = 1;
/** MUST exist */
public String name;
public String phoneticName;
/** maybe folding */
public List<String> notes = new ArrayList<String>();
/** maybe folding */
public String title;
/** binary bytes of pic. */
public byte[] photoBytes;
/** The type of Photo (e.g. JPEG, BMP, etc.) */
public String photoType;
/** Only for GET. Use addPhoneList() to PUT. */
public List<PhoneData> phoneList;
/** Only for GET. Use addContactmethodList() to PUT. */
public List<ContactMethod> contactmethodList;
/** Only for GET. Use addOrgList() to PUT. */
public List<OrganizationData> organizationList;
/** Only for GET. Use addExtension() to PUT */
public Map<String, List<String>> extensionMap;
// Use organizationList instead when handling ORG.
@Deprecated
public String company;
public static class PhoneData {
public int type;
/** maybe folding */
public String data;
public String label;
public boolean isPrimary;
}
public static class ContactMethod {
// Contacts.KIND_EMAIL, Contacts.KIND_POSTAL
public int kind;
// e.g. Contacts.ContactMethods.TYPE_HOME, Contacts.PhoneColumns.TYPE_HOME
// If type == Contacts.PhoneColumns.TYPE_CUSTOM, label is used.
public int type;
public String data;
// Used only when TYPE is TYPE_CUSTOM.
public String label;
public boolean isPrimary;
}
public static class OrganizationData {
public int type;
public String companyName;
public String positionName;
public boolean isPrimary;
}
/**
* Add a phone info to phoneList.
* @param data phone number
* @param type type col of content://contacts/phones
* @param label lable col of content://contacts/phones
*/
public void addPhone(int type, String data, String label, boolean isPrimary){
if (phoneList == null) {
phoneList = new ArrayList<PhoneData>();
}
PhoneData phoneData = new PhoneData();
phoneData.type = type;
StringBuilder builder = new StringBuilder();
String trimed = data.trim();
int length = trimed.length();
for (int i = 0; i < length; i++) {
char ch = trimed.charAt(i);
if (('0' <= ch && ch <= '9') || (i == 0 && ch == '+')) {
builder.append(ch);
}
}
phoneData.data = PhoneNumberUtils.formatNumber(builder.toString());
phoneData.label = label;
phoneData.isPrimary = isPrimary;
phoneList.add(phoneData);
}
/**
* Add a contactmethod info to contactmethodList.
* @param kind integer value defined in Contacts.java
* (e.g. Contacts.KIND_EMAIL)
* @param type type col of content://contacts/contact_methods
* @param data contact data
* @param label extra string used only when kind is Contacts.KIND_CUSTOM.
*/
public void addContactmethod(int kind, int type, String data,
String label, boolean isPrimary){
if (contactmethodList == null) {
contactmethodList = new ArrayList<ContactMethod>();
}
ContactMethod contactMethod = new ContactMethod();
contactMethod.kind = kind;
contactMethod.type = type;
contactMethod.data = data;
contactMethod.label = label;
contactMethod.isPrimary = isPrimary;
contactmethodList.add(contactMethod);
}
/**
* Add a Organization info to organizationList.
*/
public void addOrganization(int type, String companyName, String positionName,
boolean isPrimary) {
if (organizationList == null) {
organizationList = new ArrayList<OrganizationData>();
}
OrganizationData organizationData = new OrganizationData();
organizationData.type = type;
organizationData.companyName = companyName;
organizationData.positionName = positionName;
organizationData.isPrimary = isPrimary;
organizationList.add(organizationData);
}
/**
* Set "position" value to the appropriate data. If there's more than one
* OrganizationData objects, the value is set to the last one. If there's no
* OrganizationData object, a new OrganizationData is created, whose company name is
* empty.
*
* TODO: incomplete logic. fix this:
*
* e.g. This assumes ORG comes earlier, but TITLE may come earlier like this, though we do not
* know how to handle it in general cases...
* ----
* TITLE:Software Engineer
* ORG:Google
* ----
*/
public void setPosition(String positionValue) {
if (organizationList == null) {
organizationList = new ArrayList<OrganizationData>();
}
int size = organizationList.size();
if (size == 0) {
addOrganization(Contacts.OrganizationColumns.TYPE_OTHER, "", null, false);
size = 1;
}
OrganizationData lastData = organizationList.get(size - 1);
lastData.positionName = positionValue;
}
public void addExtension(PropertyNode propertyNode) {
if (propertyNode.propValue.length() == 0) {
return;
}
// Now store the string into extensionMap.
List<String> list;
String name = propertyNode.propName;
if (extensionMap == null) {
extensionMap = new HashMap<String, List<String>>();
}
if (!extensionMap.containsKey(name)){
list = new ArrayList<String>();
extensionMap.put(name, list);
} else {
list = extensionMap.get(name);
}
list.add(propertyNode.encode());
}
private static String getNameFromNProperty(List<String> elems, int nameOrderType) {
// Family, Given, Middle, Prefix, Suffix. (1 - 5)
int size = elems.size();
if (size > 1) {
StringBuilder builder = new StringBuilder();
boolean builderIsEmpty = true;
// Prefix
if (size > 3 && elems.get(3).length() > 0) {
builder.append(elems.get(3));
builderIsEmpty = false;
}
String first, second;
if (nameOrderType == NAME_ORDER_TYPE_JAPANESE) {
first = elems.get(0);
second = elems.get(1);
} else {
first = elems.get(1);
second = elems.get(0);
}
if (first.length() > 0) {
if (!builderIsEmpty) {
builder.append(' ');
}
builder.append(first);
builderIsEmpty = false;
}
// Middle name
if (size > 2 && elems.get(2).length() > 0) {
if (!builderIsEmpty) {
builder.append(' ');
}
builder.append(elems.get(2));
builderIsEmpty = false;
}
if (second.length() > 0) {
if (!builderIsEmpty) {
builder.append(' ');
}
builder.append(second);
builderIsEmpty = false;
}
// Suffix
if (size > 4 && elems.get(4).length() > 0) {
if (!builderIsEmpty) {
builder.append(' ');
}
builder.append(elems.get(4));
builderIsEmpty = false;
}
return builder.toString();
} else if (size == 1) {
return elems.get(0);
} else {
return "";
}
}
public static ContactStruct constructContactFromVNode(VNode node,
int nameOrderType) {
if (!node.VName.equals("VCARD")) {
// Impossible in current implementation. Just for safety.
Log.e(LOG_TAG, "Non VCARD data is inserted.");
return null;
}
// For name, there are three fields in vCard: FN, N, NAME.
// We prefer FN, which is a required field in vCard 3.0 , but not in vCard 2.1.
// Next, we prefer NAME, which is defined only in vCard 3.0.
// Finally, we use N, which is a little difficult to parse.
String fullName = null;
String nameFromNProperty = null;
// Some vCard has "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", and
// "X-PHONETIC-LAST-NAME"
String xPhoneticFirstName = null;
String xPhoneticMiddleName = null;
String xPhoneticLastName = null;
ContactStruct contact = new ContactStruct();
// Each Column of four properties has ISPRIMARY field
// (See android.provider.Contacts)
// If false even after the following loop, we choose the first
// entry as a "primary" entry.
boolean prefIsSetAddress = false;
boolean prefIsSetPhone = false;
boolean prefIsSetEmail = false;
boolean prefIsSetOrganization = false;
for (PropertyNode propertyNode: node.propList) {
String name = propertyNode.propName;
if (TextUtils.isEmpty(propertyNode.propValue)) {
continue;
}
if (name.equals("VERSION")) {
// vCard version. Ignore this.
} else if (name.equals("FN")) {
fullName = propertyNode.propValue;
} else if (name.equals("NAME") && fullName == null) {
// Only in vCard 3.0. Use this if FN does not exist.
// Though, note that vCard 3.0 requires FN.
fullName = propertyNode.propValue;
} else if (name.equals("N")) {
nameFromNProperty = getNameFromNProperty(propertyNode.propValue_vector,
nameOrderType);
} else if (name.equals("SORT-STRING")) {
contact.phoneticName = propertyNode.propValue;
} else if (name.equals("SOUND")) {
if (propertyNode.paramMap_TYPE.contains("X-IRMC-N") &&
contact.phoneticName == null) {
// Some Japanese mobile phones use this field for phonetic name,
// since vCard 2.1 does not have "SORT-STRING" type.
// Also, in some cases, the field has some ';' in it.
// We remove them.
StringBuilder builder = new StringBuilder();
String value = propertyNode.propValue;
int length = value.length();
for (int i = 0; i < length; i++) {
char ch = value.charAt(i);
if (ch != ';') {
builder.append(ch);
}
}
contact.phoneticName = builder.toString();
} else {
contact.addExtension(propertyNode);
}
} else if (name.equals("ADR")) {
List<String> values = propertyNode.propValue_vector;
boolean valuesAreAllEmpty = true;
for (String value : values) {
if (value.length() > 0) {
valuesAreAllEmpty = false;
break;
}
}
if (valuesAreAllEmpty) {
continue;
}
int kind = Contacts.KIND_POSTAL;
int type = -1;
String label = "";
boolean isPrimary = false;
for (String typeString : propertyNode.paramMap_TYPE) {
if (typeString.equals("PREF") && !prefIsSetAddress) {
// Only first "PREF" is considered.
prefIsSetAddress = true;
isPrimary = true;
} else if (typeString.equalsIgnoreCase("HOME")) {
type = Contacts.ContactMethodsColumns.TYPE_HOME;
label = "";
} else if (typeString.equalsIgnoreCase("WORK") ||
typeString.equalsIgnoreCase("COMPANY")) {
// "COMPANY" seems emitted by Windows Mobile, which is not
// specifically supported by vCard 2.1. We assume this is same
// as "WORK".
type = Contacts.ContactMethodsColumns.TYPE_WORK;
label = "";
} else if (typeString.equalsIgnoreCase("POSTAL")) {
kind = Contacts.KIND_POSTAL;
} else if (typeString.equalsIgnoreCase("PARCEL") ||
typeString.equalsIgnoreCase("DOM") ||
typeString.equalsIgnoreCase("INTL")) {
// We do not have a kind or type matching these.
// TODO: fix this. We may need to split entries into two.
// (e.g. entries for KIND_POSTAL and KIND_PERCEL)
} else if (typeString.toUpperCase().startsWith("X-") &&
type < 0) {
type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
label = typeString.substring(2);
} else if (type < 0) {
// vCard 3.0 allows iana-token. Also some vCard 2.1 exporters
// emit non-standard types. We do not handle their values now.
type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
label = typeString;
}
}
// We use "HOME" as default
if (type < 0) {
type = Contacts.ContactMethodsColumns.TYPE_HOME;
}
// adr-value = 0*6(text-value ";") text-value
// ; PO Box, Extended Address, Street, Locality, Region, Postal
// ; Code, Country Name
String address;
List<String> list = propertyNode.propValue_vector;
int size = list.size();
if (size > 1) {
StringBuilder builder = new StringBuilder();
boolean builderIsEmpty = true;
if (Locale.getDefault().getCountry().equals(Locale.JAPAN.getCountry())) {
// In Japan, the order is reversed.
for (int i = size - 1; i >= 0; i--) {
String addressPart = list.get(i);
if (addressPart.length() > 0) {
if (!builderIsEmpty) {
builder.append(' ');
}
builder.append(addressPart);
builderIsEmpty = false;
}
}
} else {
for (int i = 0; i < size; i++) {
String addressPart = list.get(i);
if (addressPart.length() > 0) {
if (!builderIsEmpty) {
builder.append(' ');
}
builder.append(addressPart);
builderIsEmpty = false;
}
}
}
address = builder.toString().trim();
} else {
address = propertyNode.propValue;
}
contact.addContactmethod(kind, type, address, label, isPrimary);
} else if (name.equals("ORG")) {
// vCard specification does not specify other types.
int type = Contacts.OrganizationColumns.TYPE_WORK;
boolean isPrimary = false;
for (String typeString : propertyNode.paramMap_TYPE) {
if (typeString.equals("PREF") && !prefIsSetOrganization) {
// vCard specification officially does not have PREF in ORG.
// This is just for safety.
prefIsSetOrganization = true;
isPrimary = true;
}
// XXX: Should we cope with X- words?
}
List<String> list = propertyNode.propValue_vector;
int size = list.size();
StringBuilder builder = new StringBuilder();
for (Iterator<String> iter = list.iterator(); iter.hasNext();) {
builder.append(iter.next());
if (iter.hasNext()) {
builder.append(' ');
}
}
contact.addOrganization(type, builder.toString(), "", isPrimary);
} else if (name.equals("TITLE")) {
contact.setPosition(propertyNode.propValue);
} else if (name.equals("ROLE")) {
contact.setPosition(propertyNode.propValue);
} else if (name.equals("PHOTO")) {
// We prefer PHOTO to LOGO.
String valueType = propertyNode.paramMap.getAsString("VALUE");
if (valueType != null && valueType.equals("URL")) {
// TODO: do something.
} else {
// Assume PHOTO is stored in BASE64. In that case,
// data is already stored in propValue_bytes in binary form.
// It should be automatically done by VBuilder (VDataBuilder/VCardDatabuilder)
contact.photoBytes = propertyNode.propValue_bytes;
String type = propertyNode.paramMap.getAsString("TYPE");
if (type != null) {
contact.photoType = type;
}
}
} else if (name.equals("LOGO")) {
// When PHOTO is not available this is not URL,
// we use this instead of PHOTO.
String valueType = propertyNode.paramMap.getAsString("VALUE");
if (valueType != null && valueType.equals("URL")) {
// TODO: do something.
} else if (contact.photoBytes == null) {
contact.photoBytes = propertyNode.propValue_bytes;
String type = propertyNode.paramMap.getAsString("TYPE");
if (type != null) {
contact.photoType = type;
}
}
} else if (name.equals("EMAIL")) {
int type = -1;
String label = null;
boolean isPrimary = false;
for (String typeString : propertyNode.paramMap_TYPE) {
if (typeString.equals("PREF") && !prefIsSetEmail) {
// Only first "PREF" is considered.
prefIsSetEmail = true;
isPrimary = true;
} else if (typeString.equalsIgnoreCase("HOME")) {
type = Contacts.ContactMethodsColumns.TYPE_HOME;
} else if (typeString.equalsIgnoreCase("WORK")) {
type = Contacts.ContactMethodsColumns.TYPE_WORK;
} else if (typeString.equalsIgnoreCase("CELL")) {
// We do not have Contacts.ContactMethodsColumns.TYPE_MOBILE yet.
type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
label = Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME;
} else if (typeString.toUpperCase().startsWith("X-") &&
type < 0) {
type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
label = typeString.substring(2);
} else if (type < 0) {
// vCard 3.0 allows iana-token.
// We may have INTERNET (specified in vCard spec),
// SCHOOL, etc.
type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
label = typeString;
}
}
// We use "OTHER" as default.
if (type < 0) {
type = Contacts.ContactMethodsColumns.TYPE_OTHER;
}
contact.addContactmethod(Contacts.KIND_EMAIL,
type, propertyNode.propValue,label, isPrimary);
} else if (name.equals("TEL")) {
int type = -1;
String label = null;
boolean isPrimary = false;
boolean isFax = false;
for (String typeString : propertyNode.paramMap_TYPE) {
if (typeString.equals("PREF") && !prefIsSetPhone) {
// Only first "PREF" is considered.
prefIsSetPhone = true;
isPrimary = true;
} else if (typeString.equalsIgnoreCase("HOME")) {
type = Contacts.PhonesColumns.TYPE_HOME;
} else if (typeString.equalsIgnoreCase("WORK")) {
type = Contacts.PhonesColumns.TYPE_WORK;
} else if (typeString.equalsIgnoreCase("CELL")) {
type = Contacts.PhonesColumns.TYPE_MOBILE;
} else if (typeString.equalsIgnoreCase("PAGER")) {
type = Contacts.PhonesColumns.TYPE_PAGER;
} else if (typeString.equalsIgnoreCase("FAX")) {
isFax = true;
} else if (typeString.equalsIgnoreCase("VOICE") ||
typeString.equalsIgnoreCase("MSG")) {
// Defined in vCard 3.0. Ignore these because they
// conflict with "HOME", "WORK", etc.
// XXX: do something?
} else if (typeString.toUpperCase().startsWith("X-") &&
type < 0) {
type = Contacts.PhonesColumns.TYPE_CUSTOM;
label = typeString.substring(2);
} else if (type < 0){
// We may have MODEM, CAR, ISDN, etc...
type = Contacts.PhonesColumns.TYPE_CUSTOM;
label = typeString;
}
}
// We use "HOME" as default
if (type < 0) {
type = Contacts.PhonesColumns.TYPE_HOME;
}
if (isFax) {
if (type == Contacts.PhonesColumns.TYPE_HOME) {
type = Contacts.PhonesColumns.TYPE_FAX_HOME;
} else if (type == Contacts.PhonesColumns.TYPE_WORK) {
type = Contacts.PhonesColumns.TYPE_FAX_WORK;
}
}
contact.addPhone(type, propertyNode.propValue, label, isPrimary);
} else if (name.equals("NOTE")) {
contact.notes.add(propertyNode.propValue);
} else if (name.equals("BDAY")) {
contact.addExtension(propertyNode);
} else if (name.equals("URL")) {
contact.addExtension(propertyNode);
} else if (name.equals("REV")) {
// Revision of this VCard entry. I think we can ignore this.
contact.addExtension(propertyNode);
} else if (name.equals("UID")) {
contact.addExtension(propertyNode);
} else if (name.equals("KEY")) {
// Type is X509 or PGP? I don't know how to handle this...
contact.addExtension(propertyNode);
} else if (name.equals("MAILER")) {
contact.addExtension(propertyNode);
} else if (name.equals("TZ")) {
contact.addExtension(propertyNode);
} else if (name.equals("GEO")) {
contact.addExtension(propertyNode);
} else if (name.equals("NICKNAME")) {
// vCard 3.0 only.
contact.addExtension(propertyNode);
} else if (name.equals("CLASS")) {
// vCard 3.0 only.
// e.g. CLASS:CONFIDENTIAL
contact.addExtension(propertyNode);
} else if (name.equals("PROFILE")) {
// VCard 3.0 only. Must be "VCARD". I think we can ignore this.
contact.addExtension(propertyNode);
} else if (name.equals("CATEGORIES")) {
// VCard 3.0 only.
// e.g. CATEGORIES:INTERNET,IETF,INDUSTRY,INFORMATION TECHNOLOGY
contact.addExtension(propertyNode);
} else if (name.equals("SOURCE")) {
// VCard 3.0 only.
contact.addExtension(propertyNode);
} else if (name.equals("PRODID")) {
// VCard 3.0 only.
// To specify the identifier for the product that created
// the vCard object.
contact.addExtension(propertyNode);
} else if (name.equals("X-PHONETIC-FIRST-NAME")) {
xPhoneticFirstName = propertyNode.propValue;
} else if (name.equals("X-PHONETIC-MIDDLE-NAME")) {
xPhoneticMiddleName = propertyNode.propValue;
} else if (name.equals("X-PHONETIC-LAST-NAME")) {
xPhoneticLastName = propertyNode.propValue;
} else {
// Unknown X- words and IANA token.
contact.addExtension(propertyNode);
}
}
if (fullName != null) {
contact.name = fullName;
} else if(nameFromNProperty != null) {
contact.name = nameFromNProperty;
} else {
contact.name = "";
}
if (contact.phoneticName == null &&
(xPhoneticFirstName != null || xPhoneticMiddleName != null ||
xPhoneticLastName != null)) {
// Note: In Europe, this order should be "LAST FIRST MIDDLE". See the comment around
// NAME_ORDER_TYPE_* for more detail.
String first;
String second;
if (nameOrderType == NAME_ORDER_TYPE_JAPANESE) {
first = xPhoneticLastName;
second = xPhoneticFirstName;
} else {
first = xPhoneticFirstName;
second = xPhoneticLastName;
}
StringBuilder builder = new StringBuilder();
if (first != null) {
builder.append(first);
}
if (xPhoneticMiddleName != null) {
builder.append(xPhoneticMiddleName);
}
if (second != null) {
builder.append(second);
}
contact.phoneticName = builder.toString();
}
// Remove unnecessary white spaces.
// It is found that some mobile phone emits phonetic name with just one white space
// when a user does not specify one.
// This logic is effective toward such kind of weird data.
if (contact.phoneticName != null) {
contact.phoneticName = contact.phoneticName.trim();
}
// If there is no "PREF", we choose the first entries as primary.
if (!prefIsSetPhone &&
contact.phoneList != null &&
contact.phoneList.size() > 0) {
contact.phoneList.get(0).isPrimary = true;
}
if (!prefIsSetAddress && contact.contactmethodList != null) {
for (ContactMethod contactMethod : contact.contactmethodList) {
if (contactMethod.kind == Contacts.KIND_POSTAL) {
contactMethod.isPrimary = true;
break;
}
}
}
if (!prefIsSetEmail && contact.contactmethodList != null) {
for (ContactMethod contactMethod : contact.contactmethodList) {
if (contactMethod.kind == Contacts.KIND_EMAIL) {
contactMethod.isPrimary = true;
break;
}
}
}
if (!prefIsSetOrganization &&
contact.organizationList != null &&
contact.organizationList.size() > 0) {
contact.organizationList.get(0).isPrimary = true;
}
return contact;
}
public String displayString() {
if (name.length() > 0) {
return name;
}
if (contactmethodList != null && contactmethodList.size() > 0) {
for (ContactMethod contactMethod : contactmethodList) {
if (contactMethod.kind == Contacts.KIND_EMAIL && contactMethod.isPrimary) {
return contactMethod.data;
}
}
}
if (phoneList != null && phoneList.size() > 0) {
for (PhoneData phoneData : phoneList) {
if (phoneData.isPrimary) {
return phoneData.data;
}
}
}
return "";
}
// private void pushIntoContentProviderOrResolver(Object contentSomething,
// long myContactsGroupId) {
// ContentResolver resolver = null;
// AbstractSyncableContentProvider provider = null;
// if (contentSomething instanceof ContentResolver) {
// resolver = (ContentResolver)contentSomething;
// } else if (contentSomething instanceof AbstractSyncableContentProvider) {
// provider = (AbstractSyncableContentProvider)contentSomething;
// } else {
// Log.e(LOG_TAG, "Unsupported object came.");
// return;
// }
//
// ContentValues contentValues = new ContentValues();
// contentValues.put(People.NAME, name);
// contentValues.put(People.PHONETIC_NAME, phoneticName);
//
// if (notes.size() > 1) {
// StringBuilder builder = new StringBuilder();
// for (String note : notes) {
// builder.append(note);
// builder.append("\n");
// }
// contentValues.put(People.NOTES, builder.toString());
// } else if (notes.size() == 1){
// contentValues.put(People.NOTES, notes.get(0));
// }
//
// Uri personUri;
// long personId = 0;
// if (resolver != null) {
// personUri = Contacts.People.createPersonInMyContactsGroup(
// resolver, contentValues);
// if (personUri != null) {
// personId = ContentUris.parseId(personUri);
// }
// } else {
// personUri = provider.nonTransactionalInsert(People.CONTENT_URI, contentValues);
// if (personUri != null) {
// personId = ContentUris.parseId(personUri);
// ContentValues values = new ContentValues();
// values.put(GroupMembership.PERSON_ID, personId);
// values.put(GroupMembership.GROUP_ID, myContactsGroupId);
// Uri resultUri = provider.nonTransactionalInsert(
// GroupMembership.CONTENT_URI, values);
// if (resultUri == null) {
// Log.e(LOG_TAG, "Faild to insert the person to MyContact.");
// provider.nonTransactionalDelete(personUri, null, null);
// personUri = null;
// }
// }
// }
//
// if (personUri == null) {
// Log.e(LOG_TAG, "Failed to create the contact.");
// return;
// }
//
// if (photoBytes != null) {
// if (resolver != null) {
// People.setPhotoData(resolver, personUri, photoBytes);
// } else {
// Uri photoUri = Uri.withAppendedPath(personUri, Contacts.Photos.CONTENT_DIRECTORY);
// ContentValues values = new ContentValues();
// values.put(Photos.DATA, photoBytes);
// provider.update(photoUri, values, null, null);
// }
// }
//
// long primaryPhoneId = -1;
// if (phoneList != null && phoneList.size() > 0) {
// for (PhoneData phoneData : phoneList) {
// ContentValues values = new ContentValues();
// values.put(Contacts.PhonesColumns.TYPE, phoneData.type);
// if (phoneData.type == Contacts.PhonesColumns.TYPE_CUSTOM) {
// values.put(Contacts.PhonesColumns.LABEL, phoneData.label);
// }
// // Already formatted.
// values.put(Contacts.PhonesColumns.NUMBER, phoneData.data);
//
// // Not sure about Contacts.PhonesColumns.NUMBER_KEY ...
// values.put(Contacts.PhonesColumns.ISPRIMARY, 1);
// values.put(Contacts.Phones.PERSON_ID, personId);
// Uri phoneUri;
// if (resolver != null) {
// phoneUri = resolver.insert(Phones.CONTENT_URI, values);
// } else {
// phoneUri = provider.nonTransactionalInsert(Phones.CONTENT_URI, values);
// }
// if (phoneData.isPrimary) {
// primaryPhoneId = Long.parseLong(phoneUri.getLastPathSegment());
// }
// }
// }
//
// long primaryOrganizationId = -1;
// if (organizationList != null && organizationList.size() > 0) {
// for (OrganizationData organizationData : organizationList) {
// ContentValues values = new ContentValues();
// // Currently, we do not use TYPE_CUSTOM.
// values.put(Contacts.OrganizationColumns.TYPE,
// organizationData.type);
// values.put(Contacts.OrganizationColumns.COMPANY,
// organizationData.companyName);
// values.put(Contacts.OrganizationColumns.TITLE,
// organizationData.positionName);
// values.put(Contacts.OrganizationColumns.ISPRIMARY, 1);
// values.put(Contacts.OrganizationColumns.PERSON_ID, personId);
//
// Uri organizationUri;
// if (resolver != null) {
// organizationUri = resolver.insert(Organizations.CONTENT_URI, values);
// } else {
// organizationUri = provider.nonTransactionalInsert(
// Organizations.CONTENT_URI, values);
// }
// if (organizationData.isPrimary) {
// primaryOrganizationId = Long.parseLong(organizationUri.getLastPathSegment());
// }
// }
// }
//
// long primaryEmailId = -1;
// if (contactmethodList != null && contactmethodList.size() > 0) {
// for (ContactMethod contactMethod : contactmethodList) {
// ContentValues values = new ContentValues();
// values.put(Contacts.ContactMethodsColumns.KIND, contactMethod.kind);
// values.put(Contacts.ContactMethodsColumns.TYPE, contactMethod.type);
// if (contactMethod.type == Contacts.ContactMethodsColumns.TYPE_CUSTOM) {
// values.put(Contacts.ContactMethodsColumns.LABEL, contactMethod.label);
// }
// values.put(Contacts.ContactMethodsColumns.DATA, contactMethod.data);
// values.put(Contacts.ContactMethodsColumns.ISPRIMARY, 1);
// values.put(Contacts.ContactMethods.PERSON_ID, personId);
//
// if (contactMethod.kind == Contacts.KIND_EMAIL) {
// Uri emailUri;
// if (resolver != null) {
// emailUri = resolver.insert(ContactMethods.CONTENT_URI, values);
// } else {
// emailUri = provider.nonTransactionalInsert(
// ContactMethods.CONTENT_URI, values);
// }
// if (contactMethod.isPrimary) {
// primaryEmailId = Long.parseLong(emailUri.getLastPathSegment());
// }
// } else { // probably KIND_POSTAL
// if (resolver != null) {
// resolver.insert(ContactMethods.CONTENT_URI, values);
// } else {
// provider.nonTransactionalInsert(
// ContactMethods.CONTENT_URI, values);
// }
// }
// }
// }
//
// if (extensionMap != null && extensionMap.size() > 0) {
// ArrayList<ContentValues> contentValuesArray;
// if (resolver != null) {
// contentValuesArray = new ArrayList<ContentValues>();
// } else {
// contentValuesArray = null;
// }
// for (Entry<String, List<String>> entry : extensionMap.entrySet()) {
// String key = entry.getKey();
// List<String> list = entry.getValue();
// for (String value : list) {
// ContentValues values = new ContentValues();
// values.put(Extensions.NAME, key);
// values.put(Extensions.VALUE, value);
// values.put(Extensions.PERSON_ID, personId);
// if (resolver != null) {
// contentValuesArray.add(values);
// } else {
// provider.nonTransactionalInsert(Extensions.CONTENT_URI, values);
// }
// }
// }
// if (resolver != null) {
// resolver.bulkInsert(Extensions.CONTENT_URI,
// contentValuesArray.toArray(new ContentValues[0]));
// }
// }
//
// if (primaryPhoneId >= 0 || primaryOrganizationId >= 0 || primaryEmailId >= 0) {
// ContentValues values = new ContentValues();
// if (primaryPhoneId >= 0) {
// values.put(People.PRIMARY_PHONE_ID, primaryPhoneId);
// }
// if (primaryOrganizationId >= 0) {
// values.put(People.PRIMARY_ORGANIZATION_ID, primaryOrganizationId);
// }
// if (primaryEmailId >= 0) {
// values.put(People.PRIMARY_EMAIL_ID, primaryEmailId);
// }
// if (resolver != null) {
// resolver.update(personUri, values, null, null);
// } else {
// provider.nonTransactionalUpdate(personUri, values, null, null);
// }
// }
// }
//
// /**
// * Push this object into database in the resolver.
// */
// public void pushIntoContentResolver(ContentResolver resolver) {
// pushIntoContentProviderOrResolver(resolver, 0);
// }
//
// /**
// * Push this object into AbstractSyncableContentProvider object.
// */
// public void pushIntoAbstractSyncableContentProvider(
// AbstractSyncableContentProvider provider, long myContactsGroupId) {
// boolean successful = false;
// provider.beginTransaction();
// try {
// pushIntoContentProviderOrResolver(provider, myContactsGroupId);
// successful = true;
// } finally {
// provider.endTransaction(successful);
// }
// }
public boolean isIgnorable() {
return TextUtils.isEmpty(name) &&
TextUtils.isEmpty(phoneticName) &&
(phoneList == null || phoneList.size() == 0) &&
(contactmethodList == null || contactmethodList.size() == 0);
}
}
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package a_vcard.android.provider;
//import com.android.internal.R;
//import android.content.ContentResolver;
//import android.content.ContentUris;
//import android.content.ContentValues;
//import android.content.Context;
//import android.content.Intent;
//import android.database.Cursor;
//import android.graphics.Bitmap;
//import android.graphics.BitmapFactory;
//import android.net.Uri;
//import android.text.TextUtils;
//import android.util.Log;
//import android.widget.ImageView;
//import java.io.ByteArrayInputStream;
//import java.io.InputStream;
/**
* The Contacts provider stores all information about contacts.
*/
public class Contacts {
private static final String TAG = "Contacts";
public static final String AUTHORITY = "contacts";
// /**
// * The content:// style URL for this provider
// */
// public static final Uri CONTENT_URI =
// Uri.parse("content://" + AUTHORITY);
/** Signifies an email address row that is stored in the ContactMethods table */
public static final int KIND_EMAIL = 1;
/** Signifies a postal address row that is stored in the ContactMethods table */
public static final int KIND_POSTAL = 2;
/** Signifies an IM address row that is stored in the ContactMethods table */
public static final int KIND_IM = 3;
/** Signifies an Organization row that is stored in the Organizations table */
public static final int KIND_ORGANIZATION = 4;
/** Signifies an Phone row that is stored in the Phones table */
public static final int KIND_PHONE = 5;
/**
* no public constructor since this is a utility class
*/
private Contacts() {}
// /**
// * Columns from the Settings table that other columns join into themselves.
// */
// public interface SettingsColumns {
// /**
// * The _SYNC_ACCOUNT to which this setting corresponds. This may be null.
// * <P>Type: TEXT</P>
// */
// public static final String _SYNC_ACCOUNT = "_sync_account";
//
// /**
// * The key of this setting.
// * <P>Type: TEXT</P>
// */
// public static final String KEY = "key";
//
// /**
// * The value of this setting.
// * <P>Type: TEXT</P>
// */
// public static final String VALUE = "value";
// }
//
// /**
// * The settings over all of the people
// */
// public static final class Settings implements BaseColumns, SettingsColumns {
// /**
// * no public constructor since this is a utility class
// */
// private Settings() {}
//
// /**
// * The content:// style URL for this table
// */
// public static final Uri CONTENT_URI =
// Uri.parse("content://contacts/settings");
//
// /**
// * The directory twig for this sub-table
// */
// public static final String CONTENT_DIRECTORY = "settings";
//
// /**
// * The default sort order for this table
// */
// public static final String DEFAULT_SORT_ORDER = "key ASC";
//
// /**
// * A setting that is used to indicate if we should sync down all groups for the
// * specified account. For this setting the _SYNC_ACCOUNT column must be set.
// * If this isn't set then we will only sync the groups whose SHOULD_SYNC column
// * is set to true.
// * <p>
// * This is a boolean setting. It is true if it is set and it is anything other than the
// * emptry string or "0".
// */
// public static final String SYNC_EVERYTHING = "syncEverything";
//
// public static String getSetting(ContentResolver cr, String account, String key) {
// // For now we only support a single account and the UI doesn't know what
// // the account name is, so we're using a global setting for SYNC_EVERYTHING.
// // Some day when we add multiple accounts to the UI this should honor the account
// // that was asked for.
// String selectString;
// String[] selectArgs;
// if (false) {
// selectString = (account == null)
// ? "_sync_account is null AND key=?"
// : "_sync_account=? AND key=?";
// selectArgs = (account == null)
// ? new String[]{key}
// : new String[]{account, key};
// } else {
// selectString = "key=?";
// selectArgs = new String[] {key};
// }
// Cursor cursor = cr.query(Settings.CONTENT_URI, new String[]{VALUE},
// selectString, selectArgs, null);
// try {
// if (!cursor.moveToNext()) return null;
// return cursor.getString(0);
// } finally {
// cursor.close();
// }
// }
//
// public static void setSetting(ContentResolver cr, String account, String key,
// String value) {
// ContentValues values = new ContentValues();
// // For now we only support a single account and the UI doesn't know what
// // the account name is, so we're using a global setting for SYNC_EVERYTHING.
// // Some day when we add multiple accounts to the UI this should honor the account
// // that was asked for.
// //values.put(_SYNC_ACCOUNT, account);
// values.put(KEY, key);
// values.put(VALUE, value);
// cr.update(Settings.CONTENT_URI, values, null, null);
// }
// }
//
/**
* Columns from the People table that other tables join into themselves.
*/
public interface PeopleColumns {
/**
* The person's name.
* <P>Type: TEXT</P>
*/
public static final String NAME = "name";
/**
* Phonetic equivalent of the person's name, in a locale-dependent
* character set (e.g. hiragana for Japanese).
* Used for pronunciation and/or collation in some languages.
* <p>Type: TEXT</P>
*/
public static final String PHONETIC_NAME = "phonetic_name";
/**
* The display name. If name is not null name, else if number is not null number,
* else if email is not null email.
* <P>Type: TEXT</P>
*/
public static final String DISPLAY_NAME = "display_name";
/**
* The field for sorting list phonetically. The content of this field
* may not be human readable but phonetically sortable.
* <P>Type: TEXT</p>
* @hide Used only in Contacts application for now.
*/
public static final String SORT_STRING = "sort_string";
/**
* Notes about the person.
* <P>Type: TEXT</P>
*/
public static final String NOTES = "notes";
/**
* The number of times a person has been contacted
* <P>Type: INTEGER</P>
*/
public static final String TIMES_CONTACTED = "times_contacted";
/**
* The last time a person was contacted.
* <P>Type: INTEGER</P>
*/
public static final String LAST_TIME_CONTACTED = "last_time_contacted";
/**
* A custom ringtone associated with a person. Not always present.
* <P>Type: TEXT (URI to the ringtone)</P>
*/
public static final String CUSTOM_RINGTONE = "custom_ringtone";
/**
* Whether the person should always be sent to voicemail. Not always
* present.
* <P>Type: INTEGER (0 for false, 1 for true)</P>
*/
public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
/**
* Is the contact starred?
* <P>Type: INTEGER (boolean)</P>
*/
public static final String STARRED = "starred";
/**
* The server version of the photo
* <P>Type: TEXT (the version number portion of the photo URI)</P>
*/
public static final String PHOTO_VERSION = "photo_version";
}
//
// /**
// * This table contains people.
// */
// public static final class People implements BaseColumns, SyncConstValue, PeopleColumns,
// PhonesColumns, PresenceColumns {
// /**
// * no public constructor since this is a utility class
// */
// private People() {}
//
// /**
// * The content:// style URL for this table
// */
// public static final Uri CONTENT_URI =
// Uri.parse("content://contacts/people");
//
// /**
// * The content:// style URL for filtering people by name. The filter
// * argument should be passed as an additional path segment after this URI.
// */
// public static final Uri CONTENT_FILTER_URI =
// Uri.parse("content://contacts/people/filter");
//
// /**
// * The content:// style URL for the table that holds the deleted
// * contacts.
// */
// public static final Uri DELETED_CONTENT_URI =
// Uri.parse("content://contacts/deleted_people");
//
// /**
// * The content:// style URL for filtering people that have a specific
// * E-mail or IM address. The filter argument should be passed as an
// * additional path segment after this URI. This matches any people with
// * at least one E-mail or IM {@link ContactMethods} that match the
// * filter.
// *
// * Not exposed because we expect significant changes in the contacts
// * schema and do not want to have to support this.
// * @hide
// */
// public static final Uri WITH_EMAIL_OR_IM_FILTER_URI =
// Uri.parse("content://contacts/people/with_email_or_im_filter");
//
// /**
// * The MIME type of {@link #CONTENT_URI} providing a directory of
// * people.
// */
// public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person";
//
// /**
// * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
// * person.
// */
// public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person";
//
// /**
// * The default sort order for this table
// */
// public static final String DEFAULT_SORT_ORDER = People.NAME + " ASC";
//
// /**
// * The ID of the persons preferred phone number.
// * <P>Type: INTEGER (foreign key to phones table on the _ID field)</P>
// */
// public static final String PRIMARY_PHONE_ID = "primary_phone";
//
// /**
// * The ID of the persons preferred email.
// * <P>Type: INTEGER (foreign key to contact_methods table on the
// * _ID field)</P>
// */
// public static final String PRIMARY_EMAIL_ID = "primary_email";
//
// /**
// * The ID of the persons preferred organization.
// * <P>Type: INTEGER (foreign key to organizations table on the
// * _ID field)</P>
// */
// public static final String PRIMARY_ORGANIZATION_ID = "primary_organization";
//
// /**
// * Mark a person as having been contacted.
// *
// * @param resolver the ContentResolver to use
// * @param personId the person who was contacted
// */
// public static void markAsContacted(ContentResolver resolver, long personId) {
// Uri uri = ContentUris.withAppendedId(CONTENT_URI, personId);
// uri = Uri.withAppendedPath(uri, "update_contact_time");
// ContentValues values = new ContentValues();
// // There is a trigger in place that will update TIMES_CONTACTED when
// // LAST_TIME_CONTACTED is modified.
// values.put(LAST_TIME_CONTACTED, System.currentTimeMillis());
// resolver.update(uri, values, null, null);
// }
//
// /**
// * @hide Used in vCard parser code.
// */
// public static long tryGetMyContactsGroupId(ContentResolver resolver) {
// Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION,
// Groups.SYSTEM_ID + "='" + Groups.GROUP_MY_CONTACTS + "'", null, null);
// if (groupsCursor != null) {
// try {
// if (groupsCursor.moveToFirst()) {
// return groupsCursor.getLong(0);
// }
// } finally {
// groupsCursor.close();
// }
// }
// return 0;
// }
//
// /**
// * Adds a person to the My Contacts group.
// *
// * @param resolver the resolver to use
// * @param personId the person to add to the group
// * @return the URI of the group membership row
// * @throws IllegalStateException if the My Contacts group can't be found
// */
// public static Uri addToMyContactsGroup(ContentResolver resolver, long personId) {
// long groupId = tryGetMyContactsGroupId(resolver);
// if (groupId == 0) {
// throw new IllegalStateException("Failed to find the My Contacts group");
// }
//
// return addToGroup(resolver, personId, groupId);
// }
//
// /**
// * Adds a person to a group referred to by name.
// *
// * @param resolver the resolver to use
// * @param personId the person to add to the group
// * @param groupName the name of the group to add the contact to
// * @return the URI of the group membership row
// * @throws IllegalStateException if the group can't be found
// */
// public static Uri addToGroup(ContentResolver resolver, long personId, String groupName) {
// long groupId = 0;
// Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION,
// Groups.NAME + "=?", new String[] { groupName }, null);
// if (groupsCursor != null) {
// try {
// if (groupsCursor.moveToFirst()) {
// groupId = groupsCursor.getLong(0);
// }
// } finally {
// groupsCursor.close();
// }
// }
//
// if (groupId == 0) {
// throw new IllegalStateException("Failed to find the My Contacts group");
// }
//
// return addToGroup(resolver, personId, groupId);
// }
//
// /**
// * Adds a person to a group.
// *
// * @param resolver the resolver to use
// * @param personId the person to add to the group
// * @param groupId the group to add the person to
// * @return the URI of the group membership row
// */
// public static Uri addToGroup(ContentResolver resolver, long personId, long groupId) {
// ContentValues values = new ContentValues();
// values.put(GroupMembership.PERSON_ID, personId);
// values.put(GroupMembership.GROUP_ID, groupId);
// return resolver.insert(GroupMembership.CONTENT_URI, values);
// }
//
// private static final String[] GROUPS_PROJECTION = new String[] {
// Groups._ID,
// };
//
// /**
// * Creates a new contacts and adds it to the "My Contacts" group.
// *
// * @param resolver the ContentResolver to use
// * @param values the values to use when creating the contact
// * @return the URI of the contact, or null if the operation fails
// */
// public static Uri createPersonInMyContactsGroup(ContentResolver resolver,
// ContentValues values) {
//
// Uri contactUri = resolver.insert(People.CONTENT_URI, values);
// if (contactUri == null) {
// Log.e(TAG, "Failed to create the contact");
// return null;
// }
//
// if (addToMyContactsGroup(resolver, ContentUris.parseId(contactUri)) == null) {
// resolver.delete(contactUri, null, null);
// return null;
// }
// return contactUri;
// }
//
// public static Cursor queryGroups(ContentResolver resolver, long person) {
// return resolver.query(GroupMembership.CONTENT_URI, null, "person=?",
// new String[]{String.valueOf(person)}, Groups.DEFAULT_SORT_ORDER);
// }
//
// /**
// * Set the photo for this person. data may be null
// * @param cr the ContentResolver to use
// * @param person the Uri of the person whose photo is to be updated
// * @param data the byte[] that represents the photo
// */
// public static void setPhotoData(ContentResolver cr, Uri person, byte[] data) {
// Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
// ContentValues values = new ContentValues();
// values.put(Photos.DATA, data);
// cr.update(photoUri, values, null, null);
// }
//
// /**
// * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
// * If the person's photo isn't present returns the placeholderImageResource instead.
// * @param person the person whose photo should be used
// */
// public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri person) {
// Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
// Cursor cursor = cr.query(photoUri, new String[]{Photos.DATA}, null, null, null);
// try {
// if (!cursor.moveToNext()) {
// return null;
// }
// byte[] data = cursor.getBlob(0);
// if (data == null) {
// return null;
// }
// return new ByteArrayInputStream(data);
// } finally {
// cursor.close();
// }
// }
//
// /**
// * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
// * If the person's photo isn't present returns the placeholderImageResource instead.
// * @param context the Context
// * @param person the person whose photo should be used
// * @param placeholderImageResource the image resource to use if the person doesn't
// * have a photo
// * @param options the decoding options, can be set to null
// */
// public static Bitmap loadContactPhoto(Context context, Uri person,
// int placeholderImageResource, BitmapFactory.Options options) {
// if (person == null) {
// return loadPlaceholderPhoto(placeholderImageResource, context, options);
// }
//
// InputStream stream = openContactPhotoInputStream(context.getContentResolver(), person);
// Bitmap bm = stream != null ? BitmapFactory.decodeStream(stream, null, options) : null;
// if (bm == null) {
// bm = loadPlaceholderPhoto(placeholderImageResource, context, options);
// }
// return bm;
// }
//
// private static Bitmap loadPlaceholderPhoto(int placeholderImageResource, Context context,
// BitmapFactory.Options options) {
// if (placeholderImageResource == 0) {
// return null;
// }
// return BitmapFactory.decodeResource(context.getResources(),
// placeholderImageResource, options);
// }
/**
* A sub directory of a single person that contains all of their Phones.
*/
public static final class Phones implements BaseColumns, PhonesColumns,
PeopleColumns {
/**
* no public constructor since this is a utility class
*/
private Phones() {}
/**
* The directory twig for this sub-table
*/
public static final String CONTENT_DIRECTORY = "phones";
/**
* The default sort order for this table
*/
public static final String DEFAULT_SORT_ORDER = "number ASC";
}
/**
* A subdirectory of a single person that contains all of their
* ContactMethods.
*/
public static final class ContactMethods
implements BaseColumns, ContactMethodsColumns, PeopleColumns {
/**
* no public constructor since this is a utility class
*/
private ContactMethods() {}
/**
* The directory twig for this sub-table
*/
public static final String CONTENT_DIRECTORY = "contact_methods";
/**
* The default sort order for this table
*/
public static final String DEFAULT_SORT_ORDER = "data ASC";
}
// /**
// * The extensions for a person
// */
// public static class Extensions implements BaseColumns, ExtensionsColumns {
// /**
// * no public constructor since this is a utility class
// */
// private Extensions() {}
//
// /**
// * The directory twig for this sub-table
// */
// public static final String CONTENT_DIRECTORY = "extensions";
//
// /**
// * The default sort order for this table
// */
// public static final String DEFAULT_SORT_ORDER = "name ASC";
//
// /**
// * The ID of the person this phone number is assigned to.
// * <P>Type: INTEGER (long)</P>
// */
// public static final String PERSON_ID = "person";
// }
// }
//
// /**
// * Columns from the groups table.
// */
// public interface GroupsColumns {
// /**
// * The group name.
// * <P>Type: TEXT</P>
// */
// public static final String NAME = "name";
//
// /**
// * Notes about the group.
// * <P>Type: TEXT</P>
// */
// public static final String NOTES = "notes";
//
// /**
// * Whether this group should be synced if the SYNC_EVERYTHING settings is false
// * for this group's account.
// * <P>Type: INTEGER (boolean)</P>
// */
// public static final String SHOULD_SYNC = "should_sync";
//
// /**
// * The ID of this group if it is a System Group, null otherwise.
// * <P>Type: TEXT</P>
// */
// public static final String SYSTEM_ID = "system_id";
// }
//
// /**
// * This table contains the groups for an account.
// */
// public static final class Groups
// implements BaseColumns, SyncConstValue, GroupsColumns {
// /**
// * no public constructor since this is a utility class
// */
// private Groups() {}
//
// /**
// * The content:// style URL for this table
// */
// public static final Uri CONTENT_URI =
// Uri.parse("content://contacts/groups");
//
// /**
// * The content:// style URL for the table that holds the deleted
// * groups.
// */
// public static final Uri DELETED_CONTENT_URI =
// Uri.parse("content://contacts/deleted_groups");
//
// /**
// * The MIME type of {@link #CONTENT_URI} providing a directory of
// * groups.
// */
// public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroup";
//
// /**
// * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
// * group.
// */
// public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroup";
//
// /**
// * The default sort order for this table
// */
// public static final String DEFAULT_SORT_ORDER = NAME + " ASC";
//
// /**
// *
// */
// public static final String GROUP_ANDROID_STARRED = "Starred in Android";
//
// /**
// * The "My Contacts" system group.
// */
// public static final String GROUP_MY_CONTACTS = "Contacts";
// }
//
/**
* Columns from the Phones table that other columns join into themselves.
*/
public interface PhonesColumns {
/**
* The type of the the phone number.
* <P>Type: INTEGER (one of the constants below)</P>
*/
public static final String TYPE = "type";
public static final int TYPE_CUSTOM = 0;
public static final int TYPE_HOME = 1;
public static final int TYPE_MOBILE = 2;
public static final int TYPE_WORK = 3;
public static final int TYPE_FAX_WORK = 4;
public static final int TYPE_FAX_HOME = 5;
public static final int TYPE_PAGER = 6;
public static final int TYPE_OTHER = 7;
/**
* The user provided label for the phone number, only used if TYPE is TYPE_CUSTOM.
* <P>Type: TEXT</P>
*/
public static final String LABEL = "label";
/**
* The phone number as the user entered it.
* <P>Type: TEXT</P>
*/
public static final String NUMBER = "number";
/**
* The normalized phone number
* <P>Type: TEXT</P>
*/
public static final String NUMBER_KEY = "number_key";
/**
* Whether this is the primary phone number
* <P>Type: INTEGER (if set, non-0 means true)</P>
*/
public static final String ISPRIMARY = "isprimary";
}
//
// /**
// * This table stores phone numbers and a reference to the person that the
// * contact method belongs to. Phone numbers are stored separately from
// * other contact methods to make caller ID lookup more efficient.
// */
// public static final class Phones
// implements BaseColumns, PhonesColumns, PeopleColumns {
// /**
// * no public constructor since this is a utility class
// */
// private Phones() {}
//
// public static final CharSequence getDisplayLabel(Context context, int type,
// CharSequence label, CharSequence[] labelArray) {
// CharSequence display = "";
//
// if (type != People.Phones.TYPE_CUSTOM) {
// CharSequence[] labels = labelArray != null? labelArray
// : context.getResources().getTextArray(
// com.android.internal.R.array.phoneTypes);
// try {
// display = labels[type - 1];
// } catch (ArrayIndexOutOfBoundsException e) {
// display = labels[People.Phones.TYPE_HOME - 1];
// }
// } else {
// if (!TextUtils.isEmpty(label)) {
// display = label;
// }
// }
// return display;
// }
//
// public static final CharSequence getDisplayLabel(Context context, int type,
// CharSequence label) {
// return getDisplayLabel(context, type, label, null);
// }
//
// /**
// * The content:// style URL for this table
// */
// public static final Uri CONTENT_URI =
// Uri.parse("content://contacts/phones");
//
// /**
// * The content:// style URL for filtering phone numbers
// */
// public static final Uri CONTENT_FILTER_URL =
// Uri.parse("content://contacts/phones/filter");
//
// /**
// * The MIME type of {@link #CONTENT_URI} providing a directory of
// * phones.
// */
// public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone";
//
// /**
// * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
// * phone.
// */
// public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone";
//
// /**
// * The default sort order for this table
// */
// public static final String DEFAULT_SORT_ORDER = "name ASC";
//
// /**
// * The ID of the person this phone number is assigned to.
// * <P>Type: INTEGER (long)</P>
// */
// public static final String PERSON_ID = "person";
// }
//
// public static final class GroupMembership implements BaseColumns, GroupsColumns {
// /**
// * no public constructor since this is a utility class
// */
// private GroupMembership() {}
//
// /**
// * The content:// style URL for this table
// */
// public static final Uri CONTENT_URI =
// Uri.parse("content://contacts/groupmembership");
//
// /**
// * The content:// style URL for this table
// */
// public static final Uri RAW_CONTENT_URI =
// Uri.parse("content://contacts/groupmembershipraw");
//
// /**
// * The directory twig for this sub-table
// */
// public static final String CONTENT_DIRECTORY = "groupmembership";
// /**
// * The MIME type of {@link #CONTENT_URI} providing a directory of all
// * person groups.
// */
// public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroupmembership";
//
// /**
// * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
// * person group.
// */
// public static final String CONTENT_ITEM_TYPE =
// "vnd.android.cursor.item/contactsgroupmembership";
//
// /**
// * The default sort order for this table
// */
// public static final String DEFAULT_SORT_ORDER = "group_id ASC";
//
// /**
// * The row id of the accounts group.
// * <P>Type: TEXT</P>
// */
// public static final String GROUP_ID = "group_id";
//
// /**
// * The sync id of the group.
// * <P>Type: TEXT</P>
// */
// public static final String GROUP_SYNC_ID = "group_sync_id";
//
// /**
// * The account of the group.
// * <P>Type: TEXT</P>
// */
// public static final String GROUP_SYNC_ACCOUNT = "group_sync_account";
//
// /**
// * The row id of the person.
// * <P>Type: TEXT</P>
// */
// public static final String PERSON_ID = "person";
// }
//
/**
* Columns from the ContactMethods table that other tables join into
* themseleves.
*/
public interface ContactMethodsColumns {
/**
* The kind of the the contact method. For example, email address,
* postal address, etc.
* <P>Type: INTEGER (one of the values below)</P>
*/
public static final String KIND = "kind";
/**
* The type of the contact method, must be one of the types below.
* <P>Type: INTEGER (one of the values below)</P>
*/
public static final String TYPE = "type";
public static final int TYPE_CUSTOM = 0;
public static final int TYPE_HOME = 1;
public static final int TYPE_WORK = 2;
public static final int TYPE_OTHER = 3;
/**
* @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future.
*/
public static final int MOBILE_EMAIL_TYPE_INDEX = 2;
/**
* @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future.
* This is not "mobile" but "CELL" since vCard uses it for identifying mobile phone.
*/
public static final String MOBILE_EMAIL_TYPE_NAME = "_AUTO_CELL";
/**
* The user defined label for the the contact method.
* <P>Type: TEXT</P>
*/
public static final String LABEL = "label";
/**
* The data for the contact method.
* <P>Type: TEXT</P>
*/
public static final String DATA = "data";
/**
* Auxiliary data for the contact method.
* <P>Type: TEXT</P>
*/
public static final String AUX_DATA = "aux_data";
/**
* Whether this is the primary organization
* <P>Type: INTEGER (if set, non-0 means true)</P>
*/
public static final String ISPRIMARY = "isprimary";
}
//
// /**
// * This table stores all non-phone contact methods and a reference to the
// * person that the contact method belongs to.
// */
// public static final class ContactMethods
// implements BaseColumns, ContactMethodsColumns, PeopleColumns {
// /**
// * The column with latitude data for postal locations
// * <P>Type: REAL</P>
// */
// public static final String POSTAL_LOCATION_LATITUDE = DATA;
//
// /**
// * The column with longitude data for postal locations
// * <P>Type: REAL</P>
// */
// public static final String POSTAL_LOCATION_LONGITUDE = AUX_DATA;
//
// /**
// * The predefined IM protocol types. The protocol can either be non-present, one
// * of these types, or a free-form string. These cases are encoded in the AUX_DATA
// * column as:
// * - null
// * - pre:<an integer, one of the protocols below>
// * - custom:<a string>
// */
// public static final int PROTOCOL_AIM = 0;
// public static final int PROTOCOL_MSN = 1;
// public static final int PROTOCOL_YAHOO = 2;
// public static final int PROTOCOL_SKYPE = 3;
// public static final int PROTOCOL_QQ = 4;
// public static final int PROTOCOL_GOOGLE_TALK = 5;
// public static final int PROTOCOL_ICQ = 6;
// public static final int PROTOCOL_JABBER = 7;
//
// public static String encodePredefinedImProtocol(int protocol) {
// return "pre:" + protocol;
// }
//
// public static String encodeCustomImProtocol(String protocolString) {
// return "custom:" + protocolString;
// }
//
// public static Object decodeImProtocol(String encodedString) {
// if (encodedString == null) {
// return null;
// }
//
// if (encodedString.startsWith("pre:")) {
// return Integer.parseInt(encodedString.substring(4));
// }
//
// if (encodedString.startsWith("custom:")) {
// return encodedString.substring(7);
// }
//
// throw new IllegalArgumentException(
// "the value is not a valid encoded protocol, " + encodedString);
// }
//
// /**
// * This looks up the provider name defined in
// * {@link android.provider.Im.ProviderNames} from the predefined IM protocol id.
// * This is used for interacting with the IM application.
// *
// * @param protocol the protocol ID
// * @return the provider name the IM app uses for the given protocol, or null if no
// * provider is defined for the given protocol
// * @hide
// */
// public static String lookupProviderNameFromId(int protocol) {
// switch (protocol) {
// case PROTOCOL_GOOGLE_TALK:
// return Im.ProviderNames.GTALK;
// case PROTOCOL_AIM:
// return Im.ProviderNames.AIM;
// case PROTOCOL_MSN:
// return Im.ProviderNames.MSN;
// case PROTOCOL_YAHOO:
// return Im.ProviderNames.YAHOO;
// case PROTOCOL_ICQ:
// return Im.ProviderNames.ICQ;
// case PROTOCOL_JABBER:
// return Im.ProviderNames.JABBER;
// case PROTOCOL_SKYPE:
// return Im.ProviderNames.SKYPE;
// case PROTOCOL_QQ:
// return Im.ProviderNames.QQ;
// }
// return null;
// }
//
// /**
// * no public constructor since this is a utility class
// */
// private ContactMethods() {}
//
// public static final CharSequence getDisplayLabel(Context context, int kind,
// int type, CharSequence label) {
// CharSequence display = "";
// switch (kind) {
// case KIND_EMAIL: {
// if (type != People.ContactMethods.TYPE_CUSTOM) {
// CharSequence[] labels = context.getResources().getTextArray(
// com.android.internal.R.array.emailAddressTypes);
// try {
// display = labels[type - 1];
// } catch (ArrayIndexOutOfBoundsException e) {
// display = labels[ContactMethods.TYPE_HOME - 1];
// }
// } else {
// if (!TextUtils.isEmpty(label)) {
// if (label.toString().equals(MOBILE_EMAIL_TYPE_NAME)) {
// display =
// context.getString(
// com.android.internal.R.string.mobileEmailTypeName);
// } else {
// display = label;
// }
// }
// }
// break;
// }
//
// case KIND_POSTAL: {
// if (type != People.ContactMethods.TYPE_CUSTOM) {
// CharSequence[] labels = context.getResources().getTextArray(
// com.android.internal.R.array.postalAddressTypes);
// try {
// display = labels[type - 1];
// } catch (ArrayIndexOutOfBoundsException e) {
// display = labels[ContactMethods.TYPE_HOME - 1];
// }
// } else {
// if (!TextUtils.isEmpty(label)) {
// display = label;
// }
// }
// break;
// }
//
// default:
// display = context.getString(R.string.untitled);
// }
// return display;
// }
//
// /**
// * Add a longitude and latitude location to a postal address.
// *
// * @param context the context to use when updating the database
// * @param postalId the address to update
// * @param latitude the latitude for the address
// * @param longitude the longitude for the address
// */
// public void addPostalLocation(Context context, long postalId,
// double latitude, double longitude) {
// final ContentResolver resolver = context.getContentResolver();
// // Insert the location
// ContentValues values = new ContentValues(2);
// values.put(POSTAL_LOCATION_LATITUDE, latitude);
// values.put(POSTAL_LOCATION_LONGITUDE, longitude);
// Uri loc = resolver.insert(CONTENT_URI, values);
// long locId = ContentUris.parseId(loc);
//
// // Update the postal address
// values.clear();
// values.put(AUX_DATA, locId);
// resolver.update(ContentUris.withAppendedId(CONTENT_URI, postalId), values, null, null);
// }
//
// /**
// * The content:// style URL for this table
// */
// public static final Uri CONTENT_URI =
// Uri.parse("content://contacts/contact_methods");
//
// /**
// * The content:// style URL for sub-directory of e-mail addresses.
// */
// public static final Uri CONTENT_EMAIL_URI =
// Uri.parse("content://contacts/contact_methods/email");
//
// /**
// * The MIME type of {@link #CONTENT_URI} providing a directory of
// * phones.
// */
// public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact-methods";
//
// /**
// * The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\
// * multiple {@link Contacts#KIND_EMAIL} entries.
// */
// public static final String CONTENT_EMAIL_TYPE = "vnd.android.cursor.dir/email";
//
// /**
// * The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\
// * multiple {@link Contacts#KIND_POSTAL} entries.
// */
// public static final String CONTENT_POSTAL_TYPE = "vnd.android.cursor.dir/postal-address";
//
// /**
// * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
// * {@link Contacts#KIND_EMAIL} entry.
// */
// public static final String CONTENT_EMAIL_ITEM_TYPE = "vnd.android.cursor.item/email";
//
// /**
// * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
// * {@link Contacts#KIND_POSTAL} entry.
// */
// public static final String CONTENT_POSTAL_ITEM_TYPE
// = "vnd.android.cursor.item/postal-address";
//
// /**
// * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
// * {@link Contacts#KIND_IM} entry.
// */
// public static final String CONTENT_IM_ITEM_TYPE = "vnd.android.cursor.item/jabber-im";
//
// /**
// * The default sort order for this table
// */
// public static final String DEFAULT_SORT_ORDER = "name ASC";
//
// /**
// * The ID of the person this contact method is assigned to.
// * <P>Type: INTEGER (long)</P>
// */
// public static final String PERSON_ID = "person";
// }
//
// /**
// * The IM presence columns with some contacts specific columns mixed in.
// */
// public interface PresenceColumns extends Im.CommonPresenceColumns {
// /**
// * The IM service the presence is coming from. Formatted using either
// * {@link Contacts.ContactMethods#encodePredefinedImProtocol} or
// * {@link Contacts.ContactMethods#encodeCustomImProtocol}.
// * <P>Type: STRING</P>
// */
// public static final String IM_PROTOCOL = "im_protocol";
//
// /**
// * The IM handle the presence item is for. The handle is scoped to
// * the {@link #IM_PROTOCOL}.
// * <P>Type: STRING</P>
// */
// public static final String IM_HANDLE = "im_handle";
//
// /**
// * The IM account for the local user that the presence data came from.
// * <P>Type: STRING</P>
// */
// public static final String IM_ACCOUNT = "im_account";
// }
//
// /**
// * Contains presence information about contacts.
// * @hide
// */
// public static final class Presence
// implements BaseColumns, PresenceColumns, PeopleColumns {
// /**
// * The content:// style URL for this table
// */
// public static final Uri CONTENT_URI =
// Uri.parse("content://contacts/presence");
//
// /**
// * The ID of the person this presence item is assigned to.
// * <P>Type: INTEGER (long)</P>
// */
// public static final String PERSON_ID = "person";
//
// /**
// * Gets the resource ID for the proper presence icon.
// *
// * @param status the status to get the icon for
// * @return the resource ID for the proper presence icon
// */
// public static final int getPresenceIconResourceId(int status) {
// switch (status) {
// case Contacts.People.AVAILABLE:
// return com.android.internal.R.drawable.presence_online;
//
// case Contacts.People.IDLE:
// case Contacts.People.AWAY:
// return com.android.internal.R.drawable.presence_away;
//
// case Contacts.People.DO_NOT_DISTURB:
// return com.android.internal.R.drawable.presence_busy;
//
// case Contacts.People.INVISIBLE:
// return com.android.internal.R.drawable.presence_invisible;
//
// case Contacts.People.OFFLINE:
// default:
// return com.android.internal.R.drawable.presence_offline;
// }
// }
//
// /**
// * Sets a presence icon to the proper graphic
// *
// * @param icon the icon to to set
// * @param serverStatus that status
// */
// public static final void setPresenceIcon(ImageView icon, int serverStatus) {
// icon.setImageResource(getPresenceIconResourceId(serverStatus));
// }
// }
//
/**
* Columns from the Organizations table that other columns join into themselves.
*/
public interface OrganizationColumns {
/**
* The type of the organizations.
* <P>Type: INTEGER (one of the constants below)</P>
*/
public static final String TYPE = "type";
public static final int TYPE_CUSTOM = 0;
public static final int TYPE_WORK = 1;
public static final int TYPE_OTHER = 2;
/**
* The user provided label, only used if TYPE is TYPE_CUSTOM.
* <P>Type: TEXT</P>
*/
public static final String LABEL = "label";
/**
* The name of the company for this organization.
* <P>Type: TEXT</P>
*/
public static final String COMPANY = "company";
/**
* The title within this organization.
* <P>Type: TEXT</P>
*/
public static final String TITLE = "title";
/**
* The person this organization is tied to.
* <P>Type: TEXT</P>
*/
public static final String PERSON_ID = "person";
/**
* Whether this is the primary organization
* <P>Type: INTEGER (if set, non-0 means true)</P>
*/
public static final String ISPRIMARY = "isprimary";
}
//
// /**
// * A sub directory of a single person that contains all of their Phones.
// */
// public static final class Organizations implements BaseColumns, OrganizationColumns {
// /**
// * no public constructor since this is a utility class
// */
// private Organizations() {}
//
// public static final CharSequence getDisplayLabel(Context context, int type,
// CharSequence label) {
// CharSequence display = "";
//
// if (type != TYPE_CUSTOM) {
// CharSequence[] labels = context.getResources().getTextArray(
// com.android.internal.R.array.organizationTypes);
// try {
// display = labels[type - 1];
// } catch (ArrayIndexOutOfBoundsException e) {
// display = labels[Organizations.TYPE_WORK - 1];
// }
// } else {
// if (!TextUtils.isEmpty(label)) {
// display = label;
// }
// }
// return display;
// }
//
// /**
// * The content:// style URL for this table
// */
// public static final Uri CONTENT_URI =
// Uri.parse("content://contacts/organizations");
//
// /**
// * The directory twig for this sub-table
// */
// public static final String CONTENT_DIRECTORY = "organizations";
//
// /**
// * The default sort order for this table
// */
// public static final String DEFAULT_SORT_ORDER = "company, title, isprimary ASC";
// }
//
// /**
// * Columns from the Photos table that other columns join into themselves.
// */
// public interface PhotosColumns {
// /**
// * The _SYNC_VERSION of the photo that was last downloaded
// * <P>Type: TEXT</P>
// */
// public static final String LOCAL_VERSION = "local_version";
//
// /**
// * The person this photo is associated with.
// * <P>Type: TEXT</P>
// */
// public static final String PERSON_ID = "person";
//
// /**
// * non-zero if a download is required and the photo isn't marked as a bad resource.
// * You must specify this in the columns in order to use it in the where clause.
// * <P>Type: INTEGER(boolean)</P>
// */
// public static final String DOWNLOAD_REQUIRED = "download_required";
//
// /**
// * non-zero if this photo is known to exist on the server
// * <P>Type: INTEGER(boolean)</P>
// */
// public static final String EXISTS_ON_SERVER = "exists_on_server";
//
// /**
// * Contains the description of the upload or download error from
// * the previous attempt. If null then the previous attempt succeeded.
// * <P>Type: TEXT</P>
// */
// public static final String SYNC_ERROR = "sync_error";
//
// /**
// * The image data, or null if there is no image.
// * <P>Type: BLOB</P>
// */
// public static final String DATA = "data";
//
// }
//
// /**
// * The photos over all of the people
// */
// public static final class Photos implements BaseColumns, PhotosColumns, SyncConstValue {
// /**
// * no public constructor since this is a utility class
// */
// private Photos() {}
//
// /**
// * The content:// style URL for this table
// */
// public static final Uri CONTENT_URI =
// Uri.parse("content://contacts/photos");
//
// /**
// * The directory twig for this sub-table
// */
// public static final String CONTENT_DIRECTORY = "photo";
//
// /**
// * The default sort order for this table
// */
// public static final String DEFAULT_SORT_ORDER = "person ASC";
// }
//
// public interface ExtensionsColumns {
// /**
// * The name of this extension. May not be null. There may be at most one row for each name.
// * <P>Type: TEXT</P>
// */
// public static final String NAME = "name";
//
// /**
// * The value of this extension. May not be null.
// * <P>Type: TEXT</P>
// */
// public static final String VALUE = "value";
// }
//
// /**
// * The extensions for a person
// */
// public static final class Extensions implements BaseColumns, ExtensionsColumns {
// /**
// * no public constructor since this is a utility class
// */
// private Extensions() {}
//
// /**
// * The content:// style URL for this table
// */
// public static final Uri CONTENT_URI =
// Uri.parse("content://contacts/extensions");
//
// /**
// * The MIME type of {@link #CONTENT_URI} providing a directory of
// * phones.
// */
// public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_extensions";
//
// /**
// * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
// * phone.
// */
// public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_extensions";
// /**
// * The default sort order for this table
// */
// public static final String DEFAULT_SORT_ORDER = "person, name ASC";
//
// /**
// * The ID of the person this phone number is assigned to.
// * <P>Type: INTEGER (long)</P>
// */
// public static final String PERSON_ID = "person";
// }
//
// /**
// * Contains helper classes used to create or manage {@link android.content.Intent Intents}
// * that involve contacts.
// */
// public static final class Intents {
// /**
// * This is the intent that is fired when a search suggestion is clicked on.
// */
// public static final String SEARCH_SUGGESTION_CLICKED =
// "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
//
// /**
// * This is the intent that is fired when a search suggestion for dialing a number
// * is clicked on.
// */
// public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
// "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
//
// /**
// * This is the intent that is fired when a search suggestion for creating a contact
// * is clicked on.
// */
// public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
// "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
//
// /**
// * Starts an Activity that lets the user pick a contact to attach an image to.
// * After picking the contact it launches the image cropper in face detection mode.
// */
// public static final String ATTACH_IMAGE =
// "com.android.contacts.action.ATTACH_IMAGE";
//
// /**
// * Takes as input a data URI with a mailto: or tel: scheme. If a single
// * contact exists with the given data it will be shown. If no contact
// * exists, a dialog will ask the user if they want to create a new
// * contact with the provided details filled in. If multiple contacts
// * share the data the user will be prompted to pick which contact they
// * want to view.
// * <p>
// * For <code>mailto:</code> URIs, the scheme specific portion must be a
// * raw email address, such as one built using
// * {@link Uri#fromParts(String, String, String)}.
// * <p>
// * For <code>tel:</code> URIs, the scheme specific portion is compared
// * to existing numbers using the standard caller ID lookup algorithm.
// * The number must be properly encoded, for example using
// * {@link Uri#fromParts(String, String, String)}.
// * <p>
// * Any extras from the {@link Insert} class will be passed along to the
// * create activity if there are no contacts to show.
// * <p>
// * Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip
// * prompting the user when the contact doesn't exist.
// */
// public static final String SHOW_OR_CREATE_CONTACT =
// "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
//
// /**
// * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
// * contact if no matching contact found. Otherwise, default behavior is
// * to prompt user with dialog before creating.
// * <p>
// * Type: BOOLEAN
// */
// public static final String EXTRA_FORCE_CREATE =
// "com.android.contacts.action.FORCE_CREATE";
//
// /**
// * Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact
// * description to be shown when prompting user about creating a new
// * contact.
// * <p>
// * Type: STRING
// */
// public static final String EXTRA_CREATE_DESCRIPTION =
// "com.android.contacts.action.CREATE_DESCRIPTION";
//
// /**
// * Intents related to the Contacts app UI.
// */
// public static final class UI {
// /**
// * The action for the default contacts list tab.
// */
// public static final String LIST_DEFAULT =
// "com.android.contacts.action.LIST_DEFAULT";
//
// /**
// * The action for the contacts list tab.
// */
// public static final String LIST_GROUP_ACTION =
// "com.android.contacts.action.LIST_GROUP";
//
// /**
// * When in LIST_GROUP_ACTION mode, this is the group to display.
// */
// public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
//
// /**
// * The action for the all contacts list tab.
// */
// public static final String LIST_ALL_CONTACTS_ACTION =
// "com.android.contacts.action.LIST_ALL_CONTACTS";
//
// /**
// * The action for the contacts with phone numbers list tab.
// */
// public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
// "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
//
// /**
// * The action for the starred contacts list tab.
// */
// public static final String LIST_STARRED_ACTION =
// "com.android.contacts.action.LIST_STARRED";
//
// /**
// * The action for the frequent contacts list tab.
// */
// public static final String LIST_FREQUENT_ACTION =
// "com.android.contacts.action.LIST_FREQUENT";
//
// /**
// * The action for the "strequent" contacts list tab. It first lists the starred
// * contacts in alphabetical order and then the frequent contacts in descending
// * order of the number of times they have been contacted.
// */
// public static final String LIST_STREQUENT_ACTION =
// "com.android.contacts.action.LIST_STREQUENT";
//
// /**
// * A key for to be used as an intent extra to set the activity
// * title to a custom String value.
// */
// public static final String TITLE_EXTRA_KEY =
// "com.android.contacts.extra.TITLE_EXTRA";
//
// /**
// * Activity Action: Display a filtered list of contacts
// * <p>
// * Input: Extra field {@link #FILTER_TEXT_EXTRA_KEY} is the text to use for
// * filtering
// * <p>
// * Output: Nothing.
// */
// public static final String FILTER_CONTACTS_ACTION =
// "com.android.contacts.action.FILTER_CONTACTS";
//
// /**
// * Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
// * intents to supply the text on which to filter.
// */
// public static final String FILTER_TEXT_EXTRA_KEY =
// "com.android.contacts.extra.FILTER_TEXT";
// }
//
// /**
// * Convenience class that contains string constants used
// * to create contact {@link android.content.Intent Intents}.
// */
// public static final class Insert {
// /** The action code to use when adding a contact */
// public static final String ACTION = Intent.ACTION_INSERT;
//
// /**
// * If present, forces a bypass of quick insert mode.
// */
// public static final String FULL_MODE = "full_mode";
//
// /**
// * The extra field for the contact name.
// * <P>Type: String</P>
// */
// public static final String NAME = "name";
//
// /**
// * The extra field for the contact phonetic name.
// * <P>Type: String</P>
// */
// public static final String PHONETIC_NAME = "phonetic_name";
//
// /**
// * The extra field for the contact company.
// * <P>Type: String</P>
// */
// public static final String COMPANY = "company";
//
// /**
// * The extra field for the contact job title.
// * <P>Type: String</P>
// */
// public static final String JOB_TITLE = "job_title";
//
// /**
// * The extra field for the contact notes.
// * <P>Type: String</P>
// */
// public static final String NOTES = "notes";
//
// /**
// * The extra field for the contact phone number.
// * <P>Type: String</P>
// */
// public static final String PHONE = "phone";
//
// /**
// * The extra field for the contact phone number type.
// * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
// * or a string specifying a custom label.</P>
// */
// public static final String PHONE_TYPE = "phone_type";
//
// /**
// * The extra field for the phone isprimary flag.
// * <P>Type: boolean</P>
// */
// public static final String PHONE_ISPRIMARY = "phone_isprimary";
//
// /**
// * The extra field for an optional second contact phone number.
// * <P>Type: String</P>
// */
// public static final String SECONDARY_PHONE = "secondary_phone";
//
// /**
// * The extra field for an optional second contact phone number type.
// * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
// * or a string specifying a custom label.</P>
// */
// public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
//
// /**
// * The extra field for an optional third contact phone number.
// * <P>Type: String</P>
// */
// public static final String TERTIARY_PHONE = "tertiary_phone";
//
// /**
// * The extra field for an optional third contact phone number type.
// * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
// * or a string specifying a custom label.</P>
// */
// public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
//
// /**
// * The extra field for the contact email address.
// * <P>Type: String</P>
// */
// public static final String EMAIL = "email";
//
// /**
// * The extra field for the contact email type.
// * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
// * or a string specifying a custom label.</P>
// */
// public static final String EMAIL_TYPE = "email_type";
//
// /**
// * The extra field for the email isprimary flag.
// * <P>Type: boolean</P>
// */
// public static final String EMAIL_ISPRIMARY = "email_isprimary";
//
// /**
// * The extra field for an optional second contact email address.
// * <P>Type: String</P>
// */
// public static final String SECONDARY_EMAIL = "secondary_email";
//
// /**
// * The extra field for an optional second contact email type.
// * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
// * or a string specifying a custom label.</P>
// */
// public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
//
// /**
// * The extra field for an optional third contact email address.
// * <P>Type: String</P>
// */
// public static final String TERTIARY_EMAIL = "tertiary_email";
//
// /**
// * The extra field for an optional third contact email type.
// * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
// * or a string specifying a custom label.</P>
// */
// public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
//
// /**
// * The extra field for the contact postal address.
// * <P>Type: String</P>
// */
// public static final String POSTAL = "postal";
//
// /**
// * The extra field for the contact postal address type.
// * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
// * or a string specifying a custom label.</P>
// */
// public static final String POSTAL_TYPE = "postal_type";
//
// /**
// * The extra field for the postal isprimary flag.
// * <P>Type: boolean</P>
// */
// public static final String POSTAL_ISPRIMARY = "postal_isprimary";
//
// /**
// * The extra field for an IM handle.
// * <P>Type: String</P>
// */
// public static final String IM_HANDLE = "im_handle";
//
// /**
// * The extra field for the IM protocol
// * <P>Type: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
// * or {@link Contacts.ContactMethods#encodeCustomImProtocol}.</P>
// */
// public static final String IM_PROTOCOL = "im_protocol";
//
// /**
// * The extra field for the IM isprimary flag.
// * <P>Type: boolean</P>
// */
// public static final String IM_ISPRIMARY = "im_isprimary";
// }
// }
}
接着我将给你导入导出通讯录的类
package com.hh.assistant.app.vo;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import a_vcard.android.provider.Contacts;
import a_vcard.android.syncml.pim.VDataBuilder;
import a_vcard.android.syncml.pim.VNode;
import a_vcard.android.syncml.pim.vcard.ContactStruct;
import a_vcard.android.syncml.pim.vcard.ContactStruct.ContactMethod;
import a_vcard.android.syncml.pim.vcard.ContactStruct.PhoneData;
import a_vcard.android.syncml.pim.vcard.VCardComposer;
import a_vcard.android.syncml.pim.vcard.VCardException;
import a_vcard.android.syncml.pim.vcard.VCardParser;
import android.app.Activity;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
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.RawContacts;
import android.provider.ContactsContract.RawContacts.Data;
import android.widget.Toast;
/**
* 联系人信息包装类
*
* @author LW
*
*/
public class ContactInfo {
/** MUST exist */
private String name; // 姓名
/** 联系人电话信息 */
public static class PhoneInfo{
/** 联系电话类型 */
public int type;
/** 联系电话 */
public String number;
}
/** 联系人邮箱信息 */
public static class EmailInfo{
/** 邮箱类型 */
public int type;
/** 邮箱 */
public String email;
}
private List<PhoneInfo> phoneList = new ArrayList<PhoneInfo>(); // 联系号码
private List<EmailInfo> email = new ArrayList<EmailInfo>(); // Email
/**
* 构造联系人信息
* @param name 联系人姓名
*/
public ContactInfo(String name) {
this.name = name;
}
/** 姓名 */
public String getName() {
return name;
}
/** 姓名 */
public ContactInfo setName(String name) {
this.name = name;
return this;
}
/** 联系电话信息 */
public List<PhoneInfo> getPhoneList() {
return phoneList;
}
/** 联系电话信息 */
public ContactInfo setPhoneList(List<PhoneInfo> phoneList) {
this.phoneList = phoneList;
return this;
}
/** 邮箱信息 */
public List<EmailInfo> getEmail() {
return email;
}
/** 邮箱信息 */
public ContactInfo setEmail(List<EmailInfo> email) {
this.email = email;
return this;
}
@Override
public String toString() {
return "{name: "+name+", number: "+phoneList+", email: "+email+"}";
}
/**
* 联系人
* 备份/还原操作
* @author LW
*
*/
public static class ContactHandler {
private static ContactHandler instance_ = new ContactHandler();
/** 获取实例 */
public static ContactHandler getInstance(){
return instance_;
}
/**
* 获取联系人指定信息
* @param projection 指定要获取的列数组, 获取全部列则设置为null
* @return
* @throws Exception
*/
public Cursor queryContact(Activity context, String[] projection){
// 获取联系人的所需信息
Cursor cur = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, projection, null, null, null);
return cur;
}
/**
* 获取联系人信息
* @param context
* @return
*/
public List<ContactInfo> getContactInfo(Activity context){
List<ContactInfo> infoList = new ArrayList<ContactInfo>();
Cursor cur = queryContact(context, null);
if(cur.moveToFirst()){
do{
// 获取联系人id号
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
// 获取联系人姓名
String displayName = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
ContactInfo info = new ContactInfo(displayName);// 初始化联系人信息
// 查看联系人有多少电话号码, 如果没有返回0
int phoneCount = cur.getInt(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
if(phoneCount>0){
Cursor phonesCursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + id , null, null);
if(phonesCursor.moveToFirst()) {
List<ContactInfo.PhoneInfo> phoneNumberList = new ArrayList<ContactInfo.PhoneInfo>();
do{
// 遍历所有电话号码
String phoneNumber = phonesCursor.getString(phonesCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
// 对应的联系人类型
int type = phonesCursor.getInt(phonesCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
// 初始化联系人电话信息
ContactInfo.PhoneInfo phoneInfo = new ContactInfo.PhoneInfo();
phoneInfo.type=type;
phoneInfo.number=phoneNumber;
phoneNumberList.add(phoneInfo);
}while(phonesCursor.moveToNext());
// 设置联系人电话信息
info.setPhoneList(phoneNumberList);
}
}
// 获得联系人的EMAIL
Cursor emailCur = context.getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID+"="+id, null, null);
if(emailCur.moveToFirst()){
List<ContactInfo.EmailInfo> emailList = new ArrayList<ContactInfo.EmailInfo>();
do{
// 遍历所有的email
String email = emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA1));
int type = emailCur.getInt(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));
// 初始化联系人邮箱信息
ContactInfo.EmailInfo emailInfo=new ContactInfo.EmailInfo();
emailInfo.type=type; // 设置邮箱类型
emailInfo.email=email; // 设置邮箱地址
emailList.add(emailInfo);
}while(emailCur.moveToNext());
info.setEmail(emailList);
}
//Cursor postalCursor = getContentResolver().query(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_URI, null, ContactsContract.CommonDataKinds.StructuredPostal.CONTACT_ID + "=" + id, null, null);
infoList.add(info);
}while(cur.moveToNext());
}
return infoList;
}
/**
* 备份联系人
*/
public void backupContacts(Activity context, List<ContactInfo> infos){
try {
String path = Environment.getExternalStorageDirectory() + "/contacts.vcf";
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(path),"UTF-8");
VCardComposer composer = new VCardComposer();
for (ContactInfo info : infos)
{
ContactStruct contact = new ContactStruct();
contact.name = info.getName();
// 获取联系人电话信息, 添加至 ContactStruct
List<ContactInfo.PhoneInfo> numberList = info
.getPhoneList();
for (ContactInfo.PhoneInfo phoneInfo : numberList)
{
contact.addPhone(phoneInfo.type, phoneInfo.number,
null, true);
}
// 获取联系人Email信息, 添加至 ContactStruct
List<ContactInfo.EmailInfo> emailList = info.getEmail();
for (ContactInfo.EmailInfo emailInfo : emailList)
{
contact.addContactmethod(Contacts.KIND_EMAIL,
emailInfo.type, emailInfo.email, null, true);
}
String vcardString = composer.createVCard(contact,
VCardComposer.VERSION_VCARD30_INT);
writer.write(vcardString);
writer.write("\n");
writer.flush();
}
writer.close();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (VCardException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(context, "备份成功!", Toast.LENGTH_SHORT).show();
}
/**
* 获取vCard文件中的联系人信息
* @return
*/
public List<ContactInfo> restoreContacts() throws Exception {
List<ContactInfo> contactInfoList = new ArrayList<ContactInfo>();
VCardParser parse = new VCardParser();
VDataBuilder builder = new VDataBuilder();
String file = Environment.getExternalStorageDirectory() + "/contacts.vcf";
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
String vcardString = "";
String line;
while((line = reader.readLine()) != null) {
vcardString += line + "\n";
}
reader.close();
boolean parsed = parse.parse(vcardString, "UTF-8", builder);
if(!parsed){
throw new VCardException("Could not parse vCard file: "+ file);
}
List<VNode> pimContacts = builder.vNodeList;
for (VNode contact : pimContacts) {
ContactStruct contactStruct=ContactStruct.constructContactFromVNode(contact, 1);
// 获取备份文件中的联系人电话信息
List<PhoneData> phoneDataList = contactStruct.phoneList;
List<ContactInfo.PhoneInfo> phoneInfoList = new ArrayList<ContactInfo.PhoneInfo>();
for(PhoneData phoneData : phoneDataList){
ContactInfo.PhoneInfo phoneInfo = new ContactInfo.PhoneInfo();
phoneInfo.number=phoneData.data;
phoneInfo.type=phoneData.type;
phoneInfoList.add(phoneInfo);
}
// 获取备份文件中的联系人邮箱信息
List<ContactMethod> emailList = contactStruct.contactmethodList;
List<ContactInfo.EmailInfo> emailInfoList = new ArrayList<ContactInfo.EmailInfo>();
// 存在 Email 信息
if (null!=emailList)
{
for (ContactMethod contactMethod : emailList)
{
if (Contacts.KIND_EMAIL == contactMethod.kind)
{
ContactInfo.EmailInfo emailInfo = new ContactInfo.EmailInfo();
emailInfo.email = contactMethod.data;
emailInfo.type = contactMethod.type;
emailInfoList.add(emailInfo);
}
}
}
ContactInfo info = new ContactInfo(contactStruct.name).setPhoneList(phoneInfoList).setEmail(emailInfoList);
contactInfoList.add(info);
}
return contactInfoList;
}
/**
* 向手机中录入联系人信息
* @param info 要录入的联系人信息
*/
public void addContacts(Activity context, ContactInfo info){
ContentValues values = new ContentValues();
//首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId
Uri rawContactUri = context.getContentResolver().insert(RawContacts.CONTENT_URI, values);
long rawContactId = ContentUris.parseId(rawContactUri);
//往data表入姓名数据
values.clear();
values.put(Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
values.put(StructuredName.GIVEN_NAME, info.getName());
context.getContentResolver().insert(
android.provider.ContactsContract.Data.CONTENT_URI, values);
// 获取联系人电话信息
List<ContactInfo.PhoneInfo> phoneList = info.getPhoneList();
/** 录入联系电话 */
for (ContactInfo.PhoneInfo phoneInfo : phoneList) {
values.clear();
values.put(android.provider.ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
// 设置录入联系人电话信息
values.put(Phone.NUMBER, phoneInfo.number);
values.put(Phone.TYPE, phoneInfo.type);
// 往data表入电话数据
context.getContentResolver().insert(
android.provider.ContactsContract.Data.CONTENT_URI, values);
}
// 获取联系人邮箱信息
List<ContactInfo.EmailInfo> emailList = info.getEmail();
/** 录入联系人邮箱信息 */
for (ContactInfo.EmailInfo email : emailList) {
values.clear();
values.put(android.provider.ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
// 设置录入的邮箱信息
values.put(Email.DATA, email.email);
values.put(Email.TYPE, email.type);
// 往data表入Email数据
context.getContentResolver().insert(
android.provider.ContactsContract.Data.CONTENT_URI, values);
}
}
}
}
// 获取联系人处理实例
ContactInfo.ContactHandler handler=ContactInfo.ContactHandler.getInstance();
switch (id) {
case R.id.save_linkman:
// 获取要备份的信息
List<ContactInfo> _infoList = handler.getContactInfo(this);
handler.backupContacts(this, _infoList); // 备份联系人信息
break;
case R.id.restore_linkman: // 恢复
try {
// 获取要恢复的联系人信息
List<ContactInfo> infoList = handler.restoreContacts();
for (ContactInfo contactInfo : infoList) {
// 恢复联系人
handler.addContacts(this, contactInfo);
}
Toast.makeText(this, "导入联系人信息成功!", Toast.LENGTH_LONG);
} catch (Exception e) {
Toast.makeText(this, "导入联系人信息失败!", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
break;
}
由于要对存储卡做读写操作,记得要加读写权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>