Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3c828e24 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change I9195a354 into eclair-mr2

* changes:
  Add partial support of Android-specific properties.
parents 95240270 837cba33
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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() {
    }
}
 No newline at end of file
+48 −5
Original line number Diff line number Diff line
@@ -442,6 +442,7 @@ 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.
     */
@@ -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);
+119 −25
Original line number Diff line number Diff line
@@ -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);
            }

            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);
                appendVCardLineWithCharsetAndQPDetection(builder,
                        Constants.PROPERTY_NICKNAME, nickname);
            }
            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.
     */
+19 −3
Original line number Diff line number Diff line
@@ -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);
    }
}