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

原文地址为: Android VCard联系人备份恢复(导入/导出)详解

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

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

raw_contacts表结构:

data表结构:

每个联系人在raw_contacts里有一条记录,像地址,名称,email,电话等等数据都在data存放在data里,这样设计的好处是易扩展,比如要增加一个联系人的email地址时,只要在data里增加一条记录。

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

名字:

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

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

电话:

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

phone: "data1";//号码

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

类型对应关系如下:

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

Email:

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

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

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

类型对应关系如下:

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

地址:

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

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

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

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

 

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

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

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

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

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

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

最后附上导入导出的方法

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

转载请注明本文地址: Android VCard联系人备份恢复(导入/导出)详解

猜你喜欢

转载自blog.csdn.net/xfxf996/article/details/82830560