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

Commit 85d86af9 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change I82be558f into eclair

* changes:
  Fix vCard composer in three points.
parents 609c2c08 30a2e367
Loading
Loading
Loading
Loading
+215 −63
Original line number Diff line number Diff line
@@ -284,7 +284,9 @@ public class VCardComposer {
    private final boolean mUsesQuotedPrintable;
    private final boolean mUsesAndroidProperty;
    private final boolean mUsesDefactProperty;
    private final boolean mUsesUtf8;
    private final boolean mUsesShiftJis;
    private final boolean mUsesQPToPrimaryProperties;

    private Cursor mCursor;
    private int mIdColumn;
@@ -366,7 +368,9 @@ public class VCardComposer {
        mUsesAndroidProperty = VCardConfig
                .usesAndroidSpecificProperty(vcardType);
        mUsesDefactProperty = VCardConfig.usesDefactProperty(vcardType);
        mUsesUtf8 = VCardConfig.usesUtf8(vcardType);
        mUsesShiftJis = VCardConfig.usesShiftJis(vcardType);
        mUsesQPToPrimaryProperties = VCardConfig.usesQPToPrimaryProperties(vcardType);

        if (mIsDoCoMo) {
            mCharsetString = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
@@ -400,6 +404,7 @@ public class VCardComposer {
        if (!(VCardUtils.containsOnlyPrintableAscii(phoneName))) {
            needCharset = true;
        }
        // TODO: QP should be used? Using mUsesQPToPrimaryProperties should help.
        appendVCardLine(builder, VCARD_PROPERTY_FULL_NAME, phoneName, needCharset, false);
        appendVCardLine(builder, VCARD_PROPERTY_NAME, phoneName, needCharset, false);

@@ -598,6 +603,7 @@ public class VCardComposer {
            name = mCursor.getString(NUMBER_COLUMN_INDEX);
        }
        final boolean needCharset = !(VCardUtils.containsOnlyPrintableAscii(name));
        // TODO: QP should be used? Using mUsesQPToPrimaryProperties should help.
        appendVCardLine(builder, VCARD_PROPERTY_FULL_NAME, name, needCharset, false);
        appendVCardLine(builder, VCARD_PROPERTY_NAME, name, needCharset, false);

@@ -634,8 +640,8 @@ public class VCardComposer {
                    ContentValues contentValues = namedContentValues.values;
                    String key = contentValues.getAsString(Data.MIMETYPE);
                    if (key != null) {
                        List<ContentValues> contentValuesList = contentValuesListMap
                                .get(key);
                        List<ContentValues> contentValuesList =
                                contentValuesListMap.get(key);
                        if (contentValuesList == null) {
                            contentValuesList = new ArrayList<ContentValues>();
                            contentValuesListMap.put(key, contentValuesList);
@@ -788,26 +794,46 @@ public class VCardComposer {
        final String displayName = primaryContentValues
                .getAsString(StructuredName.DISPLAY_NAME);

        // For now, some primary element is not encoded into Quoted-Printable, which is not
        // valid in vCard spec strictly. In the future, we may have to have some flag to
        // enable composer to encode these primary field into Quoted-Printable.
        if (!TextUtils.isEmpty(familyName) || !TextUtils.isEmpty(givenName)) {
            final String encodedFamily = escapeCharacters(familyName);
            final String encodedGiven = escapeCharacters(givenName);
            final String encodedMiddle = escapeCharacters(middleName);
            final String encodedPrefix = escapeCharacters(prefix);
            final String encodedSuffix = escapeCharacters(suffix);
            final String encodedFamily;
            final String encodedGiven;
            final String encodedMiddle;
            final String encodedPrefix;
            final String encodedSuffix;

            final boolean reallyUseQuotedPrintableToName =
                (mUsesQPToPrimaryProperties &&
                    !(VCardUtils.containsOnlyNonCrLfPrintableAscii(familyName) &&
                            VCardUtils.containsOnlyNonCrLfPrintableAscii(givenName) &&
                            VCardUtils.containsOnlyNonCrLfPrintableAscii(middleName) &&
                            VCardUtils.containsOnlyNonCrLfPrintableAscii(prefix) &&
                            VCardUtils.containsOnlyNonCrLfPrintableAscii(suffix)));

            if (reallyUseQuotedPrintableToName) {
                encodedFamily = encodeQuotedPrintable(familyName);
                encodedGiven = encodeQuotedPrintable(givenName);
                encodedMiddle = encodeQuotedPrintable(middleName);
                encodedPrefix = encodeQuotedPrintable(prefix);
                encodedSuffix = encodeQuotedPrintable(suffix);
            } else {
                encodedFamily = escapeCharacters(familyName);
                encodedGiven = escapeCharacters(givenName);
                encodedMiddle = escapeCharacters(middleName);
                encodedPrefix = escapeCharacters(prefix);
                encodedSuffix = escapeCharacters(suffix);
            }

            // N property. This order is specified by vCard spec and does not depend on countries.
            builder.append(VCARD_PROPERTY_NAME);
            if (!(VCardUtils.containsOnlyPrintableAscii(familyName) &&
                    VCardUtils.containsOnlyPrintableAscii(givenName) &&
                    VCardUtils.containsOnlyPrintableAscii(middleName) &&
                    VCardUtils.containsOnlyPrintableAscii(prefix) &&
                    VCardUtils.containsOnlyPrintableAscii(suffix))) {
            if (shouldAppendCharsetAttribute(Arrays.asList(
                    familyName, givenName, middleName, prefix, suffix))) {
                builder.append(VCARD_ATTR_SEPARATOR);
                builder.append(mVCardAttributeCharset);
            }
            if (reallyUseQuotedPrintableToName) {
                builder.append(VCARD_ATTR_SEPARATOR);
                builder.append(VCARD_ATTR_ENCODING_QP);
            }

            builder.append(VCARD_DATA_SEPARATOR);
            builder.append(encodedFamily);
@@ -821,25 +847,51 @@ public class VCardComposer {
            builder.append(encodedSuffix);
            builder.append(VCARD_COL_SEPARATOR);

            final String encodedFullname = VCardUtils.constructNameFromElements(
            final String fullname = VCardUtils.constructNameFromElements(
                    VCardConfig.getNameOrderType(mVCardType),
                    encodedFamily, encodedMiddle, encodedGiven, encodedPrefix, encodedSuffix);
            final boolean reallyUseQuotedPrintableToFullname =
                mUsesQPToPrimaryProperties &&
                !VCardUtils.containsOnlyNonCrLfPrintableAscii(fullname);

            final String encodedFullname =
                reallyUseQuotedPrintableToFullname ?
                        encodeQuotedPrintable(fullname) :
                            escapeCharacters(fullname);

            // FN property
            builder.append(VCARD_PROPERTY_FULL_NAME);
            if (!VCardUtils.containsOnlyPrintableAscii(encodedFullname)) {
            if (shouldAppendCharsetAttribute(encodedFullname)) {
                builder.append(VCARD_ATTR_SEPARATOR);
                builder.append(mVCardAttributeCharset);
            }
            if (reallyUseQuotedPrintableToFullname) {
                builder.append(VCARD_ATTR_SEPARATOR);
                builder.append(VCARD_ATTR_ENCODING_QP);
            }
            builder.append(VCARD_DATA_SEPARATOR);
            builder.append(encodedFullname);
            builder.append(VCARD_COL_SEPARATOR);
        } else if (!TextUtils.isEmpty(displayName)) {
            final boolean reallyUseQuotedPrintableToDisplayName =
                (mUsesQPToPrimaryProperties &&
                        !VCardUtils.containsOnlyNonCrLfPrintableAscii(displayName));
            final String encodedDisplayName =
                    reallyUseQuotedPrintableToDisplayName ?
                            encodeQuotedPrintable(displayName) :
                                escapeCharacters(displayName);

            builder.append(VCARD_PROPERTY_NAME);
            if (shouldAppendCharsetAttribute(encodedDisplayName)) {
                builder.append(VCARD_ATTR_SEPARATOR);
                builder.append(mVCardAttributeCharset);
            }
            if (reallyUseQuotedPrintableToDisplayName) {
                builder.append(VCARD_ATTR_SEPARATOR);
                builder.append(VCARD_ATTR_ENCODING_QP);
            }
            builder.append(VCARD_DATA_SEPARATOR);
            builder.append(escapeCharacters(displayName));
            builder.append(encodedDisplayName);
            builder.append(VCARD_ITEM_SEPARATOR);
            builder.append(VCARD_ITEM_SEPARATOR);
            builder.append(VCARD_ITEM_SEPARATOR);
@@ -873,54 +925,65 @@ public class VCardComposer {
            if (mIsV30) {
                final String sortString = VCardUtils
                        .constructNameFromElements(mVCardType,
                                phoneticFamilyName, phoneticMiddleName,
                                phoneticFamilyName,
                                phoneticMiddleName,
                                phoneticGivenName);
                builder.append(VCARD_PROPERTY_SORT_STRING);

                if (!VCardUtils.containsOnlyPrintableAscii(sortString)) {
                    // Strictly, adding charset information is NOT valid in
                    // VCard 3.0,
                    // but we'll add this info since parser side may be able to
                    // use the charset via
                    // this attribute field.
                    //
                    // e.g. Japanese mobile phones use Shift_Jis while RFC 2426
                    // recommends
                    // UTF-8. By adding this field, parsers may be able to know
                    // this text
                    // is NOT UTF-8 but Shift_Jis.
                // Do not need to care about QP, since vCard 3.0 does not allow it.
                final String encodedSortString = escapeCharacters(sortString);
                if (shouldAppendCharsetAttribute(encodedSortString)) {
                    builder.append(VCARD_ATTR_SEPARATOR);
                    builder.append(mVCardAttributeCharset);
                }

                builder.append(VCARD_DATA_SEPARATOR);
                builder.append(sortString);
                builder.append(encodedSortString);
                builder.append(VCARD_COL_SEPARATOR);
            } else {
                // Note: There is no appropriate property for expressing
                // phonetic name in
                // VCard 2.1, while there is in VCard 3.0 (SORT-STRING).
                // We chose to use DoCoMo's way since it is supported by a
                // lot of Japanese mobile phones.
                //
                // TODO: should use Quoted-Pritable?
                //       phonetic name in vCard 2.1, while there is in
                //       vCard 3.0 (SORT-STRING).
                //       We chose to use DoCoMo's way since it is supported by
                //       a lot of Japanese mobile phones. This is "X-" property, so
                //       any parser hopefully would not get confused with this.
                builder.append(VCARD_PROPERTY_SOUND);
                builder.append(VCARD_ATTR_SEPARATOR);
                builder.append(Constants.ATTR_TYPE_X_IRMC_N);
                builder.append(VCARD_ATTR_SEPARATOR);

                if (!(VCardUtils.containsOnlyPrintableAscii(phoneticFamilyName) &&
                        VCardUtils.containsOnlyPrintableAscii(phoneticMiddleName) &&
                        VCardUtils.containsOnlyPrintableAscii(phoneticGivenName))) {
                    builder.append(mVCardAttributeCharset);
                    builder.append(VCARD_DATA_SEPARATOR);
                boolean reallyUseQuotedPrintable =
                    (mUsesQPToPrimaryProperties &&
                            !(VCardUtils.containsOnlyNonCrLfPrintableAscii(
                                    phoneticFamilyName) &&
                              VCardUtils.containsOnlyNonCrLfPrintableAscii(
                                    phoneticMiddleName) &&
                              VCardUtils.containsOnlyNonCrLfPrintableAscii(
                                    phoneticGivenName)));

                final String encodedPhoneticFamilyName;
                final String encodedPhoneticMiddleName;
                final String encodedPhoneticGivenName;
                if (reallyUseQuotedPrintable) {
                    encodedPhoneticFamilyName = encodeQuotedPrintable(phoneticFamilyName);
                    encodedPhoneticMiddleName = encodeQuotedPrintable(phoneticMiddleName);
                    encodedPhoneticGivenName = encodeQuotedPrintable(phoneticGivenName);
                } else {
                    encodedPhoneticFamilyName = escapeCharacters(phoneticFamilyName);
                    encodedPhoneticMiddleName = escapeCharacters(phoneticMiddleName);
                    encodedPhoneticGivenName = escapeCharacters(phoneticGivenName);
                }

                builder.append(escapeCharacters(phoneticFamilyName));
                if (shouldAppendCharsetAttribute(Arrays.asList(
                        encodedPhoneticFamilyName, encodedPhoneticMiddleName,
                        encodedPhoneticGivenName))) {
                    builder.append(VCARD_ATTR_SEPARATOR);
                    builder.append(mVCardAttributeCharset);
                }
                builder.append(VCARD_DATA_SEPARATOR);
                builder.append(encodedPhoneticFamilyName);
                builder.append(VCARD_ITEM_SEPARATOR);
                builder.append(escapeCharacters(phoneticMiddleName));
                builder.append(encodedPhoneticGivenName);
                builder.append(VCARD_ITEM_SEPARATOR);
                builder.append(escapeCharacters(phoneticGivenName));
                builder.append(encodedPhoneticMiddleName);
                builder.append(VCARD_ITEM_SEPARATOR);
                builder.append(VCARD_ITEM_SEPARATOR);
                builder.append(VCARD_COL_SEPARATOR);
@@ -939,21 +1002,72 @@ public class VCardComposer {

        if (mUsesDefactProperty) {
            if (!TextUtils.isEmpty(phoneticGivenName)) {
                final boolean reallyUseQuotedPrintable =
                    (mUsesQPToPrimaryProperties &&
                            !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticGivenName));
                final String encodedPhoneticGivenName;
                if (reallyUseQuotedPrintable) {
                    encodedPhoneticGivenName = encodeQuotedPrintable(phoneticGivenName);
                } else {
                    encodedPhoneticGivenName = escapeCharacters(phoneticGivenName);
                }
                builder.append(VCARD_PROPERTY_X_PHONETIC_FIRST_NAME);
                if (shouldAppendCharsetAttribute(encodedPhoneticGivenName)) {
                    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(phoneticGivenName);
                builder.append(encodedPhoneticGivenName);
                builder.append(VCARD_COL_SEPARATOR);
            }
            if (!TextUtils.isEmpty(phoneticMiddleName)) {
                final boolean reallyUseQuotedPrintable =
                    (mUsesQPToPrimaryProperties &&
                            !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticMiddleName));
                final String encodedPhoneticMiddleName;
                if (reallyUseQuotedPrintable) {
                    encodedPhoneticMiddleName = encodeQuotedPrintable(phoneticMiddleName);
                } else {
                    encodedPhoneticMiddleName = escapeCharacters(phoneticMiddleName);
                }
                builder.append(VCARD_PROPERTY_X_PHONETIC_MIDDLE_NAME);
                if (shouldAppendCharsetAttribute(encodedPhoneticMiddleName)) {
                    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(phoneticMiddleName);
                builder.append(encodedPhoneticMiddleName);
                builder.append(VCARD_COL_SEPARATOR);
            }
            if (!TextUtils.isEmpty(phoneticFamilyName)) {
                final boolean reallyUseQuotedPrintable =
                    (mUsesQPToPrimaryProperties &&
                            !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticFamilyName));
                final String encodedPhoneticFamilyName;
                if (reallyUseQuotedPrintable) {
                    encodedPhoneticFamilyName = encodeQuotedPrintable(phoneticFamilyName);
                } else {
                    encodedPhoneticFamilyName = escapeCharacters(phoneticFamilyName);
                }
                builder.append(VCARD_PROPERTY_X_PHONETIC_LAST_NAME);
                if (shouldAppendCharsetAttribute(encodedPhoneticFamilyName)) {
                    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(phoneticFamilyName);
                builder.append(encodedPhoneticFamilyName);
                builder.append(VCARD_COL_SEPARATOR);
            }
        }
@@ -975,21 +1089,32 @@ public class VCardComposer {
            }

            for (ContentValues contentValues : contentValuesList) {
                final String nickname = contentValues
                        .getAsString(Nickname.NAME);
                final String nickname = contentValues.getAsString(Nickname.NAME);
                if (TextUtils.isEmpty(nickname)) {
                    continue;
                }
                builder.append(propertyNickname);

                if (!VCardUtils.containsOnlyPrintableAscii(propertyNickname)) {
                    //  Strictly, this is not valid in vCard 3.0. See above.
                final String encodedNickname;
                final boolean reallyUseQuotedPrintable =
                    (mUsesQuotedPrintable &&
                            !VCardUtils.containsOnlyNonCrLfPrintableAscii(nickname));
                if (reallyUseQuotedPrintable) {
                    encodedNickname = encodeQuotedPrintable(nickname);
                } 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);
                }
                builder.append(VCARD_DATA_SEPARATOR);
                builder.append(escapeCharacters(nickname));
                builder.append(encodedNickname);
                builder.append(VCARD_COL_SEPARATOR);
            }
        }
@@ -1048,7 +1173,6 @@ public class VCardComposer {
                    continue;
                }
                emailAddressExists = true;
                // Do not allow completely same email address line emitted into each file.
                if (!addressSet.contains(emailAddress)) {
                    addressSet.add(emailAddress);
                    appendVCardEmailLine(builder, type, label, emailAddress);
@@ -1065,7 +1189,6 @@ public class VCardComposer {
            final Map<String, List<ContentValues>> contentValuesListMap) {
        final List<ContentValues> contentValuesList = contentValuesListMap
                .get(StructuredPostal.CONTENT_ITEM_TYPE);

        if (contentValuesList != null) {
            if (mIsDoCoMo) {
                appendPostalsForDoCoMo(builder, contentValuesList);
@@ -1082,7 +1205,7 @@ public class VCardComposer {
    }

    /**
     * Try to append just one line. If there's no appropriate address
     * Tries to append just one line. If there's no appropriate address
     * information, append an empty line.
     */
    private void appendPostalsForDoCoMo(final StringBuilder builder,
@@ -1751,6 +1874,35 @@ public class VCardComposer {
        builder.append(type);
    }

    /**
     * Returns true when the property line should contain charset attribute
     * information. This method may return true even when vCard version is 3.0.
     *
     * Strictly, adding charset information is invalid in VCard 3.0.
     * However we'll add the info only when used charset is not UTF-8
     * in vCard 3.0 format, since parser side may be able to use the charset
     * via this field, though we may encounter another problem by adding it...
     *
     * e.g. Japanese mobile phones use Shift_Jis while RFC 2426
     * recommends UTF-8. By adding this field, parsers may be able
     * to know this text is NOT UTF-8 but Shift_Jis.
     */
    private boolean shouldAppendCharsetAttribute(final String propertyValue) {
        return (!VCardUtils.containsOnlyPrintableAscii(propertyValue) &&
                        (!mIsV30 || !mUsesUtf8));
    }

    private boolean shouldAppendCharsetAttribute(final List<String> propertyValueList) {
        boolean shouldAppendBasically = false;
        for (String propertyValue : propertyValueList) {
            if (!VCardUtils.containsOnlyPrintableAscii(propertyValue)) {
                shouldAppendBasically = true;
                break;
            }
        }
        return shouldAppendBasically && (!mIsV30 || !mUsesUtf8);
    }

    private String encodeQuotedPrintable(String str) {
        if (TextUtils.isEmpty(str)) {
            return "";
+34 −12
Original line number Diff line number Diff line
@@ -94,10 +94,20 @@ 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.
     */
    public static final int FLAG_USE_QP_TO_PRIMARY_PROPERTIES = 0x10000000;
    
    // VCard types


    /**
     * 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.
@@ -114,10 +124,10 @@ public class VCardConfig {
    /**
     * 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 especially
     * in parsing part.
     * Note that this type is not fully implemented, so probably some bugs remain both in
     * parsing and composing.
     *
     * TODO: implement this type.
     * TODO: implement this type correctly.
     */
    public static final int VCARD_TYPE_V30_GENERIC =
        (FLAG_V30 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
@@ -243,6 +253,10 @@ public class VCardConfig {
                (vcardType == VCARD_TYPE_DOCOMO));
    }

    public static boolean usesUtf8(int vcardType) {
        return ((vcardType & FLAG_CHARSET_UTF8) != 0);
    }

    public static boolean usesShiftJis(int vcardType) {
        return ((vcardType & FLAG_CHARSET_SHIFT_JIS) != 0);
    }
@@ -278,6 +292,14 @@ public class VCardConfig {
        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));
    }

    private VCardConfig() {
    }
}
 No newline at end of file