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