Merge change I170c8251 into eclair-mr2

* changes:
  Add tests and fix vCard code.
This commit is contained in:
Android (Google) Code Review
2009-10-14 19:40:25 -04:00
9 changed files with 1749 additions and 505 deletions

View File

@@ -56,7 +56,7 @@ package android.pim.vcard;
public static final String PROPERTY_X_PHONETIC_MIDDLE_NAME = "X-PHONETIC-MIDDLE-NAME";
public static final String PROPERTY_X_PHONETIC_LAST_NAME = "X-PHONETIC-LAST-NAME";
// Properties both the current (as of 2009-08-17) ContactsStruct and de-fact vCard extensions
// Properties both ContactsStruct in Eclair and de-fact vCard extensions
// shown in http://en.wikipedia.org/wiki/VCard support are defined here.
public static final String PROPERTY_X_AIM = "X-AIM";
public static final String PROPERTY_X_MSN = "X-MSN";
@@ -65,15 +65,12 @@ package android.pim.vcard;
public static final String PROPERTY_X_JABBER = "X-JABBER";
public static final String PROPERTY_X_GOOGLE_TALK = "X-GOOGLE-TALK";
public static final String PROPERTY_X_SKYPE_USERNAME = "X-SKYPE-USERNAME";
// Properties only ContactsStruct has. We alse use this.
public static final String PROPERTY_X_QQ = "X-QQ";
public static final String PROPERTY_X_NETMEETING = "X-NETMEETING";
// Phone number for Skype, available as usual phone.
public static final String PROPERTY_X_SKYPE_PSTNNUMBER = "X-SKYPE-PSTNNUMBER";
// Some device emits this "X-" attribute, which is specifically invalid but should be
// always properly accepted, and emitted in some special case (for that device/application).
public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK";
// Android specific properties
// Use only in vCard paser code.
public static final String PROPERTY_X_NICKNAME = "X-NICKNAME";
// Properties for DoCoMo vCard.
public static final String PROPERTY_X_CLASS = "X-CLASS";
@@ -81,6 +78,11 @@ package android.pim.vcard;
public static final String PROPERTY_X_NO = "X-NO";
public static final String PROPERTY_X_DCM_HMN_MODE = "X-DCM-HMN-MODE";
// For some historical reason, we often use the term "ATTR"/"attribute" especially toward
// what is called "param" in both vCard specs, while vCard, while vCard importer side uses
// "param".
//
// TODO: Confusing. Fix it.
public static final String ATTR_TYPE = "TYPE";
// How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0
@@ -102,13 +104,19 @@ package android.pim.vcard;
public static final String ATTR_TYPE_VOICE = "VOICE";
public static final String ATTR_TYPE_INTERNET = "INTERNET";
// Abbreviation of "preferable"? We interpret this value as "primary" property.
// Abbreviation of "prefered" according to vCard 2.1 specification.
// We interpret this value as "primary" property during import/export.
//
// Note: Both vCard specs does anything about the requirement about this attribute,
// but there may be some vCard importer which will get confused with more than
// one "PREF"s in one property name, while Android accepts them.
public static final String ATTR_TYPE_PREF = "PREF";
// Phone types valid in vCard and known to ContactsContract, but not so common.
public static final String ATTR_TYPE_CAR = "CAR";
public static final String ATTR_TYPE_ISDN = "ISDN";
public static final String ATTR_TYPE_PAGER = "PAGER";
public static final String ATTR_TYPE_TLX = "TLX"; // Telex
// Phone types existing in vCard 2.1 but not known to ContactsContract.
// TODO: should make parser make these TYPE_CUSTOM.
@@ -118,16 +126,16 @@ package android.pim.vcard;
public static final String ATTR_TYPE_VIDEO = "VIDEO";
// Attribute for Phones, which are not formally valid in vCard (at least 2.1).
// These types are encoded to "X-" attributes when composing vCard for now.
// Parser passes these even if "X-" is added to the attribute.
public static final String ATTR_PHONE_EXTRA_TYPE_OTHER = "OTHER";
// These types are basically encoded to "X-" attributes when composing vCard.
// Parser passes these when "X-" is added to the attribute or not.
public static final String ATTR_PHONE_EXTRA_TYPE_CALLBACK = "CALLBACK";
// TODO: may be "TYPE=COMPANY,PREF", not "COMPANY-MAIN".
public static final String ATTR_PHONE_EXTRA_TYPE_COMPANY_MAIN = "COMPANY-MAIN";
public static final String ATTR_PHONE_EXTRA_TYPE_RADIO = "RADIO";
public static final String ATTR_PHONE_EXTRA_TYPE_TELEX = "TELEX";
public static final String ATTR_PHONE_EXTRA_TYPE_TTY_TDD = "TTY-TDD";
public static final String ATTR_PHONE_EXTRA_TYPE_ASSISTANT = "ASSISTANT";
// vCard composer translates this type to "WORK" + "PREF". Just for parsing.
public static final String ATTR_PHONE_EXTRA_TYPE_COMPANY_MAIN = "COMPANY-MAIN";
// vCard composer translates this type to "VOICE" Just for parsing.
public static final String ATTR_PHONE_EXTRA_TYPE_OTHER = "OTHER";
// Attribute for addresses.
public static final String ATTR_ADR_TYPE_PARCEL = "PARCEL";
@@ -142,6 +150,14 @@ package android.pim.vcard;
// vCard 3.0.
public static final String ATTR_TYPE_X_IRMC_N = "X-IRMC-N";
public interface ImportOnly {
public static final String PROPERTY_X_NICKNAME = "X-NICKNAME";
// Some device emits this "X-" attribute for expressing Google Talk,
// which is specifically invalid but should be always properly accepted, and emitted
// in some special case (for that device/application).
public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK";
}
private Constants() {
}
}

View File

@@ -68,7 +68,8 @@ public class ContactStruct {
sImMap.put(Constants.PROPERTY_X_JABBER, Im.PROTOCOL_JABBER);
sImMap.put(Constants.PROPERTY_X_SKYPE_USERNAME, Im.PROTOCOL_SKYPE);
sImMap.put(Constants.PROPERTY_X_GOOGLE_TALK, Im.PROTOCOL_GOOGLE_TALK);
sImMap.put(Constants.PROPERTY_X_GOOGLE_TALK_WITH_SPACE, Im.PROTOCOL_GOOGLE_TALK);
sImMap.put(Constants.ImportOnly.PROPERTY_X_GOOGLE_TALK_WITH_SPACE,
Im.PROTOCOL_GOOGLE_TALK);
}
static public class PhoneData {
@@ -292,16 +293,18 @@ public class ContactStruct {
}
static public class ImData {
public final int protocol;
public final String customProtocol;
public final int type;
public final String data;
public final String label;
public final boolean isPrimary;
// TODO: ContactsConstant#PROTOCOL, ContactsConstant#CUSTOM_PROTOCOL should be used?
public ImData(int type, String data, String label, boolean isPrimary) {
public ImData(int protocol, String customProtocol, int type,
String data, boolean isPrimary) {
this.protocol = protocol;
this.customProtocol = customProtocol;
this.type = type;
this.data = data;
this.label = label;
this.isPrimary = isPrimary;
}
@@ -311,14 +314,18 @@ public class ContactStruct {
return false;
}
ImData imData = (ImData)obj;
return (type == imData.type && data.equals(imData.data) &&
label.equals(imData.label) && isPrimary == imData.isPrimary);
return (type == imData.type && protocol == imData.protocol
&& (customProtocol != null ? customProtocol.equals(imData.customProtocol) :
(imData.customProtocol == null))
&& (data != null ? data.equals(imData.data) : (imData.data == null))
&& isPrimary == imData.isPrimary);
}
@Override
public String toString() {
return String.format("type: %d, data: %s, label: %s, isPrimary: %s",
type, data, label, isPrimary);
return String.format(
"type: %d, protocol: %d, custom_protcol: %s, data: %s, isPrimary: %s",
type, protocol, customProtocol, data, isPrimary);
}
}
@@ -440,7 +447,7 @@ public class ContactStruct {
private final Account mAccount;
public ContactStruct() {
this(VCardConfig.VCARD_TYPE_V21_GENERIC);
this(VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
}
public ContactStruct(int vcardType) {
@@ -619,11 +626,12 @@ public class ContactStruct {
addNewOrganization(DEFAULT_ORGANIZATION_TYPE, null, null, title, false);
}
private void addIm(int type, String data, String label, boolean isPrimary) {
private void addIm(int protocol, String customProtocol, int type,
String propValue, boolean isPrimary) {
if (mImList == null) {
mImList = new ArrayList<ImData>();
}
mImList.add(new ImData(type, data, label, isPrimary));
mImList.add(new ImData(protocol, customProtocol, type, propValue, isPrimary));
}
private void addNote(final String note) {
@@ -720,7 +728,7 @@ public class ContactStruct {
} else if (propName.equals(Constants.PROPERTY_NICKNAME)) {
mPhoneticFullName = propValue;
} else if (propName.equals(Constants.PROPERTY_NICKNAME) ||
propName.equals(Constants.PROPERTY_X_NICKNAME)) {
propName.equals(Constants.ImportOnly.PROPERTY_X_NICKNAME)) {
addNickName(propValue);
} else if (propName.equals(Constants.PROPERTY_SOUND)) {
Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
@@ -891,25 +899,28 @@ public class ContactStruct {
isPrimary = false;
}
addPhone(type, propValue, label, isPrimary);
} else if (sImMap.containsKey(propName)){
int type = sImMap.get(propName);
} else if (sImMap.containsKey(propName)) {
final int protocol = sImMap.get(propName);
boolean isPrimary = false;
int type = -1;
final Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
if (typeCollection != null) {
for (String typeString : typeCollection) {
if (typeString.equals(Constants.ATTR_TYPE_PREF)) {
isPrimary = true;
} else if (typeString.equalsIgnoreCase(Constants.ATTR_TYPE_HOME)) {
type = Phone.TYPE_HOME;
} else if (typeString.equalsIgnoreCase(Constants.ATTR_TYPE_WORK)) {
type = Phone.TYPE_WORK;
} else if (type < 0) {
if (typeString.equalsIgnoreCase(Constants.ATTR_TYPE_HOME)) {
type = Im.TYPE_HOME;
} else if (typeString.equalsIgnoreCase(Constants.ATTR_TYPE_WORK)) {
type = Im.TYPE_WORK;
}
}
}
}
if (type < 0) {
type = Phone.TYPE_HOME;
}
addIm(type, propValue, null, isPrimary);
addIm(protocol, null, type, propValue, isPrimary);
} else if (propName.equals(Constants.PROPERTY_NOTE)) {
addNote(propValue);
} else if (propName.equals(Constants.PROPERTY_URL)) {
@@ -1158,10 +1169,10 @@ public class ContactStruct {
builder.withValueBackReference(Im.RAW_CONTACT_ID, 0);
builder.withValue(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
builder.withValue(Im.TYPE, imData.type);
if (imData.type == Im.TYPE_CUSTOM) {
builder.withValue(Im.LABEL, imData.label);
builder.withValue(Im.PROTOCOL, imData.protocol);
if (imData.protocol == Im.PROTOCOL_CUSTOM) {
builder.withValue(Im.CUSTOM_PROTOCOL, imData.customProtocol);
}
builder.withValue(Im.DATA, imData.data);
if (imData.isPrimary) {
builder.withValue(Data.IS_PRIMARY, 1);
}

File diff suppressed because it is too large Load Diff

View File

@@ -15,14 +15,20 @@
*/
package android.pim.vcard;
import android.util.Log;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* The class representing VCard related configurations. Useful static methods are not in this class
* but in VCardUtils.
*/
public class VCardConfig {
private static final String LOG_TAG = "vcard.VCardConfig";
// TODO: may be better to make the instance of this available and stop using static methods and
// one integer.
@@ -95,18 +101,63 @@ public class VCardConfig {
private static final int FLAG_DOCOMO = 0x20000000;
/**
* The flag indicating the vCard composer use Quoted-Printable toward even "primary" types.
* In this context, "primary" types means "N", "FN", etc. which are usually "not" encoded
* into Quoted-Printable format in external exporters.
* This flag is useful when some target importer does not accept "primary" property values
* without Quoted-Printable encoding.
*
* @hide Temporaly made public. We don't strictly define "primary", so we may change the
* behavior around this flag in the future. Do not use this flag without any reason.
* <P>
* The flag indicating the vCard composer does "NOT" use Quoted-Printable toward "primary"
* properties even though it is required by vCard 2.1 (QP is prohibited in vCard 3.0).
* </P>
* <P>
* We actually cannot define what is the "primary" property. Note that this is NOT defined
* in vCard specification either. Also be aware that it is NOT related to "primary" notion
* used in {@link android.provider.ContactsContract}.
* This notion is just for vCard composition in Android.
* </P>
* <P>
* We added this Android-specific notion since some (incomplete) vCard exporters for vCard 2.1
* do NOT use Quoted-Printable encoding toward some properties like "N", "FN", etc. even when
* their values contain non-ascii or/and CR/LF, while they use the encoding in the other
* properties like "ADR", "ORG", etc.
* <P>
* We are afraid of the case where some vCard importer also forget handling QP presuming QP is
* not used in such fields.
* </P>
* <P>
* This flag is useful when some target importer you are going to focus on does not accept
* such "primary" property values with Quoted-Printable encoding.
* </P>
* <P>
* Again, we should not use this flag at all for complying vCard 2.1 spec.
* </P>
* <P>
* We will change the behavior around this flag in the future, after understanding the other
* real vCard cases around this problem. Please use this flag with extreme caution even when
* needed.
* </P>
* <P>
* In vCard 3.0, Quoted-Printable is explicitly "prohibitted", so we don't need to care this
* kind of problem (hopefully).
* </P>
*/
public static final int FLAG_USE_QP_TO_PRIMARY_PROPERTIES = 0x10000000;
public static final int FLAG_REFRAIN_QP_TO_PRIMARY_PROPERTIES = 0x10000000;
/**
* <P>
* The flag indicating that phonetic name related fields must be converted to
* appropriate form. Note that "appropriate" is not defined in any vCard specification.
* This is Android-specific.
* </P>
* <P>
* One typical (and currently sole) example where we need this flag is the time when
* we need to emit Japanese phonetic names into vCard entries. The property values
* should be encoded into half-width katakana when the target importer is Japanese mobile
* phones', which are probably not able to parse full-width hiragana/katakana for
* historical reasons, while the vCard importers embedded to softwares for PC should be
* able to parse them as we expect.
* </P>
*/
public static final int FLAG_CONVERT_PHONETIC_NAME_STRINGS = 0x0800000;
/**
* <P>
* The flag indicating the vCard composer "for 2.1" emits "TYPE=" string every time
* possible. The default behavior does not emit it and is valid, while adding "TYPE="
* is also valid. In vCrad 3.0, this flag is unnecessary, since "TYPE=" is MUST in
@@ -119,87 +170,118 @@ public class VCardConfig {
*
* e.g. int vcardType = (VCARD_TYPE_V21_GENERIC | FLAG_APPEND_TYPE_PARAM);
*/
public static final int FLAG_APPEND_TYPE_PARAM = 0x08000000;
public static final int FLAG_APPEND_TYPE_PARAM = 0x04000000;
//// The followings are VCard types available from importer/exporter. ////
/**
* <P>
* General vCard format with the version 2.1. Uses UTF-8 for the charset.
* When composing a vCard entry, the US convension will be used.
*
* When composing a vCard entry, the US convension will be used toward formatting
* some values
* </P>
* <P>
* e.g. The order of the display name would be "Prefix Given Middle Family Suffix",
* while in Japan, it should be "Prefix Family Middle Given Suffix".
* while it should be "Prefix Family Middle Given Suffix" in Japan.
* </P>
*/
public static final int VCARD_TYPE_V21_GENERIC =
public static final int VCARD_TYPE_V21_GENERIC_UTF8 =
(FLAG_V21 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static String VCARD_TYPE_V21_GENERIC_STR = "v21_generic";
/* package */ static String VCARD_TYPE_V21_GENERIC_UTF8_STR = "v21_generic";
/**
* <P>
* General vCard format with the version 3.0. Uses UTF-8 for the charset.
*
* Note that this type is not fully implemented, so probably some bugs remain both in
* parsing and composing.
*
* TODO: implement this type correctly.
* </P>
* <P>
* Not ready yet. Use with caution when you use this.
* </P>
*/
public static final int VCARD_TYPE_V30_GENERIC =
public static final int VCARD_TYPE_V30_GENERIC_UTF8 =
(FLAG_V30 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V30_GENERIC_STR = "v30_generic";
/* package */ static final String VCARD_TYPE_V30_GENERIC_UTF8_STR = "v30_generic";
/**
* General vCard format with the version 2.1 with some Europe convension. Uses Utf-8.
* <P>
* General vCard format for the vCard 2.1 with some Europe convension. Uses Utf-8.
* Currently, only name order is considered ("Prefix Middle Given Family Suffix")
* </P>
*/
public static final int VCARD_TYPE_V21_EUROPE =
public static final int VCARD_TYPE_V21_EUROPE_UTF8 =
(FLAG_V21 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V21_EUROPE_STR = "v21_europe";
/* package */ static final String VCARD_TYPE_V21_EUROPE_UTF8_STR = "v21_europe";
/**
* <P>
* General vCard format with the version 3.0 with some Europe convension. Uses UTF-8
* </P>
* <P>
* Not ready yet. Use with caution when you use this.
* </P>
*/
public static final int VCARD_TYPE_V30_EUROPE =
public static final int VCARD_TYPE_V30_EUROPE_UTF8 =
(FLAG_V30 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V30_EUROPE_STR = "v30_europe";
/**
* vCard 2.1 format for miscellaneous Japanese devices. Shift_Jis is used for
* parsing/composing the vCard data.
*/
public static final int VCARD_TYPE_V21_JAPANESE =
(FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V21_JAPANESE_STR = "v21_japanese";
/**
* vCard 2.1 format for miscellaneous Japanese devices, using UTF-8 as default charset.
* <P>
* The vCard 2.1 format for miscellaneous Japanese devices, using UTF-8 as default charset.
* </P>
* <P>
* Not ready yet. Use with caution when you use this.
* </P>
*/
public static final int VCARD_TYPE_V21_JAPANESE_UTF8 =
(FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V21_JAPANESE_UTF8_STR = "v21_japanese_utf8";
/**
* <P>
* vCard 2.1 format for miscellaneous Japanese devices. Shift_Jis is used for
* parsing/composing the vCard data.
* </P>
* <P>
* Not ready yet. Use with caution when you use this.
* </P>
*/
public static final int VCARD_TYPE_V21_JAPANESE_SJIS =
(FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V21_JAPANESE_SJIS_STR = "v21_japanese_sjis";
/**
* <P>
* vCard format for miscellaneous Japanese devices, using Shift_Jis for
* parsing/composing the vCard data.
* </P>
* <P>
* Not ready yet. Use with caution when you use this.
* </P>
*/
public static final int VCARD_TYPE_V30_JAPANESE =
public static final int VCARD_TYPE_V30_JAPANESE_SJIS =
(FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V30_JAPANESE_STR = "v30_japanese";
/* package */ static final String VCARD_TYPE_V30_JAPANESE_SJIS_STR = "v30_japanese_sjis";
/**
* vCard 3.0 format for miscellaneous Japanese devices, using UTF-8 as default charset.
* <P>
* The vCard 3.0 format for miscellaneous Japanese devices, using UTF-8 as default charset.
* </P>
* <P>
* Not ready yet. Use with caution when you use this.
* </P>
*/
public static final int VCARD_TYPE_V30_JAPANESE_UTF8 =
(FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
@@ -208,38 +290,72 @@ public class VCardConfig {
/* package */ static final String VCARD_TYPE_V30_JAPANESE_UTF8_STR = "v30_japanese_utf8";
/**
* VCard format used in DoCoMo, which is one of Japanese mobile phone careers.
* Base version is vCard 2.1, but the data has several DoCoMo-specific convensions.
* No Android-specific property nor defact property is included.
* <P>
* The vCard 2.1 based format which (partially) considers the convention in Japanese
* mobile phones, where phonetic names are translated to half-width katakana if
* possible, etc.
* </P>
* <P>
* Not ready yet. Use with caution when you use this.
* </P>
*/
public static final int VCARD_TYPE_V21_JAPANESE_MOBILE =
(FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
FLAG_CONVERT_PHONETIC_NAME_STRINGS |
FLAG_REFRAIN_QP_TO_PRIMARY_PROPERTIES);
public static final String VCARD_TYPE_V21_JAPANESE_MOBILE_STR = "v21_japanese_mobile";
/**
* <P>
* VCard format used in DoCoMo, which is one of Japanese mobile phone careers.
* </p>
* <P>
* Base version is vCard 2.1, but the data has several DoCoMo-specific convensions.
* No Android-specific property nor defact property is included. The "Primary" properties
* are NOT encoded to Quoted-Printable.
* </P>
*/
public static final int VCARD_TYPE_DOCOMO =
(FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS | FLAG_DOCOMO);
(VCARD_TYPE_V21_JAPANESE_MOBILE | FLAG_DOCOMO);
private static final String VCARD_TYPE_DOCOMO_STR = "docomo";
public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC;
public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC_UTF8;
private static final Map<String, Integer> VCARD_TYPES_MAP;
private static final Map<String, Integer> sVCardTypeMap;
private static final Set<Integer> sJapaneseMobileTypeSet;
static {
VCARD_TYPES_MAP = new HashMap<String, Integer>();
VCARD_TYPES_MAP.put(VCARD_TYPE_V21_GENERIC_STR, VCARD_TYPE_V21_GENERIC);
VCARD_TYPES_MAP.put(VCARD_TYPE_V30_GENERIC_STR, VCARD_TYPE_V30_GENERIC);
VCARD_TYPES_MAP.put(VCARD_TYPE_V21_EUROPE_STR, VCARD_TYPE_V21_EUROPE);
VCARD_TYPES_MAP.put(VCARD_TYPE_V30_EUROPE_STR, VCARD_TYPE_V30_EUROPE);
VCARD_TYPES_MAP.put(VCARD_TYPE_V21_JAPANESE_STR, VCARD_TYPE_V21_JAPANESE);
VCARD_TYPES_MAP.put(VCARD_TYPE_V21_JAPANESE_UTF8_STR, VCARD_TYPE_V21_JAPANESE_UTF8);
VCARD_TYPES_MAP.put(VCARD_TYPE_V30_JAPANESE_STR, VCARD_TYPE_V30_JAPANESE);
VCARD_TYPES_MAP.put(VCARD_TYPE_V30_JAPANESE_UTF8_STR, VCARD_TYPE_V30_JAPANESE_UTF8);
VCARD_TYPES_MAP.put(VCARD_TYPE_DOCOMO_STR, VCARD_TYPE_DOCOMO);
sVCardTypeMap = new HashMap<String, Integer>();
sVCardTypeMap.put(VCARD_TYPE_V21_GENERIC_UTF8_STR, VCARD_TYPE_V21_GENERIC_UTF8);
sVCardTypeMap.put(VCARD_TYPE_V30_GENERIC_UTF8_STR, VCARD_TYPE_V30_GENERIC_UTF8);
sVCardTypeMap.put(VCARD_TYPE_V21_EUROPE_UTF8_STR, VCARD_TYPE_V21_EUROPE_UTF8);
sVCardTypeMap.put(VCARD_TYPE_V30_EUROPE_STR, VCARD_TYPE_V30_EUROPE_UTF8);
sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_SJIS_STR, VCARD_TYPE_V21_JAPANESE_SJIS);
sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_UTF8_STR, VCARD_TYPE_V21_JAPANESE_UTF8);
sVCardTypeMap.put(VCARD_TYPE_V30_JAPANESE_SJIS_STR, VCARD_TYPE_V30_JAPANESE_SJIS);
sVCardTypeMap.put(VCARD_TYPE_V30_JAPANESE_UTF8_STR, VCARD_TYPE_V30_JAPANESE_UTF8);
sVCardTypeMap.put(VCARD_TYPE_V21_JAPANESE_MOBILE_STR, VCARD_TYPE_V21_JAPANESE_MOBILE);
sVCardTypeMap.put(VCARD_TYPE_DOCOMO_STR, VCARD_TYPE_DOCOMO);
sJapaneseMobileTypeSet = new HashSet<Integer>();
sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE_SJIS);
sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE_UTF8);
sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE_SJIS);
sJapaneseMobileTypeSet.add(VCARD_TYPE_V30_JAPANESE_SJIS);
sJapaneseMobileTypeSet.add(VCARD_TYPE_V30_JAPANESE_UTF8);
sJapaneseMobileTypeSet.add(VCARD_TYPE_V21_JAPANESE_MOBILE);
sJapaneseMobileTypeSet.add(VCARD_TYPE_DOCOMO);
}
public static int getVCardTypeFromString(String vcardTypeString) {
String loweredKey = vcardTypeString.toLowerCase();
if (VCARD_TYPES_MAP.containsKey(loweredKey)) {
return VCARD_TYPES_MAP.get(loweredKey);
if (sVCardTypeMap.containsKey(loweredKey)) {
return sVCardTypeMap.get(loweredKey);
} else {
// XXX: should return the value indicating the input is invalid?
Log.e(LOG_TAG, "Unknown vCard type String: \"" + vcardTypeString + "\"");
return VCARD_TYPE_DEFAULT;
}
}
@@ -252,22 +368,6 @@ public class VCardConfig {
return !isV30(vcardType);
}
public static boolean isDoCoMo(int vcardType) {
return ((vcardType & FLAG_DOCOMO) != 0);
}
/**
* @return true if the device is Japanese and some Japanese convension is
* applied to creating "formatted" something like FORMATTED_ADDRESS.
*/
public static boolean isJapaneseDevice(int vcardType) {
return ((vcardType == VCARD_TYPE_V21_JAPANESE) ||
(vcardType == VCARD_TYPE_V21_JAPANESE_UTF8) ||
(vcardType == VCARD_TYPE_V30_JAPANESE) ||
(vcardType == VCARD_TYPE_V30_JAPANESE_UTF8) ||
(vcardType == VCARD_TYPE_DOCOMO));
}
public static boolean usesUtf8(int vcardType) {
return ((vcardType & FLAG_CHARSET_UTF8) != 0);
}
@@ -276,17 +376,6 @@ public class VCardConfig {
return ((vcardType & FLAG_CHARSET_SHIFT_JIS) != 0);
}
/**
* @return true when Japanese phonetic string must be converted to a string
* containing only half-width katakana. This method exists since Japanese mobile
* phones usually use only half-width katakana for expressing phonetic names and
* some devices are not ready for parsing other phonetic strings like hiragana and
* full-width katakana.
*/
public static boolean needsToConvertPhoneticString(int vcardType) {
return (vcardType == VCARD_TYPE_DOCOMO);
}
public static int getNameOrderType(int vcardType) {
return vcardType & NAME_ORDER_MASK;
}
@@ -299,24 +388,37 @@ public class VCardConfig {
return ((vcardType & FLAG_USE_DEFACT_PROPERTY) != 0);
}
public static boolean onlyOneNoteFieldIsAvailable(int vcardType) {
return vcardType == VCARD_TYPE_DOCOMO;
}
public static boolean showPerformanceLog() {
return (VCardConfig.LOG_LEVEL & VCardConfig.LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0;
}
/**
* @hide
*/
public static boolean usesQPToPrimaryProperties(int vcardType) {
return (usesQuotedPrintable(vcardType) &&
((vcardType & FLAG_USE_QP_TO_PRIMARY_PROPERTIES) != 0));
public static boolean refrainsQPToPrimaryProperties(int vcardType) {
return (!usesQuotedPrintable(vcardType) ||
((vcardType & FLAG_REFRAIN_QP_TO_PRIMARY_PROPERTIES) != 0));
}
public static boolean appendTypeParamName(int vcardType) {
return (vcardType & FLAG_APPEND_TYPE_PARAM) != 0;
return (isV30(vcardType) || ((vcardType & FLAG_APPEND_TYPE_PARAM) != 0));
}
/**
* @return true if the device is Japanese and some Japanese convension is
* applied to creating "formatted" something like FORMATTED_ADDRESS.
*/
public static boolean isJapaneseDevice(int vcardType) {
return sJapaneseMobileTypeSet.contains(vcardType);
}
public static boolean needsToConvertPhoneticString(int vcardType) {
return ((vcardType & FLAG_CONVERT_PHONETIC_NAME_STRINGS) != 0);
}
public static boolean onlyOneNoteFieldIsAvailable(int vcardType) {
return vcardType == VCARD_TYPE_DOCOMO;
}
public static boolean isDoCoMo(int vcardType) {
return ((vcardType & FLAG_DOCOMO) != 0);
}
private VCardConfig() {

View File

@@ -69,7 +69,7 @@ public class VCardDataBuilder implements VCardBuilder {
private List<EntryHandler> mEntryHandlers = new ArrayList<EntryHandler>();
public VCardDataBuilder() {
this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC, null);
this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8, null);
}
/**

View File

@@ -18,6 +18,7 @@ package android.pim.vcard;
import android.content.ContentProviderOperation;
import android.content.ContentValues;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.text.TextUtils;
@@ -44,38 +45,49 @@ public class VCardUtils {
private static final Map<Integer, String> sKnownPhoneTypesMap_ItoS;
private static final Set<String> sPhoneTypesSetUnknownToContacts;
private static final Map<String, Integer> sKnownPhoneTypesMap_StoI;
private static final Map<String, Integer> sKnownPhoneTypeMap_StoI;
private static final Map<Integer, String> sKnownImPropNameMap_ItoS;
static {
sKnownPhoneTypesMap_ItoS = new HashMap<Integer, String>();
sKnownPhoneTypesMap_StoI = new HashMap<String, Integer>();
sKnownPhoneTypeMap_StoI = new HashMap<String, Integer>();
sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_CAR, Constants.ATTR_TYPE_CAR);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_CAR, Phone.TYPE_CAR);
sKnownPhoneTypeMap_StoI.put(Constants.ATTR_TYPE_CAR, Phone.TYPE_CAR);
sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_PAGER, Constants.ATTR_TYPE_PAGER);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PAGER, Phone.TYPE_PAGER);
sKnownPhoneTypeMap_StoI.put(Constants.ATTR_TYPE_PAGER, Phone.TYPE_PAGER);
sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_ISDN, Constants.ATTR_TYPE_ISDN);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_ISDN, Phone.TYPE_ISDN);
sKnownPhoneTypeMap_StoI.put(Constants.ATTR_TYPE_ISDN, Phone.TYPE_ISDN);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_HOME, Phone.TYPE_HOME);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_WORK, Phone.TYPE_WORK);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_CELL, Phone.TYPE_MOBILE);
sKnownPhoneTypeMap_StoI.put(Constants.ATTR_TYPE_HOME, Phone.TYPE_HOME);
sKnownPhoneTypeMap_StoI.put(Constants.ATTR_TYPE_WORK, Phone.TYPE_WORK);
sKnownPhoneTypeMap_StoI.put(Constants.ATTR_TYPE_CELL, Phone.TYPE_MOBILE);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_PHONE_EXTRA_TYPE_OTHER, Phone.TYPE_OTHER);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_PHONE_EXTRA_TYPE_CALLBACK, Phone.TYPE_CALLBACK);
sKnownPhoneTypesMap_StoI.put(
sKnownPhoneTypeMap_StoI.put(Constants.ATTR_PHONE_EXTRA_TYPE_OTHER, Phone.TYPE_OTHER);
sKnownPhoneTypeMap_StoI.put(Constants.ATTR_PHONE_EXTRA_TYPE_CALLBACK, Phone.TYPE_CALLBACK);
sKnownPhoneTypeMap_StoI.put(
Constants.ATTR_PHONE_EXTRA_TYPE_COMPANY_MAIN, Phone.TYPE_COMPANY_MAIN);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_PHONE_EXTRA_TYPE_RADIO, Phone.TYPE_RADIO);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_PHONE_EXTRA_TYPE_TELEX, Phone.TYPE_TELEX);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_PHONE_EXTRA_TYPE_TTY_TDD, Phone.TYPE_TTY_TDD);
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_PHONE_EXTRA_TYPE_ASSISTANT,
sKnownPhoneTypeMap_StoI.put(Constants.ATTR_PHONE_EXTRA_TYPE_RADIO, Phone.TYPE_RADIO);
sKnownPhoneTypeMap_StoI.put(Constants.ATTR_PHONE_EXTRA_TYPE_TTY_TDD, Phone.TYPE_TTY_TDD);
sKnownPhoneTypeMap_StoI.put(Constants.ATTR_PHONE_EXTRA_TYPE_ASSISTANT,
Phone.TYPE_ASSISTANT);
sPhoneTypesSetUnknownToContacts = new HashSet<String>();
sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_MODEM);
sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_MSG);
sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_BBS);
sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_VIDEO);
sKnownImPropNameMap_ItoS = new HashMap<Integer, String>();
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_AIM, Constants.PROPERTY_X_AIM);
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_MSN, Constants.PROPERTY_X_MSN);
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_YAHOO, Constants.PROPERTY_X_YAHOO);
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_SKYPE, Constants.PROPERTY_X_SKYPE_USERNAME);
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_GOOGLE_TALK, Constants.PROPERTY_X_GOOGLE_TALK);
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_ICQ, Constants.PROPERTY_X_ICQ);
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_JABBER, Constants.PROPERTY_X_JABBER);
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_QQ, Constants.PROPERTY_X_QQ);
sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_NETMEETING, Constants.PROPERTY_X_NETMEETING);
}
public static String getPhoneAttributeString(Integer type) {
@@ -103,7 +115,7 @@ public class VCardUtils {
if (typeString.startsWith("X-") && type < 0) {
typeString = typeString.substring(2);
}
Integer tmp = sKnownPhoneTypesMap_StoI.get(typeString);
Integer tmp = sKnownPhoneTypeMap_StoI.get(typeString);
if (tmp != null) {
type = tmp;
} else if (type < 0) {
@@ -136,7 +148,11 @@ public class VCardUtils {
return type;
}
}
public static String getPropertyNameForIm(int protocol) {
return sKnownImPropNameMap_ItoS.get(protocol);
}
public static boolean isValidPhoneAttribute(String phoneAttribute, int vcardType) {
// TODO: check the following.
// - it may violate vCard spec
@@ -206,12 +222,12 @@ public class VCardUtils {
builder.withValue(Data.IS_PRIMARY, 1);
}
}
/**
* Returns String[] containing address information based on vCard spec
* (PO Box, Extended Address, Street, Locality, Region, Postal Code, Country Name).
* All String objects are non-null ("" is used when the relevant data is empty).
*
*
* Note that the data structure of ContactsContract is different from that defined in vCard.
* So some conversion may be performed in this method. See also
* {{@link #insertStructuredPostalDataUsingContactsStruct(int,
@@ -219,13 +235,20 @@ public class VCardUtils {
* android.pim.vcard.ContactStruct.PostalData)}
*/
public static String[] getVCardPostalElements(ContentValues contentValues) {
// adr-value = 0*6(text-value ";") text-value
// ; PO Box, Extended Address, Street, Locality, Region, Postal
// ; Code, Country Name
String[] dataArray = new String[7];
dataArray[0] = contentValues.getAsString(StructuredPostal.POBOX);
if (dataArray[0] == null) {
dataArray[0] = "";
}
// Extended addr. There's no relevant data in ContactsContract.
dataArray[1] = "";
// We keep all the data in StructuredPostal, presuming NEIGHBORHOOD is
// similar to "Extended Address".
dataArray[1] = contentValues.getAsString(StructuredPostal.NEIGHBORHOOD);
if (dataArray[1] == null) {
dataArray[1] = "";
}
dataArray[2] = contentValues.getAsString(StructuredPostal.STREET);
if (dataArray[2] == null) {
dataArray[2] = "";

View File

@@ -230,6 +230,6 @@ public class PropertyNodesVerifier {
}
mTestCase.fail("Property \"" + propName + "\" has wrong value.\n"
+ builder.toString()
+ " actual: " + actualNode.toString());
+ " actual: " + actualNode.toString());
}
}

View File

@@ -44,8 +44,17 @@ import android.pim.vcard.exception.VCardException;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Nickname;
import android.provider.ContactsContract.CommonDataKinds.Note;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
import android.test.AndroidTestCase;
import android.test.mock.MockContentResolver;
import android.test.mock.MockContext;
@@ -147,7 +156,10 @@ class MockContentProvider extends ContentProvider {
* the result of this class will not be reliable.
*/
public class VCardExporterTests extends AndroidTestCase {
/* package */ static final byte[] sPhotoByteArray =
private static final int V21 = 0;
private static final int V30 = 1;
private static final byte[] sPhotoByteArray =
VCardImporterTests.sPhotoByteArrayForComplicatedCase;
public class ExportTestResolver extends MockContentResolver {
@@ -282,17 +294,26 @@ public class VCardExporterTests extends AndroidTestCase {
final private boolean mIsV30;
int mCount;
public VCardVerificationHandler(TestCase testCase, boolean isV30) {
public VCardVerificationHandler(TestCase testCase, int version) {
mTestCase = testCase;
mPropertyNodesVerifierList = new ArrayList<PropertyNodesVerifier>();
mIsV30 = isV30;
mIsV30 = (version == V30);
mCount = 1;
}
public PropertyNodesVerifier addNewPropertyNodesVerifier() {
PropertyNodesVerifier propertyNodesVerifier = new PropertyNodesVerifier(mTestCase);
mPropertyNodesVerifierList.add(propertyNodesVerifier);
return propertyNodesVerifier;
public PropertyNodesVerifier addNewVerifier() {
PropertyNodesVerifier verifier = new PropertyNodesVerifier(mTestCase);
mPropertyNodesVerifierList.add(verifier);
verifier.addNodeWithOrder("VERSION", mIsV30 ? "3.0" : "2.1");
return verifier;
}
public PropertyNodesVerifier addNewVerifierWithEmptyName() {
PropertyNodesVerifier verifier = addNewVerifier();
if (mIsV30) {
verifier.addNodeWithOrder("N", "").addNodeWithOrder("FN", "");
}
return verifier;
}
public boolean onInit(Context context) {
@@ -344,50 +365,12 @@ public class VCardExporterTests extends AndroidTestCase {
//// Followings are actual tests ////
public void testSimple() {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "Ando");
contentValues.put(StructuredName.GIVEN_NAME, "Roid");
private void verifyOneComposition(ExportTestResolver resolver,
VCardVerificationHandler handler, int version) {
final boolean isV30 = (version == V30);
VCardVerificationHandler handler = new VCardVerificationHandler(this, false);
handler.addNewPropertyNodesVerifier()
.addNodeWithOrder("VERSION", "2.1")
.addNodeWithoutOrder("FN", "Roid Ando")
.addNodeWithoutOrder("N", "Ando;Roid;;;", Arrays.asList("Ando", "Roid", "", "", ""));
VCardComposer composer = new VCardComposer(new CustomMockContext(resolver),
VCardConfig.VCARD_TYPE_V21_GENERIC);
composer.addHandler(handler);
if (!composer.init(VCardComposer.CONTACTS_TEST_CONTENT_URI, null, null, null)) {
fail("init failed. Reason: " + composer.getErrorReason());
}
assertFalse(composer.isAfterLast());
assertTrue(composer.createOneEntry());
assertTrue(composer.isAfterLast());
composer.terminate();
}
private void testPhotoCommon(boolean isV30) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "PhotoTest");
contentValues = resolver.buildData(Photo.CONTENT_ITEM_TYPE);
contentValues.put(Photo.PHOTO, sPhotoByteArray);
ContentValues contentValuesForPhoto = new ContentValues();
contentValuesForPhoto.put("ENCODING", (isV30 ? "b" : "BASE64"));
VCardVerificationHandler handler = new VCardVerificationHandler(this, isV30);
handler.addNewPropertyNodesVerifier()
.addNodeWithOrder("VERSION", (isV30 ? "3.0" : "2.1"))
.addNodeWithoutOrder("FN", "PhotoTest")
.addNodeWithoutOrder("N", "PhotoTest;;;;", Arrays.asList("PhotoTest", "", "", "", ""))
.addNodeWithOrder("PHOTO", null, null, sPhotoByteArray,
contentValuesForPhoto, new TypeSet("JPEG"), null);
int vcardType = (isV30 ? VCardConfig.VCARD_TYPE_V30_GENERIC
: VCardConfig.VCARD_TYPE_V21_GENERIC);
int vcardType = (isV30 ? VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8
: VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
VCardComposer composer = new VCardComposer(new CustomMockContext(resolver), vcardType);
composer.addHandler(handler);
if (!composer.init(VCardComposer.CONTACTS_TEST_CONTENT_URI, null, null, null)) {
@@ -399,11 +382,830 @@ public class VCardExporterTests extends AndroidTestCase {
composer.terminate();
}
public void testSimpleV21() {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "Ando");
contentValues.put(StructuredName.GIVEN_NAME, "Roid");
VCardVerificationHandler handler = new VCardVerificationHandler(this, V21);
handler.addNewVerifier()
.addNodeWithoutOrder("FN", "Roid Ando")
.addNodeWithoutOrder("N", "Ando;Roid;;;", Arrays.asList("Ando", "Roid", "", "", ""));
verifyOneComposition(resolver, handler, V21);
}
private void testStructuredNameBasic(int version) {
final boolean isV30 = (version == V30);
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "AppropriateFamilyName");
contentValues.put(StructuredName.GIVEN_NAME, "AppropriateGivenName");
contentValues.put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName");
contentValues.put(StructuredName.PREFIX, "AppropriatePrefix");
contentValues.put(StructuredName.SUFFIX, "AppropriateSuffix");
contentValues.put(StructuredName.PHONETIC_FAMILY_NAME, "AppropriatePhoneticFamily");
contentValues.put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven");
contentValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle");
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
PropertyNodesVerifier verifier = handler.addNewVerifier()
.addNodeWithOrder("N",
"AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
+ "AppropriatePrefix;AppropriateSuffix",
Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
"AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"))
.addNodeWithOrder("FN",
"AppropriatePrefix AppropriateGivenName "
+ "AppropriateMiddleName AppropriateFamilyName AppropriateSuffix")
.addNodeWithoutOrder("X-PHONETIC-FIRST-NAME", "AppropriatePhoneticGiven")
.addNodeWithoutOrder("X-PHONETIC-MIDDLE-NAME", "AppropriatePhoneticMiddle")
.addNodeWithoutOrder("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
if (isV30) {
verifier.addNodeWithoutOrder("SORT-STRING",
"AppropriatePhoneticGiven AppropriatePhoneticMiddle "
+ "AppropriatePhoneticFamily");
}
verifyOneComposition(resolver, handler, version);
}
public void testStructuredNameBasicV21() {
testStructuredNameBasic(V21);
}
public void testStructuredNameBasicV30() {
testStructuredNameBasic(V30);
}
/**
* Test that only "primary" StructuredName is emitted, so that our vCard file
* will not confuse the external importer, assuming there may be some importer
* which presume that there's only one property toward each of "N", "FN", etc.
* Note that more than one "N", "FN", etc. properties are acceptable in vCard spec.
*/
private void testStructuredNameUsePrimaryCommon(int version) {
final boolean isV30 = (version == V30);
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName1");
contentValues.put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName1");
contentValues.put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName1");
contentValues.put(StructuredName.PREFIX, "DoNotEmitPrefix1");
contentValues.put(StructuredName.SUFFIX, "DoNotEmitSuffix1");
contentValues.put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily1");
contentValues.put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven1");
contentValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle1");
// With "IS_PRIMARY=1". This is what we should use.
contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "AppropriateFamilyName");
contentValues.put(StructuredName.GIVEN_NAME, "AppropriateGivenName");
contentValues.put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName");
contentValues.put(StructuredName.PREFIX, "AppropriatePrefix");
contentValues.put(StructuredName.SUFFIX, "AppropriateSuffix");
contentValues.put(StructuredName.PHONETIC_FAMILY_NAME, "AppropriatePhoneticFamily");
contentValues.put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven");
contentValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle");
contentValues.put(StructuredName.IS_PRIMARY, 1);
// With "IS_PRIMARY=1", but we should ignore this time, since this is second, not first.
contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName2");
contentValues.put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName2");
contentValues.put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName2");
contentValues.put(StructuredName.PREFIX, "DoNotEmitPrefix2");
contentValues.put(StructuredName.SUFFIX, "DoNotEmitSuffix2");
contentValues.put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily2");
contentValues.put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven2");
contentValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle2");
contentValues.put(StructuredName.IS_PRIMARY, 1);
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
PropertyNodesVerifier verifier = handler.addNewVerifier()
.addNodeWithOrder("N",
"AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
+ "AppropriatePrefix;AppropriateSuffix",
Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
"AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"))
.addNodeWithOrder("FN",
"AppropriatePrefix AppropriateGivenName "
+ "AppropriateMiddleName AppropriateFamilyName AppropriateSuffix")
.addNodeWithoutOrder("X-PHONETIC-FIRST-NAME", "AppropriatePhoneticGiven")
.addNodeWithoutOrder("X-PHONETIC-MIDDLE-NAME", "AppropriatePhoneticMiddle")
.addNodeWithoutOrder("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
if (isV30) {
verifier.addNodeWithoutOrder("SORT-STRING",
"AppropriatePhoneticGiven AppropriatePhoneticMiddle "
+ "AppropriatePhoneticFamily");
}
verifyOneComposition(resolver, handler, version);
}
public void testStructuredNameUsePrimaryV21() {
testStructuredNameUsePrimaryCommon(V21);
}
public void testStructuredNameUsePrimaryV30() {
testStructuredNameUsePrimaryCommon(V30);
}
/**
* Tests that only "super primary" StructuredName is emitted.
* See also the comment in {@link #testStructuredNameUsePrimaryCommon(int)}.
*/
private void testStructuredNameUseSuperPrimaryCommon(int version) {
final boolean isV30 = (version == V30);
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName1");
contentValues.put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName1");
contentValues.put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName1");
contentValues.put(StructuredName.PREFIX, "DoNotEmitPrefix1");
contentValues.put(StructuredName.SUFFIX, "DoNotEmitSuffix1");
contentValues.put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily1");
contentValues.put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven1");
contentValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle1");
// With "IS_PRIMARY=1", but we should ignore this time.
contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName2");
contentValues.put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName2");
contentValues.put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName2");
contentValues.put(StructuredName.PREFIX, "DoNotEmitPrefix2");
contentValues.put(StructuredName.SUFFIX, "DoNotEmitSuffix2");
contentValues.put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily2");
contentValues.put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven2");
contentValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle2");
contentValues.put(StructuredName.IS_PRIMARY, 1);
// With "IS_SUPER_PRIMARY=1". This is what we should use.
contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "AppropriateFamilyName");
contentValues.put(StructuredName.GIVEN_NAME, "AppropriateGivenName");
contentValues.put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName");
contentValues.put(StructuredName.PREFIX, "AppropriatePrefix");
contentValues.put(StructuredName.SUFFIX, "AppropriateSuffix");
contentValues.put(StructuredName.PHONETIC_FAMILY_NAME, "AppropriatePhoneticFamily");
contentValues.put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven");
contentValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle");
contentValues.put(StructuredName.IS_SUPER_PRIMARY, 1);
contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName3");
contentValues.put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName3");
contentValues.put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName3");
contentValues.put(StructuredName.PREFIX, "DoNotEmitPrefix3");
contentValues.put(StructuredName.SUFFIX, "DoNotEmitSuffix3");
contentValues.put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily3");
contentValues.put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven3");
contentValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle3");
contentValues.put(StructuredName.IS_PRIMARY, 1);
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
PropertyNodesVerifier verifier = handler.addNewVerifier()
.addNodeWithOrder("N",
"AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
+ "AppropriatePrefix;AppropriateSuffix",
Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
"AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"))
.addNodeWithOrder("FN",
"AppropriatePrefix AppropriateGivenName "
+ "AppropriateMiddleName AppropriateFamilyName AppropriateSuffix")
.addNodeWithoutOrder("X-PHONETIC-FIRST-NAME", "AppropriatePhoneticGiven")
.addNodeWithoutOrder("X-PHONETIC-MIDDLE-NAME", "AppropriatePhoneticMiddle")
.addNodeWithoutOrder("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
if (isV30) {
verifier.addNodeWithoutOrder("SORT-STRING",
"AppropriatePhoneticGiven AppropriatePhoneticMiddle"
+ " AppropriatePhoneticFamily");
}
verifyOneComposition(resolver, handler, version);
}
public void testStructuredNameUseSuperPrimaryV21() {
testStructuredNameUseSuperPrimaryCommon(V21);
}
public void testStructuredNameUseSuperPrimaryV30() {
testStructuredNameUseSuperPrimaryCommon(V30);
}
/**
* There's no property for nickname in vCard 2.1, so we don't have any requirement on it.
*/
public void testNickNameV30() {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Nickname.CONTENT_ITEM_TYPE);
contentValues.put(Nickname.NAME, "Nicky");
VCardVerificationHandler handler = new VCardVerificationHandler(this, V30);
handler.addNewVerifierWithEmptyName()
.addNodeWithOrder("NICKNAME", "Nicky");
verifyOneComposition(resolver, handler, V30);
}
private void testPhoneBasicCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "1");
contentValues.put(Phone.TYPE, Phone.TYPE_HOME);
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("TEL", "1", new TypeSet("HOME", "VOICE"));
verifyOneComposition(resolver, handler, version);
}
public void testPhoneBasicV21() {
testPhoneBasicCommon(V21);
}
public void testPhoneBasicV30() {
testPhoneBasicCommon(V30);
}
/**
* Tests that vCard composer emits corresponding type param which we expect.
*/
private void testPhoneVariousTypeSupport(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "10");
contentValues.put(Phone.TYPE, Phone.TYPE_HOME);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "20");
contentValues.put(Phone.TYPE, Phone.TYPE_WORK);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "30");
contentValues.put(Phone.TYPE, Phone.TYPE_FAX_HOME);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "40");
contentValues.put(Phone.TYPE, Phone.TYPE_FAX_WORK);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "50");
contentValues.put(Phone.TYPE, Phone.TYPE_MOBILE);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "60");
contentValues.put(Phone.TYPE, Phone.TYPE_PAGER);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "70");
contentValues.put(Phone.TYPE, Phone.TYPE_OTHER);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "80");
contentValues.put(Phone.TYPE, Phone.TYPE_CAR);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "90");
contentValues.put(Phone.TYPE, Phone.TYPE_COMPANY_MAIN);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "100");
contentValues.put(Phone.TYPE, Phone.TYPE_ISDN);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "110");
contentValues.put(Phone.TYPE, Phone.TYPE_MAIN);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "120");
contentValues.put(Phone.TYPE, Phone.TYPE_OTHER_FAX);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "130");
contentValues.put(Phone.TYPE, Phone.TYPE_TELEX);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "140");
contentValues.put(Phone.TYPE, Phone.TYPE_WORK_MOBILE);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "150");
contentValues.put(Phone.TYPE, Phone.TYPE_WORK_PAGER);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "160");
contentValues.put(Phone.TYPE, Phone.TYPE_MMS);
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("TEL", "10", new TypeSet("HOME"))
.addNodeWithoutOrder("TEL", "20", new TypeSet("WORK"))
.addNodeWithoutOrder("TEL", "30", new TypeSet("HOME", "FAX"))
.addNodeWithoutOrder("TEL", "40", new TypeSet("WORK", "FAX"))
.addNodeWithoutOrder("TEL", "50", new TypeSet("CELL"))
.addNodeWithoutOrder("TEL", "60", new TypeSet("PAGER"))
.addNodeWithoutOrder("TEL", "70", new TypeSet("VOICE"))
.addNodeWithoutOrder("TEL", "80", new TypeSet("CAR"))
.addNodeWithoutOrder("TEL", "90", new TypeSet("WORK", "PREF"))
.addNodeWithoutOrder("TEL", "100", new TypeSet("ISDN"))
.addNodeWithoutOrder("TEL", "110", new TypeSet("PREF"))
.addNodeWithoutOrder("TEL", "120", new TypeSet("FAX"))
.addNodeWithoutOrder("TEL", "130", new TypeSet("TLX"))
.addNodeWithoutOrder("TEL", "140", new TypeSet("WORK", "MOBILE"))
.addNodeWithoutOrder("TEL", "150", new TypeSet("WORK", "PAGER"))
.addNodeWithoutOrder("TEL", "160", new TypeSet("MSG"));
}
public void testPhoneVariousTypeSupportV21() {
testPhoneVariousTypeSupport(V21);
}
public void testPhoneVariousTypeSupportV30() {
testPhoneVariousTypeSupport(V30);
}
/**
* Tests that "PREF"s are emitted appropriately.
*/
private void testPhonePrefHandlingCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "1");
contentValues.put(Phone.TYPE, Phone.TYPE_HOME);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "2");
contentValues.put(Phone.TYPE, Phone.TYPE_WORK);
contentValues.put(Phone.IS_PRIMARY, 1);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "3");
contentValues.put(Phone.TYPE, Phone.TYPE_FAX_HOME);
contentValues.put(Phone.IS_PRIMARY, 1);
contentValues = resolver.buildData(Phone.CONTENT_ITEM_TYPE);
contentValues.put(Phone.NUMBER, "4");
contentValues.put(Phone.TYPE, Phone.TYPE_FAX_WORK);
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("TEL", "4", new TypeSet("WORK", "FAX"))
.addNodeWithoutOrder("TEL", "3", new TypeSet("HOME", "FAX", "PREF"))
.addNodeWithoutOrder("TEL", "2", new TypeSet("WORK", "VOICE", "PREF"))
.addNodeWithoutOrder("TEL", "1", new TypeSet("HOME", "VOICE"));
verifyOneComposition(resolver, handler, version);
}
public void testPhonePrefHandlingV21() {
testPhonePrefHandlingCommon(V21);
}
public void testPhonePrefHandlingV30() {
testPhonePrefHandlingCommon(V30);
}
private void testEmailBasicCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Email.CONTENT_ITEM_TYPE);
contentValues.put(Email.DATA, "sample@example.com");
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("EMAIL", "sample@example.com");
verifyOneComposition(resolver, handler, version);
}
public void testEmailBasicV21() {
testEmailBasicCommon(V21);
}
public void testEmailBasicV30() {
testEmailBasicCommon(V30);
}
private void testEmailVariousTypeSupportCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Email.CONTENT_ITEM_TYPE);
contentValues.put(Email.DATA, "type_home@example.com");
contentValues.put(Email.TYPE, Email.TYPE_HOME);
contentValues = resolver.buildData(Email.CONTENT_ITEM_TYPE);
contentValues.put(Email.DATA, "type_work@example.com");
contentValues.put(Email.TYPE, Email.TYPE_WORK);
contentValues = resolver.buildData(Email.CONTENT_ITEM_TYPE);
contentValues.put(Email.DATA, "type_mobile@example.com");
contentValues.put(Email.TYPE, Email.TYPE_MOBILE);
contentValues = resolver.buildData(Email.CONTENT_ITEM_TYPE);
contentValues.put(Email.DATA, "type_other@example.com");
contentValues.put(Email.TYPE, Email.TYPE_OTHER);
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("EMAIL", "type_home@example.com", new TypeSet("HOME"))
.addNodeWithoutOrder("EMAIL", "type_work@example.com", new TypeSet("WORK"))
.addNodeWithoutOrder("EMAIL", "type_mobile@example.com", new TypeSet("CELL"))
.addNodeWithoutOrder("EMAIL", "type_other@example.com");
verifyOneComposition(resolver, handler, version);
}
public void testEmailVariousTypeSupportV21() {
testEmailVariousTypeSupportCommon(V21);
}
public void testEmailVariousTypeSupportV30() {
testEmailVariousTypeSupportCommon(V30);
}
private void testEmailPrefHandlingCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Email.CONTENT_ITEM_TYPE);
contentValues.put(Email.DATA, "type_home@example.com");
contentValues.put(Email.TYPE, Email.TYPE_HOME);
contentValues.put(Email.IS_PRIMARY, 1);
contentValues = resolver.buildData(Email.CONTENT_ITEM_TYPE);
contentValues.put(Email.DATA, "type_notype@example.com");
contentValues.put(Email.IS_PRIMARY, 1);
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("EMAIL", "type_notype@example.com", new TypeSet("PREF"))
.addNodeWithoutOrder("EMAIL", "type_home@example.com", new TypeSet("HOME", "PREF"));
verifyOneComposition(resolver, handler, version);
}
public void testEmailPrefHandlingV21() {
testEmailPrefHandlingCommon(V21);
}
public void testEmailPrefHandlingV30() {
testEmailPrefHandlingCommon(V30);
}
private void testPostalOnlyWithStructuredDataCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
// adr-value = 0*6(text-value ";") text-value
// ; PO Box, Extended Address, Street, Locality, Region, Postal Code,
// ; Country Name
ContentValues contentValues = resolver.buildData(StructuredPostal.CONTENT_ITEM_TYPE);
contentValues.put(StructuredPostal.POBOX, "Pobox");
contentValues.put(StructuredPostal.NEIGHBORHOOD, "Neighborhood");
contentValues.put(StructuredPostal.STREET, "Street");
contentValues.put(StructuredPostal.CITY, "City");
contentValues.put(StructuredPostal.REGION, "Region");
contentValues.put(StructuredPostal.POSTCODE, "100");
contentValues.put(StructuredPostal.COUNTRY, "Country");
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("ADR", "Pobox;Neighborhood;Street;City;Region;100;Country",
Arrays.asList("Pobox", "Neighborhood", "Street", "City",
"Region", "100", "Country"), new TypeSet("HOME"));
verifyOneComposition(resolver, handler, version);
}
public void testPostalOnlyWithStructuredDataV21() {
testPostalOnlyWithStructuredDataCommon(V21);
}
public void testPostalOnlyWithStructuredDataV30() {
testPostalOnlyWithStructuredDataCommon(V30);
}
private void testPostalOnlyWithFormattedAddressCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(StructuredPostal.CONTENT_ITEM_TYPE);
contentValues.put(StructuredPostal.FORMATTED_ADDRESS,
"Formatted address CA 123-334 United Statue");
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithOrder("ADR", ";Formatted address CA 123-334 United Statue;;;;;",
Arrays.asList("", "Formatted address CA 123-334 United Statue",
"", "", "", "", ""), new TypeSet("HOME"));
verifyOneComposition(resolver, handler, version);
}
public void testPostalOnlyWithFormattedAddressV21() {
testPostalOnlyWithFormattedAddressCommon(V21);
}
public void testPostalOnlyWithFormattedAddressV30() {
testPostalOnlyWithFormattedAddressCommon(V30);
}
/**
* Tests that the vCard composer honors formatted data when it is available
* even when it is partial.
*/
private void testPostalWithBothStructuredAndFormattedCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(StructuredPostal.CONTENT_ITEM_TYPE);
contentValues.put(StructuredPostal.POBOX, "Pobox");
contentValues.put(StructuredPostal.COUNTRY, "Country");
contentValues.put(StructuredPostal.FORMATTED_ADDRESS,
"Formatted address CA 123-334 United Statue"); // Should be ignored
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("ADR", "Pobox;;;;;;Country",
Arrays.asList("Pobox", "", "", "", "", "", "Country"), new TypeSet("HOME"));
verifyOneComposition(resolver, handler, version);
}
public void testPostalWithBothStructuredAndFormattedV21() {
testPostalWithBothStructuredAndFormattedCommon(V21);
}
public void testPostalWithBothStructuredAndFormattedV30() {
testPostalWithBothStructuredAndFormattedCommon(V30);
}
private void testOrganizationCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Organization.CONTENT_ITEM_TYPE);
contentValues.put(Organization.COMPANY, "CompanyX");
contentValues.put(Organization.DEPARTMENT, "DepartmentY");
contentValues.put(Organization.TITLE, "TitleZ");
contentValues.put(Organization.JOB_DESCRIPTION, "Description Rambda"); // Ignored.
contentValues.put(Organization.OFFICE_LOCATION, "Mountain View"); // Ignored.
contentValues.put(Organization.PHONETIC_NAME, "PhoneticName!"); // Ignored
contentValues.put(Organization.SYMBOL, "(^o^)/~~"); // Ignore him (her).
contentValues = resolver.buildData(Organization.CONTENT_ITEM_TYPE);
contentValues.putNull(Organization.COMPANY);
contentValues.put(Organization.DEPARTMENT, "DepartmentXX");
contentValues.putNull(Organization.TITLE);
contentValues = resolver.buildData(Organization.CONTENT_ITEM_TYPE);
contentValues.put(Organization.COMPANY, "CompanyXYZ");
contentValues.putNull(Organization.DEPARTMENT);
contentValues.put(Organization.TITLE, "TitleXYZYX");
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
// Currently we do not use group but depend on the order.
handler.addNewVerifierWithEmptyName()
.addNodeWithOrder("ORG", "CompanyX;DepartmentY",
Arrays.asList("CompanyX", "DepartmentY"))
.addNodeWithOrder("TITLE", "TitleZ")
.addNodeWithOrder("ORG", "DepartmentXX")
.addNodeWithOrder("ORG", "CompanyXYZ")
.addNodeWithOrder("TITLE", "TitleXYZYX");
verifyOneComposition(resolver, handler, version);
}
public void testOrganizationV21() {
testOrganizationCommon(V21);
}
public void testOrganizationV30() {
testOrganizationCommon(V30);
}
private void testImVariousTypeSupportCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Im.CONTENT_ITEM_TYPE);
contentValues.put(Im.PROTOCOL, Im.PROTOCOL_AIM);
contentValues.put(Im.DATA, "aim");
contentValues = resolver.buildData(Im.CONTENT_ITEM_TYPE);
contentValues.put(Im.PROTOCOL, Im.PROTOCOL_MSN);
contentValues.put(Im.DATA, "msn");
contentValues = resolver.buildData(Im.CONTENT_ITEM_TYPE);
contentValues.put(Im.PROTOCOL, Im.PROTOCOL_YAHOO);
contentValues.put(Im.DATA, "yahoo");
contentValues = resolver.buildData(Im.CONTENT_ITEM_TYPE);
contentValues.put(Im.PROTOCOL, Im.PROTOCOL_SKYPE);
contentValues.put(Im.DATA, "skype");
contentValues = resolver.buildData(Im.CONTENT_ITEM_TYPE);
contentValues.put(Im.PROTOCOL, Im.PROTOCOL_QQ);
contentValues.put(Im.DATA, "qq");
contentValues = resolver.buildData(Im.CONTENT_ITEM_TYPE);
contentValues.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
contentValues.put(Im.DATA, "google talk");
contentValues = resolver.buildData(Im.CONTENT_ITEM_TYPE);
contentValues.put(Im.PROTOCOL, Im.PROTOCOL_ICQ);
contentValues.put(Im.DATA, "icq");
contentValues = resolver.buildData(Im.CONTENT_ITEM_TYPE);
contentValues.put(Im.PROTOCOL, Im.PROTOCOL_JABBER);
contentValues.put(Im.DATA, "jabber");
contentValues = resolver.buildData(Im.CONTENT_ITEM_TYPE);
contentValues.put(Im.PROTOCOL, Im.PROTOCOL_NETMEETING);
contentValues.put(Im.DATA, "netmeeting");
// No determined way to express unknown type...
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("X-JABBER", "jabber")
.addNodeWithoutOrder("X-ICQ", "icq")
.addNodeWithoutOrder("X-GOOGLE-TALK", "google talk")
.addNodeWithoutOrder("X-QQ", "qq")
.addNodeWithoutOrder("X-SKYPE-USERNAME", "skype")
.addNodeWithoutOrder("X-YAHOO", "yahoo")
.addNodeWithoutOrder("X-MSN", "msn")
.addNodeWithoutOrder("X-NETMEETING", "netmeeting")
.addNodeWithoutOrder("X-AIM", "aim");
verifyOneComposition(resolver, handler, version);
}
public void testImBasiV21() {
testImVariousTypeSupportCommon(V21);
}
public void testImBasicV30() {
testImVariousTypeSupportCommon(V30);
}
private void testImPrefHandlingCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Im.CONTENT_ITEM_TYPE);
contentValues.put(Im.PROTOCOL, Im.PROTOCOL_AIM);
contentValues.put(Im.DATA, "aim1");
contentValues = resolver.buildData(Im.CONTENT_ITEM_TYPE);
contentValues.put(Im.PROTOCOL, Im.PROTOCOL_AIM);
contentValues.put(Im.DATA, "aim2");
contentValues.put(Im.TYPE, Im.TYPE_HOME);
contentValues.put(Im.IS_PRIMARY, 1);
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("X-AIM", "aim1")
.addNodeWithoutOrder("X-AIM", "aim2", new TypeSet("HOME", "PREF"));
verifyOneComposition(resolver, handler, version);
}
public void testImPrefHandlingV21() {
testImPrefHandlingCommon(V21);
}
public void testImPrefHandlingV30() {
testImPrefHandlingCommon(V30);
}
private void testWebsiteCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Website.CONTENT_ITEM_TYPE);
contentValues.put(Website.URL, "http://website.example.android.com/index.html");
contentValues.put(Website.TYPE, Website.TYPE_BLOG);
contentValues = resolver.buildData(Website.CONTENT_ITEM_TYPE);
contentValues.put(Website.URL, "ftp://ftp.example.android.com/index.html");
contentValues.put(Website.TYPE, Website.TYPE_FTP);
// We drop TYPE information since vCard (especially 3.0) does not allow us to emit it.
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("URL", "ftp://ftp.example.android.com/index.html")
.addNodeWithoutOrder("URL", "http://website.example.android.com/index.html");
verifyOneComposition(resolver, handler, version);
}
public void testWebsiteV21() {
testWebsiteCommon(V21);
}
public void testWebsiteV30() {
testWebsiteCommon(V30);
}
private void testEventCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Event.CONTENT_ITEM_TYPE);
contentValues.put(Event.TYPE, Event.TYPE_ANNIVERSARY);
contentValues.put(Event.START_DATE, "1982-06-16");
contentValues = resolver.buildData(Event.CONTENT_ITEM_TYPE);
contentValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
contentValues.put(Event.START_DATE, "2008-10-22");
contentValues = resolver.buildData(Event.CONTENT_ITEM_TYPE);
contentValues.put(Event.TYPE, Event.TYPE_OTHER);
contentValues.put(Event.START_DATE, "2018-03-12");
contentValues = resolver.buildData(Event.CONTENT_ITEM_TYPE);
contentValues.put(Event.TYPE, Event.TYPE_CUSTOM);
contentValues.put(Event.LABEL, "The last day");
contentValues.put(Event.START_DATE, "When the Tower of Hanoi with 64 rings is completed.");
contentValues = resolver.buildData(Event.CONTENT_ITEM_TYPE);
contentValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
contentValues.put(Event.START_DATE, "2009-05-19");
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithoutOrder("BDAY", "2008-10-22");
verifyOneComposition(resolver, handler, version);
}
public void testEventV21() {
testEventCommon(V21);
}
public void testEventV30() {
testEventCommon(V30);
}
private void testNoteCommon(int version) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(Note.CONTENT_ITEM_TYPE);
contentValues.put(Note.NOTE, "note1");
contentValues = resolver.buildData(Note.CONTENT_ITEM_TYPE);
contentValues.put(Note.NOTE, "note2");
contentValues.put(Note.IS_PRIMARY, 1); // Just ignored.
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifierWithEmptyName()
.addNodeWithOrder("NOTE", "note1")
.addNodeWithOrder("NOTE", "note2");
verifyOneComposition(resolver, handler, version);
}
public void testNoteV21() {
testNoteCommon(V21);
}
public void testNoteV30() {
testNoteCommon(V30);
}
// TODO: test for non-ascii...
private void testPhotoCommon(int version) {
final boolean isV30 = version == V30;
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "PhotoTest");
contentValues = resolver.buildData(Photo.CONTENT_ITEM_TYPE);
contentValues.put(Photo.PHOTO, sPhotoByteArray);
ContentValues contentValuesForPhoto = new ContentValues();
contentValuesForPhoto.put("ENCODING", (isV30 ? "b" : "BASE64"));
VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
handler.addNewVerifier()
.addNodeWithoutOrder("FN", "PhotoTest")
.addNodeWithoutOrder("N", "PhotoTest;;;;", Arrays.asList("PhotoTest", "", "", "", ""))
.addNodeWithOrder("PHOTO", null, null, sPhotoByteArray,
contentValuesForPhoto, new TypeSet("JPEG"), null);
verifyOneComposition(resolver, handler, version);
}
public void testPhotoV21() {
testPhotoCommon(false);
testPhotoCommon(V21);
}
public void testPhotoV30() {
testPhotoCommon(true);
testPhotoCommon(V30);
}
}

View File

@@ -722,7 +722,7 @@ public class VCardImporterTests extends AndroidTestCase {
public void testV21SimpleCase1_Type_Generic() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_simple_1, VCardConfig.VCARD_TYPE_V21_GENERIC);
R.raw.v21_simple_1, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
ContentValues contentValues =
verifier.createExpected(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "Ando");
@@ -733,7 +733,7 @@ public class VCardImporterTests extends AndroidTestCase {
public void testV21SimpleCase1_Type_Japanese() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_simple_1, VCardConfig.VCARD_TYPE_V21_JAPANESE);
R.raw.v21_simple_1, VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
ContentValues contentValues =
verifier.createExpected(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "Ando");
@@ -746,7 +746,7 @@ public class VCardImporterTests extends AndroidTestCase {
public void testV21SimpleCase2() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_simple_2, VCardConfig.VCARD_TYPE_V21_GENERIC);
R.raw.v21_simple_2, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
ContentValues contentValues =
verifier.createExpected(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.DISPLAY_NAME, "Ando Roid");
@@ -755,7 +755,7 @@ public class VCardImporterTests extends AndroidTestCase {
public void testV21SimpleCase3() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_simple_3, VCardConfig.VCARD_TYPE_V21_GENERIC);
R.raw.v21_simple_3, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
ContentValues contentValues =
verifier.createExpected(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "Ando");
@@ -790,7 +790,7 @@ public class VCardImporterTests extends AndroidTestCase {
*/
public void testV21BackslashCase() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_backslash, VCardConfig.VCARD_TYPE_V21_GENERIC);
R.raw.v21_backslash, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
ContentValues contentValues =
verifier.createExpected(StructuredName.CONTENT_ITEM_TYPE);
// FAMILY_NAME is empty and removed in this test...
@@ -804,7 +804,7 @@ public class VCardImporterTests extends AndroidTestCase {
public void testOrgBeforTitle() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_org_before_title, VCardConfig.VCARD_TYPE_V21_GENERIC);
R.raw.v21_org_before_title, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
ContentValues contentValues =
verifier.createExpected(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.DISPLAY_NAME, "Normal Guy");
@@ -819,7 +819,7 @@ public class VCardImporterTests extends AndroidTestCase {
public void testTitleBeforOrg() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_title_before_org, VCardConfig.VCARD_TYPE_V21_GENERIC);
R.raw.v21_title_before_org, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
ContentValues contentValues =
verifier.createExpected(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.DISPLAY_NAME, "Nice Guy");
@@ -838,7 +838,7 @@ public class VCardImporterTests extends AndroidTestCase {
*/
public void testV21PrefToIsPrimary() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_pref_handling, VCardConfig.VCARD_TYPE_V21_GENERIC);
R.raw.v21_pref_handling, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
ContentValues contentValues =
verifier.createExpected(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
@@ -952,7 +952,7 @@ public class VCardImporterTests extends AndroidTestCase {
*/
public void testV21ComplicatedCase() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_complicated, VCardConfig.VCARD_TYPE_V21_GENERIC);
R.raw.v21_complicated, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
ContentValues contentValues =
verifier.createExpected(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "Gump");
@@ -1068,7 +1068,7 @@ public class VCardImporterTests extends AndroidTestCase {
public void testV30Simple() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v30_simple, VCardConfig.VCARD_TYPE_V30_GENERIC);
R.raw.v30_simple, VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8);
ContentValues contentValues =
verifier.createExpected(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "And");
@@ -1139,25 +1139,28 @@ public class VCardImporterTests extends AndroidTestCase {
verifier.verify();
}
/**
* Verifies vCard with Japanese can be parsed correctly with VCARD_TYPE_V21_GENERIC.
* Verifies vCard with Japanese can be parsed correctly with
* {@link android.pim.vcard.VCardConfig#VCARD_TYPE_V21_GENERIC_UTF8}.
*/
public void testV21Japanese1_Type_Generic() throws IOException, VCardException {
public void testV21Japanese1_Type_Generic_Utf8() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_japanese_1, VCardConfig.VCARD_TYPE_V21_GENERIC);
R.raw.v21_japanese_1, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
testV21Japanese1Common(verifier, false);
}
/**
* Verifies vCard with Japanese can be parsed correctly with VCARD_TYPE_V21_JAPANESE.
* Verifies vCard with Japanese can be parsed correctly with
* {@link android.pim.vcard.VCardConfig#VCARD_TYPE_V21_JAPANESE_SJIS}.
*/
public void testV21Japanese1_Type_Japanese() throws IOException, VCardException {
public void testV21Japanese1_Type_Japanese_Sjis() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_japanese_1, VCardConfig.VCARD_TYPE_V21_JAPANESE);
R.raw.v21_japanese_1, VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
testV21Japanese1Common(verifier, true);
}
/**
* Verifies vCard with Japanese can be parsed correctly with VCARD_TYPE_V21_JAPANESE_UTF8,
* Verifies vCard with Japanese can be parsed correctly with
* {@link android.pim.vcard.VCardConfig#VCARD_TYPE_V21_JAPANESE_UTF8}.
* since vCard 2.1 specifies the charset of each line if it contains non-Ascii.
*/
public void testV21Japanese1_Type_Japanese_Utf8() throws IOException, VCardException {
@@ -1205,9 +1208,9 @@ public class VCardImporterTests extends AndroidTestCase {
verifier.verify(builder.vNodeList.get(0));
}
public void testV21Japanese2_Type_Generic() throws IOException, VCardException {
public void testV21Japanese2_Type_Generic_Utf8() throws IOException, VCardException {
ContactStructVerifier verifier = new ContactStructVerifier(
R.raw.v21_japanese_2, VCardConfig.VCARD_TYPE_V21_GENERIC);
R.raw.v21_japanese_2, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
ContentValues contentValues =
verifier.createExpected(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "\u5B89\u85E4");