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

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

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

raw_contacts表结构:

Android VCard联系人备份恢复(导入/导出)详解_第1张图片

data表结构:
Android VCard联系人备份恢复(导入/导出)详解_第2张图片
每个联系人在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 notes = new ArrayList();
 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 phoneList;
 80     /** Only for GET. Use addContactmethodList() to PUT. */
 81     public List contactmethodList;
 82     /** Only for GET. Use addOrgList() to PUT. */
 83     public List organizationList;
 84     /** Only for GET. Use addExtension() to PUT */
 85     public Map> 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();
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();
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();
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();
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 list;
218         String name = propertyNode.propName;
219         if (extensionMap == null) {
220             extensionMap = new HashMap>();
221         }
222         if (!extensionMap.containsKey(name)){
223             list = new ArrayList();
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 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 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 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 list = propertyNode.propValue_vector; 
471                 int size = list.size();
472                 StringBuilder builder = new StringBuilder();
473                 for (Iterator 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 contentValuesArray;
905 //            if (resolver != null) {
906 //                contentValuesArray = new ArrayList();
907 //            } else {
908 //                contentValuesArray = null;
909 //            }
910 //            for (Entry> entry : extensionMap.entrySet()) {
911 //                String key = entry.getKey();
912 //                List 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 //         * 

Type: TEXT

74 // */ 75 // public static final String _SYNC_ACCOUNT = "_sync_account"; 76 // 77 // /** 78 // * The key of this setting. 79 // *

Type: TEXT

80 // */ 81 // public static final String KEY = "key"; 82 // 83 // /** 84 // * The value of this setting. 85 // *

Type: TEXT

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 // *

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 *

Type: TEXT

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 *

Type: TEXT

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 *

Type: TEXT

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 *

Type: TEXT

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 *

Type: TEXT

204 */ 205 public static final String NOTES = "notes"; 206 207 /** 208 * The number of times a person has been contacted 209 *

Type: INTEGER

210 */ 211 public static final String TIMES_CONTACTED = "times_contacted"; 212 213 /** 214 * The last time a person was contacted. 215 *

Type: INTEGER

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 *

Type: TEXT (URI to the ringtone)

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 *

Type: INTEGER (0 for false, 1 for true)

229 */ 230 public static final String SEND_TO_VOICEMAIL = "send_to_voicemail"; 231 232 /** 233 * Is the contact starred? 234 *

Type: INTEGER (boolean)

235 */ 236 public static final String STARRED = "starred"; 237 238 /** 239 * The server version of the photo 240 *

Type: TEXT (the version number portion of the photo URI)

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 // *

Type: INTEGER (foreign key to phones table on the _ID field)

309 // */ 310 // public static final String PRIMARY_PHONE_ID = "primary_phone"; 311 // 312 // /** 313 // * The ID of the persons preferred email. 314 // *

Type: INTEGER (foreign key to contact_methods table on the 315 // * _ID field)

316 // */ 317 // public static final String PRIMARY_EMAIL_ID = "primary_email"; 318 // 319 // /** 320 // * The ID of the persons preferred organization. 321 // *

Type: INTEGER (foreign key to organizations table on the 322 // * _ID field)

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 // *

Type: INTEGER (long)

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 // *

Type: TEXT

598 // */ 599 // public static final String NAME = "name"; 600 // 601 // /** 602 // * Notes about the group. 603 // *

Type: TEXT

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 // *

Type: INTEGER (boolean)

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 // *

Type: TEXT

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 *

Type: INTEGER (one of the constants below)

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 *

Type: TEXT

694 */ 695 public static final String LABEL = "label"; 696 697 /** 698 * The phone number as the user entered it. 699 *

Type: TEXT

700 */ 701 public static final String NUMBER = "number"; 702 703 /** 704 * The normalized phone number 705 *

Type: TEXT

706 */ 707 public static final String NUMBER_KEY = "number_key"; 708 709 /** 710 * Whether this is the primary phone number 711 *

Type: INTEGER (if set, non-0 means true)

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 // *

Type: INTEGER (long)

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 // *

Type: TEXT

833 // */ 834 // public static final String GROUP_ID = "group_id"; 835 // 836 // /** 837 // * The sync id of the group. 838 // *

Type: TEXT

839 // */ 840 // public static final String GROUP_SYNC_ID = "group_sync_id"; 841 // 842 // /** 843 // * The account of the group. 844 // *

Type: TEXT

845 // */ 846 // public static final String GROUP_SYNC_ACCOUNT = "group_sync_account"; 847 // 848 // /** 849 // * The row id of the person. 850 // *

Type: TEXT

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 *

Type: INTEGER (one of the values below)

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 *

Type: INTEGER (one of the values below)

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 *

Type: TEXT

891 */ 892 public static final String LABEL = "label"; 893 894 /** 895 * The data for the contact method. 896 *

Type: TEXT

897 */ 898 public static final String DATA = "data"; 899 900 /** 901 * Auxiliary data for the contact method. 902 *

Type: TEXT

903 */ 904 public static final String AUX_DATA = "aux_data"; 905 906 /** 907 * Whether this is the primary organization 908 *

Type: INTEGER (if set, non-0 means true)

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 // *

Type: REAL

922 // */ 923 // public static final String POSTAL_LOCATION_LATITUDE = DATA; 924 // 925 // /** 926 // * The column with longitude data for postal locations 927 // *

Type: REAL

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: 937 // * - custom: 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 // *

Type: INTEGER (long)

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 // *

Type: STRING

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 // *

Type: STRING

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 // *

Type: STRING

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 // *

Type: INTEGER (long)

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 *

Type: INTEGER (one of the constants below)

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 *

Type: TEXT

1244 */ 1245 public static final String LABEL = "label"; 1246 1247 /** 1248 * The name of the company for this organization. 1249 *

Type: TEXT

1250 */ 1251 public static final String COMPANY = "company"; 1252 1253 /** 1254 * The title within this organization. 1255 *

Type: TEXT

1256 */ 1257 public static final String TITLE = "title"; 1258 1259 /** 1260 * The person this organization is tied to. 1261 *

Type: TEXT

1262 */ 1263 public static final String PERSON_ID = "person"; 1264 1265 /** 1266 * Whether this is the primary organization 1267 *

Type: INTEGER (if set, non-0 means true)

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 // *

Type: TEXT

1325 // */ 1326 // public static final String LOCAL_VERSION = "local_version"; 1327 // 1328 // /** 1329 // * The person this photo is associated with. 1330 // *

Type: TEXT

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 // *

Type: INTEGER(boolean)

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 // *

Type: INTEGER(boolean)

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 // *

Type: TEXT

1351 // */ 1352 // public static final String SYNC_ERROR = "sync_error"; 1353 // 1354 // /** 1355 // * The image data, or null if there is no image. 1356 // *

Type: BLOB

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 // *

Type: TEXT

1392 // */ 1393 // public static final String NAME = "name"; 1394 // 1395 // /** 1396 // * The value of this extension. May not be null. 1397 // *

Type: TEXT

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 // *

Type: INTEGER (long)

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 // *

1480 // * For mailto: 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 // *

1484 // * For tel: 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 // *

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 // *

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 // *

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 // *

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 // *

1581 // * Input: Extra field {@link #FILTER_TEXT_EXTRA_KEY} is the text to use for 1582 // * filtering 1583 // *

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 // *

Type: String

1613 // */ 1614 // public static final String NAME = "name"; 1615 // 1616 // /** 1617 // * The extra field for the contact phonetic name. 1618 // *

Type: String

1619 // */ 1620 // public static final String PHONETIC_NAME = "phonetic_name"; 1621 // 1622 // /** 1623 // * The extra field for the contact company. 1624 // *

Type: String

1625 // */ 1626 // public static final String COMPANY = "company"; 1627 // 1628 // /** 1629 // * The extra field for the contact job title. 1630 // *

Type: String

1631 // */ 1632 // public static final String JOB_TITLE = "job_title"; 1633 // 1634 // /** 1635 // * The extra field for the contact notes. 1636 // *

Type: String

1637 // */ 1638 // public static final String NOTES = "notes"; 1639 // 1640 // /** 1641 // * The extra field for the contact phone number. 1642 // *

Type: String

1643 // */ 1644 // public static final String PHONE = "phone"; 1645 // 1646 // /** 1647 // * The extra field for the contact phone number type. 1648 // *

Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns}, 1649 // * or a string specifying a custom label.

1650 // */ 1651 // public static final String PHONE_TYPE = "phone_type"; 1652 // 1653 // /** 1654 // * The extra field for the phone isprimary flag. 1655 // *

Type: boolean

1656 // */ 1657 // public static final String PHONE_ISPRIMARY = "phone_isprimary"; 1658 // 1659 // /** 1660 // * The extra field for an optional second contact phone number. 1661 // *

Type: String

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 // *

Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns}, 1668 // * or a string specifying a custom label.

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 // *

Type: String

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 // *

Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns}, 1681 // * or a string specifying a custom label.

1682 // */ 1683 // public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type"; 1684 // 1685 // /** 1686 // * The extra field for the contact email address. 1687 // *

Type: String

1688 // */ 1689 // public static final String EMAIL = "email"; 1690 // 1691 // /** 1692 // * The extra field for the contact email type. 1693 // *

Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} 1694 // * or a string specifying a custom label.

1695 // */ 1696 // public static final String EMAIL_TYPE = "email_type"; 1697 // 1698 // /** 1699 // * The extra field for the email isprimary flag. 1700 // *

Type: boolean

1701 // */ 1702 // public static final String EMAIL_ISPRIMARY = "email_isprimary"; 1703 // 1704 // /** 1705 // * The extra field for an optional second contact email address. 1706 // *

Type: String

1707 // */ 1708 // public static final String SECONDARY_EMAIL = "secondary_email"; 1709 // 1710 // /** 1711 // * The extra field for an optional second contact email type. 1712 // *

Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} 1713 // * or a string specifying a custom label.

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 // *

Type: String

1720 // */ 1721 // public static final String TERTIARY_EMAIL = "tertiary_email"; 1722 // 1723 // /** 1724 // * The extra field for an optional third contact email type. 1725 // *

Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} 1726 // * or a string specifying a custom label.

1727 // */ 1728 // public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type"; 1729 // 1730 // /** 1731 // * The extra field for the contact postal address. 1732 // *

Type: String

1733 // */ 1734 // public static final String POSTAL = "postal"; 1735 // 1736 // /** 1737 // * The extra field for the contact postal address type. 1738 // *

Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} 1739 // * or a string specifying a custom label.

1740 // */ 1741 // public static final String POSTAL_TYPE = "postal_type"; 1742 // 1743 // /** 1744 // * The extra field for the postal isprimary flag. 1745 // *

Type: boolean

1746 // */ 1747 // public static final String POSTAL_ISPRIMARY = "postal_isprimary"; 1748 // 1749 // /** 1750 // * The extra field for an IM handle. 1751 // *

Type: String

1752 // */ 1753 // public static final String IM_HANDLE = "im_handle"; 1754 // 1755 // /** 1756 // * The extra field for the IM protocol 1757 // *

Type: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol} 1758 // * or {@link Contacts.ContactMethods#encodeCustomImProtocol}.

1759 // */ 1760 // public static final String IM_PROTOCOL = "im_protocol"; 1761 // 1762 // /** 1763 // * The extra field for the IM isprimary flag. 1764 // *

Type: boolean

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 phoneList = new ArrayList(); // 联系号码
 66     private List email = new ArrayList(); // 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 getPhoneList() {
 87         return phoneList;
 88     }
 89     /** 联系电话信息 */
 90     public ContactInfo setPhoneList(List phoneList) {
 91         this.phoneList = phoneList;
 92         return this;
 93     }
 94     /** 邮箱信息 */
 95     public List getEmail() {
 96         return email;
 97     }
 98     /** 邮箱信息 */
 99     public ContactInfo setEmail(List 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 getContactInfo(Activity context){
142             List infoList = new ArrayList();
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 phoneNumberList = new ArrayList();
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 emailList = new ArrayList();
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 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 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 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 restoreContacts() throws Exception {
270             List contactInfoList = new ArrayList();
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 pimContacts = builder.vNodeList;
292             
293             for (VNode contact : pimContacts) {
294                 
295                 ContactStruct contactStruct=ContactStruct.constructContactFromVNode(contact, 1);
296                 // 获取备份文件中的联系人电话信息
297                 List phoneDataList = contactStruct.phoneList;
298                 List phoneInfoList = new ArrayList();
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 emailList = contactStruct.contactmethodList;
308                 List emailInfoList = new ArrayList();
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 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 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 _infoList = handler.getContactInfo(this);
 8             handler.backupContacts(this, _infoList);    // 备份联系人信息
 9             break;
10 
11         case R.id.restore_linkman:    // 恢复
12             try {
13                 // 获取要恢复的联系人信息
14                 List 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         }
复制代码

你可能感兴趣的:(vcard)