summaryrefslogtreecommitdiffstats
path: root/core/java/android/pim
diff options
context:
space:
mode:
authorDaisuke Miyakawa <dmiyakawa@google.com>2010-04-06 08:50:13 +0900
committerDaisuke Miyakawa <dmiyakawa@google.com>2010-04-06 13:41:27 +0900
commit82b8b686521323948cd76946e9bd6d6be019797d (patch)
tree8dbdf9be9a20dd7ca1fff53c8e7a0585713f79fb /core/java/android/pim
parent1021da0af5f975e1ddd0ae4580b3e03e69af8993 (diff)
downloadframeworks_base-82b8b686521323948cd76946e9bd6d6be019797d.zip
frameworks_base-82b8b686521323948cd76946e9bd6d6be019797d.tar.gz
frameworks_base-82b8b686521323948cd76946e9bd6d6be019797d.tar.bz2
Let vCard importer/exporter select charset.
There are some other bug where charset for import/export is used during vCard handling. Bug: 2572064 Change-Id: I0aef8a6eba0a7e9263e47368a43dbba05efa91b0
Diffstat (limited to 'core/java/android/pim')
-rw-r--r--core/java/android/pim/vcard/VCardBuilder.java220
-rw-r--r--core/java/android/pim/vcard/VCardComposer.java222
-rw-r--r--core/java/android/pim/vcard/VCardConfig.java68
-rw-r--r--core/java/android/pim/vcard/VCardEntryConstructor.java2
-rw-r--r--core/java/android/pim/vcard/VCardParser.java38
-rw-r--r--core/java/android/pim/vcard/VCardParser_V21.java58
6 files changed, 384 insertions, 224 deletions
diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java
index 0a6415d..c2b342f 100644
--- a/core/java/android/pim/vcard/VCardBuilder.java
+++ b/core/java/android/pim/vcard/VCardBuilder.java
@@ -47,7 +47,22 @@ import java.util.Map;
import java.util.Set;
/**
- * The class which lets users create their own vCard String.
+ * <p>
+ * The class which lets users create their own vCard String. Typical usage is as follows:
+ * </p>
+ * <pre class="prettyprint">final VCardBuilder builder = new VCardBuilder(vcardType);
+ * builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
+ * .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
+ * .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE))
+ * .appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE))
+ * .appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE))
+ * .appendOrganizations(contentValuesListMap.get(Organization.CONTENT_ITEM_TYPE))
+ * .appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE))
+ * .appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE))
+ * .appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE))
+ * .appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE))
+ * .appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE))
+ * .appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE)); </pre>
*/
public class VCardBuilder {
private static final String LOG_TAG = "VCardBuilder";
@@ -81,7 +96,6 @@ public class VCardBuilder {
private static final String VCARD_PARAM_ENCODING_BASE64_V30 = "ENCODING=b";
private static final String SHIFT_JIS = "SHIFT_JIS";
- private static final String UTF_8 = "UTF-8";
private final int mVCardType;
@@ -92,21 +106,28 @@ public class VCardBuilder {
private final boolean mShouldUseQuotedPrintable;
private final boolean mUsesAndroidProperty;
private final boolean mUsesDefactProperty;
- private final boolean mUsesUtf8;
- private final boolean mUsesShiftJis;
private final boolean mAppendTypeParamName;
private final boolean mRefrainsQPToNameProperties;
private final boolean mNeedsToConvertPhoneticString;
private final boolean mShouldAppendCharsetParam;
- private final String mCharsetString;
+ private final String mCharset;
private final String mVCardCharsetParameter;
private StringBuilder mBuilder;
private boolean mEndAppended;
public VCardBuilder(final int vcardType) {
+ // Default charset should be used
+ this(vcardType, null);
+ }
+
+ /**
+ * @param vcardType
+ * @param charset If null, we use default charset for export.
+ */
+ public VCardBuilder(final int vcardType, String charset) {
mVCardType = vcardType;
mIsV30 = VCardConfig.isV30(vcardType);
@@ -116,40 +137,77 @@ public class VCardBuilder {
mOnlyOneNoteFieldIsAvailable = VCardConfig.onlyOneNoteFieldIsAvailable(vcardType);
mUsesAndroidProperty = VCardConfig.usesAndroidSpecificProperty(vcardType);
mUsesDefactProperty = VCardConfig.usesDefactProperty(vcardType);
- mUsesUtf8 = VCardConfig.usesUtf8(vcardType);
- mUsesShiftJis = VCardConfig.usesShiftJis(vcardType);
mRefrainsQPToNameProperties = VCardConfig.shouldRefrainQPToNameProperties(vcardType);
mAppendTypeParamName = VCardConfig.appendTypeParamName(vcardType);
mNeedsToConvertPhoneticString = VCardConfig.needsToConvertPhoneticString(vcardType);
- mShouldAppendCharsetParam = !(mIsV30 && mUsesUtf8);
-
- if (mIsDoCoMo) {
- String charset;
- try {
- charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
- } catch (UnsupportedCharsetException e) {
- Log.e(LOG_TAG, "DoCoMo-specific SHIFT_JIS was not found. Use SHIFT_JIS as is.");
- charset = SHIFT_JIS;
- }
- mCharsetString = charset;
- // Do not use mCharsetString bellow since it is different from "SHIFT_JIS" but
- // may be "DOCOMO_SHIFT_JIS" or something like that (internal expression used in
- // Android, not shown to the public).
- mVCardCharsetParameter = "CHARSET=" + SHIFT_JIS;
- } else if (mUsesShiftJis) {
- String charset;
- try {
- charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
- } catch (UnsupportedCharsetException e) {
- Log.e(LOG_TAG, "Vendor-specific SHIFT_JIS was not found. Use SHIFT_JIS as is.");
- charset = SHIFT_JIS;
- }
- mCharsetString = charset;
+ final boolean shouldUseUtf8 = VCardConfig.shouldUseUtf8ForExport(vcardType);
+ final boolean shouldUseShiftJis = VCardConfig.shouldUseShiftJisForExport(vcardType);
+
+ // vCard 2.1 requires charset.
+ // vCard 3.0 does not allow it but we found some devices use it to determine
+ // the exact charset.
+ // We currently append it only when charset other than UTF_8 is used.
+ mShouldAppendCharsetParam = !(mIsV30 && shouldUseUtf8);
+
+ if (VCardConfig.isDoCoMo(vcardType) || shouldUseShiftJis) {
+ if (!SHIFT_JIS.equalsIgnoreCase(charset)) {
+ Log.w(LOG_TAG,
+ "The charset \"" + charset + "\" is used while "
+ + SHIFT_JIS + " is needed to be used.");
+ if (TextUtils.isEmpty(charset)) {
+ mCharset = SHIFT_JIS;
+ } else {
+ try {
+ charset = CharsetUtils.charsetForVendor(charset).name();
+ } catch (UnsupportedCharsetException e) {
+ Log.i(LOG_TAG,
+ "Career-specific \"" + charset + "\" was not found (as usual). "
+ + "Use it as is.");
+ }
+ mCharset = charset;
+ }
+ } else {
+ if (mIsDoCoMo) {
+ try {
+ charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
+ } catch (UnsupportedCharsetException e) {
+ Log.e(LOG_TAG,
+ "DoCoMo-specific SHIFT_JIS was not found. "
+ + "Use SHIFT_JIS as is.");
+ charset = SHIFT_JIS;
+ }
+ } else {
+ try {
+ charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
+ } catch (UnsupportedCharsetException e) {
+ Log.e(LOG_TAG,
+ "Career-specific SHIFT_JIS was not found. "
+ + "Use SHIFT_JIS as is.");
+ charset = SHIFT_JIS;
+ }
+ }
+ mCharset = charset;
+ }
mVCardCharsetParameter = "CHARSET=" + SHIFT_JIS;
} else {
- mCharsetString = UTF_8;
- mVCardCharsetParameter = "CHARSET=" + UTF_8;
+ if (TextUtils.isEmpty(charset)) {
+ Log.i(LOG_TAG,
+ "Use the charset \"" + VCardConfig.DEFAULT_EXPORT_CHARSET
+ + "\" for export.");
+ mCharset = VCardConfig.DEFAULT_EXPORT_CHARSET;
+ mVCardCharsetParameter = "CHARSET=" + VCardConfig.DEFAULT_EXPORT_CHARSET;
+ } else {
+ try {
+ charset = CharsetUtils.charsetForVendor(charset).name();
+ } catch (UnsupportedCharsetException e) {
+ Log.i(LOG_TAG,
+ "Career-specific \"" + charset + "\" was not found (as usual). "
+ + "Use it as is.");
+ }
+ mCharset = charset;
+ mVCardCharsetParameter = "CHARSET=" + charset;
+ }
}
clear();
}
@@ -379,8 +437,8 @@ public class VCardBuilder {
mBuilder.append(VCardConstants.PROPERTY_FN);
// Note: "CHARSET" param is not allowed in vCard 3.0, but we may add it
- // when it would be useful for external importers, assuming no external
- // importer allows this vioration.
+ // when it would be useful or necessary for external importers,
+ // assuming the external importer allows this vioration of the spec.
if (shouldAppendCharsetParam(displayName)) {
mBuilder.append(VCARD_PARAM_SEPARATOR);
mBuilder.append(mVCardCharsetParameter);
@@ -454,18 +512,18 @@ public class VCardBuilder {
mBuilder.append(VCARD_END_OF_LINE);
} else if (mIsJapaneseMobilePhone) {
// Note: There is no appropriate property for expressing
- // phonetic name in vCard 2.1, while there is in
+ // phonetic name (Yomigana in Japanese) in vCard 2.1, while there is in
// vCard 3.0 (SORT-STRING).
- // We chose to use DoCoMo's way when the device is Japanese one
- // 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.
+ // We use DoCoMo's way when the device is Japanese one since it is already
+ // supported by a lot of Japanese mobile phones.
+ // This is "X-" property, so any parser hopefully would not get
+ // confused with this.
//
// Also, DoCoMo's specification requires vCard composer to use just the first
// column.
// i.e.
- // o SOUND;X-IRMC-N:Miyakawa Daisuke;;;;
- // x SOUND;X-IRMC-N:Miyakawa;Daisuke;;;
+ // good: SOUND;X-IRMC-N:Miyakawa Daisuke;;;;
+ // bad : SOUND;X-IRMC-N:Miyakawa;Daisuke;;;
mBuilder.append(VCardConstants.PROPERTY_SOUND);
mBuilder.append(VCARD_PARAM_SEPARATOR);
mBuilder.append(VCardConstants.PARAM_TYPE_X_IRMC_N);
@@ -519,10 +577,10 @@ public class VCardBuilder {
mBuilder.append(encodedPhoneticGivenName);
}
}
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
- mBuilder.append(VCARD_ITEM_SEPARATOR);
+ mBuilder.append(VCARD_ITEM_SEPARATOR); // family;given
+ mBuilder.append(VCARD_ITEM_SEPARATOR); // given;middle
+ mBuilder.append(VCARD_ITEM_SEPARATOR); // middle;prefix
+ mBuilder.append(VCARD_ITEM_SEPARATOR); // prefix;suffix
mBuilder.append(VCARD_END_OF_LINE);
}
@@ -549,7 +607,7 @@ public class VCardBuilder {
mBuilder.append(VCARD_DATA_SEPARATOR);
mBuilder.append(encodedPhoneticGivenName);
mBuilder.append(VCARD_END_OF_LINE);
- }
+ } // if (!TextUtils.isEmpty(phoneticGivenName))
if (!TextUtils.isEmpty(phoneticMiddleName)) {
final boolean reallyUseQuotedPrintable =
(mShouldUseQuotedPrintable &&
@@ -572,7 +630,7 @@ public class VCardBuilder {
mBuilder.append(VCARD_DATA_SEPARATOR);
mBuilder.append(encodedPhoneticMiddleName);
mBuilder.append(VCARD_END_OF_LINE);
- }
+ } // if (!TextUtils.isEmpty(phoneticGivenName))
if (!TextUtils.isEmpty(phoneticFamilyName)) {
final boolean reallyUseQuotedPrintable =
(mShouldUseQuotedPrintable &&
@@ -595,7 +653,7 @@ public class VCardBuilder {
mBuilder.append(VCARD_DATA_SEPARATOR);
mBuilder.append(encodedPhoneticFamilyName);
mBuilder.append(VCARD_END_OF_LINE);
- }
+ } // if (!TextUtils.isEmpty(phoneticFamilyName))
}
}
@@ -903,21 +961,21 @@ public class VCardBuilder {
encodedCountry = escapeCharacters(rawCountry);
encodedNeighborhood = escapeCharacters(rawNeighborhood);
}
- final StringBuffer addressBuffer = new StringBuffer();
- addressBuffer.append(encodedPoBox);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedStreet);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedLocality);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedRegion);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedPostalCode);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedCountry);
+ final StringBuilder addressBuilder = new StringBuilder();
+ addressBuilder.append(encodedPoBox);
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // PO BOX ; Extended Address
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // Extended Address : Street
+ addressBuilder.append(encodedStreet);
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // Street : Locality
+ addressBuilder.append(encodedLocality);
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // Locality : Region
+ addressBuilder.append(encodedRegion);
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // Region : Postal Code
+ addressBuilder.append(encodedPostalCode);
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // Postal Code : Country
+ addressBuilder.append(encodedCountry);
return new PostalStruct(
- reallyUseQuotedPrintable, appendCharset, addressBuffer.toString());
+ reallyUseQuotedPrintable, appendCharset, addressBuilder.toString());
} else { // VCardUtils.areAllEmpty(rawAddressArray) == true
// Try to use FORMATTED_ADDRESS instead.
final String rawFormattedAddress =
@@ -940,16 +998,16 @@ public class VCardBuilder {
// We use the second value ("Extended Address") just because Japanese mobile phones
// do so. If the other importer expects the value be in the other field, some flag may
// be needed.
- final StringBuffer addressBuffer = new StringBuffer();
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(encodedFormattedAddress);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
- addressBuffer.append(VCARD_ITEM_SEPARATOR);
+ final StringBuilder addressBuilder = new StringBuilder();
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // PO BOX ; Extended Address
+ addressBuilder.append(encodedFormattedAddress);
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // Extended Address : Street
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // Street : Locality
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // Locality : Region
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // Region : Postal Code
+ addressBuilder.append(VCARD_ITEM_SEPARATOR); // Postal Code : Country
return new PostalStruct(
- reallyUseQuotedPrintable, appendCharset, addressBuffer.toString());
+ reallyUseQuotedPrintable, appendCharset, addressBuilder.toString());
}
}
@@ -1146,6 +1204,8 @@ public class VCardBuilder {
}
public VCardBuilder appendEvents(final List<ContentValues> contentValuesList) {
+ // There's possibility where a given object may have more than one birthday, which
+ // is inappropriate. We just build one birthday.
if (contentValuesList != null) {
String primaryBirthday = null;
String secondaryBirthday = null;
@@ -1213,16 +1273,19 @@ public class VCardBuilder {
return this;
}
+ /**
+ * @param emitEveryTime If true, builder builds the line even when there's no entry.
+ */
public void appendPostalLine(final int type, final String label,
final ContentValues contentValues,
- final boolean isPrimary, final boolean emitLineEveryTime) {
+ final boolean isPrimary, final boolean emitEveryTime) {
final boolean reallyUseQuotedPrintable;
final boolean appendCharset;
final String addressValue;
{
PostalStruct postalStruct = tryConstructPostalStruct(contentValues);
if (postalStruct == null) {
- if (emitLineEveryTime) {
+ if (emitEveryTime) {
reallyUseQuotedPrintable = false;
appendCharset = false;
addressValue = "";
@@ -1537,7 +1600,8 @@ public class VCardBuilder {
mBuilder.append(VCARD_END_OF_LINE);
}
- public void appendAndroidSpecificProperty(final String mimeType, ContentValues contentValues) {
+ public void appendAndroidSpecificProperty(
+ final String mimeType, ContentValues contentValues) {
if (!sAllowedAndroidPropertySet.contains(mimeType)) {
return;
}
@@ -1659,7 +1723,7 @@ public class VCardBuilder {
encodedValue = encodeQuotedPrintable(rawValue);
} else {
// TODO: one line may be too huge, which may be invalid in vCard spec, though
- // several (even well-known) applications do not care this.
+ // several (even well-known) applications do not care that violation.
encodedValue = escapeCharacters(rawValue);
}
@@ -1794,9 +1858,9 @@ public class VCardBuilder {
byte[] strArray = null;
try {
- strArray = str.getBytes(mCharsetString);
+ strArray = str.getBytes(mCharset);
} catch (UnsupportedEncodingException e) {
- Log.e(LOG_TAG, "Charset " + mCharsetString + " cannot be used. "
+ Log.e(LOG_TAG, "Charset " + mCharset + " cannot be used. "
+ "Try default charset");
strArray = str.getBytes();
}
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index dc0d864..1bc7785 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -41,6 +41,7 @@ import android.provider.ContactsContract.CommonDataKinds.Relation;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.text.TextUtils;
import android.util.CharsetUtils;
import android.util.Log;
@@ -61,15 +62,11 @@ import java.util.Map;
/**
* <p>
- * The class for composing VCard from Contacts information. Note that this is
- * completely differnt implementation from
- * android.syncml.pim.vcard.VCardComposer, which is not maintained anymore.
+ * The class for composing vCard from Contacts information.
* </p>
- *
* <p>
* Usually, this class should be used like this.
* </p>
- *
* <pre class="prettyprint">VCardComposer composer = null;
* try {
* composer = new VCardComposer(context);
@@ -94,14 +91,17 @@ import java.util.Map;
* composer.terminate();
* }
* } </pre>
+ * <P>
+ * Users have to manually take care of memory efficiency. Even one vCard may contain
+ * image of non-trivial size for mobile devices.
+ * </P>
+ * <P>
+ * In default, Default {@link VCardBuilder} class is used to build each vCard.
+ * </P>
*/
public class VCardComposer {
private static final String LOG_TAG = "VCardComposer";
- public static final int DEFAULT_PHONE_TYPE = Phone.TYPE_HOME;
- public static final int DEFAULT_POSTAL_TYPE = StructuredPostal.TYPE_HOME;
- public static final int DEFAULT_EMAIL_TYPE = Email.TYPE_OTHER;
-
public static final String FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO =
"Failed to get database information";
@@ -119,6 +119,8 @@ public class VCardComposer {
public static final String VCARD_TYPE_STRING_DOCOMO = "docomo";
+ // Strictly speaking, "Shift_JIS" is the most appropriate, but we use upper version here,
+ // since usual vCard devices for Japanese devices already use it.
private static final String SHIFT_JIS = "SHIFT_JIS";
private static final String UTF_8 = "UTF-8";
@@ -141,7 +143,7 @@ public class VCardComposer {
sImMap.put(Im.PROTOCOL_ICQ, VCardConstants.PROPERTY_X_ICQ);
sImMap.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER);
sImMap.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME);
- // Google talk is a special case.
+ // We don't add Google talk here since it has to be handled separately.
}
public static interface OneEntryHandler {
@@ -152,37 +154,37 @@ public class VCardComposer {
/**
* <p>
- * An useful example handler, which emits VCard String to outputstream one by one.
+ * An useful handler for emitting vCard String to an OutputStream object one by one.
* </p>
* <p>
* The input OutputStream object is closed() on {@link #onTerminate()}.
- * Must not close the stream outside.
+ * Must not close the stream outside this class.
* </p>
*/
public class HandlerForOutputStream implements OneEntryHandler {
@SuppressWarnings("hiding")
private static final String LOG_TAG = "vcard.VCardComposer.HandlerForOutputStream";
- final private OutputStream mOutputStream; // mWriter will close this.
- private Writer mWriter;
-
private boolean mOnTerminateIsCalled = false;
+ final private OutputStream mOutputStream; // mWriter will close this.
+ protected Writer mWriter;
+
/**
* Input stream will be closed on the detruction of this object.
*/
- public HandlerForOutputStream(OutputStream outputStream) {
+ public HandlerForOutputStream(final OutputStream outputStream) {
mOutputStream = outputStream;
}
- public boolean onInit(Context context) {
+ public final boolean onInit(final Context context) {
try {
mWriter = new BufferedWriter(new OutputStreamWriter(
- mOutputStream, mCharsetString));
+ mOutputStream, mCharset));
} catch (UnsupportedEncodingException e1) {
- Log.e(LOG_TAG, "Unsupported charset: " + mCharsetString);
+ Log.e(LOG_TAG, "Unsupported charset: " + mCharset);
mErrorReason = "Encoding is not supported (usually this does not happen!): "
- + mCharsetString;
+ + mCharset;
return false;
}
@@ -205,7 +207,7 @@ public class VCardComposer {
return true;
}
- public boolean onEntryCreated(String vcard) {
+ public final boolean onEntryCreated(String vcard) {
try {
mWriter.write(vcard);
} catch (IOException e) {
@@ -218,7 +220,7 @@ public class VCardComposer {
return true;
}
- public void onTerminate() {
+ public final void onTerminate() {
mOnTerminateIsCalled = true;
if (mWriter != null) {
try {
@@ -235,14 +237,21 @@ public class VCardComposer {
"IOException during closing the output stream: "
+ e.getMessage());
} finally {
- try {
- mWriter.close();
- } catch (IOException e) {
- }
+ closeOutputStream();
}
}
}
+ // Users can override this if they want to (e.g. if they don't want to close the stream).
+ // TODO: Should expose bare OutputStream instead?
+ public void closeOutputStream() {
+ try {
+ mWriter.close();
+ } catch (IOException e) {
+ Log.w(LOG_TAG, "IOException is thrown during close(). Ignoring.");
+ }
+ }
+
@Override
public void finalize() {
if (!mOnTerminateIsCalled) {
@@ -257,11 +266,10 @@ public class VCardComposer {
private final ContentResolver mContentResolver;
private final boolean mIsDoCoMo;
- private final boolean mUsesShiftJis;
private Cursor mCursor;
private int mIdColumn;
- private final String mCharsetString;
+ private final String mCharset;
private boolean mTerminateIsCalled;
private final List<OneEntryHandler> mHandlerList;
@@ -272,11 +280,14 @@ public class VCardComposer {
};
public VCardComposer(Context context) {
- this(context, VCardConfig.VCARD_TYPE_DEFAULT, true);
+ this(context, VCardConfig.VCARD_TYPE_DEFAULT, null, true);
}
+ /**
+ * The variant which sets charset to null and sets careHandlerErrors to true.
+ */
public VCardComposer(Context context, int vcardType) {
- this(context, vcardType, true);
+ this(context, vcardType, null, true);
}
public VCardComposer(Context context, String vcardTypeStr, boolean careHandlerErrors) {
@@ -284,9 +295,25 @@ public class VCardComposer {
}
/**
+ * The variant which sets charset to null.
+ */
+ public VCardComposer(final Context context, final int vcardType,
+ final boolean careHandlerErrors) {
+ this(context, vcardType, null, careHandlerErrors);
+ }
+
+ /**
* Construct for supporting call log entry vCard composing.
+ *
+ * @param context Context to be used during the composition.
+ * @param vcardType The type of vCard, typically available via {@link VCardConfig}.
+ * @param charset The charset to be used. Use null when you don't need the charset.
+ * @param careHandlerErrors If true, This object returns false everytime
+ * a Handler object given via {{@link #addHandler(OneEntryHandler)} returns false.
+ * If false, this ignores those errors.
*/
public VCardComposer(final Context context, final int vcardType,
+ String charset,
final boolean careHandlerErrors) {
mContext = context;
mVCardType = vcardType;
@@ -294,30 +321,62 @@ public class VCardComposer {
mContentResolver = context.getContentResolver();
mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
- mUsesShiftJis = VCardConfig.usesShiftJis(vcardType);
mHandlerList = new ArrayList<OneEntryHandler>();
- if (mIsDoCoMo) {
- String charset;
- try {
- charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
- } catch (UnsupportedCharsetException e) {
- Log.e(LOG_TAG, "DoCoMo-specific SHIFT_JIS was not found. Use SHIFT_JIS as is.");
- charset = SHIFT_JIS;
- }
- mCharsetString = charset;
- } else if (mUsesShiftJis) {
- String charset;
- try {
- charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
- } catch (UnsupportedCharsetException e) {
- Log.e(LOG_TAG, "Vendor-specific SHIFT_JIS was not found. Use SHIFT_JIS as is.");
- charset = SHIFT_JIS;
+ if (mIsDoCoMo || VCardConfig.shouldUseShiftJisForExport(vcardType)) {
+ if (!SHIFT_JIS.equalsIgnoreCase(charset)) {
+ Log.w(LOG_TAG,
+ "The charset \"" + charset + "\" is used while "
+ + SHIFT_JIS + " is needed to be used.");
+ if (TextUtils.isEmpty(charset)) {
+ mCharset = SHIFT_JIS;
+ } else {
+ try {
+ charset = CharsetUtils.charsetForVendor(charset).name();
+ } catch (UnsupportedCharsetException e) {
+ Log.i(LOG_TAG,
+ "Career-specific \"" + charset + "\" was not found (as usual). "
+ + "Use it as is.");
+ }
+ mCharset = charset;
+ }
+ } else {
+ if (mIsDoCoMo) {
+ try {
+ charset = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
+ } catch (UnsupportedCharsetException e) {
+ Log.e(LOG_TAG,
+ "DoCoMo-specific SHIFT_JIS was not found. "
+ + "Use SHIFT_JIS as is.");
+ charset = SHIFT_JIS;
+ }
+ } else {
+ try {
+ charset = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
+ } catch (UnsupportedCharsetException e) {
+ Log.e(LOG_TAG,
+ "Career-specific SHIFT_JIS was not found. "
+ + "Use SHIFT_JIS as is.");
+ charset = SHIFT_JIS;
+ }
+ }
+ mCharset = charset;
}
- mCharsetString = charset;
} else {
- mCharsetString = UTF_8;
+ if (TextUtils.isEmpty(charset)) {
+ mCharset = UTF_8;
+ } else {
+ try {
+ charset = CharsetUtils.charsetForVendor(charset).name();
+ } catch (UnsupportedCharsetException e) {
+ Log.i(LOG_TAG,
+ "Career-specific \"" + charset + "\" was not found (as usual). "
+ + "Use it as is.");
+ }
+ mCharset = charset;
+ }
}
+ Log.d(LOG_TAG, "use the charset \"" + mCharset + "\"");
}
/**
@@ -351,7 +410,7 @@ public class VCardComposer {
}
if (mCareHandlerErrors) {
- List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
+ final List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
mHandlerList.size());
for (OneEntryHandler handler : mHandlerList) {
if (!handler.onInit(mContext)) {
@@ -414,7 +473,7 @@ public class VCardComposer {
mErrorReason = FAILURE_REASON_NOT_INITIALIZED;
return false;
}
- String vcard;
+ final String vcard;
try {
if (mIdColumn >= 0) {
vcard = createOneEntryInternal(mCursor.getString(mIdColumn),
@@ -437,8 +496,7 @@ public class VCardComposer {
mCursor.moveToNext();
}
- // This function does not care the OutOfMemoryError on the handler side
- // :-P
+ // This function does not care the OutOfMemoryError on the handler side :-P
if (mCareHandlerErrors) {
List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
mHandlerList.size());
@@ -457,7 +515,7 @@ public class VCardComposer {
}
private String createOneEntryInternal(final String contactId,
- Method getEntityIteratorMethod) throws VCardException {
+ final Method getEntityIteratorMethod) throws VCardException {
final Map<String, List<ContentValues>> contentValuesListMap =
new HashMap<String, List<ContentValues>>();
// The resolver may return the entity iterator with no data. It is possible.
@@ -527,20 +585,34 @@ public class VCardComposer {
}
}
- final VCardBuilder builder = new VCardBuilder(mVCardType);
- builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
- .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
- .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE))
- .appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE))
- .appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE))
- .appendOrganizations(contentValuesListMap.get(Organization.CONTENT_ITEM_TYPE))
- .appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE))
- .appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE))
- .appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE))
- .appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE))
- .appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE))
- .appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE));
- return builder.toString();
+ return buildVCard(contentValuesListMap);
+ }
+
+ /**
+ * Builds and returns vCard using given map, whose key is CONTENT_ITEM_TYPE defined in
+ * {ContactsContract}. Developers can override this method to customize the output.
+ */
+ public String buildVCard(final Map<String, List<ContentValues>> contentValuesListMap) {
+ if (contentValuesListMap == null) {
+ Log.e(LOG_TAG, "The given map is null. Ignore and return empty String");
+ return "";
+ } else {
+ final VCardBuilder builder = new VCardBuilder(mVCardType, mCharset);
+ // TODO: Android-specific X attributes?
+ builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
+ .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
+ .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE))
+ .appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE))
+ .appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE))
+ .appendOrganizations(contentValuesListMap.get(Organization.CONTENT_ITEM_TYPE))
+ .appendWebsites(contentValuesListMap.get(Website.CONTENT_ITEM_TYPE))
+ .appendPhotos(contentValuesListMap.get(Photo.CONTENT_ITEM_TYPE))
+ .appendNotes(contentValuesListMap.get(Note.CONTENT_ITEM_TYPE))
+ .appendEvents(contentValuesListMap.get(Event.CONTENT_ITEM_TYPE))
+ .appendIms(contentValuesListMap.get(Im.CONTENT_ITEM_TYPE))
+ .appendRelation(contentValuesListMap.get(Relation.CONTENT_ITEM_TYPE));
+ return builder.toString();
+ }
}
public void terminate() {
@@ -563,26 +635,38 @@ public class VCardComposer {
@Override
public void finalize() {
if (!mTerminateIsCalled) {
+ Log.w(LOG_TAG, "terminate() is not called yet. We call it in finalize() step.");
terminate();
}
}
+ /**
+ * @return returns the number of available entities. The return value is undefined
+ * when this object is not ready yet (typically when {{@link #init()} is not called
+ * or when {@link #terminate()} is already called).
+ */
public int getCount() {
if (mCursor == null) {
+ Log.w(LOG_TAG, "This object is not ready yet.");
return 0;
}
return mCursor.getCount();
}
+ /**
+ * @return true when there's no entity to be built. The return value is undefined
+ * when this object is not ready yet.
+ */
public boolean isAfterLast() {
if (mCursor == null) {
+ Log.w(LOG_TAG, "This object is not ready yet.");
return false;
}
return mCursor.isAfterLast();
}
/**
- * @return Return the error reason if possible.
+ * @return Returns the error reason.
*/
public String getErrorReason() {
return mErrorReason;
diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java
index 3442ae7..40566ca 100644
--- a/core/java/android/pim/vcard/VCardConfig.java
+++ b/core/java/android/pim/vcard/VCardConfig.java
@@ -43,10 +43,28 @@ public class VCardConfig {
/* package */ static final int PARSE_TYPE_FOMA = 3; // For Japanese FOMA mobile phones.
/* package */ static final int PARSE_TYPE_WINDOWS_MOBILE_JP = 4;
- // Assumes that "iso-8859-1" is able to map "all" 8bit characters to some unicode and
- // decode the unicode to the original charset. If not, this setting will cause some bug.
- public static final String DEFAULT_CHARSET = "iso-8859-1";
-
+ /**
+ * <P>
+ * The charset used during import.
+ * </P>
+ * <P>
+ * We cannot determine which charset should be used to interpret a given vCard file,
+ * while we have to decode sime encoded data (e.g. BASE64) to binary.
+ * In order to avoid "misinterpretation" of charset as much as possible,
+ * "ISO-8859-1" (a.k.a Latin-1) is first used for reading a stream.
+ * When charset is specified in a property (with "CHARSET=..." parameter),
+ * the string is decoded to raw bytes and encoded into the specific charset,
+ * assuming "ISO-8859-1" is able to map "all" 8bit characters to some unicode,
+ * and it has 1 to 1 mapping in all 8bit characters.
+ * If the assumption is not correct, this setting will cause some bug.
+ * </P>
+ */
+ /* package */ static final String DEFAULT_TEMPORARY_CHARSET = "ISO-8859-1";
+
+ // TODO: still intermediate procedures uses this charset. Fix it.
+ public static final String DEFAULT_IMPORT_CHARSET = "ISO-8859-1";
+ public static final String DEFAULT_EXPORT_CHARSET = "UTF-8";
+
public static final int FLAG_V21 = 0;
public static final int FLAG_V30 = 1;
@@ -58,10 +76,13 @@ public class VCardConfig {
private static final int NAME_ORDER_MASK = 0xC;
// 0x10 is reserved for safety
-
- private static final int FLAG_CHARSET_UTF8 = 0;
- private static final int FLAG_CHARSET_SHIFT_JIS = 0x100;
- private static final int FLAG_CHARSET_MASK = 0xF00;
+
+ /*
+ * These flags are ignored when charset is explicitly given by a caller.
+ */
+ private static final int FLAG_USE_UTF8_FOR_EXPORT = 0;
+ private static final int FLAG_USE_SHIFT_JIS_FOR_EXPORT = 0x100;
+ private static final int FLAG_CHARSET_MASK_FOR_EKPORT = 0xF00;
/**
* The flag indicating the vCard composer will add some "X-" properties used only in Android
@@ -196,7 +217,7 @@ public class VCardConfig {
* </P>
*/
public static final int VCARD_TYPE_V21_GENERIC_UTF8 =
- (FLAG_V21 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
+ (FLAG_V21 | NAME_ORDER_DEFAULT | FLAG_USE_UTF8_FOR_EXPORT |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static String VCARD_TYPE_V21_GENERIC_UTF8_STR = "v21_generic";
@@ -210,7 +231,7 @@ public class VCardConfig {
* </P>
*/
public static final int VCARD_TYPE_V30_GENERIC_UTF8 =
- (FLAG_V30 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
+ (FLAG_V30 | NAME_ORDER_DEFAULT | FLAG_USE_UTF8_FOR_EXPORT |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V30_GENERIC_UTF8_STR = "v30_generic";
@@ -222,7 +243,7 @@ public class VCardConfig {
* </P>
*/
public static final int VCARD_TYPE_V21_EUROPE_UTF8 =
- (FLAG_V21 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
+ (FLAG_V21 | NAME_ORDER_EUROPE | FLAG_USE_UTF8_FOR_EXPORT |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V21_EUROPE_UTF8_STR = "v21_europe";
@@ -236,7 +257,7 @@ public class VCardConfig {
* </P>
*/
public static final int VCARD_TYPE_V30_EUROPE_UTF8 =
- (FLAG_V30 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
+ (FLAG_V30 | NAME_ORDER_EUROPE | FLAG_USE_UTF8_FOR_EXPORT |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V30_EUROPE_STR = "v30_europe";
@@ -250,7 +271,7 @@ public class VCardConfig {
* </P>
*/
public static final int VCARD_TYPE_V21_JAPANESE_UTF8 =
- (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
+ (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_USE_UTF8_FOR_EXPORT |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V21_JAPANESE_UTF8_STR = "v21_japanese_utf8";
@@ -265,7 +286,7 @@ public class VCardConfig {
* </P>
*/
public static final int VCARD_TYPE_V21_JAPANESE_SJIS =
- (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
+ (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_USE_SHIFT_JIS_FOR_EXPORT |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V21_JAPANESE_SJIS_STR = "v21_japanese_sjis";
@@ -280,7 +301,7 @@ public class VCardConfig {
* </P>
*/
public static final int VCARD_TYPE_V30_JAPANESE_SJIS =
- (FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
+ (FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_USE_SHIFT_JIS_FOR_EXPORT |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V30_JAPANESE_SJIS_STR = "v30_japanese_sjis";
@@ -294,7 +315,7 @@ public class VCardConfig {
* </P>
*/
public static final int VCARD_TYPE_V30_JAPANESE_UTF8 =
- (FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
+ (FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_USE_UTF8_FOR_EXPORT |
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
/* package */ static final String VCARD_TYPE_V30_JAPANESE_UTF8_STR = "v30_japanese_utf8";
@@ -310,7 +331,7 @@ public class VCardConfig {
* </P>
*/
public static final int VCARD_TYPE_V21_JAPANESE_MOBILE =
- (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
+ (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_USE_SHIFT_JIS_FOR_EXPORT |
FLAG_CONVERT_PHONETIC_NAME_STRINGS |
FLAG_REFRAIN_QP_TO_NAME_PROPERTIES);
@@ -379,12 +400,17 @@ public class VCardConfig {
return !isV30(vcardType);
}
- public static boolean usesUtf8(final int vcardType) {
- return ((vcardType & FLAG_CHARSET_MASK) == FLAG_CHARSET_UTF8);
+ /* package */ static boolean shouldUseUtf8ForExport(final int vcardType) {
+ return ((vcardType & FLAG_CHARSET_MASK_FOR_EKPORT) == FLAG_USE_UTF8_FOR_EXPORT);
}
- public static boolean usesShiftJis(final int vcardType) {
- return ((vcardType & FLAG_CHARSET_MASK) == FLAG_CHARSET_SHIFT_JIS);
+ /**
+ * Shift_JIS (a charset for Japanese text files) needs special handling to select
+ * carrer specific variants.
+ * @hide just for test
+ */
+ public static boolean shouldUseShiftJisForExport(final int vcardType) {
+ return ((vcardType & FLAG_CHARSET_MASK_FOR_EKPORT) == FLAG_USE_SHIFT_JIS_FOR_EXPORT);
}
public static int getNameOrderType(final int vcardType) {
diff --git a/core/java/android/pim/vcard/VCardEntryConstructor.java b/core/java/android/pim/vcard/VCardEntryConstructor.java
index 290ca2b..4efb105 100644
--- a/core/java/android/pim/vcard/VCardEntryConstructor.java
+++ b/core/java/android/pim/vcard/VCardEntryConstructor.java
@@ -80,7 +80,7 @@ public class VCardEntryConstructor implements VCardInterpreter {
if (inputCharset != null) {
mInputCharset = inputCharset;
} else {
- mInputCharset = VCardConfig.DEFAULT_CHARSET;
+ mInputCharset = VCardConfig.DEFAULT_TEMPORARY_CHARSET;
}
if (charsetForDetodedBytes != null) {
mCharsetForDecodedBytes = charsetForDetodedBytes;
diff --git a/core/java/android/pim/vcard/VCardParser.java b/core/java/android/pim/vcard/VCardParser.java
index 57c52a6..b38ea93 100644
--- a/core/java/android/pim/vcard/VCardParser.java
+++ b/core/java/android/pim/vcard/VCardParser.java
@@ -34,26 +34,17 @@ public abstract class VCardParser {
/**
* <P>
- * Parses the given stream and send the VCard data into VCardBuilderBase object.
+ * Parses the given stream and send the vCard data into VCardBuilderBase object.
* </P.
* <P>
* 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)
+ * formally allowed in vCard 2.1, but not allowed in vCard 3.0. In vCard 2.1,
+ * In some exreme case, it is allowed for vCard to have different charsets in one vCard.
* </P>
* <P>
- * 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,
- * </P>
- * <P>
- * 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.
+ * We recommend you use {@link VCardSourceDetector} and detect which kind of source the
+ * vCard comes from and explicitly specify a charset using the result.
* </P>
*
* @param is The source to parse.
@@ -61,27 +52,24 @@ public abstract class VCardParser {
* @return Returns true for success. Otherwise returns false.
* @throws IOException, VCardException
*/
- public abstract boolean parse(InputStream is, VCardInterpreter interepreter)
- throws IOException, VCardException;
-
+ public final boolean parse(InputStream is, VCardInterpreter interepreter)
+ throws IOException, VCardException {
+ return parse(is, VCardConfig.DEFAULT_TEMPORARY_CHARSET, interepreter);
+ }
+
/**
* <P>
* The method variants which accept charset.
* </P>
- * <P>
- * 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).
- * </P>
*
* @param is The source to parse.
* @param charset Charset to be used.
- * @param builder The VCardBuilderBase object.
+ * @param interpreter The VCardBuilderBase object.
* @return Returns true when successful. Otherwise returns false.
* @throws IOException, VCardException
*/
- public abstract boolean parse(InputStream is, String charset, VCardInterpreter builder)
+ public abstract boolean parse(InputStream is, String charset,
+ VCardInterpreter interpreter)
throws IOException, VCardException;
/**
diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java
index fe8cfb0..4f85150 100644
--- a/core/java/android/pim/vcard/VCardParser_V21.java
+++ b/core/java/android/pim/vcard/VCardParser_V21.java
@@ -68,7 +68,28 @@ public class VCardParser_V21 extends VCardParser {
private static final HashSet<String> sAvailableEncodingV21 =
new HashSet<String>(Arrays.asList(
"7BIT", "8BIT", "QUOTED-PRINTABLE", "BASE64", "B"));
-
+
+ private static final class CustomBufferedReader extends BufferedReader {
+ private long mTime;
+
+ public CustomBufferedReader(Reader in) {
+ super(in);
+ }
+
+ @Override
+ public String readLine() throws IOException {
+ long start = System.currentTimeMillis();
+ String ret = super.readLine();
+ long end = System.currentTimeMillis();
+ mTime += end - start;
+ return ret;
+ }
+
+ public long getTotalmillisecond() {
+ return mTime;
+ }
+ }
+
// Used only for parsing END:VCARD.
private String mPreviousLine;
@@ -839,19 +860,17 @@ public class VCardParser_V21 extends VCardParser {
return null;
}
}
-
- @Override
- public boolean parse(final InputStream is, final VCardInterpreter builder)
- throws IOException, VCardException {
- return parse(is, VCardConfig.DEFAULT_CHARSET, builder);
- }
-
+
@Override
public boolean parse(InputStream is, String charset, VCardInterpreter builder)
throws IOException, VCardException {
+ if (is == null) {
+ throw new NullPointerException("InputStream must not be null.");
+ }
if (charset == null) {
- charset = VCardConfig.DEFAULT_CHARSET;
+ charset = VCardConfig.DEFAULT_TEMPORARY_CHARSET;
}
+
final InputStreamReader tmpReader = new InputStreamReader(is, charset);
if (VCardConfig.showPerformanceLog()) {
mReader = new CustomBufferedReader(tmpReader);
@@ -913,24 +932,3 @@ public class VCardParser_V21 extends VCardParser {
return false;
}
}
-
-class CustomBufferedReader extends BufferedReader {
- private long mTime;
-
- public CustomBufferedReader(Reader in) {
- super(in);
- }
-
- @Override
- public String readLine() throws IOException {
- long start = System.currentTimeMillis();
- String ret = super.readLine();
- long end = System.currentTimeMillis();
- mTime += end - start;
- return ret;
- }
-
- public long getTotalmillisecond() {
- return mTime;
- }
-}