Merge change I9195a354 into eclair-mr2
* changes: Add partial support of Android-specific properties.
This commit is contained in:
@@ -72,6 +72,9 @@ package android.pim.vcard;
|
||||
// Phone number for Skype, available as usual phone.
|
||||
public static final String PROPERTY_X_SKYPE_PSTNNUMBER = "X-SKYPE-PSTNNUMBER";
|
||||
|
||||
// Property for Android-specific fields.
|
||||
public static final String PROPERTY_X_ANDROID_CUSTOM = "X-ANDROID-CUSTOM";
|
||||
|
||||
// Properties for DoCoMo vCard.
|
||||
public static final String PROPERTY_X_CLASS = "X-CLASS";
|
||||
public static final String PROPERTY_X_REDUCTION = "X-REDUCTION";
|
||||
@@ -158,6 +161,9 @@ package android.pim.vcard;
|
||||
public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK";
|
||||
}
|
||||
|
||||
// TODO: Should be in ContactsContract?
|
||||
/* package */ static final int MAX_DATA_COLUMN = 15;
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
}
|
||||
@@ -442,7 +442,8 @@ public class ContactStruct {
|
||||
private List<ImData> mImList;
|
||||
private List<PhotoData> mPhotoList;
|
||||
private List<String> mWebsiteList;
|
||||
|
||||
private List<List<String>> mAndroidCustomPropertyList;
|
||||
|
||||
private final int mVCardType;
|
||||
private final Account mAccount;
|
||||
|
||||
@@ -928,14 +929,19 @@ public class ContactStruct {
|
||||
mWebsiteList = new ArrayList<String>(1);
|
||||
}
|
||||
mWebsiteList.add(propValue);
|
||||
} else if (propName.equals(Constants.PROPERTY_BDAY)) {
|
||||
mBirthday = propValue;
|
||||
} else if (propName.equals(Constants.PROPERTY_X_PHONETIC_FIRST_NAME)) {
|
||||
mPhoneticGivenName = propValue;
|
||||
} else if (propName.equals(Constants.PROPERTY_X_PHONETIC_MIDDLE_NAME)) {
|
||||
mPhoneticMiddleName = propValue;
|
||||
} else if (propName.equals(Constants.PROPERTY_X_PHONETIC_LAST_NAME)) {
|
||||
mPhoneticFamilyName = propValue;
|
||||
} else if (propName.equals(Constants.PROPERTY_BDAY)) {
|
||||
mBirthday = propValue;
|
||||
} else if (propName.equals(Constants.PROPERTY_X_ANDROID_CUSTOM)) {
|
||||
final List<String> customPropertyList =
|
||||
VCardUtils.constructListFromValue(propValue,
|
||||
VCardConfig.isV30(mVCardType));
|
||||
handleAndroidCustomProperty(customPropertyList);
|
||||
/*} else if (propName.equals("REV")) {
|
||||
// Revision of this VCard entry. I think we can ignore this.
|
||||
} else if (propName.equals("UID")) {
|
||||
@@ -963,6 +969,13 @@ public class ContactStruct {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAndroidCustomProperty(final List<String> customPropertyList) {
|
||||
if (mAndroidCustomPropertyList == null) {
|
||||
mAndroidCustomPropertyList = new ArrayList<List<String>>();
|
||||
}
|
||||
mAndroidCustomPropertyList.add(customPropertyList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the display name. The constructed data must not be null.
|
||||
*/
|
||||
@@ -1017,7 +1030,7 @@ public class ContactStruct {
|
||||
mDisplayName = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Consolidate several fielsds (like mName) using name candidates,
|
||||
*/
|
||||
@@ -1028,7 +1041,7 @@ public class ContactStruct {
|
||||
mPhoneticFullName = mPhoneticFullName.trim();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// From GoogleSource.java in Contacts app.
|
||||
private static final String ACCOUNT_TYPE_GOOGLE = "com.google";
|
||||
private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts";
|
||||
@@ -1224,6 +1237,36 @@ public class ContactStruct {
|
||||
operationList.add(builder.build());
|
||||
}
|
||||
|
||||
if (mAndroidCustomPropertyList != null) {
|
||||
for (List<String> customPropertyList : mAndroidCustomPropertyList) {
|
||||
int size = customPropertyList.size();
|
||||
if (size < 2 || TextUtils.isEmpty(customPropertyList.get(0))) {
|
||||
continue;
|
||||
} else if (size > Constants.MAX_DATA_COLUMN + 1) {
|
||||
size = Constants.MAX_DATA_COLUMN + 1;
|
||||
customPropertyList =
|
||||
customPropertyList.subList(0, Constants.MAX_DATA_COLUMN + 2);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (final String customPropertyValue : customPropertyList) {
|
||||
if (i == 0) {
|
||||
final String mimeType = customPropertyValue;
|
||||
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
|
||||
builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0);
|
||||
builder.withValue(Data.MIMETYPE, mimeType);
|
||||
} else { // 1 <= i && i <= MAX_DATA_COLUMNS
|
||||
if (!TextUtils.isEmpty(customPropertyValue)) {
|
||||
builder.withValue("data" + i, customPropertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
operationList.add(builder.build());
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (myGroupsId != null) {
|
||||
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
|
||||
builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0);
|
||||
|
||||
@@ -1019,11 +1019,11 @@ public class VCardComposer {
|
||||
return;
|
||||
}
|
||||
|
||||
final String propertyNickname;
|
||||
final boolean useAndroidProperty;
|
||||
if (mIsV30) {
|
||||
propertyNickname = Constants.PROPERTY_NICKNAME;
|
||||
/*} else if (mUsesAndroidProperty) {
|
||||
propertyNickname = VCARD_PROPERTY_X_NICKNAME;*/
|
||||
useAndroidProperty = false;
|
||||
} else if (mUsesAndroidProperty) {
|
||||
useAndroidProperty = true;
|
||||
} else {
|
||||
// There's no way to add this field.
|
||||
return;
|
||||
@@ -1034,29 +1034,13 @@ public class VCardComposer {
|
||||
if (TextUtils.isEmpty(nickname)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String encodedNickname;
|
||||
final boolean reallyUseQuotedPrintable =
|
||||
(mUsesQuotedPrintable &&
|
||||
!VCardUtils.containsOnlyNonCrLfPrintableAscii(nickname));
|
||||
if (reallyUseQuotedPrintable) {
|
||||
encodedNickname = encodeQuotedPrintable(nickname);
|
||||
if (useAndroidProperty) {
|
||||
appendAndroidSpecificProperty(builder, Nickname.CONTENT_ITEM_TYPE,
|
||||
contentValues);
|
||||
} else {
|
||||
encodedNickname = escapeCharacters(nickname);
|
||||
appendVCardLineWithCharsetAndQPDetection(builder,
|
||||
Constants.PROPERTY_NICKNAME, nickname);
|
||||
}
|
||||
|
||||
builder.append(propertyNickname);
|
||||
if (shouldAppendCharsetAttribute(propertyNickname)) {
|
||||
builder.append(VCARD_ATTR_SEPARATOR);
|
||||
builder.append(mVCardAttributeCharset);
|
||||
}
|
||||
if (reallyUseQuotedPrintable) {
|
||||
builder.append(VCARD_ATTR_SEPARATOR);
|
||||
builder.append(VCARD_ATTR_ENCODING_QP);
|
||||
}
|
||||
builder.append(VCARD_DATA_SEPARATOR);
|
||||
builder.append(encodedNickname);
|
||||
builder.append(VCARD_COL_SEPARATOR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1491,6 +1475,33 @@ public class VCardComposer {
|
||||
}
|
||||
}
|
||||
|
||||
private void appendAndroidSpecificProperty(final StringBuilder builder,
|
||||
final String mimeType, ContentValues contentValues) {
|
||||
List<String> rawDataList = new ArrayList<String>();
|
||||
rawDataList.add(mimeType);
|
||||
final List<String> columnNameList;
|
||||
if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
|
||||
|
||||
} else {
|
||||
// If you add the other field, please check all the columns are able to be
|
||||
// converted to String.
|
||||
//
|
||||
// e.g. BLOB is not what we can handle here now.
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Constants.MAX_DATA_COLUMN; i++) {
|
||||
String value = contentValues.getAsString("data" + i);
|
||||
if (value == null) {
|
||||
value = "";
|
||||
}
|
||||
rawDataList.add(value);
|
||||
}
|
||||
|
||||
appendVCardLineWithCharsetAndQPDetection(builder,
|
||||
Constants.PROPERTY_X_ANDROID_CUSTOM, rawDataList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append '\' to the characters which should be escaped. The character set is different
|
||||
* not only between vCard 2.1 and vCard 3.0 but also among each device.
|
||||
@@ -1968,6 +1979,8 @@ public class VCardComposer {
|
||||
}
|
||||
}
|
||||
|
||||
// appendVCardLine() variants accepting one String.
|
||||
|
||||
private void appendVCardLineWithCharsetAndQPDetection(final StringBuilder builder,
|
||||
final String propertyName, final String rawData) {
|
||||
appendVCardLineWithCharsetAndQPDetection(builder, propertyName, null, rawData);
|
||||
@@ -2026,6 +2039,87 @@ public class VCardComposer {
|
||||
builder.append(VCARD_COL_SEPARATOR);
|
||||
}
|
||||
|
||||
// appendVCardLine() variants accepting List<String>.
|
||||
|
||||
private void appendVCardLineWithCharsetAndQPDetection(final StringBuilder builder,
|
||||
final String propertyName, final List<String> rawDataList) {
|
||||
appendVCardLineWithCharsetAndQPDetection(builder, propertyName, null, rawDataList);
|
||||
}
|
||||
|
||||
private void appendVCardLineWithCharsetAndQPDetection(final StringBuilder builder,
|
||||
final String propertyName,
|
||||
final List<String> attributeList, final List<String> rawDataList) {
|
||||
boolean needCharset = false;
|
||||
boolean reallyUseQuotedPrintable = false;
|
||||
for (String rawData : rawDataList) {
|
||||
if (!needCharset && mUsesQuotedPrintable &&
|
||||
!VCardUtils.containsOnlyPrintableAscii(rawData)) {
|
||||
needCharset = true;
|
||||
}
|
||||
if (!reallyUseQuotedPrintable &&
|
||||
!VCardUtils.containsOnlyNonCrLfPrintableAscii(rawData)) {
|
||||
reallyUseQuotedPrintable = true;
|
||||
}
|
||||
if (needCharset && reallyUseQuotedPrintable) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
appendVCardLine(builder, propertyName, attributeList,
|
||||
rawDataList, needCharset, reallyUseQuotedPrintable);
|
||||
}
|
||||
|
||||
/*
|
||||
private void appendVCardLine(final StringBuilder builder,
|
||||
final String propertyName, final List<String> rawDataList) {
|
||||
appendVCardLine(builder, propertyName, rawDataList, false, false);
|
||||
}
|
||||
|
||||
private void appendVCardLine(final StringBuilder builder,
|
||||
final String propertyName, final List<String> rawDataList,
|
||||
final boolean needCharset, boolean needQuotedPrintable) {
|
||||
appendVCardLine(builder, propertyName, null, rawDataList, needCharset, needQuotedPrintable);
|
||||
}*/
|
||||
|
||||
private void appendVCardLine(final StringBuilder builder,
|
||||
final String propertyName,
|
||||
final List<String> attributeList,
|
||||
final List<String> rawDataList, final boolean needCharset,
|
||||
boolean needQuotedPrintable) {
|
||||
builder.append(propertyName);
|
||||
if (attributeList != null && attributeList.size() > 0) {
|
||||
builder.append(VCARD_ATTR_SEPARATOR);
|
||||
appendTypeAttributes(builder, attributeList);
|
||||
}
|
||||
if (needCharset) {
|
||||
builder.append(VCARD_ATTR_SEPARATOR);
|
||||
builder.append(mVCardAttributeCharset);
|
||||
}
|
||||
|
||||
builder.append(VCARD_DATA_SEPARATOR);
|
||||
boolean first = true;
|
||||
for (String rawData : rawDataList) {
|
||||
final String encodedData;
|
||||
if (needQuotedPrintable) {
|
||||
builder.append(VCARD_ATTR_SEPARATOR);
|
||||
builder.append(VCARD_ATTR_ENCODING_QP);
|
||||
encodedData = encodeQuotedPrintable(rawData);
|
||||
} else {
|
||||
// TODO: one line may be too huge, which may be invalid in vCard spec, though
|
||||
// several (even well-known) applications do not care this.
|
||||
encodedData = escapeCharacters(rawData);
|
||||
}
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
builder.append(VCARD_ITEM_SEPARATOR);
|
||||
}
|
||||
builder.append(encodedData);
|
||||
}
|
||||
builder.append(VCARD_COL_SEPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* VCARD_ATTR_SEPARATOR must be appended before this method being called.
|
||||
*/
|
||||
|
||||
@@ -643,9 +643,6 @@ public class VCardExporterTests extends AndroidTestCase {
|
||||
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);
|
||||
@@ -1269,4 +1266,23 @@ public class VCardExporterTests extends AndroidTestCase {
|
||||
|
||||
verifyOneComposition(resolver, handler, version);
|
||||
}
|
||||
|
||||
/**
|
||||
* There's no "NICKNAME" property in vCard 2.1, while there is in vCard 3.0.
|
||||
* We use Android-specific "X-ANDROID-CUSTOM" property.
|
||||
* This test verifies the functionality.
|
||||
*/
|
||||
public void testNickNameV21() {
|
||||
ExportTestResolver resolver = new ExportTestResolver();
|
||||
ContentValues contentValues = resolver.buildData(Nickname.CONTENT_ITEM_TYPE);
|
||||
contentValues.put(Nickname.NAME, "Nicky");
|
||||
|
||||
VCardVerificationHandler handler = new VCardVerificationHandler(this, V21);
|
||||
handler.addNewVerifierWithEmptyName()
|
||||
.addNodeWithOrder("X-ANDROID-CUSTOM", Nickname.CONTENT_ITEM_TYPE + ";Nicky");
|
||||
|
||||
// TODO: also test import part.
|
||||
|
||||
verifyOneComposition(resolver, handler, V21);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user