首先我们简单的看下在Android中联系人的存储结构.

工作环境:android 2.3.3
联系人的主要数据存放在raw_contacts和data表里,它两构成主从表关系。

raw_contacts表结构:

Android VCard联系人备份恢复(导入/导出)详解

data表结构:
Android VCard联系人备份恢复(导入/导出)详解
每个联系人在raw_contacts里有一条记录,像地址,名称,email,电话等等数据都在data存放在data里,这样设计的好处是易扩展,比如要增加一个联系人的email地址时,只要在data里增加一条记录。

下面说说我在开发工作中用到的一些联系人的数据。

名字:

Uri: Uri.parse("content://com.android.contacts/data")

PREFIX = "data4"; //名称前缀
MID_NAME = "data5";//中间名
GIVEN_NAME = "data2";//名字
FAMILY_NAME = "data3";//姓氏
MID_PINYIN="data8"; //中间名拼音
String FAMILY_NAME_PINYIN="data9"; //姓氏拼音
String SUFIX = "data6"; //名称后缀
String SUFIX_PINYIN="data7"; //名字拼音

电话:

Uri: Uri.parse("content://com.android.contacts/data/phones"

phone: "data1";//号码

Type: "data2";//这个字段是整形值,指示电话类型

类型对应关系如下:

TYPE_CUSTOM = 0;
TYPE_HOME = 1;
TYPE_MOBILE = 2;
TYPE_WORK = 3;
TYPE_FAX_WORK = 4;
TYPE_FAX_HOME = 5;
TYPE_PAGER = 6;
TYPE_OTHER = 7;

Email:

Uri:Uri.parse("content://com.android.contacts/data/emails")

Email: "data1";//邮箱地址

Type: "data2";//这个字段是整形值,指示Email类型

类型对应关系如下:

TYPE_CUSTOM = 0;
TYPE_HOME = 1;
TYPE_WORK = 2;
TYPE_OTHER = 3;
TYPE_MOBILE = 4;

地址:

Uri:Uri.parse("content://com.android.contacts/data/postals")

STREET="data4";//街道
CITY="data8";//城市
STATE="data7";//州
ZIP_CODE="data9";//邮政编码

Type:"data2";//type的类型如下

TYPE_CUSTOM = 0;
TYPE_HOME = 1;
TYPE_WORK = 2;
TYPE_OTHER = 3;

好的下面开始介绍VCard的导出和导入.

VCard规范 通俗点讲,就是让知道规范的人都能认识它.

在使用VCard时,我们需要下载VCard 的jar包

下载后里面会有2个Example {ReadExample.java / WriteExample.java} 。
但是凭借这两个Example,不足以让你更好的完成其他信息的备份和恢复,于是你要看下源码。

其中比较的2个类的源码如下.

Android VCard联系人备份恢复(导入/导出)详解 View Code
  1 /*  2  * Copyright (C) 2007 The Android Open Source Project  3  *  4  * Licensed under the Apache License, Version 2.0 (the "License");  5  * you may not use this file except in compliance with the License.  6  * You may obtain a copy of the License at  7  *  8  *      http://www.apache.org/licenses/LICENSE-2.0  9  * 10  * Unless required by applicable law or agreed to in writing, software 11  * distributed under the License is distributed on an "AS IS" BASIS, 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13  * See the License for the specific language governing permissions and 14  * limitations under the License. 15  */ 16  17 package a_vcard.android.syncml.pim.vcard; 18  19 //import android.content.AbstractSyncableContentProvider; 20 //import android.content.ContentResolver; 21 //import android.content.ContentUris; 22 //import android.content.ContentValues; 23 //import android.net.Uri; 24 import a_vcard.android.provider.Contacts; 25 import a_vcard.android.provider.Contacts.ContactMethods; 26 //import android.provider.Contacts.Extensions; 27 //import android.provider.Contacts.GroupMembership; 28 //import android.provider.Contacts.Organizations; 29 //import android.provider.Contacts.People; 30 import a_vcard.android.provider.Contacts.Phones; 31 //import android.provider.Contacts.Photos; 32 import a_vcard.android.syncml.pim.PropertyNode; 33 import a_vcard.android.syncml.pim.VNode; 34 import a_vcard.android.telephony.PhoneNumberUtils; 35 import a_vcard.android.text.TextUtils; 36 import a_vcard.android.util.Log; 37  38 import java.util.ArrayList; 39 import java.util.HashMap; 40 import java.util.Iterator; 41 import java.util.List; 42 import java.util.Locale; 43 import java.util.Map; 44 import java.util.Map.Entry; 45  46 /** 47  * The parameter class of VCardComposer. 48  * This class standy by the person-contact in 49  * Android system, we must use this class instance as parameter to transmit to 50  * VCardComposer so that create vCard string. 51  */ 52 // TODO: rename the class name, next step 53 public class ContactStruct { 54     private static final String LOG_TAG = "ContactStruct"; 55      56     // Note: phonetic name probably should be "LAST FIRST MIDDLE" for European languages, and 57     //       space should be added between each element while it should not be in Japanese. 58     //       But unfortunately, we currently do not have the data and are not sure whether we should 59     //       support European version of name ordering. 60     // 61     // TODO: Implement the logic described above if we really need European version of 62     //        phonetic name handling. Also, adding the appropriate test case of vCard would be 63     //        highly appreciated. 64     public static final int NAME_ORDER_TYPE_ENGLISH = 0; 65     public static final int NAME_ORDER_TYPE_JAPANESE = 1; 66  67     /** MUST exist */ 68     public String name; 69     public String phoneticName; 70     /** maybe folding */ 71     public List<String> notes = new ArrayList<String>(); 72     /** maybe folding */ 73     public String title; 74     /** binary bytes of pic. */ 75     public byte[] photoBytes; 76     /** The type of Photo (e.g. JPEG, BMP, etc.) */ 77     public String photoType; 78     /** Only for GET. Use addPhoneList() to PUT. */ 79     public List<PhoneData> phoneList; 80     /** Only for GET. Use addContactmethodList() to PUT. */ 81     public List<ContactMethod> contactmethodList; 82     /** Only for GET. Use addOrgList() to PUT. */ 83     public List<OrganizationData> organizationList; 84     /** Only for GET. Use addExtension() to PUT */ 85     public Map<String, List<String>> extensionMap; 86  87     // Use organizationList instead when handling ORG. 88     @Deprecated 89     public String company; 90      91     public static class PhoneData { 92         public int type; 93         /** maybe folding */ 94         public String data; 95         public String label; 96         public boolean isPrimary;  97     } 98  99     public static class ContactMethod {100         // Contacts.KIND_EMAIL, Contacts.KIND_POSTAL101         public int kind;102         // e.g. Contacts.ContactMethods.TYPE_HOME, Contacts.PhoneColumns.TYPE_HOME103         // If type == Contacts.PhoneColumns.TYPE_CUSTOM, label is used.104         public int type;105         public String data;106         // Used only when TYPE is TYPE_CUSTOM.107         public String label;108         public boolean isPrimary;109     }110     111     public static class OrganizationData {112         public int type;113         public String companyName;114         public String positionName;115         public boolean isPrimary;116     }117 118     /**119      * Add a phone info to phoneList.120      * @param data phone number121      * @param type type col of content://contacts/phones122      * @param label lable col of content://contacts/phones123      */124     public void addPhone(int type, String data, String label, boolean isPrimary){125         if (phoneList == null) {126             phoneList = new ArrayList<PhoneData>();127         }128         PhoneData phoneData = new PhoneData();129         phoneData.type = type;130         131         StringBuilder builder = new StringBuilder();132         String trimed = data.trim();133         int length = trimed.length();134         for (int i = 0; i < length; i++) {135             char ch = trimed.charAt(i);136             if (('0' <= ch && ch <= '9') || (i == 0 && ch == '+')) {137                 builder.append(ch);138             }139         }140         phoneData.data = PhoneNumberUtils.formatNumber(builder.toString());141         phoneData.label = label;142         phoneData.isPrimary = isPrimary;143         phoneList.add(phoneData);144     }145 146     /**147      * Add a contactmethod info to contactmethodList.148      * @param kind integer value defined in Contacts.java149      * (e.g. Contacts.KIND_EMAIL)150      * @param type type col of content://contacts/contact_methods151      * @param data contact data152      * @param label extra string used only when kind is Contacts.KIND_CUSTOM.153      */154     public void addContactmethod(int kind, int type, String data,155             String label, boolean isPrimary){156         if (contactmethodList == null) {157             contactmethodList = new ArrayList<ContactMethod>();158         }159         ContactMethod contactMethod = new ContactMethod();160         contactMethod.kind = kind;161         contactMethod.type = type;162         contactMethod.data = data;163         contactMethod.label = label;164         contactMethod.isPrimary = isPrimary;165         contactmethodList.add(contactMethod);166     }167     168     /**169      * Add a Organization info to organizationList.170      */171     public void addOrganization(int type, String companyName, String positionName,172             boolean isPrimary) {173         if (organizationList == null) {174             organizationList = new ArrayList<OrganizationData>();175         }176         OrganizationData organizationData = new OrganizationData();177         organizationData.type = type;178         organizationData.companyName = companyName;179         organizationData.positionName = positionName;180         organizationData.isPrimary = isPrimary;181         organizationList.add(organizationData);182     }183 184     /**185      * Set "position" value to the appropriate data. If there's more than one186      * OrganizationData objects, the value is set to the last one. If there's no187      * OrganizationData object, a new OrganizationData is created, whose company name is188      * empty.  189      * 190      * TODO: incomplete logic. fix this:191      * 192      * e.g. This assumes ORG comes earlier, but TITLE may come earlier like this, though we do not193      * know how to handle it in general cases...194      * ----195      * TITLE:Software Engineer196      * ORG:Google197      * ----198      */199     public void setPosition(String positionValue) {200         if (organizationList == null) {201             organizationList = new ArrayList<OrganizationData>();202         }203         int size = organizationList.size();204         if (size == 0) {205             addOrganization(Contacts.OrganizationColumns.TYPE_OTHER, "", null, false);206             size = 1;207         }208         OrganizationData lastData = organizationList.get(size - 1);209         lastData.positionName = positionValue;210     }211     212     public void addExtension(PropertyNode propertyNode) {213         if (propertyNode.propValue.length() == 0) {214             return;215         }216         // Now store the string into extensionMap.217         List<String> list;218         String name = propertyNode.propName;219         if (extensionMap == null) {220             extensionMap = new HashMap<String, List<String>>();221         }222         if (!extensionMap.containsKey(name)){223             list = new ArrayList<String>();224             extensionMap.put(name, list);225         } else {226             list = extensionMap.get(name);227         }        228         229         list.add(propertyNode.encode());230     }231     232     private static String getNameFromNProperty(List<String> elems, int nameOrderType) {233         // Family, Given, Middle, Prefix, Suffix. (1 - 5)234         int size = elems.size();235         if (size > 1) {236             StringBuilder builder = new StringBuilder();237             boolean builderIsEmpty = true;238             // Prefix239             if (size > 3 && elems.get(3).length() > 0) {240                 builder.append(elems.get(3));241                 builderIsEmpty = false;242             }243             String first, second;244             if (nameOrderType == NAME_ORDER_TYPE_JAPANESE) {245                 first = elems.get(0);246                 second = elems.get(1);247             } else {248                 first = elems.get(1);249                 second = elems.get(0);250             }251             if (first.length() > 0) {252                 if (!builderIsEmpty) {253                     builder.append(' ');254                 }255                 builder.append(first);256                 builderIsEmpty = false;257             }258             // Middle name259             if (size > 2 && elems.get(2).length() > 0) {260                 if (!builderIsEmpty) {261                     builder.append(' ');262                 }263                 builder.append(elems.get(2));264                 builderIsEmpty = false;265             }266             if (second.length() > 0) {267                 if (!builderIsEmpty) {268                     builder.append(' ');269                 }270                 builder.append(second);271                 builderIsEmpty = false;272             }273             // Suffix274             if (size > 4 && elems.get(4).length() > 0) {275                 if (!builderIsEmpty) {276                     builder.append(' ');277                 }278                 builder.append(elems.get(4));279                 builderIsEmpty = false;280             }281             return builder.toString();282         } else if (size == 1) {283             return elems.get(0);284         } else {285             return "";286         }287     }288     289     public static ContactStruct constructContactFromVNode(VNode node,290             int nameOrderType) {291         if (!node.VName.equals("VCARD")) {292             // Impossible in current implementation. Just for safety.293             Log.e(LOG_TAG, "Non VCARD data is inserted.");294             return null;295         }296 297         // For name, there are three fields in vCard: FN, N, NAME.298         // We prefer FN, which is a required field in vCard 3.0 , but not in vCard 2.1.299         // Next, we prefer NAME, which is defined only in vCard 3.0.300         // Finally, we use N, which is a little difficult to parse.301         String fullName = null;302         String nameFromNProperty = null;303 304         // Some vCard has "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", and305         // "X-PHONETIC-LAST-NAME"306         String xPhoneticFirstName = null;307         String xPhoneticMiddleName = null;308         String xPhoneticLastName = null;309         310         ContactStruct contact = new ContactStruct();311 312         // Each Column of four properties has ISPRIMARY field313         // (See android.provider.Contacts)314         // If false even after the following loop, we choose the first315         // entry as a "primary" entry.316         boolean prefIsSetAddress = false;317         boolean prefIsSetPhone = false;318         boolean prefIsSetEmail = false;319         boolean prefIsSetOrganization = false;320         321         for (PropertyNode propertyNode: node.propList) {322             String name = propertyNode.propName;323 324             if (TextUtils.isEmpty(propertyNode.propValue)) {325                 continue;326             }327             328             if (name.equals("VERSION")) {329                 // vCard version. Ignore this.330             } else if (name.equals("FN")) {331                 fullName = propertyNode.propValue;332             } else if (name.equals("NAME") && fullName == null) {333                 // Only in vCard 3.0. Use this if FN does not exist.334                 // Though, note that vCard 3.0 requires FN.335                 fullName = propertyNode.propValue;336             } else if (name.equals("N")) {337                 nameFromNProperty = getNameFromNProperty(propertyNode.propValue_vector,338                         nameOrderType);339             } else if (name.equals("SORT-STRING")) {340                 contact.phoneticName = propertyNode.propValue;341             } else if (name.equals("SOUND")) {342                 if (propertyNode.paramMap_TYPE.contains("X-IRMC-N") &&343                         contact.phoneticName == null) {344                     // Some Japanese mobile phones use this field for phonetic name,345                     // since vCard 2.1 does not have "SORT-STRING" type.346                     // Also, in some cases, the field has some ';' in it.347                     // We remove them.348                     StringBuilder builder = new StringBuilder();349                     String value = propertyNode.propValue;350                     int length = value.length();351                     for (int i = 0; i < length; i++) {352                         char ch = value.charAt(i);353                         if (ch != ';') {354                             builder.append(ch);355                         }356                     }357                     contact.phoneticName = builder.toString();358                 } else {359                     contact.addExtension(propertyNode);360                 }361             } else if (name.equals("ADR")) {362                 List<String> values = propertyNode.propValue_vector;363                 boolean valuesAreAllEmpty = true;364                 for (String value : values) {365                     if (value.length() > 0) {366                         valuesAreAllEmpty = false;367                         break;368                     }369                 }370                 if (valuesAreAllEmpty) {371                     continue;372                 }373 374                 int kind = Contacts.KIND_POSTAL;375                 int type = -1;376                 String label = "";377                 boolean isPrimary = false;378                 for (String typeString : propertyNode.paramMap_TYPE) {379                     if (typeString.equals("PREF") && !prefIsSetAddress) {380                         // Only first "PREF" is considered.381                         prefIsSetAddress = true;382                         isPrimary = true;383                     } else if (typeString.equalsIgnoreCase("HOME")) {384                         type = Contacts.ContactMethodsColumns.TYPE_HOME;385                         label = "";386                     } else if (typeString.equalsIgnoreCase("WORK") || 387                             typeString.equalsIgnoreCase("COMPANY")) {388                         // "COMPANY" seems emitted by Windows Mobile, which is not389                         // specifically supported by vCard 2.1. We assume this is same390                         // as "WORK".391                         type = Contacts.ContactMethodsColumns.TYPE_WORK;392                         label = "";393                     } else if (typeString.equalsIgnoreCase("POSTAL")) {394                         kind = Contacts.KIND_POSTAL;395                     } else if (typeString.equalsIgnoreCase("PARCEL") || 396                             typeString.equalsIgnoreCase("DOM") ||397                             typeString.equalsIgnoreCase("INTL")) {398                         // We do not have a kind or type matching these.399                         // TODO: fix this. We may need to split entries into two.400                         // (e.g. entries for KIND_POSTAL and KIND_PERCEL)401                     } else if (typeString.toUpperCase().startsWith("X-") &&402                             type < 0) {403                         type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;404                         label = typeString.substring(2);405                     } else if (type < 0) {406                         // vCard 3.0 allows iana-token. Also some vCard 2.1 exporters407                         // emit non-standard types. We do not handle their values now.408                         type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;409                         label = typeString;410                     }411                 }412                 // We use "HOME" as default413                 if (type < 0) {414                     type = Contacts.ContactMethodsColumns.TYPE_HOME;415                 }416                                 417                 // adr-value    = 0*6(text-value ";") text-value418                 //              ; PO Box, Extended Address, Street, Locality, Region, Postal419                 //              ; Code, Country Name420                 String address;421                 List<String> list = propertyNode.propValue_vector;422                 int size = list.size();423                 if (size > 1) {424                     StringBuilder builder = new StringBuilder();425                     boolean builderIsEmpty = true;426                     if (Locale.getDefault().getCountry().equals(Locale.JAPAN.getCountry())) {427                         // In Japan, the order is reversed.428                         for (int i = size - 1; i >= 0; i--) {429                             String addressPart = list.get(i);430                             if (addressPart.length() > 0) {431                                 if (!builderIsEmpty) {432                                     builder.append(' ');433                                 }434                                 builder.append(addressPart);435                                 builderIsEmpty = false;436                             }437                         }438                     } else {439                         for (int i = 0; i < size; i++) {440                             String addressPart = list.get(i);441                             if (addressPart.length() > 0) {442                                 if (!builderIsEmpty) {443                                     builder.append(' ');444                                 }445                                 builder.append(addressPart);446                                 builderIsEmpty = false;447                             }448                         }449                     }450                     address = builder.toString().trim();451                 } else {452                     address = propertyNode.propValue; 453                 }454                 contact.addContactmethod(kind, type, address, label, isPrimary);455             } else if (name.equals("ORG")) {456                 // vCard specification does not specify other types.457                 int type = Contacts.OrganizationColumns.TYPE_WORK;458                 boolean isPrimary = false;459                 460                 for (String typeString : propertyNode.paramMap_TYPE) {461                     if (typeString.equals("PREF") && !prefIsSetOrganization) {462                         // vCard specification officially does not have PREF in ORG.463                         // This is just for safety.464                         prefIsSetOrganization = true;465                         isPrimary = true;466                     }467                     // XXX: Should we cope with X- words?468                 }469 470                 List<String> list = propertyNode.propValue_vector; 471                 int size = list.size();472                 StringBuilder builder = new StringBuilder();473                 for (Iterator<String> iter = list.iterator(); iter.hasNext();) {474                     builder.append(iter.next());475                     if (iter.hasNext()) {476                         builder.append(' ');477                     }478                 }479 480                 contact.addOrganization(type, builder.toString(), "", isPrimary);481             } else if (name.equals("TITLE")) {482                 contact.setPosition(propertyNode.propValue);483             } else if (name.equals("ROLE")) {484                 contact.setPosition(propertyNode.propValue);485             } else if (name.equals("PHOTO")) {486                 // We prefer PHOTO to LOGO.487                 String valueType = propertyNode.paramMap.getAsString("VALUE");488                 if (valueType != null && valueType.equals("URL")) {489                     // TODO: do something.490                 } else {491                     // Assume PHOTO is stored in BASE64. In that case,492                     // data is already stored in propValue_bytes in binary form.493                     // It should be automatically done by VBuilder (VDataBuilder/VCardDatabuilder) 494                     contact.photoBytes = propertyNode.propValue_bytes;495                     String type = propertyNode.paramMap.getAsString("TYPE");496                     if (type != null) {497                         contact.photoType = type;498                     }499                 }500             } else if (name.equals("LOGO")) {501                 // When PHOTO is not available this is not URL,502                 // we use this instead of PHOTO.503                 String valueType = propertyNode.paramMap.getAsString("VALUE");504                 if (valueType != null && valueType.equals("URL")) {505                     // TODO: do something.506                 } else if (contact.photoBytes == null) {507                     contact.photoBytes = propertyNode.propValue_bytes;508                     String type = propertyNode.paramMap.getAsString("TYPE");509                     if (type != null) {510                         contact.photoType = type;511                     }512                 }513             } else if (name.equals("EMAIL")) {514                 int type = -1;515                 String label = null;516                 boolean isPrimary = false;517                 for (String typeString : propertyNode.paramMap_TYPE) {518                     if (typeString.equals("PREF") && !prefIsSetEmail) {519                         // Only first "PREF" is considered.520                         prefIsSetEmail = true;521                         isPrimary = true;522                     } else if (typeString.equalsIgnoreCase("HOME")) {523                         type = Contacts.ContactMethodsColumns.TYPE_HOME;524                     } else if (typeString.equalsIgnoreCase("WORK")) {525                         type = Contacts.ContactMethodsColumns.TYPE_WORK;526                     } else if (typeString.equalsIgnoreCase("CELL")) {527                         // We do not have Contacts.ContactMethodsColumns.TYPE_MOBILE yet.528                         type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;529                         label = Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME;530                     } else if (typeString.toUpperCase().startsWith("X-") &&531                             type < 0) {532                         type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;533                         label = typeString.substring(2);534                     } else if (type < 0) {535                         // vCard 3.0 allows iana-token.536                         // We may have INTERNET (specified in vCard spec),537                         // SCHOOL, etc.538                         type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;539                         label = typeString;540                     }541                 }542                 // We use "OTHER" as default.543                 if (type < 0) {544                     type = Contacts.ContactMethodsColumns.TYPE_OTHER;545                 }546                 contact.addContactmethod(Contacts.KIND_EMAIL,547                         type, propertyNode.propValue,label, isPrimary);548             } else if (name.equals("TEL")) {549                 int type = -1;550                 String label = null;551                 boolean isPrimary = false;552                 boolean isFax = false;553                 for (String typeString : propertyNode.paramMap_TYPE) {554                     if (typeString.equals("PREF") && !prefIsSetPhone) {555                         // Only first "PREF" is considered.556                         prefIsSetPhone = true;557                         isPrimary = true;558                     } else if (typeString.equalsIgnoreCase("HOME")) {559                         type = Contacts.PhonesColumns.TYPE_HOME;560                     } else if (typeString.equalsIgnoreCase("WORK")) {561                         type = Contacts.PhonesColumns.TYPE_WORK;562                     } else if (typeString.equalsIgnoreCase("CELL")) {563                         type = Contacts.PhonesColumns.TYPE_MOBILE;564                     } else if (typeString.equalsIgnoreCase("PAGER")) {565                         type = Contacts.PhonesColumns.TYPE_PAGER;566                     } else if (typeString.equalsIgnoreCase("FAX")) {567                         isFax = true;568                     } else if (typeString.equalsIgnoreCase("VOICE") ||569                             typeString.equalsIgnoreCase("MSG")) {570                         // Defined in vCard 3.0. Ignore these because they571                         // conflict with "HOME", "WORK", etc.572                         // XXX: do something?573                     } else if (typeString.toUpperCase().startsWith("X-") &&574                             type < 0) {575                         type = Contacts.PhonesColumns.TYPE_CUSTOM;576                         label = typeString.substring(2);577                     } else if (type < 0){578                         // We may have MODEM, CAR, ISDN, etc...579                         type = Contacts.PhonesColumns.TYPE_CUSTOM;580                         label = typeString;581                     }582                 }583                 // We use "HOME" as default584                 if (type < 0) {585                     type = Contacts.PhonesColumns.TYPE_HOME;586                 }587                 if (isFax) {588                     if (type == Contacts.PhonesColumns.TYPE_HOME) {589                         type = Contacts.PhonesColumns.TYPE_FAX_HOME; 590                     } else if (type == Contacts.PhonesColumns.TYPE_WORK) {591                         type = Contacts.PhonesColumns.TYPE_FAX_WORK; 592                     }593                 }594 595                 contact.addPhone(type, propertyNode.propValue, label, isPrimary);596             } else if (name.equals("NOTE")) {597                 contact.notes.add(propertyNode.propValue);598             } else if (name.equals("BDAY")) {599                 contact.addExtension(propertyNode);600             } else if (name.equals("URL")) {601                 contact.addExtension(propertyNode);602             } else if (name.equals("REV")) {                603                 // Revision of this VCard entry. I think we can ignore this.604                 contact.addExtension(propertyNode);605             } else if (name.equals("UID")) {606                 contact.addExtension(propertyNode);607             } else if (name.equals("KEY")) {608                 // Type is X509 or PGP? I don't know how to handle this...609                 contact.addExtension(propertyNode);610             } else if (name.equals("MAILER")) {611                 contact.addExtension(propertyNode);612             } else if (name.equals("TZ")) {613                 contact.addExtension(propertyNode);614             } else if (name.equals("GEO")) {615                 contact.addExtension(propertyNode);616             } else if (name.equals("NICKNAME")) {617                 // vCard 3.0 only.618                 contact.addExtension(propertyNode);619             } else if (name.equals("CLASS")) {620                 // vCard 3.0 only.621                 // e.g. CLASS:CONFIDENTIAL622                 contact.addExtension(propertyNode);623             } else if (name.equals("PROFILE")) {624                 // VCard 3.0 only. Must be "VCARD". I think we can ignore this.625                 contact.addExtension(propertyNode);626             } else if (name.equals("CATEGORIES")) {627                 // VCard 3.0 only.628                 // e.g. CATEGORIES:INTERNET,IETF,INDUSTRY,INFORMATION TECHNOLOGY629                 contact.addExtension(propertyNode);630             } else if (name.equals("SOURCE")) {631                 // VCard 3.0 only.632                 contact.addExtension(propertyNode);633             } else if (name.equals("PRODID")) {634                 // VCard 3.0 only.635                 // To specify the identifier for the product that created636                 // the vCard object.637                 contact.addExtension(propertyNode);638             } else if (name.equals("X-PHONETIC-FIRST-NAME")) {639                 xPhoneticFirstName = propertyNode.propValue;640             } else if (name.equals("X-PHONETIC-MIDDLE-NAME")) {641                 xPhoneticMiddleName = propertyNode.propValue;642             } else if (name.equals("X-PHONETIC-LAST-NAME")) {643                 xPhoneticLastName = propertyNode.propValue;644             } else {645                 // Unknown X- words and IANA token.646                 contact.addExtension(propertyNode);647             }648         }649 650         if (fullName != null) {651             contact.name = fullName;652         } else if(nameFromNProperty != null) {653             contact.name = nameFromNProperty;654         } else {655             contact.name = "";656         }657 658         if (contact.phoneticName == null &&659                 (xPhoneticFirstName != null || xPhoneticMiddleName != null ||660                         xPhoneticLastName != null)) {661             // Note: In Europe, this order should be "LAST FIRST MIDDLE". See the comment around662             //       NAME_ORDER_TYPE_* for more detail.663             String first;664             String second;665             if (nameOrderType == NAME_ORDER_TYPE_JAPANESE) {666                 first = xPhoneticLastName;667                 second = xPhoneticFirstName;668             } else {669                 first = xPhoneticFirstName;670                 second = xPhoneticLastName;671             }672             StringBuilder builder = new StringBuilder();673             if (first != null) {674                 builder.append(first);675             }676             if (xPhoneticMiddleName != null) {677                 builder.append(xPhoneticMiddleName);678             }679             if (second != null) {680                 builder.append(second);681             }682             contact.phoneticName = builder.toString();683         }684         685         // Remove unnecessary white spaces.686         // It is found that some mobile phone emits  phonetic name with just one white space687         // when a user does not specify one.688         // This logic is effective toward such kind of weird data.689         if (contact.phoneticName != null) {690             contact.phoneticName = contact.phoneticName.trim();691         }692 693         // If there is no "PREF", we choose the first entries as primary.694         if (!prefIsSetPhone &&695                 contact.phoneList != null && 696                 contact.phoneList.size() > 0) {697             contact.phoneList.get(0).isPrimary = true;698         }699 700         if (!prefIsSetAddress && contact.contactmethodList != null) {701             for (ContactMethod contactMethod : contact.contactmethodList) {702                 if (contactMethod.kind == Contacts.KIND_POSTAL) {703                     contactMethod.isPrimary = true;704                     break;705                 }706             }707         }708         if (!prefIsSetEmail && contact.contactmethodList != null) {709             for (ContactMethod contactMethod : contact.contactmethodList) {710                 if (contactMethod.kind == Contacts.KIND_EMAIL) {711                     contactMethod.isPrimary = true;712                     break;713                 }714             }715         }716         if (!prefIsSetOrganization &&717                 contact.organizationList != null &&718                 contact.organizationList.size() > 0) {719             contact.organizationList.get(0).isPrimary = true;720         }721         722         return contact;723     }724     725     public String displayString() {726         if (name.length() > 0) {727             return name;728         }729         if (contactmethodList != null && contactmethodList.size() > 0) {730             for (ContactMethod contactMethod : contactmethodList) {731                 if (contactMethod.kind == Contacts.KIND_EMAIL && contactMethod.isPrimary) {732                     return contactMethod.data;733                 }734             }735         }736         if (phoneList != null && phoneList.size() > 0) {737             for (PhoneData phoneData : phoneList) {738                 if (phoneData.isPrimary) {739                     return phoneData.data;740                 }741             }742         }743         return "";744     }745     746 //    private void pushIntoContentProviderOrResolver(Object contentSomething,747 //            long myContactsGroupId) {748 //        ContentResolver resolver = null;749 //        AbstractSyncableContentProvider provider = null;750 //        if (contentSomething instanceof ContentResolver) {751 //            resolver = (ContentResolver)contentSomething;752 //        } else if (contentSomething instanceof AbstractSyncableContentProvider) {753 //            provider = (AbstractSyncableContentProvider)contentSomething;754 //        } else {755 //            Log.e(LOG_TAG, "Unsupported object came.");756 //            return;757 //        }758 //759 //        ContentValues contentValues = new ContentValues();760 //        contentValues.put(People.NAME, name);761 //        contentValues.put(People.PHONETIC_NAME, phoneticName);762 //763 //        if (notes.size() > 1) {764 //            StringBuilder builder = new StringBuilder();765 //            for (String note : notes) {766 //                builder.append(note);767 //                builder.append("\n");768 //            }769 //            contentValues.put(People.NOTES, builder.toString());770 //        } else if (notes.size() == 1){771 //            contentValues.put(People.NOTES, notes.get(0));772 //        }773 //774 //        Uri personUri;775 //        long personId = 0;776 //        if (resolver != null) {777 //            personUri = Contacts.People.createPersonInMyContactsGroup(778 //                    resolver, contentValues);779 //            if (personUri != null) {780 //                personId = ContentUris.parseId(personUri);781 //            }782 //        } else {783 //            personUri = provider.nonTransactionalInsert(People.CONTENT_URI, contentValues);784 //            if (personUri != null) {785 //                personId = ContentUris.parseId(personUri);786 //                ContentValues values = new ContentValues();787 //                values.put(GroupMembership.PERSON_ID, personId);788 //                values.put(GroupMembership.GROUP_ID, myContactsGroupId);789 //                Uri resultUri = provider.nonTransactionalInsert(790 //                        GroupMembership.CONTENT_URI, values);791 //                if (resultUri == null) {792 //                    Log.e(LOG_TAG, "Faild to insert the person to MyContact.");793 //                    provider.nonTransactionalDelete(personUri, null, null);794 //                    personUri = null;795 //                }796 //            }797 //        }798 //799 //        if (personUri == null) {800 //            Log.e(LOG_TAG, "Failed to create the contact.");801 //            return;802 //        }803 //804 //        if (photoBytes != null) {805 //            if (resolver != null) {806 //                People.setPhotoData(resolver, personUri, photoBytes);807 //            } else {808 //                Uri photoUri = Uri.withAppendedPath(personUri, Contacts.Photos.CONTENT_DIRECTORY);809 //                ContentValues values = new ContentValues();810 //                values.put(Photos.DATA, photoBytes);811 //                provider.update(photoUri, values, null, null);812 //            }813 //        }814 //815 //        long primaryPhoneId = -1;816 //        if (phoneList != null && phoneList.size() > 0) {817 //            for (PhoneData phoneData : phoneList) {818 //                ContentValues values = new ContentValues();819 //                values.put(Contacts.PhonesColumns.TYPE, phoneData.type);820 //                if (phoneData.type == Contacts.PhonesColumns.TYPE_CUSTOM) {821 //                    values.put(Contacts.PhonesColumns.LABEL, phoneData.label);822 //                }823 //                // Already formatted.824 //                values.put(Contacts.PhonesColumns.NUMBER, phoneData.data);825 //826 //                // Not sure about Contacts.PhonesColumns.NUMBER_KEY ...827 //                values.put(Contacts.PhonesColumns.ISPRIMARY, 1);828 //                values.put(Contacts.Phones.PERSON_ID, personId);829 //                Uri phoneUri;830 //                if (resolver != null) {831 //                    phoneUri = resolver.insert(Phones.CONTENT_URI, values);832 //                } else {833 //                    phoneUri = provider.nonTransactionalInsert(Phones.CONTENT_URI, values);834 //                }835 //                if (phoneData.isPrimary) {836 //                    primaryPhoneId = Long.parseLong(phoneUri.getLastPathSegment());837 //                }838 //            }839 //        }840 //841 //        long primaryOrganizationId = -1;842 //        if (organizationList != null && organizationList.size() > 0) {843 //            for (OrganizationData organizationData : organizationList) {844 //                ContentValues values = new ContentValues();845 //                // Currently, we do not use TYPE_CUSTOM.846 //                values.put(Contacts.OrganizationColumns.TYPE,847 //                        organizationData.type);848 //                values.put(Contacts.OrganizationColumns.COMPANY,849 //                        organizationData.companyName);850 //                values.put(Contacts.OrganizationColumns.TITLE,851 //                        organizationData.positionName);852 //                values.put(Contacts.OrganizationColumns.ISPRIMARY, 1);853 //                values.put(Contacts.OrganizationColumns.PERSON_ID, personId);854 //855 //                Uri organizationUri;856 //                if (resolver != null) {857 //                    organizationUri = resolver.insert(Organizations.CONTENT_URI, values);858 //                } else {859 //                    organizationUri = provider.nonTransactionalInsert(860 //                            Organizations.CONTENT_URI, values);861 //                }862 //                if (organizationData.isPrimary) {863 //                    primaryOrganizationId = Long.parseLong(organizationUri.getLastPathSegment());864 //                }865 //            }866 //        }867 //868 //        long primaryEmailId = -1;869 //        if (contactmethodList != null && contactmethodList.size() > 0) {870 //            for (ContactMethod contactMethod : contactmethodList) {871 //                ContentValues values = new ContentValues();872 //                values.put(Contacts.ContactMethodsColumns.KIND, contactMethod.kind);873 //                values.put(Contacts.ContactMethodsColumns.TYPE, contactMethod.type);874 //                if (contactMethod.type == Contacts.ContactMethodsColumns.TYPE_CUSTOM) {875 //                    values.put(Contacts.ContactMethodsColumns.LABEL, contactMethod.label);876 //                }877 //                values.put(Contacts.ContactMethodsColumns.DATA, contactMethod.data);878 //                values.put(Contacts.ContactMethodsColumns.ISPRIMARY, 1);879 //                values.put(Contacts.ContactMethods.PERSON_ID, personId);880 //881 //                if (contactMethod.kind == Contacts.KIND_EMAIL) {882 //                    Uri emailUri;883 //                    if (resolver != null) {884 //                        emailUri = resolver.insert(ContactMethods.CONTENT_URI, values);885 //                    } else {886 //                        emailUri = provider.nonTransactionalInsert(887 //                                ContactMethods.CONTENT_URI, values);888 //                    }889 //                    if (contactMethod.isPrimary) {890 //                        primaryEmailId = Long.parseLong(emailUri.getLastPathSegment());891 //                    }892 //                } else {  // probably KIND_POSTAL893 //                    if (resolver != null) {894 //                        resolver.insert(ContactMethods.CONTENT_URI, values);895 //                    } else {896 //                        provider.nonTransactionalInsert(897 //                                ContactMethods.CONTENT_URI, values);898 //                    }899 //                }900 //            }901 //        }902 //903 //        if (extensionMap != null && extensionMap.size() > 0) {904 //            ArrayList<ContentValues> contentValuesArray;905 //            if (resolver != null) {906 //                contentValuesArray = new ArrayList<ContentValues>();907 //            } else {908 //                contentValuesArray = null;909 //            }910 //            for (Entry<String, List<String>> entry : extensionMap.entrySet()) {911 //                String key = entry.getKey();912 //                List<String> list = entry.getValue();913 //                for (String value : list) {914 //                    ContentValues values = new ContentValues();915 //                    values.put(Extensions.NAME, key);916 //                    values.put(Extensions.VALUE, value);917 //                    values.put(Extensions.PERSON_ID, personId);918 //                    if (resolver != null) {919 //                        contentValuesArray.add(values);920 //                    } else {921 //                        provider.nonTransactionalInsert(Extensions.CONTENT_URI, values);922 //                    }923 //                }924 //            }925 //            if (resolver != null) {926 //                resolver.bulkInsert(Extensions.CONTENT_URI,927 //                        contentValuesArray.toArray(new ContentValues[0]));928 //            }929 //        }930 //931 //        if (primaryPhoneId >= 0 || primaryOrganizationId >= 0 || primaryEmailId >= 0) {932 //            ContentValues values = new ContentValues();933 //            if (primaryPhoneId >= 0) {934 //                values.put(People.PRIMARY_PHONE_ID, primaryPhoneId);935 //            }936 //            if (primaryOrganizationId >= 0) {937 //                values.put(People.PRIMARY_ORGANIZATION_ID, primaryOrganizationId);938 //            }939 //            if (primaryEmailId >= 0) {940 //                values.put(People.PRIMARY_EMAIL_ID, primaryEmailId);941 //            }942 //            if (resolver != null) {943 //                resolver.update(personUri, values, null, null);944 //            } else {945 //                provider.nonTransactionalUpdate(personUri, values, null, null);946 //            }947 //        }948 //    }949 //950 //    /**951 //     * Push this object into database in the resolver.952 //     */953 //    public void pushIntoContentResolver(ContentResolver resolver) {954 //        pushIntoContentProviderOrResolver(resolver, 0);955 //    }956 //957 //    /**958 //     * Push this object into AbstractSyncableContentProvider object.959 //     */960 //    public void pushIntoAbstractSyncableContentProvider(961 //            AbstractSyncableContentProvider provider, long myContactsGroupId) {962 //        boolean successful = false;963 //        provider.beginTransaction();964 //        try {965 //            pushIntoContentProviderOrResolver(provider, myContactsGroupId);966 //            successful = true;967 //        } finally {968 //            provider.endTransaction(successful);969 //        }970 //    }971     972     public boolean isIgnorable() {973         return TextUtils.isEmpty(name) &&974                 TextUtils.isEmpty(phoneticName) &&975                 (phoneList == null || phoneList.size() == 0) &&976                 (contactmethodList == null || contactmethodList.size() == 0);977     }978 }
Android VCard联系人备份恢复(导入/导出)详解 View Code
   1 /*   2  * Copyright (C) 2006 The Android Open Source Project   3  *   4  * Licensed under the Apache License, Version 2.0 (the "License");   5  * you may not use this file except in compliance with the License.   6  * You may obtain a copy of the License at   7  *   8  *      http://www.apache.org/licenses/LICENSE-2.0   9  *  10  * Unless required by applicable law or agreed to in writing, software  11  * distributed under the License is distributed on an "AS IS" BASIS,  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  13  * See the License for the specific language governing permissions and  14  * limitations under the License.  15  */  16   17 package a_vcard.android.provider;  18   19 //import com.android.internal.R;  20   21 //import android.content.ContentResolver;  22 //import android.content.ContentUris;  23 //import android.content.ContentValues;  24 //import android.content.Context;  25 //import android.content.Intent;  26 //import android.database.Cursor;  27 //import android.graphics.Bitmap;  28 //import android.graphics.BitmapFactory;  29 //import android.net.Uri;  30 //import android.text.TextUtils;  31 //import android.util.Log;  32 //import android.widget.ImageView;  33   34 //import java.io.ByteArrayInputStream;  35 //import java.io.InputStream;  36   37 /**  38  * The Contacts provider stores all information about contacts.  39  */  40 public class Contacts {  41     private static final String TAG = "Contacts";  42       43     public static final String AUTHORITY = "contacts";  44   45 //    /**  46 //     * The content:// style URL for this provider  47 //     */  48 //    public static final Uri CONTENT_URI =  49 //        Uri.parse("content://" + AUTHORITY);  50   51     /** Signifies an email address row that is stored in the ContactMethods table */  52     public static final int KIND_EMAIL = 1;  53     /** Signifies a postal address row that is stored in the ContactMethods table */  54     public static final int KIND_POSTAL = 2;  55     /** Signifies an IM address row that is stored in the ContactMethods table */  56     public static final int KIND_IM = 3;  57     /** Signifies an Organization row that is stored in the Organizations table */  58     public static final int KIND_ORGANIZATION = 4;  59     /** Signifies an Phone row that is stored in the Phones table */  60     public static final int KIND_PHONE = 5;  61   62     /**  63      * no public constructor since this is a utility class  64      */  65     private Contacts() {}  66   67 //    /**  68 //     * Columns from the Settings table that other columns join into themselves.  69 //     */  70 //    public interface SettingsColumns {  71 //        /**  72 //         * The _SYNC_ACCOUNT to which this setting corresponds. This may be null.  73 //         * <P>Type: TEXT</P>  74 //         */  75 //        public static final String _SYNC_ACCOUNT = "_sync_account";  76 //  77 //        /**  78 //         * The key of this setting.  79 //         * <P>Type: TEXT</P>  80 //         */  81 //        public static final String KEY = "key";  82 //  83 //        /**  84 //         * The value of this setting.  85 //         * <P>Type: TEXT</P>  86 //         */  87 //        public static final String VALUE = "value";  88 //    }  89 //  90 //    /**  91 //     * The settings over all of the people  92 //     */  93 //    public static final class Settings implements BaseColumns, SettingsColumns {  94 //        /**  95 //         * no public constructor since this is a utility class  96 //         */  97 //        private Settings() {}  98 //  99 //        /** 100 //         * The content:// style URL for this table 101 //         */ 102 //        public static final Uri CONTENT_URI = 103 //            Uri.parse("content://contacts/settings"); 104 // 105 //        /** 106 //         * The directory twig for this sub-table 107 //         */ 108 //        public static final String CONTENT_DIRECTORY = "settings"; 109 // 110 //        /** 111 //         * The default sort order for this table 112 //         */ 113 //        public static final String DEFAULT_SORT_ORDER = "key ASC"; 114 // 115 //        /** 116 //         * A setting that is used to indicate if we should sync down all groups for the 117 //         * specified account. For this setting the _SYNC_ACCOUNT column must be set. 118 //         * If this isn't set then we will only sync the groups whose SHOULD_SYNC column 119 //         * is set to true. 120 //         * <p> 121 //         * This is a boolean setting. It is true if it is set and it is anything other than the 122 //         * emptry string or "0". 123 //         */ 124 //        public static final String SYNC_EVERYTHING = "syncEverything"; 125 // 126 //        public static String getSetting(ContentResolver cr, String account, String key) { 127 //            // For now we only support a single account and the UI doesn't know what 128 //            // the account name is, so we're using a global setting for SYNC_EVERYTHING. 129 //            // Some day when we add multiple accounts to the UI this should honor the account 130 //            // that was asked for. 131 //            String selectString; 132 //            String[] selectArgs; 133 //            if (false) { 134 //                selectString = (account == null) 135 //                        ? "_sync_account is null AND key=?" 136 //                        : "_sync_account=? AND key=?"; 137 //                selectArgs = (account == null) 138 //                ? new String[]{key} 139 //                : new String[]{account, key}; 140 //            } else { 141 //                selectString = "key=?"; 142 //                selectArgs = new String[] {key}; 143 //            } 144 //            Cursor cursor = cr.query(Settings.CONTENT_URI, new String[]{VALUE}, 145 //                    selectString, selectArgs, null); 146 //            try { 147 //                if (!cursor.moveToNext()) return null; 148 //                return cursor.getString(0); 149 //            } finally { 150 //                cursor.close(); 151 //            } 152 //        } 153 // 154 //        public static void setSetting(ContentResolver cr, String account, String key, 155 //                String value) { 156 //            ContentValues values = new ContentValues(); 157 //            // For now we only support a single account and the UI doesn't know what 158 //            // the account name is, so we're using a global setting for SYNC_EVERYTHING. 159 //            // Some day when we add multiple accounts to the UI this should honor the account 160 //            // that was asked for. 161 //            //values.put(_SYNC_ACCOUNT, account); 162 //            values.put(KEY, key); 163 //            values.put(VALUE, value); 164 //            cr.update(Settings.CONTENT_URI, values, null, null); 165 //        } 166 //    } 167 // 168     /** 169      * Columns from the People table that other tables join into themselves. 170      */ 171     public interface PeopleColumns { 172         /** 173          * The person's name. 174          * <P>Type: TEXT</P> 175          */ 176         public static final String NAME = "name"; 177  178         /** 179          * Phonetic equivalent of the person's name, in a locale-dependent 180          * character set (e.g. hiragana for Japanese). 181          * Used for pronunciation and/or collation in some languages. 182          * <p>Type: TEXT</P> 183          */ 184         public static final String PHONETIC_NAME = "phonetic_name"; 185          186         /** 187          * The display name. If name is not null name, else if number is not null number, 188          * else if email is not null email. 189          * <P>Type: TEXT</P> 190          */ 191         public static final String DISPLAY_NAME = "display_name"; 192  193         /** 194          * The field for sorting list phonetically. The content of this field 195          * may not be human readable but phonetically sortable. 196          * <P>Type: TEXT</p> 197          * @hide Used only in Contacts application for now. 198          */ 199         public static final String SORT_STRING = "sort_string"; 200          201         /** 202          * Notes about the person. 203          * <P>Type: TEXT</P> 204          */ 205         public static final String NOTES = "notes"; 206  207         /** 208          * The number of times a person has been contacted 209          * <P>Type: INTEGER</P> 210          */ 211         public static final String TIMES_CONTACTED = "times_contacted"; 212  213         /** 214          * The last time a person was contacted. 215          * <P>Type: INTEGER</P> 216          */ 217         public static final String LAST_TIME_CONTACTED = "last_time_contacted"; 218  219         /** 220          * A custom ringtone associated with a person. Not always present. 221          * <P>Type: TEXT (URI to the ringtone)</P> 222          */ 223         public static final String CUSTOM_RINGTONE = "custom_ringtone"; 224  225         /** 226          * Whether the person should always be sent to voicemail. Not always 227          * present. 228          * <P>Type: INTEGER (0 for false, 1 for true)</P> 229          */ 230         public static final String SEND_TO_VOICEMAIL = "send_to_voicemail"; 231  232         /** 233          * Is the contact starred? 234          * <P>Type: INTEGER (boolean)</P> 235          */ 236         public static final String STARRED = "starred"; 237  238         /** 239          * The server version of the photo 240          * <P>Type: TEXT (the version number portion of the photo URI)</P> 241          */ 242         public static final String PHOTO_VERSION = "photo_version";        243     } 244 // 245 //    /** 246 //     * This table contains people. 247 //     */ 248 //    public static final class People implements BaseColumns, SyncConstValue, PeopleColumns, 249 //            PhonesColumns, PresenceColumns { 250 //        /** 251 //         * no public constructor since this is a utility class 252 //         */ 253 //        private People() {} 254 // 255 //        /** 256 //         * The content:// style URL for this table 257 //         */ 258 //        public static final Uri CONTENT_URI = 259 //            Uri.parse("content://contacts/people"); 260 // 261 //        /** 262 //         * The content:// style URL for filtering people by name. The filter 263 //         * argument should be passed as an additional path segment after this URI. 264 //         */ 265 //        public static final Uri CONTENT_FILTER_URI = 266 //            Uri.parse("content://contacts/people/filter"); 267 // 268 //        /** 269 //         * The content:// style URL for the table that holds the deleted 270 //         * contacts. 271 //         */ 272 //        public static final Uri DELETED_CONTENT_URI = 273 //            Uri.parse("content://contacts/deleted_people"); 274 // 275 //        /** 276 //         * The content:// style URL for filtering people that have a specific 277 //         * E-mail or IM address. The filter argument should be passed as an 278 //         * additional path segment after this URI. This matches any people with 279 //         * at least one E-mail or IM {@link ContactMethods} that match the 280 //         * filter. 281 //         * 282 //         * Not exposed because we expect significant changes in the contacts 283 //         * schema and do not want to have to support this. 284 //         * @hide 285 //         */ 286 //        public static final Uri WITH_EMAIL_OR_IM_FILTER_URI = 287 //            Uri.parse("content://contacts/people/with_email_or_im_filter"); 288 // 289 //        /** 290 //         * The MIME type of {@link #CONTENT_URI} providing a directory of 291 //         * people. 292 //         */ 293 //        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person"; 294 // 295 //        /** 296 //         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single 297 //         * person. 298 //         */ 299 //        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person"; 300 // 301 //        /** 302 //         * The default sort order for this table 303 //         */ 304 //        public static final String DEFAULT_SORT_ORDER = People.NAME + " ASC"; 305 // 306 //        /** 307 //         * The ID of the persons preferred phone number. 308 //         * <P>Type: INTEGER (foreign key to phones table on the _ID field)</P> 309 //         */ 310 //        public static final String PRIMARY_PHONE_ID = "primary_phone"; 311 // 312 //        /** 313 //         * The ID of the persons preferred email. 314 //         * <P>Type: INTEGER (foreign key to contact_methods table on the 315 //         * _ID field)</P> 316 //         */ 317 //        public static final String PRIMARY_EMAIL_ID = "primary_email"; 318 // 319 //        /** 320 //         * The ID of the persons preferred organization. 321 //         * <P>Type: INTEGER (foreign key to organizations table on the 322 //         * _ID field)</P> 323 //         */ 324 //        public static final String PRIMARY_ORGANIZATION_ID = "primary_organization"; 325 // 326 //        /** 327 //         * Mark a person as having been contacted. 328 //         * 329 //         * @param resolver the ContentResolver to use 330 //         * @param personId the person who was contacted 331 //         */ 332 //        public static void markAsContacted(ContentResolver resolver, long personId) { 333 //            Uri uri = ContentUris.withAppendedId(CONTENT_URI, personId); 334 //            uri = Uri.withAppendedPath(uri, "update_contact_time"); 335 //            ContentValues values = new ContentValues(); 336 //            // There is a trigger in place that will update TIMES_CONTACTED when 337 //            // LAST_TIME_CONTACTED is modified. 338 //            values.put(LAST_TIME_CONTACTED, System.currentTimeMillis()); 339 //            resolver.update(uri, values, null, null); 340 //        } 341 // 342 //        /** 343 //         * @hide Used in vCard parser code. 344 //         */ 345 //        public static long tryGetMyContactsGroupId(ContentResolver resolver) { 346 //            Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION, 347 //                    Groups.SYSTEM_ID + "='" + Groups.GROUP_MY_CONTACTS + "'", null, null); 348 //            if (groupsCursor != null) { 349 //                try { 350 //                    if (groupsCursor.moveToFirst()) { 351 //                        return groupsCursor.getLong(0); 352 //                    } 353 //                } finally { 354 //                    groupsCursor.close(); 355 //                } 356 //            } 357 //            return 0; 358 //        } 359 // 360 //        /** 361 //         * Adds a person to the My Contacts group. 362 //         * 363 //         * @param resolver the resolver to use 364 //         * @param personId the person to add to the group 365 //         * @return the URI of the group membership row 366 //         * @throws IllegalStateException if the My Contacts group can't be found 367 //         */ 368 //        public static Uri addToMyContactsGroup(ContentResolver resolver, long personId) { 369 //            long groupId = tryGetMyContactsGroupId(resolver); 370 //            if (groupId == 0) { 371 //                throw new IllegalStateException("Failed to find the My Contacts group"); 372 //            } 373 // 374 //            return addToGroup(resolver, personId, groupId); 375 //        } 376 // 377 //        /** 378 //         * Adds a person to a group referred to by name. 379 //         * 380 //         * @param resolver the resolver to use 381 //         * @param personId the person to add to the group 382 //         * @param groupName the name of the group to add the contact to 383 //         * @return the URI of the group membership row 384 //         * @throws IllegalStateException if the group can't be found 385 //         */ 386 //        public static Uri addToGroup(ContentResolver resolver, long personId, String groupName) { 387 //            long groupId = 0; 388 //            Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION, 389 //                    Groups.NAME + "=?", new String[] { groupName }, null); 390 //            if (groupsCursor != null) { 391 //                try { 392 //                    if (groupsCursor.moveToFirst()) { 393 //                        groupId = groupsCursor.getLong(0); 394 //                    } 395 //                } finally { 396 //                    groupsCursor.close(); 397 //                } 398 //            } 399 // 400 //            if (groupId == 0) { 401 //                throw new IllegalStateException("Failed to find the My Contacts group"); 402 //            } 403 // 404 //            return addToGroup(resolver, personId, groupId); 405 //        } 406 // 407 //        /** 408 //         * Adds a person to a group. 409 //         * 410 //         * @param resolver the resolver to use 411 //         * @param personId the person to add to the group 412 //         * @param groupId the group to add the person to 413 //         * @return the URI of the group membership row 414 //         */ 415 //        public static Uri addToGroup(ContentResolver resolver, long personId, long groupId) { 416 //            ContentValues values = new ContentValues(); 417 //            values.put(GroupMembership.PERSON_ID, personId); 418 //            values.put(GroupMembership.GROUP_ID, groupId); 419 //            return resolver.insert(GroupMembership.CONTENT_URI, values); 420 //        } 421 // 422 //        private static final String[] GROUPS_PROJECTION = new String[] { 423 //            Groups._ID, 424 //        }; 425 // 426 //        /** 427 //         * Creates a new contacts and adds it to the "My Contacts" group. 428 //         * 429 //         * @param resolver the ContentResolver to use 430 //         * @param values the values to use when creating the contact 431 //         * @return the URI of the contact, or null if the operation fails 432 //         */ 433 //        public static Uri createPersonInMyContactsGroup(ContentResolver resolver, 434 //                ContentValues values) { 435 // 436 //            Uri contactUri = resolver.insert(People.CONTENT_URI, values); 437 //            if (contactUri == null) { 438 //                Log.e(TAG, "Failed to create the contact"); 439 //                return null; 440 //            } 441 // 442 //            if (addToMyContactsGroup(resolver, ContentUris.parseId(contactUri)) == null) { 443 //                resolver.delete(contactUri, null, null); 444 //                return null; 445 //            } 446 //            return contactUri; 447 //        } 448 // 449 //        public static Cursor queryGroups(ContentResolver resolver, long person) { 450 //            return resolver.query(GroupMembership.CONTENT_URI, null, "person=?", 451 //                    new String[]{String.valueOf(person)}, Groups.DEFAULT_SORT_ORDER); 452 //        } 453 // 454 //        /** 455 //         * Set the photo for this person. data may be null 456 //         * @param cr the ContentResolver to use 457 //         * @param person the Uri of the person whose photo is to be updated 458 //         * @param data the byte[] that represents the photo 459 //         */ 460 //        public static void setPhotoData(ContentResolver cr, Uri person, byte[] data) { 461 //            Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY); 462 //            ContentValues values = new ContentValues(); 463 //            values.put(Photos.DATA, data); 464 //            cr.update(photoUri, values, null, null); 465 //        } 466 // 467 //        /** 468 //         * Opens an InputStream for the person's photo and returns the photo as a Bitmap. 469 //         * If the person's photo isn't present returns the placeholderImageResource instead. 470 //         * @param person the person whose photo should be used 471 //         */ 472 //        public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri person) { 473 //            Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY); 474 //            Cursor cursor = cr.query(photoUri, new String[]{Photos.DATA}, null, null, null); 475 //            try { 476 //                if (!cursor.moveToNext()) { 477 //                    return null; 478 //                } 479 //                byte[] data = cursor.getBlob(0); 480 //                if (data == null) { 481 //                    return null; 482 //                } 483 //                return new ByteArrayInputStream(data); 484 //            } finally { 485 //                cursor.close(); 486 //            } 487 //        } 488 // 489 //        /** 490 //         * Opens an InputStream for the person's photo and returns the photo as a Bitmap. 491 //         * If the person's photo isn't present returns the placeholderImageResource instead. 492 //         * @param context the Context 493 //         * @param person the person whose photo should be used 494 //         * @param placeholderImageResource the image resource to use if the person doesn't 495 //         *   have a photo 496 //         * @param options the decoding options, can be set to null 497 //         */ 498 //        public static Bitmap loadContactPhoto(Context context, Uri person, 499 //                int placeholderImageResource, BitmapFactory.Options options) { 500 //            if (person == null) { 501 //                return loadPlaceholderPhoto(placeholderImageResource, context, options); 502 //            } 503 // 504 //            InputStream stream = openContactPhotoInputStream(context.getContentResolver(), person); 505 //            Bitmap bm = stream != null ? BitmapFactory.decodeStream(stream, null, options) : null; 506 //            if (bm == null) { 507 //                bm = loadPlaceholderPhoto(placeholderImageResource, context, options); 508 //            } 509 //            return bm; 510 //        } 511 // 512 //        private static Bitmap loadPlaceholderPhoto(int placeholderImageResource, Context context, 513 //                BitmapFactory.Options options) { 514 //            if (placeholderImageResource == 0) { 515 //                return null; 516 //            } 517 //            return BitmapFactory.decodeResource(context.getResources(), 518 //                    placeholderImageResource, options); 519 //        } 520  521         /** 522          * A sub directory of a single person that contains all of their Phones. 523          */ 524         public static final class Phones implements BaseColumns, PhonesColumns, 525                 PeopleColumns { 526             /** 527              * no public constructor since this is a utility class 528              */ 529             private Phones() {} 530  531             /** 532              * The directory twig for this sub-table 533              */ 534             public static final String CONTENT_DIRECTORY = "phones"; 535  536             /** 537              * The default sort order for this table 538              */ 539             public static final String DEFAULT_SORT_ORDER = "number ASC"; 540         } 541  542         /** 543          * A subdirectory of a single person that contains all of their 544          * ContactMethods. 545          */ 546         public static final class ContactMethods 547                 implements BaseColumns, ContactMethodsColumns, PeopleColumns { 548             /** 549              * no public constructor since this is a utility class 550              */ 551             private ContactMethods() {} 552  553             /** 554              * The directory twig for this sub-table 555              */ 556             public static final String CONTENT_DIRECTORY = "contact_methods"; 557  558             /** 559              * The default sort order for this table 560              */ 561             public static final String DEFAULT_SORT_ORDER = "data ASC"; 562         } 563  564 //        /** 565 //         * The extensions for a person 566 //         */ 567 //        public static class Extensions implements BaseColumns, ExtensionsColumns { 568 //            /** 569 //             * no public constructor since this is a utility class 570 //             */ 571 //            private Extensions() {} 572 // 573 //            /** 574 //             * The directory twig for this sub-table 575 //             */ 576 //            public static final String CONTENT_DIRECTORY = "extensions"; 577 // 578 //            /** 579 //             * The default sort order for this table 580 //             */ 581 //            public static final String DEFAULT_SORT_ORDER = "name ASC"; 582 // 583 //            /** 584 //             * The ID of the person this phone number is assigned to. 585 //             * <P>Type: INTEGER (long)</P> 586 //             */ 587 //            public static final String PERSON_ID = "person"; 588 //        } 589 //    } 590 // 591 //    /** 592 //     * Columns from the groups table. 593 //     */ 594 //    public interface GroupsColumns { 595 //        /** 596 //         * The group name. 597 //         * <P>Type: TEXT</P> 598 //         */ 599 //        public static final String NAME = "name"; 600 // 601 //        /** 602 //         * Notes about the group. 603 //         * <P>Type: TEXT</P> 604 //         */ 605 //        public static final String NOTES = "notes"; 606 // 607 //        /** 608 //         * Whether this group should be synced if the SYNC_EVERYTHING settings is false 609 //         * for this group's account. 610 //         * <P>Type: INTEGER (boolean)</P> 611 //         */ 612 //        public static final String SHOULD_SYNC = "should_sync"; 613 // 614 //        /** 615 //         * The ID of this group if it is a System Group, null otherwise. 616 //         * <P>Type: TEXT</P> 617 //         */ 618 //        public static final String SYSTEM_ID = "system_id"; 619 //    } 620 // 621 //    /** 622 //     * This table contains the groups for an account. 623 //     */ 624 //    public static final class Groups 625 //            implements BaseColumns, SyncConstValue, GroupsColumns { 626 //        /** 627 //         * no public constructor since this is a utility class 628 //         */ 629 //        private Groups() {} 630 // 631 //        /** 632 //         * The content:// style URL for this table 633 //         */ 634 //        public static final Uri CONTENT_URI = 635 //            Uri.parse("content://contacts/groups"); 636 // 637 //        /** 638 //         * The content:// style URL for the table that holds the deleted 639 //         * groups. 640 //         */ 641 //        public static final Uri DELETED_CONTENT_URI = 642 //            Uri.parse("content://contacts/deleted_groups"); 643 // 644 //        /** 645 //         * The MIME type of {@link #CONTENT_URI} providing a directory of 646 //         * groups. 647 //         */ 648 //        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroup"; 649 // 650 //        /** 651 //         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single 652 //         * group. 653 //         */ 654 //        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroup"; 655 // 656 //        /** 657 //         * The default sort order for this table 658 //         */ 659 //        public static final String DEFAULT_SORT_ORDER = NAME + " ASC"; 660 // 661 //        /** 662 //         * 663 //         */ 664 //        public static final String GROUP_ANDROID_STARRED = "Starred in Android"; 665 // 666 //        /** 667 //         * The "My Contacts" system group. 668 //         */ 669 //        public static final String GROUP_MY_CONTACTS = "Contacts"; 670 //    } 671 // 672     /** 673      * Columns from the Phones table that other columns join into themselves. 674      */ 675     public interface PhonesColumns { 676         /** 677          * The type of the the phone number. 678          * <P>Type: INTEGER (one of the constants below)</P> 679          */ 680         public static final String TYPE = "type"; 681  682         public static final int TYPE_CUSTOM = 0; 683         public static final int TYPE_HOME = 1; 684         public static final int TYPE_MOBILE = 2; 685         public static final int TYPE_WORK = 3; 686         public static final int TYPE_FAX_WORK = 4; 687         public static final int TYPE_FAX_HOME = 5; 688         public static final int TYPE_PAGER = 6; 689         public static final int TYPE_OTHER = 7; 690  691         /** 692          * The user provided label for the phone number, only used if TYPE is TYPE_CUSTOM. 693          * <P>Type: TEXT</P> 694          */ 695         public static final String LABEL = "label"; 696  697         /** 698          * The phone number as the user entered it. 699          * <P>Type: TEXT</P> 700          */ 701         public static final String NUMBER = "number"; 702  703         /** 704          * The normalized phone number 705          * <P>Type: TEXT</P> 706          */ 707         public static final String NUMBER_KEY = "number_key"; 708  709         /** 710          * Whether this is the primary phone number 711          * <P>Type: INTEGER (if set, non-0 means true)</P> 712          */ 713         public static final String ISPRIMARY = "isprimary"; 714     } 715 // 716 //    /** 717 //     * This table stores phone numbers and a reference to the person that the 718 //     * contact method belongs to. Phone numbers are stored separately from 719 //     * other contact methods to make caller ID lookup more efficient. 720 //     */ 721 //    public static final class Phones 722 //            implements BaseColumns, PhonesColumns, PeopleColumns { 723 //        /** 724 //         * no public constructor since this is a utility class 725 //         */ 726 //        private Phones() {} 727 // 728 //        public static final CharSequence getDisplayLabel(Context context, int type, 729 //                CharSequence label, CharSequence[] labelArray) { 730 //            CharSequence display = ""; 731 // 732 //            if (type != People.Phones.TYPE_CUSTOM) { 733 //                CharSequence[] labels = labelArray != null? labelArray 734 //                        : context.getResources().getTextArray( 735 //                                com.android.internal.R.array.phoneTypes); 736 //                try { 737 //                    display = labels[type - 1]; 738 //                } catch (ArrayIndexOutOfBoundsException e) { 739 //                    display = labels[People.Phones.TYPE_HOME - 1]; 740 //                } 741 //            } else { 742 //                if (!TextUtils.isEmpty(label)) { 743 //                    display = label; 744 //                } 745 //            } 746 //            return display; 747 //        } 748 // 749 //        public static final CharSequence getDisplayLabel(Context context, int type, 750 //                CharSequence label) { 751 //            return getDisplayLabel(context, type, label, null); 752 //        } 753 // 754 //        /** 755 //         * The content:// style URL for this table 756 //         */ 757 //        public static final Uri CONTENT_URI = 758 //            Uri.parse("content://contacts/phones"); 759 // 760 //        /** 761 //         * The content:// style URL for filtering phone numbers 762 //         */ 763 //        public static final Uri CONTENT_FILTER_URL = 764 //            Uri.parse("content://contacts/phones/filter"); 765 // 766 //        /** 767 //         * The MIME type of {@link #CONTENT_URI} providing a directory of 768 //         * phones. 769 //         */ 770 //        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone"; 771 // 772 //        /** 773 //         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single 774 //         * phone. 775 //         */ 776 //        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone"; 777 // 778 //        /** 779 //         * The default sort order for this table 780 //         */ 781 //        public static final String DEFAULT_SORT_ORDER = "name ASC"; 782 // 783 //        /** 784 //         * The ID of the person this phone number is assigned to. 785 //         * <P>Type: INTEGER (long)</P> 786 //         */ 787 //        public static final String PERSON_ID = "person"; 788 //    } 789 // 790 //    public static final class GroupMembership implements BaseColumns, GroupsColumns { 791 //        /** 792 //         * no public constructor since this is a utility class 793 //         */ 794 //        private GroupMembership() {} 795 // 796 //        /** 797 //         * The content:// style URL for this table 798 //         */ 799 //        public static final Uri CONTENT_URI = 800 //            Uri.parse("content://contacts/groupmembership"); 801 // 802 //        /** 803 //         * The content:// style URL for this table 804 //         */ 805 //        public static final Uri RAW_CONTENT_URI = 806 //            Uri.parse("content://contacts/groupmembershipraw"); 807 // 808 //        /** 809 //         * The directory twig for this sub-table 810 //         */ 811 //        public static final String CONTENT_DIRECTORY = "groupmembership"; 812 //        /** 813 //         * The MIME type of {@link #CONTENT_URI} providing a directory of all 814 //         * person groups. 815 //         */ 816 //        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroupmembership"; 817 // 818 //        /** 819 //         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single 820 //         * person group. 821 //         */ 822 //        public static final String CONTENT_ITEM_TYPE = 823 //                "vnd.android.cursor.item/contactsgroupmembership"; 824 // 825 //        /** 826 //         * The default sort order for this table 827 //         */ 828 //        public static final String DEFAULT_SORT_ORDER = "group_id ASC"; 829 // 830 //        /** 831 //         * The row id of the accounts group. 832 //         * <P>Type: TEXT</P> 833 //         */ 834 //        public static final String GROUP_ID = "group_id"; 835 // 836 //        /** 837 //         * The sync id of the group. 838 //         * <P>Type: TEXT</P> 839 //         */ 840 //        public static final String GROUP_SYNC_ID = "group_sync_id"; 841 // 842 //        /** 843 //         * The account of the group. 844 //         * <P>Type: TEXT</P> 845 //         */ 846 //        public static final String GROUP_SYNC_ACCOUNT = "group_sync_account"; 847 // 848 //        /** 849 //         * The row id of the person. 850 //         * <P>Type: TEXT</P> 851 //         */ 852 //        public static final String PERSON_ID = "person"; 853 //    } 854 // 855     /** 856      * Columns from the ContactMethods table that other tables join into 857      * themseleves. 858      */ 859     public interface ContactMethodsColumns { 860         /** 861          * The kind of the the contact method. For example, email address, 862          * postal address, etc. 863          * <P>Type: INTEGER (one of the values below)</P> 864          */ 865         public static final String KIND = "kind"; 866  867         /** 868          * The type of the contact method, must be one of the types below. 869          * <P>Type: INTEGER (one of the values below)</P> 870          */ 871         public static final String TYPE = "type"; 872         public static final int TYPE_CUSTOM = 0; 873         public static final int TYPE_HOME = 1; 874         public static final int TYPE_WORK = 2; 875         public static final int TYPE_OTHER = 3; 876  877         /** 878          * @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future. 879          */ 880         public static final int MOBILE_EMAIL_TYPE_INDEX = 2; 881  882         /** 883          * @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future. 884          * This is not "mobile" but "CELL" since vCard uses it for identifying mobile phone. 885          */ 886         public static final String MOBILE_EMAIL_TYPE_NAME = "_AUTO_CELL"; 887  888         /** 889          * The user defined label for the the contact method. 890          * <P>Type: TEXT</P> 891          */ 892         public static final String LABEL = "label"; 893  894         /** 895          * The data for the contact method. 896          * <P>Type: TEXT</P> 897          */ 898         public static final String DATA = "data"; 899  900         /** 901          * Auxiliary data for the contact method. 902          * <P>Type: TEXT</P> 903          */ 904         public static final String AUX_DATA = "aux_data"; 905  906         /** 907          * Whether this is the primary organization 908          * <P>Type: INTEGER (if set, non-0 means true)</P> 909          */ 910         public static final String ISPRIMARY = "isprimary"; 911     } 912 // 913 //    /** 914 //     * This table stores all non-phone contact methods and a reference to the 915 //     * person that the contact method belongs to. 916 //     */ 917 //    public static final class ContactMethods 918 //            implements BaseColumns, ContactMethodsColumns, PeopleColumns { 919 //        /** 920 //         * The column with latitude data for postal locations 921 //         * <P>Type: REAL</P> 922 //         */ 923 //        public static final String POSTAL_LOCATION_LATITUDE = DATA; 924 // 925 //        /** 926 //         * The column with longitude data for postal locations 927 //         * <P>Type: REAL</P> 928 //         */ 929 //        public static final String POSTAL_LOCATION_LONGITUDE = AUX_DATA; 930 // 931 //        /** 932 //         * The predefined IM protocol types. The protocol can either be non-present, one 933 //         * of these types, or a free-form string. These cases are encoded in the AUX_DATA 934 //         * column as: 935 //         *  - null 936 //         *  - pre:<an integer, one of the protocols below> 937 //         *  - custom:<a string> 938 //         */ 939 //        public static final int PROTOCOL_AIM = 0; 940 //        public static final int PROTOCOL_MSN = 1; 941 //        public static final int PROTOCOL_YAHOO = 2; 942 //        public static final int PROTOCOL_SKYPE = 3; 943 //        public static final int PROTOCOL_QQ = 4; 944 //        public static final int PROTOCOL_GOOGLE_TALK = 5; 945 //        public static final int PROTOCOL_ICQ = 6; 946 //        public static final int PROTOCOL_JABBER = 7; 947 // 948 //        public static String encodePredefinedImProtocol(int protocol) { 949 //            return "pre:" + protocol; 950 //        } 951 // 952 //        public static String encodeCustomImProtocol(String protocolString) { 953 //            return "custom:" + protocolString; 954 //        } 955 // 956 //        public static Object decodeImProtocol(String encodedString) { 957 //            if (encodedString == null) { 958 //                return null; 959 //            } 960 // 961 //            if (encodedString.startsWith("pre:")) { 962 //                return Integer.parseInt(encodedString.substring(4)); 963 //            } 964 // 965 //            if (encodedString.startsWith("custom:")) { 966 //                return encodedString.substring(7); 967 //            } 968 // 969 //            throw new IllegalArgumentException( 970 //                    "the value is not a valid encoded protocol, " + encodedString); 971 //        } 972 // 973 //        /** 974 //         * This looks up the provider name defined in 975 //         * {@link android.provider.Im.ProviderNames} from the predefined IM protocol id. 976 //         * This is used for interacting with the IM application. 977 //         * 978 //         * @param protocol the protocol ID 979 //         * @return the provider name the IM app uses for the given protocol, or null if no 980 //         * provider is defined for the given protocol 981 //         * @hide 982 //         */ 983 //        public static String lookupProviderNameFromId(int protocol) { 984 //            switch (protocol) { 985 //                case PROTOCOL_GOOGLE_TALK: 986 //                    return Im.ProviderNames.GTALK; 987 //                case PROTOCOL_AIM: 988 //                    return Im.ProviderNames.AIM; 989 //                case PROTOCOL_MSN: 990 //                    return Im.ProviderNames.MSN; 991 //                case PROTOCOL_YAHOO: 992 //                    return Im.ProviderNames.YAHOO; 993 //                case PROTOCOL_ICQ: 994 //                    return Im.ProviderNames.ICQ; 995 //                case PROTOCOL_JABBER: 996 //                    return Im.ProviderNames.JABBER; 997 //                case PROTOCOL_SKYPE: 998 //                    return Im.ProviderNames.SKYPE; 999 //                case PROTOCOL_QQ:1000 //                    return Im.ProviderNames.QQ;1001 //            }1002 //            return null;1003 //        }1004 //1005 //        /**1006 //         * no public constructor since this is a utility class1007 //         */1008 //        private ContactMethods() {}1009 //1010 //        public static final CharSequence getDisplayLabel(Context context, int kind,1011 //                int type, CharSequence label) {1012 //            CharSequence display = "";1013 //            switch (kind) {1014 //                case KIND_EMAIL: {1015 //                    if (type != People.ContactMethods.TYPE_CUSTOM) {1016 //                        CharSequence[] labels = context.getResources().getTextArray(1017 //                                com.android.internal.R.array.emailAddressTypes);1018 //                        try {1019 //                            display = labels[type - 1];1020 //                        } catch (ArrayIndexOutOfBoundsException e) {1021 //                            display = labels[ContactMethods.TYPE_HOME - 1];1022 //                        }1023 //                    } else {1024 //                        if (!TextUtils.isEmpty(label)) {1025 //                            if (label.toString().equals(MOBILE_EMAIL_TYPE_NAME)) {1026 //                                display =1027 //                                    context.getString(1028 //                                            com.android.internal.R.string.mobileEmailTypeName);1029 //                            } else {1030 //                                display = label;1031 //                            }1032 //                        }1033 //                    }1034 //                    break;1035 //                }1036 //1037 //                case KIND_POSTAL: {1038 //                    if (type != People.ContactMethods.TYPE_CUSTOM) {1039 //                        CharSequence[] labels = context.getResources().getTextArray(1040 //                                com.android.internal.R.array.postalAddressTypes);1041 //                        try {1042 //                            display = labels[type - 1];1043 //                        } catch (ArrayIndexOutOfBoundsException e) {1044 //                            display = labels[ContactMethods.TYPE_HOME - 1];1045 //                        }1046 //                    } else {1047 //                        if (!TextUtils.isEmpty(label)) {1048 //                            display = label;1049 //                        }1050 //                    }1051 //                    break;1052 //                }1053 //1054 //                default:1055 //                    display = context.getString(R.string.untitled);1056 //            }1057 //            return display;1058 //        }1059 //1060 //        /**1061 //         * Add a longitude and latitude location to a postal address.1062 //         *1063 //         * @param context the context to use when updating the database1064 //         * @param postalId the address to update1065 //         * @param latitude the latitude for the address1066 //         * @param longitude the longitude for the address1067 //         */1068 //        public void addPostalLocation(Context context, long postalId,1069 //                double latitude, double longitude) {1070 //            final ContentResolver resolver = context.getContentResolver();1071 //            // Insert the location1072 //            ContentValues values = new ContentValues(2);1073 //            values.put(POSTAL_LOCATION_LATITUDE, latitude);1074 //            values.put(POSTAL_LOCATION_LONGITUDE, longitude);1075 //            Uri loc = resolver.insert(CONTENT_URI, values);1076 //            long locId = ContentUris.parseId(loc);1077 //1078 //            // Update the postal address1079 //            values.clear();1080 //            values.put(AUX_DATA, locId);1081 //            resolver.update(ContentUris.withAppendedId(CONTENT_URI, postalId), values, null, null);1082 //        }1083 //1084 //        /**1085 //         * The content:// style URL for this table1086 //         */1087 //        public static final Uri CONTENT_URI =1088 //            Uri.parse("content://contacts/contact_methods");1089 //1090 //        /**1091 //         * The content:// style URL for sub-directory of e-mail addresses.1092 //         */1093 //        public static final Uri CONTENT_EMAIL_URI =1094 //            Uri.parse("content://contacts/contact_methods/email");1095 //1096 //        /**1097 //         * The MIME type of {@link #CONTENT_URI} providing a directory of1098 //         * phones.1099 //         */1100 //        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact-methods";1101 //1102 //        /**1103 //         * The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\1104 //         * multiple {@link Contacts#KIND_EMAIL} entries.1105 //         */1106 //        public static final String CONTENT_EMAIL_TYPE = "vnd.android.cursor.dir/email";1107 //1108 //        /**1109 //         * The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\1110 //         * multiple {@link Contacts#KIND_POSTAL} entries.1111 //         */1112 //        public static final String CONTENT_POSTAL_TYPE = "vnd.android.cursor.dir/postal-address";1113 //1114 //        /**1115 //         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single1116 //         * {@link Contacts#KIND_EMAIL} entry.1117 //         */1118 //        public static final String CONTENT_EMAIL_ITEM_TYPE = "vnd.android.cursor.item/email";1119 //1120 //        /**1121 //         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single1122 //         * {@link Contacts#KIND_POSTAL} entry.1123 //         */1124 //        public static final String CONTENT_POSTAL_ITEM_TYPE1125 //                = "vnd.android.cursor.item/postal-address";1126 //1127 //        /**1128 //         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single1129 //         * {@link Contacts#KIND_IM} entry.1130 //         */1131 //        public static final String CONTENT_IM_ITEM_TYPE = "vnd.android.cursor.item/jabber-im";1132 //1133 //        /**1134 //         * The default sort order for this table1135 //         */1136 //        public static final String DEFAULT_SORT_ORDER = "name ASC";1137 //1138 //        /**1139 //         * The ID of the person this contact method is assigned to.1140 //         * <P>Type: INTEGER (long)</P>1141 //         */1142 //        public static final String PERSON_ID = "person";1143 //    }1144 //1145 //    /**1146 //     * The IM presence columns with some contacts specific columns mixed in.1147 //     */1148 //    public interface PresenceColumns extends Im.CommonPresenceColumns {1149 //        /**1150 //         * The IM service the presence is coming from. Formatted using either1151 //         * {@link Contacts.ContactMethods#encodePredefinedImProtocol} or1152 //         * {@link Contacts.ContactMethods#encodeCustomImProtocol}.1153 //         * <P>Type: STRING</P>1154 //         */1155 //        public static final String IM_PROTOCOL = "im_protocol";1156 //1157 //        /**1158 //         * The IM handle the presence item is for. The handle is scoped to1159 //         * the {@link #IM_PROTOCOL}.1160 //         * <P>Type: STRING</P>1161 //         */1162 //        public static final String IM_HANDLE = "im_handle";1163 //1164 //        /**1165 //         * The IM account for the local user that the presence data came from.1166 //         * <P>Type: STRING</P>1167 //         */1168 //        public static final String IM_ACCOUNT = "im_account";1169 //    }1170 //1171 //    /**1172 //     * Contains presence information about contacts.1173 //     * @hide1174 //     */1175 //    public static final class Presence1176 //            implements BaseColumns, PresenceColumns, PeopleColumns {1177 //        /**1178 //         * The content:// style URL for this table1179 //         */1180 //        public static final Uri CONTENT_URI =1181 //            Uri.parse("content://contacts/presence");1182 //1183 //        /**1184 //         * The ID of the person this presence item is assigned to.1185 //         * <P>Type: INTEGER (long)</P>1186 //         */1187 //        public static final String PERSON_ID = "person";1188 //1189 //        /**1190 //         * Gets the resource ID for the proper presence icon.1191 //         *1192 //         * @param status the status to get the icon for1193 //         * @return the resource ID for the proper presence icon1194 //         */1195 //        public static final int getPresenceIconResourceId(int status) {1196 //            switch (status) {1197 //                case Contacts.People.AVAILABLE:1198 //                    return com.android.internal.R.drawable.presence_online;1199 //1200 //                case Contacts.People.IDLE:1201 //                case Contacts.People.AWAY:1202 //                    return com.android.internal.R.drawable.presence_away;1203 //1204 //                case Contacts.People.DO_NOT_DISTURB:1205 //                    return com.android.internal.R.drawable.presence_busy;1206 //1207 //                case Contacts.People.INVISIBLE:1208 //                    return com.android.internal.R.drawable.presence_invisible;1209 //1210 //                case Contacts.People.OFFLINE:1211 //                default:1212 //                    return com.android.internal.R.drawable.presence_offline;1213 //            }1214 //        }1215 //1216 //        /**1217 //         * Sets a presence icon to the proper graphic1218 //         *1219 //         * @param icon the icon to to set1220 //         * @param serverStatus that status1221 //         */1222 //        public static final void setPresenceIcon(ImageView icon, int serverStatus) {1223 //            icon.setImageResource(getPresenceIconResourceId(serverStatus));1224 //        }1225 //    }1226 //1227     /**1228      * Columns from the Organizations table that other columns join into themselves.1229      */1230     public interface OrganizationColumns {1231         /**1232          * The type of the organizations.1233          * <P>Type: INTEGER (one of the constants below)</P>1234          */1235         public static final String TYPE = "type";1236 1237         public static final int TYPE_CUSTOM = 0;1238         public static final int TYPE_WORK = 1;1239         public static final int TYPE_OTHER = 2;1240 1241         /**1242          * The user provided label, only used if TYPE is TYPE_CUSTOM.1243          * <P>Type: TEXT</P>1244          */1245         public static final String LABEL = "label";1246 1247         /**1248          * The name of the company for this organization.1249          * <P>Type: TEXT</P>1250          */1251         public static final String COMPANY = "company";1252 1253         /**1254          * The title within this organization.1255          * <P>Type: TEXT</P>1256          */1257         public static final String TITLE = "title";1258 1259         /**1260          * The person this organization is tied to.1261          * <P>Type: TEXT</P>1262          */1263         public static final String PERSON_ID = "person";1264 1265         /**1266          * Whether this is the primary organization1267          * <P>Type: INTEGER (if set, non-0 means true)</P>1268          */1269         public static final String ISPRIMARY = "isprimary";1270     }1271 //1272 //    /**1273 //     * A sub directory of a single person that contains all of their Phones.1274 //     */1275 //    public static final class Organizations implements BaseColumns, OrganizationColumns {1276 //        /**1277 //         * no public constructor since this is a utility class1278 //         */1279 //        private Organizations() {}1280 //1281 //        public static final CharSequence getDisplayLabel(Context context, int type,1282 //                CharSequence label) {1283 //            CharSequence display = "";1284 //1285 //            if (type != TYPE_CUSTOM) {1286 //                CharSequence[] labels = context.getResources().getTextArray(1287 //                        com.android.internal.R.array.organizationTypes);1288 //                try {1289 //                    display = labels[type - 1];1290 //                } catch (ArrayIndexOutOfBoundsException e) {1291 //                    display = labels[Organizations.TYPE_WORK - 1];1292 //                }1293 //            } else {1294 //                if (!TextUtils.isEmpty(label)) {1295 //                    display = label;1296 //                }1297 //            }1298 //            return display;1299 //        }1300 //1301 //        /**1302 //         * The content:// style URL for this table1303 //         */1304 //        public static final Uri CONTENT_URI =1305 //            Uri.parse("content://contacts/organizations");1306 //1307 //        /**1308 //         * The directory twig for this sub-table1309 //         */1310 //        public static final String CONTENT_DIRECTORY = "organizations";1311 //1312 //        /**1313 //         * The default sort order for this table1314 //         */1315 //        public static final String DEFAULT_SORT_ORDER = "company, title, isprimary ASC";1316 //    }1317 //1318 //    /**1319 //     * Columns from the Photos table that other columns join into themselves.1320 //     */1321 //    public interface PhotosColumns {1322 //        /**1323 //         * The _SYNC_VERSION of the photo that was last downloaded1324 //         * <P>Type: TEXT</P>1325 //         */1326 //        public static final String LOCAL_VERSION = "local_version";1327 //1328 //        /**1329 //         * The person this photo is associated with.1330 //         * <P>Type: TEXT</P>1331 //         */1332 //        public static final String PERSON_ID = "person";1333 //1334 //        /**1335 //         * non-zero if a download is required and the photo isn't marked as a bad resource.1336 //         * You must specify this in the columns in order to use it in the where clause.1337 //         * <P>Type: INTEGER(boolean)</P>1338 //         */1339 //        public static final String DOWNLOAD_REQUIRED = "download_required";1340 //1341 //        /**1342 //         * non-zero if this photo is known to exist on the server1343 //         * <P>Type: INTEGER(boolean)</P>1344 //         */1345 //        public static final String EXISTS_ON_SERVER = "exists_on_server";1346 //1347 //        /**1348 //         * Contains the description of the upload or download error from1349 //         * the previous attempt. If null then the previous attempt succeeded.1350 //         * <P>Type: TEXT</P>1351 //         */1352 //        public static final String SYNC_ERROR = "sync_error";1353 //1354 //        /**1355 //         * The image data, or null if there is no image.1356 //         * <P>Type: BLOB</P>1357 //         */1358 //        public static final String DATA = "data";1359 //1360 //    }1361 //1362 //    /**1363 //     * The photos over all of the people1364 //     */1365 //    public static final class Photos implements BaseColumns, PhotosColumns, SyncConstValue {1366 //        /**1367 //         * no public constructor since this is a utility class1368 //         */1369 //        private Photos() {}1370 //1371 //        /**1372 //         * The content:// style URL for this table1373 //         */1374 //        public static final Uri CONTENT_URI =1375 //            Uri.parse("content://contacts/photos");1376 //1377 //        /**1378 //         * The directory twig for this sub-table1379 //         */1380 //        public static final String CONTENT_DIRECTORY = "photo";1381 //1382 //        /**1383 //         * The default sort order for this table1384 //         */1385 //        public static final String DEFAULT_SORT_ORDER = "person ASC";1386 //    }1387 //1388 //    public interface ExtensionsColumns {1389 //        /**1390 //         * The name of this extension. May not be null. There may be at most one row for each name.1391 //         * <P>Type: TEXT</P>1392 //         */1393 //        public static final String NAME = "name";1394 //1395 //        /**1396 //         * The value of this extension. May not be null.1397 //         * <P>Type: TEXT</P>1398 //         */1399 //        public static final String VALUE = "value";1400 //    }1401 //1402 //    /**1403 //     * The extensions for a person1404 //     */1405 //    public static final class Extensions implements BaseColumns, ExtensionsColumns {1406 //        /**1407 //         * no public constructor since this is a utility class1408 //         */1409 //        private Extensions() {}1410 //1411 //        /**1412 //         * The content:// style URL for this table1413 //         */1414 //        public static final Uri CONTENT_URI =1415 //            Uri.parse("content://contacts/extensions");1416 //1417 //        /**1418 //         * The MIME type of {@link #CONTENT_URI} providing a directory of1419 //         * phones.1420 //         */1421 //        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_extensions";1422 //1423 //        /**1424 //         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single1425 //         * phone.1426 //         */1427 //        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_extensions";1428 //        /**1429 //         * The default sort order for this table1430 //         */1431 //        public static final String DEFAULT_SORT_ORDER = "person, name ASC";1432 //1433 //        /**1434 //         * The ID of the person this phone number is assigned to.1435 //         * <P>Type: INTEGER (long)</P>1436 //         */1437 //        public static final String PERSON_ID = "person";1438 //    }1439 //1440 //    /**1441 //     * Contains helper classes used to create or manage {@link android.content.Intent Intents}1442 //     * that involve contacts.1443 //     */1444 //    public static final class Intents {1445 //        /**1446 //         * This is the intent that is fired when a search suggestion is clicked on.1447 //         */1448 //        public static final String SEARCH_SUGGESTION_CLICKED =1449 //                "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";1450 //1451 //        /**1452 //         * This is the intent that is fired when a search suggestion for dialing a number1453 //         * is clicked on.1454 //         */1455 //        public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =1456 //                "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";1457 //1458 //        /**1459 //         * This is the intent that is fired when a search suggestion for creating a contact1460 //         * is clicked on.1461 //         */1462 //        public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =1463 //                "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";1464 //1465 //        /**1466 //         * Starts an Activity that lets the user pick a contact to attach an image to.1467 //         * After picking the contact it launches the image cropper in face detection mode.1468 //         */1469 //        public static final String ATTACH_IMAGE =1470 //                "com.android.contacts.action.ATTACH_IMAGE";1471 //1472 //        /**1473 //         * Takes as input a data URI with a mailto: or tel: scheme. If a single1474 //         * contact exists with the given data it will be shown. If no contact1475 //         * exists, a dialog will ask the user if they want to create a new1476 //         * contact with the provided details filled in. If multiple contacts1477 //         * share the data the user will be prompted to pick which contact they1478 //         * want to view.1479 //         * <p>1480 //         * For <code>mailto:</code> URIs, the scheme specific portion must be a1481 //         * raw email address, such as one built using1482 //         * {@link Uri#fromParts(String, String, String)}.1483 //         * <p>1484 //         * For <code>tel:</code> URIs, the scheme specific portion is compared1485 //         * to existing numbers using the standard caller ID lookup algorithm.1486 //         * The number must be properly encoded, for example using1487 //         * {@link Uri#fromParts(String, String, String)}.1488 //         * <p>1489 //         * Any extras from the {@link Insert} class will be passed along to the1490 //         * create activity if there are no contacts to show.1491 //         * <p>1492 //         * Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip1493 //         * prompting the user when the contact doesn't exist.1494 //         */1495 //        public static final String SHOW_OR_CREATE_CONTACT =1496 //                "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";1497 //1498 //        /**1499 //         * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new1500 //         * contact if no matching contact found. Otherwise, default behavior is1501 //         * to prompt user with dialog before creating.1502 //         * <p>1503 //         * Type: BOOLEAN1504 //         */1505 //        public static final String EXTRA_FORCE_CREATE =1506 //                "com.android.contacts.action.FORCE_CREATE";1507 //1508 //        /**1509 //         * Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact1510 //         * description to be shown when prompting user about creating a new1511 //         * contact.1512 //         * <p>1513 //         * Type: STRING1514 //         */1515 //        public static final String EXTRA_CREATE_DESCRIPTION =1516 //            "com.android.contacts.action.CREATE_DESCRIPTION";1517 //1518 //        /**1519 //         * Intents related to the Contacts app UI.1520 //         */1521 //        public static final class UI {1522 //            /**1523 //             * The action for the default contacts list tab.1524 //             */1525 //            public static final String LIST_DEFAULT =1526 //                    "com.android.contacts.action.LIST_DEFAULT";1527 //1528 //            /**1529 //             * The action for the contacts list tab.1530 //             */1531 //            public static final String LIST_GROUP_ACTION =1532 //                    "com.android.contacts.action.LIST_GROUP";1533 //1534 //            /**1535 //             * When in LIST_GROUP_ACTION mode, this is the group to display.1536 //             */1537 //            public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";1538 //1539 //            /**1540 //             * The action for the all contacts list tab.1541 //             */1542 //            public static final String LIST_ALL_CONTACTS_ACTION =1543 //                    "com.android.contacts.action.LIST_ALL_CONTACTS";1544 //1545 //            /**1546 //             * The action for the contacts with phone numbers list tab.1547 //             */1548 //            public static final String LIST_CONTACTS_WITH_PHONES_ACTION =1549 //                    "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";1550 //1551 //            /**1552 //             * The action for the starred contacts list tab.1553 //             */1554 //            public static final String LIST_STARRED_ACTION =1555 //                    "com.android.contacts.action.LIST_STARRED";1556 //1557 //            /**1558 //             * The action for the frequent contacts list tab.1559 //             */1560 //            public static final String LIST_FREQUENT_ACTION =1561 //                    "com.android.contacts.action.LIST_FREQUENT";1562 //1563 //            /**1564 //             * The action for the "strequent" contacts list tab. It first lists the starred1565 //             * contacts in alphabetical order and then the frequent contacts in descending1566 //             * order of the number of times they have been contacted.1567 //             */1568 //            public static final String LIST_STREQUENT_ACTION =1569 //                    "com.android.contacts.action.LIST_STREQUENT";1570 //1571 //            /**1572 //             * A key for to be used as an intent extra to set the activity1573 //             * title to a custom String value.1574 //             */1575 //            public static final String TITLE_EXTRA_KEY =1576 //                "com.android.contacts.extra.TITLE_EXTRA";1577 //1578 //            /**1579 //             * Activity Action: Display a filtered list of contacts1580 //             * <p>1581 //             * Input: Extra field {@link #FILTER_TEXT_EXTRA_KEY} is the text to use for1582 //             * filtering1583 //             * <p>1584 //             * Output: Nothing.1585 //             */1586 //            public static final String FILTER_CONTACTS_ACTION =1587 //                "com.android.contacts.action.FILTER_CONTACTS";1588 //1589 //            /**1590 //             * Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}1591 //             * intents to supply the text on which to filter.1592 //             */1593 //            public static final String FILTER_TEXT_EXTRA_KEY =1594 //                "com.android.contacts.extra.FILTER_TEXT";1595 //        }1596 //1597 //        /**1598 //         * Convenience class that contains string constants used1599 //         * to create contact {@link android.content.Intent Intents}.1600 //         */1601 //        public static final class Insert {1602 //            /** The action code to use when adding a contact */1603 //            public static final String ACTION = Intent.ACTION_INSERT;1604 //1605 //            /**1606 //             * If present, forces a bypass of quick insert mode.1607 //             */1608 //            public static final String FULL_MODE = "full_mode";1609 //1610 //            /**1611 //             * The extra field for the contact name.1612 //             * <P>Type: String</P>1613 //             */1614 //            public static final String NAME = "name";1615 //1616 //            /**1617 //             * The extra field for the contact phonetic name.1618 //             * <P>Type: String</P>1619 //             */1620 //            public static final String PHONETIC_NAME = "phonetic_name";1621 //1622 //            /**1623 //             * The extra field for the contact company.1624 //             * <P>Type: String</P>1625 //             */1626 //            public static final String COMPANY = "company";1627 //1628 //            /**1629 //             * The extra field for the contact job title.1630 //             * <P>Type: String</P>1631 //             */1632 //            public static final String JOB_TITLE = "job_title";1633 //1634 //            /**1635 //             * The extra field for the contact notes.1636 //             * <P>Type: String</P>1637 //             */1638 //            public static final String NOTES = "notes";1639 //1640 //            /**1641 //             * The extra field for the contact phone number.1642 //             * <P>Type: String</P>1643 //             */1644 //            public static final String PHONE = "phone";1645 //1646 //            /**1647 //             * The extra field for the contact phone number type.1648 //             * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},1649 //             *  or a string specifying a custom label.</P>1650 //             */1651 //            public static final String PHONE_TYPE = "phone_type";1652 //1653 //            /**1654 //             * The extra field for the phone isprimary flag.1655 //             * <P>Type: boolean</P>1656 //             */1657 //            public static final String PHONE_ISPRIMARY = "phone_isprimary";1658 //1659 //            /**1660 //             * The extra field for an optional second contact phone number.1661 //             * <P>Type: String</P>1662 //             */1663 //            public static final String SECONDARY_PHONE = "secondary_phone";1664 //1665 //            /**1666 //             * The extra field for an optional second contact phone number type.1667 //             * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},1668 //             *  or a string specifying a custom label.</P>1669 //             */1670 //            public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";1671 //1672 //            /**1673 //             * The extra field for an optional third contact phone number.1674 //             * <P>Type: String</P>1675 //             */1676 //            public static final String TERTIARY_PHONE = "tertiary_phone";1677 //1678 //            /**1679 //             * The extra field for an optional third contact phone number type.1680 //             * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},1681 //             *  or a string specifying a custom label.</P>1682 //             */1683 //            public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";1684 //1685 //            /**1686 //             * The extra field for the contact email address.1687 //             * <P>Type: String</P>1688 //             */1689 //            public static final String EMAIL = "email";1690 //1691 //            /**1692 //             * The extra field for the contact email type.1693 //             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}1694 //             *  or a string specifying a custom label.</P>1695 //             */1696 //            public static final String EMAIL_TYPE = "email_type";1697 //1698 //            /**1699 //             * The extra field for the email isprimary flag.1700 //             * <P>Type: boolean</P>1701 //             */1702 //            public static final String EMAIL_ISPRIMARY = "email_isprimary";1703 //1704 //            /**1705 //             * The extra field for an optional second contact email address.1706 //             * <P>Type: String</P>1707 //             */1708 //            public static final String SECONDARY_EMAIL = "secondary_email";1709 //1710 //            /**1711 //             * The extra field for an optional second contact email type.1712 //             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}1713 //             *  or a string specifying a custom label.</P>1714 //             */1715 //            public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";1716 //1717 //            /**1718 //             * The extra field for an optional third contact email address.1719 //             * <P>Type: String</P>1720 //             */1721 //            public static final String TERTIARY_EMAIL = "tertiary_email";1722 //1723 //            /**1724 //             * The extra field for an optional third contact email type.1725 //             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}1726 //             *  or a string specifying a custom label.</P>1727 //             */1728 //            public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";1729 //1730 //            /**1731 //             * The extra field for the contact postal address.1732 //             * <P>Type: String</P>1733 //             */1734 //            public static final String POSTAL = "postal";1735 //1736 //            /**1737 //             * The extra field for the contact postal address type.1738 //             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}1739 //             *  or a string specifying a custom label.</P>1740 //             */1741 //            public static final String POSTAL_TYPE = "postal_type";1742 //1743 //            /**1744 //             * The extra field for the postal isprimary flag.1745 //             * <P>Type: boolean</P>1746 //             */1747 //            public static final String POSTAL_ISPRIMARY = "postal_isprimary";1748 //1749 //            /**1750 //             * The extra field for an IM handle.1751 //             * <P>Type: String</P>1752 //             */1753 //            public static final String IM_HANDLE = "im_handle";1754 //1755 //            /**1756 //             * The extra field for the IM protocol1757 //             * <P>Type: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}1758 //             * or {@link Contacts.ContactMethods#encodeCustomImProtocol}.</P>1759 //             */1760 //            public static final String IM_PROTOCOL = "im_protocol";1761 //1762 //            /**1763 //             * The extra field for the IM isprimary flag.1764 //             * <P>Type: boolean</P>1765 //             */1766 //            public static final String IM_ISPRIMARY = "im_isprimary";1767 //        }1768 //    }1769 }

最后附上导入导出的方法

  1 package com.hh.assistant.app.vo;  2   3 import java.io.BufferedReader;  4 import java.io.FileInputStream;  5 import java.io.FileNotFoundException;  6 import java.io.FileOutputStream;  7 import java.io.IOException;  8 import java.io.InputStreamReader;  9 import java.io.OutputStreamWriter; 10 import java.io.UnsupportedEncodingException; 11 import java.util.ArrayList; 12 import java.util.List; 13  14 import a_vcard.android.provider.Contacts; 15 import a_vcard.android.syncml.pim.VDataBuilder; 16 import a_vcard.android.syncml.pim.VNode; 17 import a_vcard.android.syncml.pim.vcard.ContactStruct; 18 import a_vcard.android.syncml.pim.vcard.ContactStruct.ContactMethod; 19 import a_vcard.android.syncml.pim.vcard.ContactStruct.PhoneData; 20 import a_vcard.android.syncml.pim.vcard.VCardComposer; 21 import a_vcard.android.syncml.pim.vcard.VCardException; 22 import a_vcard.android.syncml.pim.vcard.VCardParser; 23 import android.app.Activity; 24 import android.content.ContentUris; 25 import android.content.ContentValues; 26 import android.database.Cursor; 27 import android.net.Uri; 28 import android.os.Environment; 29 import android.provider.ContactsContract; 30 import android.provider.ContactsContract.CommonDataKinds.Email; 31 import android.provider.ContactsContract.CommonDataKinds.Phone; 32 import android.provider.ContactsContract.CommonDataKinds.StructuredName; 33 import android.provider.ContactsContract.RawContacts; 34 import android.provider.ContactsContract.RawContacts.Data; 35 import android.widget.Toast; 36  37  38 /** 39  * 联系人信息包装类 40  *  41  * @author LW 42  *  43  */ 44 public class ContactInfo { 45  46     /** MUST exist */ 47     private String name; // 姓名 48      49     /** 联系人电话信息 */ 50     public static class PhoneInfo{ 51         /** 联系电话类型 */ 52         public int type; 53         /** 联系电话 */ 54         public String number; 55     } 56      57     /** 联系人邮箱信息 */ 58     public static class EmailInfo{ 59         /** 邮箱类型 */ 60         public int type; 61         /** 邮箱 */ 62         public String email; 63     } 64      65     private List<PhoneInfo> phoneList = new ArrayList<PhoneInfo>(); // 联系号码 66     private List<EmailInfo> email = new ArrayList<EmailInfo>(); // Email 67  68     /** 69      * 构造联系人信息 70      * @param name 联系人姓名  71      */ 72     public ContactInfo(String name) { 73         this.name = name; 74     } 75      76     /** 姓名 */ 77     public String getName() { 78         return name; 79     } 80     /** 姓名 */ 81     public ContactInfo setName(String name) { 82         this.name = name; 83         return this; 84     } 85     /** 联系电话信息 */ 86     public List<PhoneInfo> getPhoneList() { 87         return phoneList; 88     } 89     /** 联系电话信息 */ 90     public ContactInfo setPhoneList(List<PhoneInfo> phoneList) { 91         this.phoneList = phoneList; 92         return this; 93     } 94     /** 邮箱信息 */ 95     public List<EmailInfo> getEmail() { 96         return email; 97     } 98     /** 邮箱信息 */ 99     public ContactInfo setEmail(List<EmailInfo> email) {100         this.email = email;101         return this;102     }103 104     @Override105     public String toString() {106         return "{name: "+name+", number: "+phoneList+", email: "+email+"}";107     }108     109     /**110      * 联系人111      *         备份/还原操作112      * @author LW113      *114      */115     public static class ContactHandler {116 117         private static ContactHandler instance_ = new ContactHandler();118         119         /** 获取实例 */120         public static ContactHandler getInstance(){121             return instance_;122         }123         124         /**125          * 获取联系人指定信息126          * @param projection 指定要获取的列数组, 获取全部列则设置为null127          * @return128          * @throws Exception129          */130         public Cursor queryContact(Activity context, String[] projection){131             // 获取联系人的所需信息132             Cursor cur = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, projection, null, null, null);133             return cur;134         }135         136         /**137          * 获取联系人信息138          * @param context139          * @return140          */141         public List<ContactInfo> getContactInfo(Activity context){142             List<ContactInfo> infoList = new ArrayList<ContactInfo>();143             144             Cursor cur = queryContact(context, null);145             146             if(cur.moveToFirst()){147                 do{148                     149                     // 获取联系人id号150                     String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));151                     // 获取联系人姓名152                     String displayName = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));153                     ContactInfo info = new ContactInfo(displayName);// 初始化联系人信息154                     155                     // 查看联系人有多少电话号码, 如果没有返回0156                     int phoneCount = cur.getInt(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));157                     158                     if(phoneCount>0){159                         160                         Cursor phonesCursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + id , null, null);161                         162                         if(phonesCursor.moveToFirst()) {163                             List<ContactInfo.PhoneInfo> phoneNumberList = new ArrayList<ContactInfo.PhoneInfo>();164                             do{165                                 // 遍历所有电话号码166                                 String phoneNumber = phonesCursor.getString(phonesCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));167                                 // 对应的联系人类型168                                 int type = phonesCursor.getInt(phonesCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));169                                 170                                 // 初始化联系人电话信息171                                 ContactInfo.PhoneInfo phoneInfo = new ContactInfo.PhoneInfo();172                                 phoneInfo.type=type;173                                 phoneInfo.number=phoneNumber;174                                 175                                 phoneNumberList.add(phoneInfo);176                             }while(phonesCursor.moveToNext());177                             // 设置联系人电话信息178                             info.setPhoneList(phoneNumberList);179                         }180                     }181                     182                     // 获得联系人的EMAIL183                     Cursor emailCur = context.getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID+"="+id, null, null);184                     185                     if(emailCur.moveToFirst()){186                         List<ContactInfo.EmailInfo> emailList = new ArrayList<ContactInfo.EmailInfo>();187                         do{188                             // 遍历所有的email189                             String email = emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA1));190                             int type = emailCur.getInt(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));191                             192                             // 初始化联系人邮箱信息193                             ContactInfo.EmailInfo emailInfo=new ContactInfo.EmailInfo();194                             emailInfo.type=type;    // 设置邮箱类型195                             emailInfo.email=email;    // 设置邮箱地址196                             197                             emailList.add(emailInfo);198                         }while(emailCur.moveToNext());199                         200                         info.setEmail(emailList);201                     }202                     203                     //Cursor postalCursor = getContentResolver().query(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_URI, null, ContactsContract.CommonDataKinds.StructuredPostal.CONTACT_ID + "=" + id, null, null);204                     infoList.add(info);205                 }while(cur.moveToNext());206             }207             return infoList;208         }209         210         /**211          * 备份联系人212          */213         public void backupContacts(Activity context, List<ContactInfo> infos){214             215             try {216                 217                 String path = Environment.getExternalStorageDirectory() + "/contacts.vcf";218                 219                 OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(path),"UTF-8");220                 221                 VCardComposer composer = new VCardComposer();222                 223                 for (ContactInfo info : infos)224                 {225                     ContactStruct contact = new ContactStruct();226                     contact.name = info.getName();227                     // 获取联系人电话信息, 添加至 ContactStruct 228                     List<ContactInfo.PhoneInfo> numberList = info229                             .getPhoneList();230                     for (ContactInfo.PhoneInfo phoneInfo : numberList)231                     {232                         contact.addPhone(phoneInfo.type, phoneInfo.number,233                                 null, true);234                     }235                     // 获取联系人Email信息, 添加至 ContactStruct 236                     List<ContactInfo.EmailInfo> emailList = info.getEmail();237                     for (ContactInfo.EmailInfo emailInfo : emailList)238                     {239                         contact.addContactmethod(Contacts.KIND_EMAIL,240                                 emailInfo.type, emailInfo.email, null, true);241                     }242                     String vcardString = composer.createVCard(contact,243                             VCardComposer.VERSION_VCARD30_INT);244                     writer.write(vcardString);245                     writer.write("\n");246                     247                     writer.flush();248                 }249                 writer.close();250             251             } catch (UnsupportedEncodingException e) {252                 e.printStackTrace();253             } catch (FileNotFoundException e) {254                 e.printStackTrace();255             } catch (VCardException e) {256                 e.printStackTrace();257             } catch (IOException e) {258                 e.printStackTrace();259             }260             261             Toast.makeText(context, "备份成功!", Toast.LENGTH_SHORT).show();262         }263         264         265         /**266          * 获取vCard文件中的联系人信息 267          * @return 268          */269         public List<ContactInfo> restoreContacts() throws Exception {270             List<ContactInfo> contactInfoList = new ArrayList<ContactInfo>();271             272             VCardParser parse = new VCardParser();273             VDataBuilder builder = new VDataBuilder();274             String file = Environment.getExternalStorageDirectory() + "/contacts.vcf";275             276             BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));277             278             String vcardString = "";279             String line;280             while((line = reader.readLine()) != null) {281                 vcardString += line + "\n";282             }283             reader.close();284             285             boolean parsed = parse.parse(vcardString, "UTF-8", builder);286             287             if(!parsed){288                 throw new VCardException("Could not parse vCard file: "+ file);289             }290             291             List<VNode> pimContacts = builder.vNodeList;292             293             for (VNode contact : pimContacts) {294                 295                 ContactStruct contactStruct=ContactStruct.constructContactFromVNode(contact, 1);296                 // 获取备份文件中的联系人电话信息297                 List<PhoneData> phoneDataList = contactStruct.phoneList;298                 List<ContactInfo.PhoneInfo> phoneInfoList = new ArrayList<ContactInfo.PhoneInfo>();299                 for(PhoneData phoneData : phoneDataList){300                     ContactInfo.PhoneInfo phoneInfo = new ContactInfo.PhoneInfo();301                     phoneInfo.number=phoneData.data;302                     phoneInfo.type=phoneData.type;303                     phoneInfoList.add(phoneInfo);304                 }305                 306                 // 获取备份文件中的联系人邮箱信息307                 List<ContactMethod> emailList = contactStruct.contactmethodList;308                 List<ContactInfo.EmailInfo> emailInfoList = new ArrayList<ContactInfo.EmailInfo>();309                 // 存在 Email 信息310                 if (null!=emailList)311                 {312                     for (ContactMethod contactMethod : emailList)313                     {314                         if (Contacts.KIND_EMAIL == contactMethod.kind)315                         {316                             ContactInfo.EmailInfo emailInfo = new ContactInfo.EmailInfo();317                             emailInfo.email = contactMethod.data;318                             emailInfo.type = contactMethod.type;319                             emailInfoList.add(emailInfo);320                         }321                     }322                 }323                 ContactInfo info = new ContactInfo(contactStruct.name).setPhoneList(phoneInfoList).setEmail(emailInfoList);324                 contactInfoList.add(info);325             }326             327             return contactInfoList;328         }329 330         331         /**332          * 向手机中录入联系人信息333          * @param info 要录入的联系人信息334          */335         public void addContacts(Activity context, ContactInfo info){336             ContentValues values = new ContentValues();337             //首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId338             Uri rawContactUri = context.getContentResolver().insert(RawContacts.CONTENT_URI, values);339             long rawContactId = ContentUris.parseId(rawContactUri);340             341             //往data表入姓名数据342             values.clear();343             values.put(Data.RAW_CONTACT_ID, rawContactId);344             values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);345             values.put(StructuredName.GIVEN_NAME, info.getName());346             context.getContentResolver().insert(347                     android.provider.ContactsContract.Data.CONTENT_URI, values);348             349             // 获取联系人电话信息350             List<ContactInfo.PhoneInfo> phoneList = info.getPhoneList();351             /** 录入联系电话 */352             for (ContactInfo.PhoneInfo phoneInfo : phoneList) {353                 values.clear();354                 values.put(android.provider.ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);355                 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);356                 // 设置录入联系人电话信息357                 values.put(Phone.NUMBER, phoneInfo.number);358                 values.put(Phone.TYPE, phoneInfo.type);359                 // 往data表入电话数据360                 context.getContentResolver().insert(361                         android.provider.ContactsContract.Data.CONTENT_URI, values);362             }363             364             // 获取联系人邮箱信息365             List<ContactInfo.EmailInfo> emailList = info.getEmail();366             367             /** 录入联系人邮箱信息 */368             for (ContactInfo.EmailInfo email : emailList) {369                 values.clear();370                 values.put(android.provider.ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);371                 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);372                 // 设置录入的邮箱信息373                 values.put(Email.DATA, email.email);374                 values.put(Email.TYPE, email.type);375                 // 往data表入Email数据376                 context.getContentResolver().insert(377                         android.provider.ContactsContract.Data.CONTENT_URI, values);378             }379             380         }381         382     }383 }
 1 // 获取联系人处理实例 2         ContactInfo.ContactHandler handler=ContactInfo.ContactHandler.getInstance(); 3          4         switch (id) { 5         case R.id.save_linkman: 6             // 获取要备份的信息 7             List<ContactInfo> _infoList = handler.getContactInfo(this); 8             handler.backupContacts(this, _infoList);    // 备份联系人信息 9             break;10 11         case R.id.restore_linkman:    // 恢复12             try {13                 // 获取要恢复的联系人信息14                 List<ContactInfo> infoList = handler.restoreContacts();15                 for (ContactInfo contactInfo : infoList) {16                     // 恢复联系人17                     handler.addContacts(this, contactInfo);18                 }19                 20                 Toast.makeText(this, "导入联系人信息成功!", Toast.LENGTH_LONG);21                 22             } catch (Exception e) {23                 Toast.makeText(this, "导入联系人信息失败!", Toast.LENGTH_SHORT).show();24                 e.printStackTrace();25             }26             27             break;28         }

更多相关文章

  1. Android的SocketTCP客户端发送信息
  2. 信息浏览器从Android的浏览器中传递cookie数据到App中信息浏览器
  3. 懒骨头的Android文档备份2:运行你的App
  4. Android和Unity混合开发——Activity和Unity脚本交互和信息传递
  5. android操作sim卡联系人信息
  6. Android不同版本获取当前wifi信息方法
  7. android 获取当前手机的 DHCP 信息ip,server 等
  8. Android菜鸟笔记-获取设备信息

随机推荐

  1. Android(安卓)使用多线程来做多文件上传O
  2. Android商店不能承受之乱:第三方商店估值
  3. Android技术沙龙系列之:Android(安卓)广播
  4. WindowsMobile与Android的比较
  5. Android将允许纯C/C++开发应用
  6. android 对于asset下文件的操作
  7. android内存溢出分析
  8. Android应用启动后自动创建桌面快捷方式
  9. 安卓系统设备升级巨慢 为什么安卓设备系
  10. AllJoyn+Android开发案例-android跨设备