diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java index 4c62515bc921a..377e20155bf17 100644 --- a/core/java/android/pim/vcard/VCardBuilder.java +++ b/core/java/android/pim/vcard/VCardBuilder.java @@ -1072,7 +1072,7 @@ public class VCardBuilder { public VCardBuilder appendNotes(final List contentValuesList) { if (contentValuesList != null) { if (mOnlyOneNoteFieldIsAvailable) { - StringBuilder noteBuilder = new StringBuilder(); + final StringBuilder noteBuilder = new StringBuilder(); boolean first = true; for (final ContentValues contentValues : contentValuesList) { String note = contentValues.getAsString(Note.NOTE); @@ -1593,8 +1593,7 @@ public class VCardBuilder { } public void appendLine(final String propertyName, final List parameterList, - final String rawValue, final boolean needCharset, - boolean needQuotedPrintable) { + final String rawValue, final boolean needCharset, boolean needQuotedPrintable) { mBuilder.append(propertyName); if (parameterList != null && parameterList.size() > 0) { mBuilder.append(VCARD_PARAM_SEPARATOR); @@ -1725,31 +1724,12 @@ public class VCardBuilder { return false; } - private String encodeQuotedPrintable(String str) { + private String encodeQuotedPrintable(final String str) { if (TextUtils.isEmpty(str)) { return ""; } - { - // Replace "\n" and "\r" with "\r\n". - final StringBuilder tmpBuilder = new StringBuilder(); - int length = str.length(); - for (int i = 0; i < length; i++) { - char ch = str.charAt(i); - if (ch == '\r') { - if (i + 1 < length && str.charAt(i + 1) == '\n') { - i++; - } - tmpBuilder.append("\r\n"); - } else if (ch == '\n') { - tmpBuilder.append("\r\n"); - } else { - tmpBuilder.append(ch); - } - } - str = tmpBuilder.toString(); - } - final StringBuilder tmpBuilder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(); int index = 0; int lineCount = 0; byte[] strArray = null; @@ -1762,7 +1742,7 @@ public class VCardBuilder { strArray = str.getBytes(); } while (index < strArray.length) { - tmpBuilder.append(String.format("=%02X", strArray[index])); + builder.append(String.format("=%02X", strArray[index])); index += 1; lineCount += 3; @@ -1774,12 +1754,12 @@ public class VCardBuilder { // it will become // 6 bytes. // 76 - 6 - 3 = 67 - tmpBuilder.append("=\r\n"); + builder.append("=\r\n"); lineCount = 0; } } - return tmpBuilder.toString(); + return builder.toString(); } diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java index 45c0172288f04..36f9006a59854 100644 --- a/core/java/android/pim/vcard/VCardUtils.java +++ b/core/java/android/pim/vcard/VCardUtils.java @@ -74,6 +74,7 @@ public class VCardUtils { sPhoneTypesUnknownToContactsSet = new HashSet(); sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MODEM); + sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MSG); sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_BBS); sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_VIDEO); @@ -399,10 +400,10 @@ public class VCardUtils { final int length = str.length(); final int asciiFirst = 0x20; - final int asciiLast = 0x126; + final int asciiLast = 0x7E; // included for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) { - int c = str.codePointAt(i); - if (c < asciiFirst || asciiLast < c) { + final int c = str.codePointAt(i); + if (!((asciiFirst <= c && c <= asciiLast) || c == '\r' || c == '\n')) { return false; } } @@ -421,10 +422,10 @@ public class VCardUtils { final int length = str.length(); final int asciiFirst = 0x20; - final int asciiLast = 0x126; + final int asciiLast = 0x7E; // included for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) { - int c = str.codePointAt(i); - if (c < asciiFirst || asciiLast < c || c == '\n' || c == '\r') { + final int c = str.codePointAt(i); + if (!(asciiFirst <= c && c <= asciiLast)) { return false; } } @@ -445,19 +446,19 @@ public class VCardUtils { return true; } - final int lowerAlphabetFirst = 0x41; // included ('A') - final int lowerAlphabetLast = 0x5b; // not included ('[') - final int upperAlphabetFirst = 0x61; // included ('a') - final int upperAlphabetLast = 0x7b; // included ('{') - final int digitFirst = 0x30; // included ('0') - final int digitLast = 0x39; // included ('9') + final int upperAlphabetFirst = 0x41; // A + final int upperAlphabetAfterLast = 0x5b; // [ + final int lowerAlphabetFirst = 0x61; // a + final int lowerAlphabetAfterLast = 0x7b; // { + final int digitFirst = 0x30; // 0 + final int digitAfterLast = 0x3A; // : final int hyphen = '-'; final int length = str.length(); for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) { int codepoint = str.codePointAt(i); - if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetLast) || - (upperAlphabetFirst <= codepoint && codepoint < upperAlphabetLast) || - (digitFirst <= codepoint && codepoint < digitLast) || + if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetAfterLast) || + (upperAlphabetFirst <= codepoint && codepoint < upperAlphabetAfterLast) || + (digitFirst <= codepoint && codepoint < digitAfterLast) || (codepoint == hyphen))) { return false; } diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java index 89134a13ededd..14a789abd861f 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java @@ -122,21 +122,17 @@ public class PropertyNode { if (propName == null || !propName.equals(node.propName)) { return false; - } else if (!paramMap.equals(node.paramMap)) { + } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) { return false; - } else if (!(paramMap_TYPE.size() == node.paramMap_TYPE.size()) && - !paramMap_TYPE.equals(node.paramMap_TYPE)) { - Log.d("@@@", "paramMap_Type: " + paramMap_TYPE.size() + ", " - + node.paramMap_TYPE.size()); + } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) { return false; } else if (!propGroupSet.equals(node.propGroupSet)) { return false; } - + if (propValue_bytes != null && Arrays.equals(propValue_bytes, node.propValue_bytes)) { return true; } else { - // Log.d("@@@", propValue + ", " + node.propValue); if (!propValue.equals(node.propValue)) { return false; } @@ -173,6 +169,7 @@ public class PropertyNode { builder.append("]"); if (!propGroupSet.isEmpty()) { builder.append(", propGroupSet: ["); + first = true; for (String elem : propGroupSet) { if (first) { first = false; @@ -193,8 +190,9 @@ public class PropertyNode { builder.append(", propValue_bytes size: "); builder.append(propValue_bytes.length); } - builder.append(", propValue: "); + builder.append(", propValue: \""); builder.append(propValue); + builder.append("\""); return builder.toString(); } } diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java index faafb999916ec..052286753b77b 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardJapanizationTests.java @@ -18,10 +18,14 @@ package com.android.unit_tests.vcard; import android.content.ContentValues; import android.pim.vcard.VCardConfig; +import android.provider.ContactsContract.CommonDataKinds.Note; +import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.CommonDataKinds.StructuredName; import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; import com.android.unit_tests.vcard.PropertyNodesVerifierElem.TypeSet; +import com.android.unit_tests.vcard.VCardTestsBase.ContactEntry; +import com.android.unit_tests.vcard.VCardTestsBase.VCardVerifier; import java.util.Arrays; @@ -317,4 +321,53 @@ public class VCardJapanizationTests extends VCardTestsBase { Arrays.asList("3", "", "", "", "", "", ""), new TypeSet("HOME")); verifier.verify(); } -} \ No newline at end of file + + private void testJapanesePhoneNumberCommon(int vcardType) { + VCardVerifier verifier = new VCardVerifier(vcardType); + ContactEntry entry = verifier.addInputEntry(); + entry.buildData(Phone.CONTENT_ITEM_TYPE) + .put(Phone.NUMBER, "0312341234") + .put(Phone.TYPE, Phone.TYPE_HOME); + entry.buildData(Phone.CONTENT_ITEM_TYPE) + .put(Phone.NUMBER, "09012341234") + .put(Phone.TYPE, Phone.TYPE_MOBILE); + verifier.addPropertyNodesVerifierElemWithEmptyName() + .addNodeWithoutOrder("TEL", "03-1234-1234", new TypeSet("HOME")) + .addNodeWithoutOrder("TEL", "090-1234-1234", new TypeSet("WORK")); + } + + public void testJapanesePhoneNumberV21_1() { + testJapanesePhoneNumberCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE_UTF8); + } + + public void testJapanesePhoneNumberDoCoMo() { + testJapanesePhoneNumberCommon(VCardConfig.VCARD_TYPE_DOCOMO); + } + + public void testJapanesePhoneNumberV30() { + testJapanesePhoneNumberCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE_UTF8); + } + + public void testNoteDoCoMo() { + VCardVerifier verifier = new VCardVerifier(VCardConfig.VCARD_TYPE_DOCOMO); + ContactEntry entry = verifier.addInputEntry(); + entry.buildData(Note.CONTENT_ITEM_TYPE) + .put(Note.NOTE, "note1"); + entry.buildData(Note.CONTENT_ITEM_TYPE) + .put(Note.NOTE, "note2"); + entry.buildData(Note.CONTENT_ITEM_TYPE) + .put(Note.NOTE, "note3"); + + // More than one note fields must be aggregated into one note. + verifier.addPropertyNodesVerifierElemWithEmptyName() + .addNodeWithoutOrder("TEL", "", new TypeSet("HOME")) + .addNodeWithoutOrder("EMAIL", "", new TypeSet("HOME")) + .addNodeWithoutOrder("X-CLASS", "PUBLIC") + .addNodeWithoutOrder("X-REDUCTION", "") + .addNodeWithoutOrder("X-NO", "") + .addNodeWithoutOrder("X-DCM-HMN-MODE", "") + .addNodeWithoutOrder("ADR", "", new TypeSet("HOME")) + .addNodeWithoutOrder("NOTE", "note1\nnote2\nnote3", mContentValuesForQP); + verifier.verify(); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java index 00debb52e3c06..7b5f2168ff5db 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java @@ -957,8 +957,9 @@ class CustomMockContext extends MockContext { final String value = entry.getValue(); builder.append(' '); builder.append(key); - builder.append('='); + builder.append("=\""); builder.append(value); + builder.append('"'); } return builder.toString(); } diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardUtilsTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardUtilsTests.java new file mode 100644 index 0000000000000..6202bdba29347 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardUtilsTests.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.unit_tests.vcard; + +import android.pim.vcard.VCardUtils; + +import junit.framework.TestCase; + +public class VCardUtilsTests extends TestCase { + public void testContainsOnlyPrintableAscii() { + assertTrue(VCardUtils.containsOnlyPrintableAscii(null)); + assertTrue(VCardUtils.containsOnlyPrintableAscii("")); + assertTrue(VCardUtils.containsOnlyPrintableAscii("abcdefghijklmnopqrstuvwxyz")); + assertTrue(VCardUtils.containsOnlyPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + StringBuilder builder = new StringBuilder(); + for (int i = 0x20; i < 0x7F; i++) { + builder.append((char)i); + } + assertTrue(VCardUtils.containsOnlyPrintableAscii(builder.toString())); + assertTrue(VCardUtils.containsOnlyPrintableAscii("\r\n")); + assertFalse(VCardUtils.containsOnlyPrintableAscii("\u0019")); + assertFalse(VCardUtils.containsOnlyPrintableAscii("\u007F")); + } + + public void testContainsOnlyNonCrLfPrintableAscii() { + assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii(null)); + assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("")); + assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz")); + assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + StringBuilder builder = new StringBuilder(); + for (int i = 0x20; i < 0x7F; i++) { + builder.append((char)i); + } + assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii(builder.toString())); + assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\u0019")); + assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\u007F")); + assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\r")); + assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\n")); + } + + public void testContainsOnlyAlphaDigitHyphen() { + assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen(null)); + assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen("")); + assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz")); + assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("0123456789-")); + for (int i = 0; i < 0x30; i++) { + if (i == 0x2D) { // - + continue; + } + assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i))); + } + for (int i = 0x3A; i < 0x41; i++) { + assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i))); + } + for (int i = 0x5B; i < 0x61; i++) { + assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i))); + } + for (int i = 0x7B; i < 0x100; i++) { + assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i))); + } + } +}