From d2145b97fb6d5eb4ef0f746869e9390e5a6853d6 Mon Sep 17 00:00:00 2001 From: Daisuke Miyakawa Date: Tue, 17 Nov 2009 17:03:23 +0900 Subject: [PATCH] Clean up codes and remove/modify stale codes/comments. Internal issue number: 2195990 --- core/java/android/pim/vcard/VCardBuilder.java | 27 +- core/java/android/pim/vcard/VCardConfig.java | 17 +- core/java/android/pim/vcard/VCardEntry.java | 127 ++++------ .../pim/vcard/VCardEntryCommitter.java | 17 +- .../pim/vcard/VCardEntryConstructor.java | 125 ++++------ .../android/pim/vcard/VCardEntryCounter.java | 9 +- .../android/pim/vcard/VCardEntryHandler.java | 4 + .../android/pim/vcard/VCardInterpreter.java | 68 +++-- ...n.java => VCardInterpreterCollection.java} | 57 +++-- core/java/android/pim/vcard/VCardParser.java | 33 +-- .../android/pim/vcard/VCardParser_V21.java | 234 +++++++++--------- .../android/pim/vcard/VCardParser_V30.java | 39 ++- .../pim/vcard/VCardSourceDetector.java | 4 +- .../vcard/PropertyNodesVerifier.java | 6 +- .../unit_tests/vcard/VCardTestsBase.java | 4 +- .../unit_tests/vcard/VNodeBuilder.java | 7 +- 16 files changed, 387 insertions(+), 391 deletions(-) rename core/java/android/pim/vcard/{VCardInterPreterCollection.java => VCardInterpreterCollection.java} (54%) diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java index eb40a3f48e7fb..4c62515bc921a 100644 --- a/core/java/android/pim/vcard/VCardBuilder.java +++ b/core/java/android/pim/vcard/VCardBuilder.java @@ -89,7 +89,7 @@ public class VCardBuilder { private final boolean mIsJapaneseMobilePhone; private final boolean mOnlyOneNoteFieldIsAvailable; private final boolean mIsDoCoMo; - private final boolean mUsesQuotedPrintable; + private final boolean mShouldUseQuotedPrintable; private final boolean mUsesAndroidProperty; private final boolean mUsesDefactProperty; private final boolean mUsesUtf8; @@ -110,7 +110,7 @@ public class VCardBuilder { mVCardType = vcardType; mIsV30 = VCardConfig.isV30(vcardType); - mUsesQuotedPrintable = VCardConfig.usesQuotedPrintable(vcardType); + mShouldUseQuotedPrintable = VCardConfig.shouldUseQuotedPrintable(vcardType); mIsDoCoMo = VCardConfig.isDoCoMo(vcardType); mIsJapaneseMobilePhone = VCardConfig.needsToConvertPhoneticString(vcardType); mOnlyOneNoteFieldIsAvailable = VCardConfig.onlyOneNoteFieldIsAvailable(vcardType); @@ -529,7 +529,7 @@ public class VCardBuilder { if (mUsesDefactProperty) { if (!TextUtils.isEmpty(phoneticGivenName)) { final boolean reallyUseQuotedPrintable = - (mUsesQuotedPrintable && + (mShouldUseQuotedPrintable && !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticGivenName)); final String encodedPhoneticGivenName; if (reallyUseQuotedPrintable) { @@ -552,7 +552,7 @@ public class VCardBuilder { } if (!TextUtils.isEmpty(phoneticMiddleName)) { final boolean reallyUseQuotedPrintable = - (mUsesQuotedPrintable && + (mShouldUseQuotedPrintable && !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticMiddleName)); final String encodedPhoneticMiddleName; if (reallyUseQuotedPrintable) { @@ -575,7 +575,7 @@ public class VCardBuilder { } if (!TextUtils.isEmpty(phoneticFamilyName)) { final boolean reallyUseQuotedPrintable = - (mUsesQuotedPrintable && + (mShouldUseQuotedPrintable && !VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticFamilyName)); final String encodedPhoneticFamilyName; if (reallyUseQuotedPrintable) { @@ -846,7 +846,7 @@ public class VCardBuilder { if (!appendCharset && !VCardUtils.containsOnlyPrintableAscii(data)) { appendCharset = true; } - if (mUsesQuotedPrintable && + if (mShouldUseQuotedPrintable && !VCardUtils.containsOnlyNonCrLfPrintableAscii(data)) { reallyUseQuotedPrintable = true; break; @@ -1017,13 +1017,13 @@ public class VCardBuilder { final String orgline = orgBuilder.toString(); appendLine(VCardConstants.PROPERTY_ORG, orgline, !VCardUtils.containsOnlyPrintableAscii(orgline), - (mUsesQuotedPrintable && + (mShouldUseQuotedPrintable && !VCardUtils.containsOnlyNonCrLfPrintableAscii(orgline))); if (!TextUtils.isEmpty(title)) { appendLine(VCardConstants.PROPERTY_TITLE, title, !VCardUtils.containsOnlyPrintableAscii(title), - (mUsesQuotedPrintable && + (mShouldUseQuotedPrintable && !VCardUtils.containsOnlyNonCrLfPrintableAscii(title))); } } @@ -1094,7 +1094,7 @@ public class VCardBuilder { final boolean shouldAppendCharsetInfo = !VCardUtils.containsOnlyPrintableAscii(noteStr); final boolean reallyUseQuotedPrintable = - (mUsesQuotedPrintable && + (mShouldUseQuotedPrintable && !VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr)); appendLine(VCardConstants.PROPERTY_NOTE, noteStr, shouldAppendCharsetInfo, reallyUseQuotedPrintable); @@ -1105,7 +1105,7 @@ public class VCardBuilder { final boolean shouldAppendCharsetInfo = !VCardUtils.containsOnlyPrintableAscii(noteStr); final boolean reallyUseQuotedPrintable = - (mUsesQuotedPrintable && + (mShouldUseQuotedPrintable && !VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr)); appendLine(VCardConstants.PROPERTY_NOTE, noteStr, shouldAppendCharsetInfo, reallyUseQuotedPrintable); @@ -1541,9 +1541,10 @@ public class VCardBuilder { public void appendLineWithCharsetAndQPDetection(final String propertyName, final List parameterList, final String rawValue) { final boolean needCharset = - (mUsesQuotedPrintable && !VCardUtils.containsOnlyPrintableAscii(rawValue)); + !VCardUtils.containsOnlyPrintableAscii(rawValue); final boolean reallyUseQuotedPrintable = - !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValue); + (mShouldUseQuotedPrintable && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValue)); appendLine(propertyName, parameterList, rawValue, needCharset, reallyUseQuotedPrintable); } @@ -1553,7 +1554,7 @@ public class VCardBuilder { boolean needCharset = false; boolean reallyUseQuotedPrintable = false; for (String rawValue : rawValueList) { - if (!needCharset && mUsesQuotedPrintable && + if (!needCharset && mShouldUseQuotedPrintable && !VCardUtils.containsOnlyPrintableAscii(rawValue)) { needCharset = true; } diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java index 9a7fb214f904f..ff150a4f1717d 100644 --- a/core/java/android/pim/vcard/VCardConfig.java +++ b/core/java/android/pim/vcard/VCardConfig.java @@ -27,10 +27,7 @@ import java.util.Set; * 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. + private static final String LOG_TAG = "VCardConfig"; /* package */ static final int LOG_LEVEL_NONE = 0; /* package */ static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1; @@ -44,9 +41,6 @@ public class VCardConfig { // decode the unicode to the original charset. If not, this setting will cause some bug. public static final String DEFAULT_CHARSET = "iso-8859-1"; - // TODO: make the other codes use this flag - public static final boolean IGNORE_CASE_EXCEPT_VALUE = true; - public static final int FLAG_V21 = 0; public static final int FLAG_V30 = 1; @@ -319,7 +313,7 @@ public class VCardConfig { FLAG_CONVERT_PHONETIC_NAME_STRINGS | FLAG_REFRAIN_QP_TO_PRIMARY_PROPERTIES); - public static final String VCARD_TYPE_V21_JAPANESE_MOBILE_STR = "v21_japanese_mobile"; + /* package */ static final String VCARD_TYPE_V21_JAPANESE_MOBILE_STR = "v21_japanese_mobile"; /** *

@@ -334,7 +328,7 @@ public class VCardConfig { public static final int VCARD_TYPE_DOCOMO = (VCARD_TYPE_V21_JAPANESE_MOBILE | FLAG_DOCOMO); - private static final String VCARD_TYPE_DOCOMO_STR = "docomo"; + /* package */ static final String VCARD_TYPE_DOCOMO_STR = "docomo"; public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC_UTF8; @@ -369,7 +363,6 @@ public class VCardConfig { 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; } @@ -379,7 +372,7 @@ public class VCardConfig { return ((vcardType & FLAG_V30) != 0); } - public static boolean usesQuotedPrintable(final int vcardType) { + public static boolean shouldUseQuotedPrintable(final int vcardType) { return !isV30(vcardType); } @@ -408,7 +401,7 @@ public class VCardConfig { } public static boolean refrainsQPToPrimaryProperties(final int vcardType) { - return (!usesQuotedPrintable(vcardType) || + return (!shouldUseQuotedPrintable(vcardType) || ((vcardType & FLAG_REFRAIN_QP_TO_PRIMARY_PROPERTIES) != 0)); } diff --git a/core/java/android/pim/vcard/VCardEntry.java b/core/java/android/pim/vcard/VCardEntry.java index a6e432d734693..20eee84fa8c0b 100644 --- a/core/java/android/pim/vcard/VCardEntry.java +++ b/core/java/android/pim/vcard/VCardEntry.java @@ -46,6 +46,7 @@ import android.util.Log; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -57,11 +58,11 @@ import java.util.Map; public class VCardEntry { private static final String LOG_TAG = "VCardEntry"; + private final static int DEFAULT_ORGANIZATION_TYPE = Organization.TYPE_WORK; + private static final String ACCOUNT_TYPE_GOOGLE = "com.google"; private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts"; - // Key: the name shown in VCard. e.g. "X-AIM", "X-ICQ" - // Value: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol} private static final Map sImMap = new HashMap(); static { @@ -107,9 +108,6 @@ public class VCardEntry { } } - /** - * @hide only for testing - */ static public class EmailData { public final int type; public final String data; @@ -154,17 +152,12 @@ public class VCardEntry { public final String region; public final String postalCode; public final String country; - public final int type; - - // Used only when type variable is TYPE_CUSTOM. public final String label; - - // isPrimary is changable only when there's no appropriate one existing in - // the original VCard. public boolean isPrimary; - public PostalData(int type, List propValueList, - String label, boolean isPrimary) { + + public PostalData(final int type, final List propValueList, + final String label, boolean isPrimary) { this.type = type; dataArray = new String[ADDR_MAX_DATA_SIZE]; @@ -173,9 +166,9 @@ public class VCardEntry { size = ADDR_MAX_DATA_SIZE; } - // adr-value = 0*6(text-value ";") text-value - // ; PO Box, Extended Address, Street, Locality, Region, Postal - // ; Code, Country Name + // adr-value = 0*6(text-value ";") text-value + // ; PO Box, Extended Address, Street, Locality, Region, Postal + // ; Code, Country Name // // Use Iterator assuming List may be LinkedList, though actually it is // always ArrayList in the current implementation. @@ -197,7 +190,6 @@ public class VCardEntry { this.region = dataArray[4]; this.postalCode = dataArray[5]; this.country = dataArray[6]; - this.label = label; this.isPrimary = isPrimary; } @@ -207,15 +199,15 @@ public class VCardEntry { if (!(obj instanceof PostalData)) { return false; } - PostalData postalData = (PostalData)obj; + final PostalData postalData = (PostalData)obj; return (Arrays.equals(dataArray, postalData.dataArray) && (type == postalData.type && (type == StructuredPostal.TYPE_CUSTOM ? (label == postalData.label) : true)) && (isPrimary == postalData.isPrimary)); } - - public String getFormattedAddress(int vcardType) { + + public String getFormattedAddress(final int vcardType) { StringBuilder builder = new StringBuilder(); boolean empty = true; if (VCardConfig.isJapaneseDevice(vcardType)) { @@ -225,9 +217,10 @@ public class VCardEntry { if (!TextUtils.isEmpty(addressPart)) { if (!empty) { builder.append(' '); + } else { + empty = false; } builder.append(addressPart); - empty = false; } } } else { @@ -236,9 +229,10 @@ public class VCardEntry { if (!TextUtils.isEmpty(addressPart)) { if (!empty) { builder.append(' '); + } else { + empty = false; } builder.append(addressPart); - empty = false; } } } @@ -252,17 +246,16 @@ public class VCardEntry { type, label, isPrimary); } } - + static public class OrganizationData { public final int type; - // non-final is Intended: we may change the values since this info is separated into + // non-final is Intentional: we may change the values since this info is separated into // two parts in vCard: "ORG" + "TITLE". public String companyName; public String departmentName; public String titleName; - // isPrimary is changable only when there's no appropriate one existing in - // the original VCard. public boolean isPrimary; + public OrganizationData(int type, String companyName, String departmentName, @@ -302,16 +295,16 @@ public class VCardEntry { public final int type; public final String data; public final boolean isPrimary; - - public ImData(int protocol, String customProtocol, int type, - String data, boolean isPrimary) { + + public ImData(final int protocol, final String customProtocol, final int type, + final String data, final boolean isPrimary) { this.protocol = protocol; this.customProtocol = customProtocol; this.type = type; this.data = data; this.isPrimary = isPrimary; } - + @Override public boolean equals(Object obj) { if (!(obj instanceof ImData)) { @@ -324,7 +317,7 @@ public class VCardEntry { && (data != null ? data.equals(imData.data) : (imData.data == null)) && isPrimary == imData.isPrimary); } - + @Override public String toString() { return String.format( @@ -333,7 +326,7 @@ public class VCardEntry { } } - static public class PhotoData { + public static class PhotoData { public static final String FORMAT_FLASH = "SWF"; public final int type; public final String formatName; // used when type is not defined in ContactsContract. @@ -367,13 +360,13 @@ public class VCardEntry { } } - static /* package */ class Property { + /* package */ static class Property { private String mPropertyName; private Map> mParameterMap = new HashMap>(); private List mPropertyValueList = new ArrayList(); private byte[] mPropertyBytes; - + public void setPropertyName(final String propertyName) { mPropertyName = propertyName; } @@ -464,18 +457,12 @@ public class VCardEntry { mAccount = account; } - /** - * Add a phone info to phoneList. - * @param data phone number - * @param type type col of content://contacts/phones - * @param label lable col of content://contacts/phones - */ - private void addPhone(int type, String data, String label, boolean isPrimary){ + private void addPhone(int type, String data, String label, boolean isPrimary) { if (mPhoneList == null) { mPhoneList = new ArrayList(); } - StringBuilder builder = new StringBuilder(); - String trimed = data.trim(); + final StringBuilder builder = new StringBuilder(); + final String trimed = data.trim(); final String formattedNumber; if (type == Phone.TYPE_PAGER) { formattedNumber = trimed; @@ -532,13 +519,15 @@ public class VCardEntry { departmentName, titleName, isPrimary)); } - private static final List sEmptyList = new ArrayList(0); - + private static final List sEmptyList = + Collections.unmodifiableList(new ArrayList(0)); + /** * Set "ORG" related values to the appropriate data. If there's more than one - * OrganizationData objects, this input data are attached to the last one which does not - * have valid values (not including empty but only null). If there's no - * OrganizationData object, a new OrganizationData is created, whose title is set to null. + * {@link OrganizationData} objects, this input data are attached to the last one which + * does not have valid values (not including empty but only null). If there's no + * {@link OrganizationData} object, a new {@link OrganizationData} is created, + * whose title is set to null. */ private void handleOrgValue(final int type, List orgList, boolean isPrimary) { if (orgList == null) { @@ -596,8 +585,6 @@ public class VCardEntry { addNewOrganization(type, companyName, departmentName, null, isPrimary); } - private final static int DEFAULT_ORGANIZATION_TYPE = Organization.TYPE_WORK; - /** * Set "title" value to the appropriate data. If there's more than one * OrganizationData objects, this input is attached to the last one which does not @@ -658,25 +645,20 @@ public class VCardEntry { } switch (size) { - // fallthrough - case 5: - mSuffix = elems.get(4); - case 4: - mPrefix = elems.get(3); - case 3: - mMiddleName = elems.get(2); - case 2: - mGivenName = elems.get(1); - default: - mFamilyName = elems.get(0); + // fallthrough + case 5: mSuffix = elems.get(4); + case 4: mPrefix = elems.get(3); + case 3: mMiddleName = elems.get(2); + case 2: mGivenName = elems.get(1); + default: mFamilyName = elems.get(0); } } /** - * Some Japanese mobile phones use this field for phonetic name, - * since vCard 2.1 does not have "SORT-STRING" type. - * Also, in some cases, the field has some ';'s in it. - * Assume the ';' means the same meaning in N property + * Note: Some Japanese mobile phones use this field for phonetic name, + * since vCard 2.1 does not have "SORT-STRING" type. + * Also, in some cases, the field has some ';'s in it. + * Assume the ';' means the same meaning in N property */ @SuppressWarnings("fallthrough") private void handlePhoneticNameFromSound(List elems) { @@ -728,18 +710,15 @@ public class VCardEntry { } switch (size) { - // fallthrough - case 3: - mPhoneticMiddleName = elems.get(2); - case 2: - mPhoneticGivenName = elems.get(1); - default: - mPhoneticFamilyName = elems.get(0); + // fallthrough + case 3: mPhoneticMiddleName = elems.get(2); + case 2: mPhoneticGivenName = elems.get(1); + default: mPhoneticFamilyName = elems.get(0); } } - public void addProperty(Property property) { - String propName = property.mPropertyName; + public void addProperty(final Property property) { + final String propName = property.mPropertyName; final Map> paramMap = property.mParameterMap; final List propValueList = property.mPropertyValueList; byte[] propBytes = property.mPropertyBytes; diff --git a/core/java/android/pim/vcard/VCardEntryCommitter.java b/core/java/android/pim/vcard/VCardEntryCommitter.java index a340ccabe24c2..ebbbab69f88c6 100644 --- a/core/java/android/pim/vcard/VCardEntryCommitter.java +++ b/core/java/android/pim/vcard/VCardEntryCommitter.java @@ -19,26 +19,29 @@ import android.content.ContentResolver; import android.util.Log; /** - * EntryHandler implementation which commits the entry to ContentResolver. - * - * Note: + *

+ * {@link VCardEntryHandler} implementation which commits the entry to ContentResolver. + *

+ *

+ * Note:
* Each vCard may contain big photo images encoded by BASE64, * If we store all vCard entries in memory, OutOfMemoryError may be thrown. * Thus, this class push each VCard entry into ContentResolver immediately. + *

*/ public class VCardEntryCommitter implements VCardEntryHandler { - public static String LOG_TAG = "vcard.EntryComitter"; + public static String LOG_TAG = "VCardEntryComitter"; - private ContentResolver mContentResolver; + private final ContentResolver mContentResolver; private long mTimeToCommit; - + public VCardEntryCommitter(ContentResolver resolver) { mContentResolver = resolver; } public void onStart() { } - + public void onEnd() { if (VCardConfig.showPerformanceLog()) { Log.d(LOG_TAG, String.format("time to commit entries: %d ms", mTimeToCommit)); diff --git a/core/java/android/pim/vcard/VCardEntryConstructor.java b/core/java/android/pim/vcard/VCardEntryConstructor.java index e82c0c2fdb8f4..290ca2bfec14d 100644 --- a/core/java/android/pim/vcard/VCardEntryConstructor.java +++ b/core/java/android/pim/vcard/VCardEntryConstructor.java @@ -32,69 +32,60 @@ import java.util.List; public class VCardEntryConstructor implements VCardInterpreter { private static String LOG_TAG = "VCardEntryConstructor"; - + /** * If there's no other information available, this class uses this charset for encoding - * byte arrays. + * byte arrays to String. */ - static public String TARGET_CHARSET = "UTF-8"; + /* package */ static final String DEFAULT_CHARSET_FOR_DECODED_BYTES = "UTF-8"; private VCardEntry.Property mCurrentProperty = new VCardEntry.Property(); private VCardEntry mCurrentContactStruct; private String mParamType; /** - * The charset using which VParser parses the text. + * The charset using which {@link VCardInterpreter} parses the text. */ - private String mSourceCharset; - + private String mInputCharset; + /** * The charset with which byte array is encoded to String. */ - private String mTargetCharset; - private boolean mStrictLineBreakParsing; - + final private String mCharsetForDecodedBytes; + final private boolean mStrictLineBreakParsing; final private int mVCardType; final private Account mAccount; - // Just for testing. + /** For measuring performance. */ private long mTimePushIntoContentResolver; - - private List mEntryHandlers = new ArrayList(); - + + final private List mEntryHandlers = new ArrayList(); + public VCardEntryConstructor() { this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8, null); } - public VCardEntryConstructor(int vcardType) { + public VCardEntryConstructor(final int vcardType) { this(null, null, false, vcardType, null); } - /** - * @hide - */ - public VCardEntryConstructor(String charset, - boolean strictLineBreakParsing, int vcardType, Account account) { + public VCardEntryConstructor(final String charset, final boolean strictLineBreakParsing, + final int vcardType, final Account account) { this(null, charset, strictLineBreakParsing, vcardType, account); } - /** - * @hide - */ - public VCardEntryConstructor(String sourceCharset, - String targetCharset, - boolean strictLineBreakParsing, - int vcardType, - Account account) { - if (sourceCharset != null) { - mSourceCharset = sourceCharset; + public VCardEntryConstructor(final String inputCharset, final String charsetForDetodedBytes, + final boolean strictLineBreakParsing, final int vcardType, + final Account account) { + if (inputCharset != null) { + mInputCharset = inputCharset; } else { - mSourceCharset = VCardConfig.DEFAULT_CHARSET; + mInputCharset = VCardConfig.DEFAULT_CHARSET; } - if (targetCharset != null) { - mTargetCharset = targetCharset; + if (charsetForDetodedBytes != null) { + mCharsetForDecodedBytes = charsetForDetodedBytes; } else { - mTargetCharset = TARGET_CHARSET; + mCharsetForDecodedBytes = DEFAULT_CHARSET_FOR_DECODED_BYTES; } mStrictLineBreakParsing = strictLineBreakParsing; mVCardType = vcardType; @@ -118,11 +109,7 @@ public class VCardEntryConstructor implements VCardInterpreter { } /** - * Called when the parse failed between startRecord() and endRecord(). - * Currently it happens only when the vCard format is 3.0. - * (VCardVersionException is thrown by VCardParser_V21 and this object is reused by - * VCardParser_V30. At that time, startRecord() is called twice before endRecord() is called.) - * TODO: Should this be in VCardBuilder interface? + * Called when the parse failed between {@link #startEntry()} and {@link #endEntry()}. */ public void clear() { mCurrentContactStruct = null; @@ -132,22 +119,14 @@ public class VCardEntryConstructor implements VCardInterpreter { /** * Assume that VCard is not nested. In other words, this code does not accept */ - public void startRecord(String type) { - // TODO: add the method clear() instead of using null for reducing GC? + public void startEntry() { if (mCurrentContactStruct != null) { - // This means startRecord() is called inside startRecord() - endRecord() block. - // TODO: should throw some Exception Log.e(LOG_TAG, "Nested VCard code is not supported now."); } - if (!type.equalsIgnoreCase("VCARD")) { - // TODO: add test case for this - Log.e(LOG_TAG, "This is not VCARD!"); - } - mCurrentContactStruct = new VCardEntry(mVCardType, mAccount); } - public void endRecord() { + public void endEntry() { mCurrentContactStruct.consolidateFields(); for (VCardEntryHandler entryHandler : mEntryHandlers) { entryHandler.onEntryCreated(mCurrentContactStruct); @@ -168,9 +147,8 @@ public class VCardEntryConstructor implements VCardInterpreter { } public void propertyGroup(String group) { - // ContactStruct does not support Group. } - + public void propertyParamType(String type) { if (mParamType != null) { Log.e(LOG_TAG, "propertyParamType() is called more than once " + @@ -187,26 +165,26 @@ public class VCardEntryConstructor implements VCardInterpreter { mCurrentProperty.addParameter(mParamType, value); mParamType = null; } - - private String encodeString(String originalString, String targetCharset) { - if (mSourceCharset.equalsIgnoreCase(targetCharset)) { + + private String encodeString(String originalString, String charsetForDecodedBytes) { + if (mInputCharset.equalsIgnoreCase(charsetForDecodedBytes)) { return originalString; } - Charset charset = Charset.forName(mSourceCharset); + Charset charset = Charset.forName(mInputCharset); ByteBuffer byteBuffer = charset.encode(originalString); // byteBuffer.array() "may" return byte array which is larger than // byteBuffer.remaining(). Here, we keep on the safe side. byte[] bytes = new byte[byteBuffer.remaining()]; byteBuffer.get(bytes); try { - return new String(bytes, targetCharset); + return new String(bytes, charsetForDecodedBytes); } catch (UnsupportedEncodingException e) { - Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset); + Log.e(LOG_TAG, "Failed to encode: charset=" + charsetForDecodedBytes); return null; } } - - private String handleOneValue(String value, String targetCharset, String encoding) { + + private String handleOneValue(String value, String charsetForDecodedBytes, String encoding) { if (encoding != null) { if (encoding.equals("BASE64") || encoding.equals("B")) { mCurrentProperty.setPropertyBytes(Base64.decodeBase64(value.getBytes())); @@ -272,9 +250,9 @@ public class VCardEntryConstructor implements VCardInterpreter { } byte[] bytes; try { - bytes = builder.toString().getBytes(mSourceCharset); + bytes = builder.toString().getBytes(mInputCharset); } catch (UnsupportedEncodingException e1) { - Log.e(LOG_TAG, "Failed to encode: charset=" + mSourceCharset); + Log.e(LOG_TAG, "Failed to encode: charset=" + mInputCharset); bytes = builder.toString().getBytes(); } @@ -286,38 +264,37 @@ public class VCardEntryConstructor implements VCardInterpreter { } try { - return new String(bytes, targetCharset); + return new String(bytes, charsetForDecodedBytes); } catch (UnsupportedEncodingException e) { - Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset); + Log.e(LOG_TAG, "Failed to encode: charset=" + charsetForDecodedBytes); return new String(bytes); } } // Unknown encoding. Fall back to default. } - return encodeString(value, targetCharset); + return encodeString(value, charsetForDecodedBytes); } public void propertyValues(List values) { - if (values == null || values.size() == 0) { + if (values == null || values.isEmpty()) { return; } final Collection charsetCollection = mCurrentProperty.getParameters("CHARSET"); - String charset = + final String charset = ((charsetCollection != null) ? charsetCollection.iterator().next() : null); - String targetCharset = CharsetUtils.nameForDefaultVendor(charset); - final Collection encodingCollection = mCurrentProperty.getParameters("ENCODING"); - String encoding = + final String encoding = ((encodingCollection != null) ? encodingCollection.iterator().next() : null); - - if (targetCharset == null || targetCharset.length() == 0) { - targetCharset = mTargetCharset; + + String charsetForDecodedBytes = CharsetUtils.nameForDefaultVendor(charset); + if (charsetForDecodedBytes == null || charsetForDecodedBytes.length() == 0) { + charsetForDecodedBytes = mCharsetForDecodedBytes; } - - for (String value : values) { + + for (final String value : values) { mCurrentProperty.addToPropertyValueList( - handleOneValue(value, targetCharset, encoding)); + handleOneValue(value, charsetForDecodedBytes, encoding)); } } diff --git a/core/java/android/pim/vcard/VCardEntryCounter.java b/core/java/android/pim/vcard/VCardEntryCounter.java index 1c221ebe0917e..7bab50dcdb591 100644 --- a/core/java/android/pim/vcard/VCardEntryCounter.java +++ b/core/java/android/pim/vcard/VCardEntryCounter.java @@ -17,6 +17,9 @@ package android.pim.vcard; import java.util.List; +/** + * The class which just counts the number of vCard entries in the specified input. + */ public class VCardEntryCounter implements VCardInterpreter { private int mCount; @@ -30,10 +33,10 @@ public class VCardEntryCounter implements VCardInterpreter { public void end() { } - public void startRecord(String type) { + public void startEntry() { } - public void endRecord() { + public void endEntry() { mCount++; } @@ -57,4 +60,4 @@ public class VCardEntryCounter implements VCardInterpreter { public void propertyValues(List values) { } -} \ No newline at end of file +} diff --git a/core/java/android/pim/vcard/VCardEntryHandler.java b/core/java/android/pim/vcard/VCardEntryHandler.java index 3b6bad55c0c4d..83a67fe2c6f87 100644 --- a/core/java/android/pim/vcard/VCardEntryHandler.java +++ b/core/java/android/pim/vcard/VCardEntryHandler.java @@ -15,6 +15,10 @@ */ package android.pim.vcard; +/** + * The interface called by {@link VCardEntryConstructor}. Useful when you don't want to + * handle detailed information as what {@link VCardParser} provides via {@link VCardInterpreter}. + */ public interface VCardEntryHandler { /** * Called when the parsing started. diff --git a/core/java/android/pim/vcard/VCardInterpreter.java b/core/java/android/pim/vcard/VCardInterpreter.java index 1f2408d118268..b5237c066bf03 100644 --- a/core/java/android/pim/vcard/VCardInterpreter.java +++ b/core/java/android/pim/vcard/VCardInterpreter.java @@ -17,48 +17,86 @@ package android.pim.vcard; import java.util.List; +/** + *

+ * The interface which should be implemented by the classes which have to analyze each + * vCard entry more minutely than {@link VCardEntry} class analysis. + *

+ *

+ * Here, there are several terms specific to vCard (and this library). + *

+ *

+ * The term "entry" is one vCard representation in the input, which should start with "BEGIN:VCARD" + * and end with "END:VCARD". + *

+ *

+ * The term "property" is one line in vCard entry, which consists of "group", "property name", + * "parameter(param) names and values", and "property values". + *

+ *

+ * e.g. group1.propName;paramName1=paramValue1;paramName2=paramValue2;propertyValue1;propertyValue2... + *

+ */ public interface VCardInterpreter { + /** + * Called when vCard interpretation started. + */ void start(); + /** + * Called when vCard interpretation finished. + */ void end(); /** - * BEGIN:VCARD + * Called when parsing one vCard entry started. + * More specifically, this method is called when "BEGIN:VCARD" is read. */ - void startRecord(String type); + void startEntry(); - /** END:VCARD */ - void endRecord(); + /** + * Called when parsing one vCard entry ended. + * More specifically, this method is called when "END:VCARD" is read. + * Note that {@link #startEntry()} may be called since + * vCard (especially 2.1) allows nested vCard. + */ + void endEntry(); + /** + * Called when reading one property started. + */ void startProperty(); + /** + * Called when reading one property ended. + */ void endProperty(); /** - * @param group + * @param group A group name. This method may be called more than once or may not be + * called at all, depending on how many gruoups are appended to the property. */ void propertyGroup(String group); - + /** - * @param name - * N
- * N + * @param name A property name like "N", "FN", "ADR", etc. */ void propertyName(String name); /** - * @param type - * LANGUAGE \ ENCODING
- * ;LANGUage= \ ;ENCODING= + * @param type A parameter name like "ENCODING", "CHARSET", etc. */ void propertyParamType(String type); /** - * @param value - * FR-EN \ GBK
- * FR-EN \ GBK + * @param value A parameter value. This method may be called without + * {@link #propertyParamType(String)} being called (when the vCard is vCard 2.1). */ void propertyParamValue(String value); + /** + * @param values List of property values. The size of values would be 1 unless + * coressponding property name is "N", "ADR", or "ORG". + */ void propertyValues(List values); } diff --git a/core/java/android/pim/vcard/VCardInterPreterCollection.java b/core/java/android/pim/vcard/VCardInterpreterCollection.java similarity index 54% rename from core/java/android/pim/vcard/VCardInterPreterCollection.java rename to core/java/android/pim/vcard/VCardInterpreterCollection.java index 19f040642342e..99f81f704d779 100644 --- a/core/java/android/pim/vcard/VCardInterPreterCollection.java +++ b/core/java/android/pim/vcard/VCardInterpreterCollection.java @@ -18,81 +18,84 @@ package android.pim.vcard; import java.util.Collection; import java.util.List; -public class VCardInterPreterCollection implements VCardInterpreter { +/** + * The {@link VCardInterpreter} implementation which aggregates more than one + * {@link VCardInterpreter} objects and make a user object treat them as one + * {@link VCardInterpreter} object. + */ +public class VCardInterpreterCollection implements VCardInterpreter { + private final Collection mInterpreterCollection; + + public VCardInterpreterCollection(Collection interpreterCollection) { + mInterpreterCollection = interpreterCollection; + } - private final Collection mVCardBuilderCollection; - - public VCardInterPreterCollection(Collection vBuilderCollection) { - mVCardBuilderCollection = vBuilderCollection; - } - public Collection getCollection() { - return mVCardBuilderCollection; + return mInterpreterCollection; } - + public void start() { - for (VCardInterpreter builder : mVCardBuilderCollection) { + for (VCardInterpreter builder : mInterpreterCollection) { builder.start(); } } - + public void end() { - for (VCardInterpreter builder : mVCardBuilderCollection) { + for (VCardInterpreter builder : mInterpreterCollection) { builder.end(); } } - public void startRecord(String type) { - for (VCardInterpreter builder : mVCardBuilderCollection) { - builder.startRecord(type); + public void startEntry() { + for (VCardInterpreter builder : mInterpreterCollection) { + builder.startEntry(); } } - - public void endRecord() { - for (VCardInterpreter builder : mVCardBuilderCollection) { - builder.endRecord(); + + public void endEntry() { + for (VCardInterpreter builder : mInterpreterCollection) { + builder.endEntry(); } } public void startProperty() { - for (VCardInterpreter builder : mVCardBuilderCollection) { + for (VCardInterpreter builder : mInterpreterCollection) { builder.startProperty(); } } - public void endProperty() { - for (VCardInterpreter builder : mVCardBuilderCollection) { + for (VCardInterpreter builder : mInterpreterCollection) { builder.endProperty(); } } public void propertyGroup(String group) { - for (VCardInterpreter builder : mVCardBuilderCollection) { + for (VCardInterpreter builder : mInterpreterCollection) { builder.propertyGroup(group); } } public void propertyName(String name) { - for (VCardInterpreter builder : mVCardBuilderCollection) { + for (VCardInterpreter builder : mInterpreterCollection) { builder.propertyName(name); } } public void propertyParamType(String type) { - for (VCardInterpreter builder : mVCardBuilderCollection) { + for (VCardInterpreter builder : mInterpreterCollection) { builder.propertyParamType(type); } } public void propertyParamValue(String value) { - for (VCardInterpreter builder : mVCardBuilderCollection) { + for (VCardInterpreter builder : mInterpreterCollection) { builder.propertyParamValue(value); } } public void propertyValues(List values) { - for (VCardInterpreter builder : mVCardBuilderCollection) { + for (VCardInterpreter builder : mInterpreterCollection) { builder.propertyValues(values); } } diff --git a/core/java/android/pim/vcard/VCardParser.java b/core/java/android/pim/vcard/VCardParser.java index 44c6fcddd16d2..6afb95e577fab 100644 --- a/core/java/android/pim/vcard/VCardParser.java +++ b/core/java/android/pim/vcard/VCardParser.java @@ -39,43 +39,48 @@ public abstract class VCardParser { } /** + *

* Parses the given stream and send the VCard data into VCardBuilderBase object. - * + * * Note that vCard 2.1 specification allows "CHARSET" parameter, and some career sets * local encoding to it. For example, Japanese phone career uses Shift_JIS, which is * formally allowed in VCard 2.1, but not recommended in VCard 3.0. In VCard 2.1, * In some exreme case, some VCard may have different charsets in one VCard (though * we do not see any device which emits such kind of malicious data) - * + *

+ *

* In order to avoid "misunderstanding" charset as much as possible, this method * use "ISO-8859-1" for reading the stream. When charset is specified in some property * (with "CHARSET=..." parameter), the string is decoded to raw bytes and encoded to * the charset. This method assumes that "ISO-8859-1" has 1 to 1 mapping in all 8bit * characters, which is not completely sure. In some cases, this "decoding-encoding" * scheme may fail. To avoid the case, - * - * We recommend you to use VCardSourceDetector and detect which kind of source the + *

+ *

+ * We recommend you to use {@link VCardSourceDetector} and detect which kind of source the * VCard comes from and explicitly specify a charset using the result. - * + *

+ * * @param is The source to parse. - * @param builder The VCardBuilderBase object which used to construct data. If you want to - * include multiple VCardBuilderBase objects in this field, consider using - * {#link VCardBuilderCollection} class. + * @param interepreter A {@link VCardInterpreter} object which used to construct data. * @return Returns true for success. Otherwise returns false. * @throws IOException, VCardException */ - public abstract boolean parse(InputStream is, VCardInterpreter builder) + public abstract boolean parse(InputStream is, VCardInterpreter interepreter) throws IOException, VCardException; /** + *

* The method variants which accept charset. - * + *

+ *

* RFC 2426 "recommends" (not forces) to use UTF-8, so it may be OK to use * UTF-8 as an encoding when parsing vCard 3.0. But note that some Japanese * phone uses Shift_JIS as a charset (e.g. W61SH), and another uses - * "CHARSET=SHIFT_JIS", which is explicitly prohibited in vCard 3.0 specification - * (e.g. W53K). - * + * "CHARSET=SHIFT_JIS", which is explicitly prohibited in vCard 3.0 specification (e.g. W53K). + *

+ * * @param is The source to parse. * @param charset Charset to be used. * @param builder The VCardBuilderBase object. @@ -87,8 +92,6 @@ public abstract class VCardParser { /** * The method variants which tells this object the operation is already canceled. - * XXX: Is this really necessary? - * @hide */ public abstract void parse(InputStream is, String charset, VCardInterpreter builder, boolean canceled) diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java index 0dea972db0490..ef3fb8d66370a 100644 --- a/core/java/android/pim/vcard/VCardParser_V21.java +++ b/core/java/android/pim/vcard/VCardParser_V21.java @@ -31,13 +31,14 @@ import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; +import java.util.Set; /** - * This class is used to parse vcard. Please refer to vCard Specification 2.1. + * This class is used to parse vCard. Please refer to vCard Specification 2.1 for more detail. */ public class VCardParser_V21 extends VCardParser { - private static final String LOG_TAG = "vcard.VCardParser_V21"; - + private static final String LOG_TAG = "VCardParser_V21"; + /** Store the known-type */ private static final HashSet sKnownTypeSet = new HashSet( Arrays.asList("DOM", "INTL", "POSTAL", "PARCEL", "HOME", "WORK", @@ -52,7 +53,7 @@ public class VCardParser_V21 extends VCardParser { /** Store the known-value */ private static final HashSet sKnownValueSet = new HashSet( Arrays.asList("INLINE", "URL", "CONTENT-ID", "CID")); - + /** Store the property names available in vCard 2.1 */ private static final HashSet sAvailablePropertyNameSetV21 = new HashSet(Arrays.asList( @@ -82,7 +83,7 @@ public class VCardParser_V21 extends VCardParser { protected final String sDefaultEncoding = "8BIT"; - // Should not directly read a line from this. Use getLine() instead. + // Should not directly read a line from this object. Use getLine() instead. protected BufferedReader mReader; // In some cases, vCard is nested. Currently, we only consider the most interior vCard data. @@ -91,16 +92,16 @@ public class VCardParser_V21 extends VCardParser { // In order to reduce warning message as much as possible, we hold the value which made Logger // emit a warning message. - protected HashSet mUnknownTypeMap = new HashSet(); - protected HashSet mUnknownValueMap = new HashSet(); + protected Set mUnknownTypeMap = new HashSet(); + protected Set mUnknownValueMap = new HashSet(); // It seems Windows Mobile 6.5 uses "AGENT" property with completely wrong usage. // We should just ignore just one line. // e.g. // "AGENT;CHARSET=SHIFT_JIS:some text" - private boolean mIgnoreAgentLine = false; + private boolean mIgnoreInvalidAgentLine = false; - // Just for debugging + // For measuring performance. private long mTimeTotal; private long mTimeReadStartRecord; private long mTimeReadEndRecord; @@ -114,9 +115,6 @@ public class VCardParser_V21 extends VCardParser { private long mTimeHandleQuotedPrintable; private long mTimeHandleBase64; - /** - * Create a new VCard parser. - */ public VCardParser_V21() { this(null, PARSER_MODE_DEFAULT); } @@ -139,17 +137,18 @@ public class VCardParser_V21 extends VCardParser { if (type == VCardSourceDetector.TYPE_FOMA) { mNestCount = 1; } else if (type == VCardSourceDetector.TYPE_JAPANESE_MOBILE_PHONE) { - mIgnoreAgentLine = true; + mIgnoreInvalidAgentLine = true; } } if (parserMode == PARSER_MODE_SCAN) { - mIgnoreAgentLine = true; + mIgnoreInvalidAgentLine = true; } } /** - * Parse the file at the given position + * Parses the file at the given position. + * * vcard_file = [wsls] vcard [wsls] */ protected void parseVCardFile() throws IOException, VCardException { @@ -225,11 +224,11 @@ public class VCardParser_V21 extends VCardParser { } } } - + /** - * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF - * items *CRLF - * "END" [ws] ":" [ws] "VCARD" + * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF + * items *CRLF + * "END" [ws] ":" [ws] "VCARD" */ private boolean parseOneVCard(boolean firstReading) throws IOException, VCardException { boolean allowGarbage = false; @@ -250,7 +249,7 @@ public class VCardParser_V21 extends VCardParser { long start; if (mBuilder != null) { start = System.currentTimeMillis(); - mBuilder.startRecord("VCARD"); + mBuilder.startEntry(); mTimeReadStartRecord += System.currentTimeMillis() - start; } start = System.currentTimeMillis(); @@ -259,7 +258,7 @@ public class VCardParser_V21 extends VCardParser { readEndVCard(true, false); if (mBuilder != null) { start = System.currentTimeMillis(); - mBuilder.endRecord(); + mBuilder.endEntry(); mTimeReadEndRecord += System.currentTimeMillis() - start; } return true; @@ -270,8 +269,7 @@ public class VCardParser_V21 extends VCardParser { * @throws IOException * @throws VCardException */ - protected boolean readBeginVCard(boolean allowGarbage) - throws IOException, VCardException { + protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException { String line; do { while (true) { @@ -286,8 +284,9 @@ public class VCardParser_V21 extends VCardParser { int length = strArray.length; // Though vCard 2.1/3.0 specification does not allow lower cases, - // some data may have them, so we allow it (Actually, previous code - // had explicitly allowed "BEGIN:vCard" though there's no example). + // vCard file emitted by some external vCard expoter have such invalid Strings. + // So we allow it. + // e.g. BEGIN:vCard if (length == 2 && strArray[0].trim().equalsIgnoreCase("BEGIN") && strArray[1].trim().equalsIgnoreCase("VCARD")) { @@ -310,7 +309,7 @@ public class VCardParser_V21 extends VCardParser { /** * The arguments useCache and allowGarbase are usually true and false accordingly when * this function is called outside this function itself. - * + * * @param useCache When true, line is obtained from mPreviousline. Otherwise, getLine() * is used. * @param allowGarbage When true, ignore non "END:VCARD" line. @@ -353,7 +352,6 @@ public class VCardParser_V21 extends VCardParser { * / item */ protected void parseItems() throws IOException, VCardException { - /* items *CRLF item / item */ boolean ended = false; if (mBuilder != null) { @@ -399,7 +397,7 @@ public class VCardParser_V21 extends VCardParser { protected boolean parseItem() throws IOException, VCardException { mEncoding = sDefaultEncoding; - String line = getNonEmptyLine(); + final String line = getNonEmptyLine(); long start = System.currentTimeMillis(); String[] propertyNameAndValue = separateLineAndHandleGroup(line); @@ -441,23 +439,22 @@ public class VCardParser_V21 extends VCardParser { return false; } - throw new VCardException("Unknown property name: \"" + - propertyName + "\""); + throw new VCardException("Unknown property name: \"" + propertyName + "\""); } static private final int STATE_GROUP_OR_PROPNAME = 0; static private final int STATE_PARAMS = 1; - // vCard 3.1 specification allows double-quoted param-value, while vCard 2.1 does not. + // vCard 3.0 specification allows double-quoted param-value, while vCard 2.1 does not. // This is just for safety. static private final int STATE_PARAMS_IN_DQUOTE = 2; - + protected String[] separateLineAndHandleGroup(String line) throws VCardException { - int length = line.length(); int state = STATE_GROUP_OR_PROPNAME; int nameIndex = 0; - String[] propertyNameAndValue = new String[2]; + final String[] propertyNameAndValue = new String[2]; + final int length = line.length(); if (length > 0 && line.charAt(0) == '#') { throw new VCardInvalidCommentLineException(); } @@ -465,82 +462,84 @@ public class VCardParser_V21 extends VCardParser { for (int i = 0; i < length; i++) { char ch = line.charAt(i); switch (state) { - case STATE_GROUP_OR_PROPNAME: - if (ch == ':') { - String propertyName = line.substring(nameIndex, i); - if (propertyName.equalsIgnoreCase("END")) { - mPreviousLine = line; - return null; + case STATE_GROUP_OR_PROPNAME: { + if (ch == ':') { + final String propertyName = line.substring(nameIndex, i); + if (propertyName.equalsIgnoreCase("END")) { + mPreviousLine = line; + return null; + } + if (mBuilder != null) { + mBuilder.propertyName(propertyName); + } + propertyNameAndValue[0] = propertyName; + if (i < length - 1) { + propertyNameAndValue[1] = line.substring(i + 1); + } else { + propertyNameAndValue[1] = ""; + } + return propertyNameAndValue; + } else if (ch == '.') { + String groupName = line.substring(nameIndex, i); + if (mBuilder != null) { + mBuilder.propertyGroup(groupName); + } + nameIndex = i + 1; + } else if (ch == ';') { + String propertyName = line.substring(nameIndex, i); + if (propertyName.equalsIgnoreCase("END")) { + mPreviousLine = line; + return null; + } + if (mBuilder != null) { + mBuilder.propertyName(propertyName); + } + propertyNameAndValue[0] = propertyName; + nameIndex = i + 1; + state = STATE_PARAMS; } - if (mBuilder != null) { - mBuilder.propertyName(propertyName); - } - propertyNameAndValue[0] = propertyName; - if (i < length - 1) { - propertyNameAndValue[1] = line.substring(i + 1); - } else { - propertyNameAndValue[1] = ""; - } - return propertyNameAndValue; - } else if (ch == '.') { - String groupName = line.substring(nameIndex, i); - if (mBuilder != null) { - mBuilder.propertyGroup(groupName); - } - nameIndex = i + 1; - } else if (ch == ';') { - String propertyName = line.substring(nameIndex, i); - if (propertyName.equalsIgnoreCase("END")) { - mPreviousLine = line; - return null; - } - if (mBuilder != null) { - mBuilder.propertyName(propertyName); - } - propertyNameAndValue[0] = propertyName; - nameIndex = i + 1; - state = STATE_PARAMS; + break; } - break; - case STATE_PARAMS: - if (ch == '"') { - state = STATE_PARAMS_IN_DQUOTE; - } else if (ch == ';') { - handleParams(line.substring(nameIndex, i)); - nameIndex = i + 1; - } else if (ch == ':') { - handleParams(line.substring(nameIndex, i)); - if (i < length - 1) { - propertyNameAndValue[1] = line.substring(i + 1); - } else { - propertyNameAndValue[1] = ""; + case STATE_PARAMS: { + if (ch == '"') { + state = STATE_PARAMS_IN_DQUOTE; + } else if (ch == ';') { + handleParams(line.substring(nameIndex, i)); + nameIndex = i + 1; + } else if (ch == ':') { + handleParams(line.substring(nameIndex, i)); + if (i < length - 1) { + propertyNameAndValue[1] = line.substring(i + 1); + } else { + propertyNameAndValue[1] = ""; + } + return propertyNameAndValue; } - return propertyNameAndValue; + break; } - break; - case STATE_PARAMS_IN_DQUOTE: - if (ch == '"') { - state = STATE_PARAMS; + case STATE_PARAMS_IN_DQUOTE: { + if (ch == '"') { + state = STATE_PARAMS; + } + break; } - break; } } throw new VCardInvalidLineException("Invalid line: \"" + line + "\""); } - - + /** - * params = ";" [ws] paramlist - * paramlist = paramlist [ws] ";" [ws] param - * / param - * param = "TYPE" [ws] "=" [ws] ptypeval - * / "VALUE" [ws] "=" [ws] pvalueval - * / "ENCODING" [ws] "=" [ws] pencodingval - * / "CHARSET" [ws] "=" [ws] charsetval - * / "LANGUAGE" [ws] "=" [ws] langval - * / "X-" word [ws] "=" [ws] word - * / knowntype + * params = ";" [ws] paramlist + * paramlist = paramlist [ws] ";" [ws] param + * / param + * param = "TYPE" [ws] "=" [ws] ptypeval + * / "VALUE" [ws] "=" [ws] pvalueval + * / "ENCODING" [ws] "=" [ws] pencodingval + * / "CHARSET" [ws] "=" [ws] charsetval + * / "LANGUAGE" [ws] "=" [ws] langval + * / "X-" word [ws] "=" [ws] word + * / knowntype */ protected void handleParams(String params) throws VCardException { String[] strArray = params.split("=", 2); @@ -624,8 +623,8 @@ public class VCardParser_V21 extends VCardParser { } /** - * vCard specification only allows us-ascii and iso-8859-xxx (See RFC 1521), - * but some vCard contains other charset, so we allow them. + * vCard 2.1 specification only allows us-ascii and iso-8859-xxx (See RFC 1521), + * but today's vCard often contains other charset, so we allow them. */ protected void handleCharset(String charsetval) { if (mBuilder != null) { @@ -633,7 +632,7 @@ public class VCardParser_V21 extends VCardParser { mBuilder.propertyParamValue(charsetval); } } - + /** * See also Section 7.1 of RFC 1521 */ @@ -671,12 +670,12 @@ public class VCardParser_V21 extends VCardParser { mBuilder.propertyParamValue(paramValue); } } - - protected void handlePropertyValue(String propertyName, String propertyValue) throws - IOException, VCardException { + + protected void handlePropertyValue(String propertyName, String propertyValue) + throws IOException, VCardException { if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) { - long start = System.currentTimeMillis(); - String result = getQuotedPrintable(propertyValue); + final long start = System.currentTimeMillis(); + final String result = getQuotedPrintable(propertyValue); if (mBuilder != null) { ArrayList v = new ArrayList(); v.add(result); @@ -685,11 +684,11 @@ public class VCardParser_V21 extends VCardParser { mTimeHandleQuotedPrintable += System.currentTimeMillis() - start; } else if (mEncoding.equalsIgnoreCase("BASE64") || mEncoding.equalsIgnoreCase("B")) { - long start = System.currentTimeMillis(); + final long start = System.currentTimeMillis(); // It is very rare, but some BASE64 data may be so big that // OutOfMemoryError occurs. To ignore such cases, use try-catch. try { - String result = getBase64(propertyValue); + final String result = getBase64(propertyValue); if (mBuilder != null) { ArrayList v = new ArrayList(); v.add(result); @@ -709,7 +708,7 @@ public class VCardParser_V21 extends VCardParser { Log.w(LOG_TAG, "The encoding unsupported by vCard spec: \"" + mEncoding + "\"."); } - long start = System.currentTimeMillis(); + final long start = System.currentTimeMillis(); if (mBuilder != null) { ArrayList v = new ArrayList(); v.add(maybeUnescapeText(propertyValue)); @@ -820,16 +819,15 @@ public class VCardParser_V21 extends VCardParser { /** * vCard 2.1 specifies AGENT allows one vcard entry. It is not encoded at all. - * - * item = ... - * / [groups "."] "AGENT" - * [params] ":" vcard CRLF - * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF - * items *CRLF "END" [ws] ":" [ws] "VCARD" - * + * + * item = ... + * / [groups "."] "AGENT" + * [params] ":" vcard CRLF + * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF + * items *CRLF "END" [ws] ":" [ws] "VCARD" */ protected void handleAgent(final String propertyValue) throws VCardException { - if (mIgnoreAgentLine) { + if (mIgnoreInvalidAgentLine && !propertyValue.toUpperCase().contains("BEGIN:VCARD")) { return; } else { throw new VCardAgentNotSupportedException("AGENT Property is not supported now."); diff --git a/core/java/android/pim/vcard/VCardParser_V30.java b/core/java/android/pim/vcard/VCardParser_V30.java index 7314b87d8f857..4ecfe9750c66e 100644 --- a/core/java/android/pim/vcard/VCardParser_V30.java +++ b/core/java/android/pim/vcard/VCardParser_V30.java @@ -23,12 +23,12 @@ import java.util.Arrays; import java.util.HashSet; /** - * This class is used to parse vcard3.0.
- * Please refer to vCard Specification 3.0 (http://tools.ietf.org/html/rfc2426) + * The class used to parse vCard 3.0. + * Please refer to vCard Specification 3.0 (http://tools.ietf.org/html/rfc2426). */ public class VCardParser_V30 extends VCardParser_V21 { - private static final String LOG_TAG = "vcard.VCardParser_V30"; - + private static final String LOG_TAG = "VCardParser_V30"; + private static final HashSet sAcceptablePropsWithParam = new HashSet( Arrays.asList( "BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND", @@ -185,17 +185,17 @@ public class VCardParser_V30 extends VCardParser_V21 { /** - * vcard = [group "."] "BEGIN" ":" "VCARD" 1*CRLF - * 1*(contentline) + * vcard = [group "."] "BEGIN" ":" "VCARD" 1 * CRLF + * 1 * (contentline) * ;A vCard object MUST include the VERSION, FN and N types. - * [group "."] "END" ":" "VCARD" 1*CRLF + * [group "."] "END" ":" "VCARD" 1 * CRLF */ @Override protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException { // TODO: vCard 3.0 supports group. return super.readBeginVCard(allowGarbage); } - + @Override protected void readEndVCard(boolean useCache, boolean allowGarbage) throws IOException, VCardException { @@ -222,14 +222,9 @@ public class VCardParser_V30 extends VCardParser_V21 { } } } - + @Override protected void handleAnyParam(String paramName, String paramValue) { - // vCard 3.0 accept comma-separated multiple values, but - // current PropertyNode does not accept it. - // For now, we do not split the values. - // - // TODO: fix this. super.handleAnyParam(paramName, paramValue); } @@ -266,7 +261,7 @@ public class VCardParser_V30 extends VCardParser_V21 { @Override protected void handleAgent(String propertyValue) { - // The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.0. + // The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.1. // // e.g. // AGENT:BEGIN:VCARD\nFN:Joe Friday\nTEL:+1-919-555-7878\n @@ -281,13 +276,13 @@ public class VCardParser_V30 extends VCardParser_V21 { // AGENT;VALUE=uri: // CID:JQPUBLIC.part3.960129T083020.xyzMail@host3.com // - // This is not VCARD. Should we support this? - // throw new VCardException("AGENT in vCard 3.0 is not supported yet."); + // This is not vCard. Should we support this? + // + // Just ignore the line for now, since we cannot know how to handle it... if (!mEmittedAgentWarning) { Log.w(LOG_TAG, "AGENT in vCard 3.0 is not supported yet. Ignore it"); mEmittedAgentWarning = true; } - // Just ignore the line for now, since we cannot know how to handle it... } /** @@ -298,7 +293,7 @@ public class VCardParser_V30 extends VCardParser_V21 { protected String getBase64(String firstString) throws IOException, VCardException { StringBuilder builder = new StringBuilder(); builder.append(firstString); - + while (true) { String line = getLine(); if (line == null) { @@ -322,8 +317,8 @@ public class VCardParser_V30 extends VCardParser_V21 { * ; \\ encodes \, \n or \N encodes newline * ; \; encodes ;, \, encodes , * - * Note: Apple escape ':' into '\:' while does not escape '\' - */ + * Note: Apple escapes ':' into '\:' while does not escape '\' + */ @Override protected String maybeUnescapeText(String text) { return unescapeText(text); @@ -347,7 +342,7 @@ public class VCardParser_V30 extends VCardParser_V21 { } return builder.toString(); } - + @Override protected String maybeUnescapeCharacter(char ch) { return unescapeCharacter(ch); diff --git a/core/java/android/pim/vcard/VCardSourceDetector.java b/core/java/android/pim/vcard/VCardSourceDetector.java index 01c13001fd11f..d3f451ce44b97 100644 --- a/core/java/android/pim/vcard/VCardSourceDetector.java +++ b/core/java/android/pim/vcard/VCardSourceDetector.java @@ -62,7 +62,7 @@ public class VCardSourceDetector implements VCardInterpreter { public void end() { } - public void startRecord(String type) { + public void startEntry() { } public void startProperty() { @@ -72,7 +72,7 @@ public class VCardSourceDetector implements VCardInterpreter { public void endProperty() { } - public void endRecord() { + public void endEntry() { } public void propertyGroup(String group) { diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java index 1d4589347a786..4eb47c02001b3 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java @@ -64,7 +64,7 @@ public class PropertyNodesVerifier extends VNodeBuilder { public void verify(InputStream is, int vCardType) throws IOException, VCardException { final VCardParser vCardParser; if (VCardConfig.isV30(vCardType)) { - vCardParser = new VCardParser_V30(true); // use StrictParsing + vCardParser = new VCardParser_V30(true); // Use StrictParsing. } else { vCardParser = new VCardParser_V21(); } @@ -86,8 +86,8 @@ public class PropertyNodesVerifier extends VNodeBuilder { } @Override - public void endRecord() { - super.endRecord(); + public void endEntry() { + super.endEntry(); mAndroidTestCase.assertTrue(mIndex < mPropertyNodesVerifierElemList.size()); mAndroidTestCase.assertTrue(mIndex < vNodeList.size()); mPropertyNodesVerifierElemList.get(mIndex).verify(vNodeList.get(mIndex)); 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 659085533dbd0..73f96e8dd14b0 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java @@ -37,7 +37,7 @@ import android.pim.vcard.VCardEntry; import android.pim.vcard.VCardEntryCommitter; import android.pim.vcard.VCardEntryHandler; import android.pim.vcard.VCardInterpreter; -import android.pim.vcard.VCardInterPreterCollection; +import android.pim.vcard.VCardInterpreterCollection; import android.pim.vcard.VCardComposer; import android.pim.vcard.VCardConfig; import android.pim.vcard.VCardEntryConstructor; @@ -863,7 +863,7 @@ class CustomMockContext extends MockContext { new VCardEntryConstructor(mVCardType); vcardDataBuilder.addEntryHandler(mImportVerifier); if (mPropertyNodesVerifier != null) { - builder = new VCardInterPreterCollection(Arrays.asList( + builder = new VCardInterpreterCollection(Arrays.asList( mPropertyNodesVerifier, vcardDataBuilder)); } else { builder = vnodeBuilder; diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java index c38b54c862ad3..971fe0dc494a7 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java @@ -115,11 +115,10 @@ public class VNodeBuilder implements VCardInterpreter { // I leave this code as is since I'm not familiar with vcalendar specification. // But I believe we should refactor this code in the future. // Until this, the last entry has to be removed when some error occurs. - public void startRecord(String type) { - + public void startEntry() { VNode vnode = new VNode(); vnode.parseStatus = 1; - vnode.VName = type; + vnode.VName = "VCARD"; // I feel this should be done in endRecord(), but it cannot be done because of // the reason above. vNodeList.add(vnode); @@ -127,7 +126,7 @@ public class VNodeBuilder implements VCardInterpreter { mCurrentVNode = vNodeList.get(mNodeListPos); } - public void endRecord() { + public void endEntry() { VNode endNode = vNodeList.get(mNodeListPos); endNode.parseStatus = 0; while(mNodeListPos > 0){