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

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

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

raw_contacts表结构:

data表结构:

每个联系人在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个类的源码如下.

复制代码
  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_POSTAL
101         public int kind;
102         // e.g. Contacts.ContactMethods.TYPE_HOME, Contacts.PhoneColumns.TYPE_HOME
103         // 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 number
121      * @param type type col of content://contacts/phones
122      * @param label lable col of content://contacts/phones
123      */
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.java
149      * (e.g. Contacts.KIND_EMAIL)
150      * @param type type col of content://contacts/contact_methods
151      * @param data contact data
152      * @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 one
186      * OrganizationData objects, the value is set to the last one. If there's no
187      * OrganizationData object, a new OrganizationData is created, whose company name is
188      * 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 not
193      * know how to handle it in general cases...
194      * ----
195      * TITLE:Software Engineer
196      * ORG:Google
197      * ----
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             // Prefix
239             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 name
259             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             // Suffix
274             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", and
305         // "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 field
313         // (See android.provider.Contacts)
314         // If false even after the following loop, we choose the first
315         // 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 not
389                         // specifically supported by vCard 2.1. We assume this is same
390                         // 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 exporters
407                         // 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 default
413                 if (type < 0) {
414                     type = Contacts.ContactMethodsColumns.TYPE_HOME;
415                 }
416                                 
417                 // adr-value    = 0*6(text-value ";") text-value
418                 //              ; PO Box, Extended Address, Street, Locality, Region, Postal
419                 //              ; Code, Country Name
420                 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 they
571                         // 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 default
584                 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:CONFIDENTIAL
622                 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 TECHNOLOGY
629                 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 created
636                 // 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 around
662             //       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 space
687         // 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_POSTAL
893 //                    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 }
复制代码
复制代码
   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 class
1007 //         */
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 database
1064 //         * @param postalId the address to update
1065 //         * @param latitude the latitude for the address
1066 //         * @param longitude the longitude for the address
1067 //         */
1068 //        public void addPostalLocation(Context context, long postalId,
1069 //                double latitude, double longitude) {
1070 //            final ContentResolver resolver = context.getContentResolver();
1071 //            // Insert the location
1072 //            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 address
1079 //            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 table
1086 //         */
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 of
1098 //         * 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 single
1116 //         * {@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 single
1122 //         * {@link Contacts#KIND_POSTAL} entry.
1123 //         */
1124 //        public static final String CONTENT_POSTAL_ITEM_TYPE
1125 //                = "vnd.android.cursor.item/postal-address";
1126 //
1127 //        /**
1128 //         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
1129 //         * {@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 table
1135 //         */
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 either
1151 //         * {@link Contacts.ContactMethods#encodePredefinedImProtocol} or
1152 //         * {@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 to
1159 //         * 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 //     * @hide
1174 //     */
1175 //    public static final class Presence
1176 //            implements BaseColumns, PresenceColumns, PeopleColumns {
1177 //        /**
1178 //         * The content:// style URL for this table
1179 //         */
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 for
1193 //         * @return the resource ID for the proper presence icon
1194 //         */
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 graphic
1218 //         *
1219 //         * @param icon the icon to to set
1220 //         * @param serverStatus that status
1221 //         */
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 organization
1267          * <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 class
1278 //         */
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 table
1303 //         */
1304 //        public static final Uri CONTENT_URI =
1305 //            Uri.parse("content://contacts/organizations");
1306 //
1307 //        /**
1308 //         * The directory twig for this sub-table
1309 //         */
1310 //        public static final String CONTENT_DIRECTORY = "organizations";
1311 //
1312 //        /**
1313 //         * The default sort order for this table
1314 //         */
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 downloaded
1324 //         * <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 server
1343 //         * <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 from
1349 //         * 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 people
1364 //     */
1365 //    public static final class Photos implements BaseColumns, PhotosColumns, SyncConstValue {
1366 //        /**
1367 //         * no public constructor since this is a utility class
1368 //         */
1369 //        private Photos() {}
1370 //
1371 //        /**
1372 //         * The content:// style URL for this table
1373 //         */
1374 //        public static final Uri CONTENT_URI =
1375 //            Uri.parse("content://contacts/photos");
1376 //
1377 //        /**
1378 //         * The directory twig for this sub-table
1379 //         */
1380 //        public static final String CONTENT_DIRECTORY = "photo";
1381 //
1382 //        /**
1383 //         * The default sort order for this table
1384 //         */
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 person
1404 //     */
1405 //    public static final class Extensions implements BaseColumns, ExtensionsColumns {
1406 //        /**
1407 //         * no public constructor since this is a utility class
1408 //         */
1409 //        private Extensions() {}
1410 //
1411 //        /**
1412 //         * The content:// style URL for this table
1413 //         */
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 of
1419 //         * 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 single
1425 //         * phone.
1426 //         */
1427 //        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_extensions";
1428 //        /**
1429 //         * The default sort order for this table
1430 //         */
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 number
1453 //         * 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 contact
1460 //         * 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 single
1474 //         * contact exists with the given data it will be shown. If no contact
1475 //         * exists, a dialog will ask the user if they want to create a new
1476 //         * contact with the provided details filled in. If multiple contacts
1477 //         * share the data the user will be prompted to pick which contact they
1478 //         * want to view.
1479 //         * <p>
1480 //         * For <code>mailto:</code> URIs, the scheme specific portion must be a
1481 //         * raw email address, such as one built using
1482 //         * {@link Uri#fromParts(String, String, String)}.
1483 //         * <p>
1484 //         * For <code>tel:</code> URIs, the scheme specific portion is compared
1485 //         * to existing numbers using the standard caller ID lookup algorithm.
1486 //         * The number must be properly encoded, for example using
1487 //         * {@link Uri#fromParts(String, String, String)}.
1488 //         * <p>
1489 //         * Any extras from the {@link Insert} class will be passed along to the
1490 //         * create activity if there are no contacts to show.
1491 //         * <p>
1492 //         * Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip
1493 //         * 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 new
1500 //         * contact if no matching contact found. Otherwise, default behavior is
1501 //         * to prompt user with dialog before creating.
1502 //         * <p>
1503 //         * Type: BOOLEAN
1504 //         */
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 exact
1510 //         * description to be shown when prompting user about creating a new
1511 //         * contact.
1512 //         * <p>
1513 //         * Type: STRING
1514 //         */
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 starred
1565 //             * contacts in alphabetical order and then the frequent contacts in descending
1566 //             * 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 activity
1573 //             * 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 contacts
1580 //             * <p>
1581 //             * Input: Extra field {@link #FILTER_TEXT_EXTRA_KEY} is the text to use for
1582 //             * filtering
1583 //             * <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 used
1599 //         * 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 protocol
1757 //             * <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     @Override
105     public String toString() {
106         return "{name: "+name+", number: "+phoneList+", email: "+email+"}";
107     }
108     
109     /**
110      * 联系人
111      *         备份/还原操作
112      * @author LW
113      *
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 指定要获取的列数组, 获取全部列则设置为null
127          * @return
128          * @throws Exception
129          */
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 context
139          * @return
140          */
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                     // 查看联系人有多少电话号码, 如果没有返回0
156                     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                     // 获得联系人的EMAIL
183                     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                             // 遍历所有的email
189                             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 = info
229                             .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执行一个空值插入,目的是获取系统返回的rawContactId
338             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         }
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值