Refactor VCard handling code, phase 2, 3, 4, 5
Phase 2 Make VCard Importer use Data structures in ContactsContract instead of using old Conatacts structure. Phase 3 Developed VCardComposer, which was originally in Contacts package, but now in base/core/java. Also made it use queryEntries() as per jsharkey's suggestion. Phase 4 Added VCardUtils and moved some common methods to it, some of which should be in public API, but hidden for now. Phase 5 Made VCardComposer emits (almost) valid vCard 3.0 data. Confirmed with vCard data emitted by Mac. Related issue: 1784580, 1728351, 1967349 Note: Probable next step: - Add "fast parse" mode in VCradBuilder, in which, VCardBuilder skip parsing the value of each property. It will make the parsing faster. -- Note that parsing the parameters of each entry cannot be skipped, since it may contains the information about Encoding of the property. In other words, if the line is in Quoted-Printable format, the next line may be the part of the property, not a separated property, which should be parsed accordingly. - Needs test
This commit is contained in:
94
core/java/android/pim/vcard/Constants.java
Normal file
94
core/java/android/pim/vcard/Constants.java
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.pim.vcard;
|
||||
|
||||
/**
|
||||
* Constants used in both composer and parser.
|
||||
*/
|
||||
/* package */ class Constants {
|
||||
|
||||
public static final String ATTR_TYPE = "TYPE";
|
||||
|
||||
public static final String VERSION_V21 = "2.1";
|
||||
public static final String VERSION_V30 = "3.0";
|
||||
|
||||
// Properties both the current (as of 2009-08-17) ContactsStruct and de-fact vCard extensions
|
||||
// shown in http://en.wikipedia.org/wiki/VCard support are defined here.
|
||||
public static final String PROPERTY_X_AIM = "X-AIM";
|
||||
public static final String PROPERTY_X_MSN = "X-MSN";
|
||||
public static final String PROPERTY_X_YAHOO = "X-YAHOO";
|
||||
public static final String PROPERTY_X_ICQ = "X-ICQ";
|
||||
public static final String PROPERTY_X_JABBER = "X-JABBER";
|
||||
public static final String PROPERTY_X_GOOGLE_TALK = "X-GOOGLE-TALK";
|
||||
public static final String PROPERTY_X_SKYPE_USERNAME = "X-SKYPE-USERNAME";
|
||||
// Phone number for Skype, available as usual phone.
|
||||
public static final String PROPERTY_X_SKYPE_PSTNNUMBER = "X-SKYPE-PSTNNUMBER";
|
||||
// Some device emits this "X-" attribute, which is specifically invalid but should be
|
||||
// always properly accepted, and emitted in some special case (for that device/application).
|
||||
public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK";
|
||||
|
||||
// How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0
|
||||
//
|
||||
// e.g.
|
||||
// 1) Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..."
|
||||
// 2) Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..."
|
||||
// 3) Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..."
|
||||
//
|
||||
// 2) has been the default of VCard exporter/importer in Android, but we can see the other
|
||||
// formats in vCard data emitted by the other softwares/devices.
|
||||
//
|
||||
// So we are currently not sure which type is the best; probably we will have to change which
|
||||
// type should be emitted depending on the device.
|
||||
public static final String ATTR_TYPE_HOME = "HOME";
|
||||
public static final String ATTR_TYPE_WORK = "WORK";
|
||||
public static final String ATTR_TYPE_FAX = "FAX";
|
||||
public static final String ATTR_TYPE_CELL = "CELL";
|
||||
public static final String ATTR_TYPE_VOICE = "VOICE";
|
||||
public static final String ATTR_TYPE_INTERNET = "INTERNET";
|
||||
|
||||
public static final String ATTR_TYPE_PREF = "PREF";
|
||||
|
||||
// Phone types valid in vCard and known to ContactsContract, but not so common.
|
||||
public static final String ATTR_TYPE_CAR = "CAR";
|
||||
public static final String ATTR_TYPE_ISDN = "ISDN";
|
||||
public static final String ATTR_TYPE_PAGER = "PAGER";
|
||||
|
||||
// Phone types existing in vCard 2.1 but not known to ContactsContract.
|
||||
// TODO: should make parser make these TYPE_CUSTOM.
|
||||
public static final String ATTR_TYPE_MODEM = "MODEM";
|
||||
public static final String ATTR_TYPE_MSG = "MSG";
|
||||
public static final String ATTR_TYPE_BBS = "BBS";
|
||||
public static final String ATTR_TYPE_VIDEO = "VIDEO";
|
||||
|
||||
// Phone types existing in the current Contacts structure but not valid in vCard (at least 2.1)
|
||||
// These types are encoded to "X-" attributes when composing vCard for now.
|
||||
// Parser passes these even if "X-" is added to the attribute.
|
||||
public static final String ATTR_TYPE_PHONE_EXTRA_OTHER = "OTHER";
|
||||
public static final String ATTR_TYPE_PHONE_EXTRA_CALLBACK = "CALLBACK";
|
||||
// TODO: may be "TYPE=COMPANY,PREF", not "COMPANY-MAIN".
|
||||
public static final String ATTR_TYPE_PHONE_EXTRA_COMPANY_MAIN = "COMPANY-MAIN";
|
||||
public static final String ATTR_TYPE_PHONE_EXTRA_RADIO = "RADIO";
|
||||
public static final String ATTR_TYPE_PHONE_EXTRA_TELEX = "TELEX";
|
||||
public static final String ATTR_TYPE_PHONE_EXTRA_TTY_TDD = "TTY-TDD";
|
||||
public static final String ATTR_TYPE_PHONE_EXTRA_ASSISTANT = "ASSISTANT";
|
||||
|
||||
// DoCoMo specific attribute. Used with "SOUND" property, which is alternate of SORT-STRING in
|
||||
// vCard 3.0.
|
||||
public static final String ATTR_TYPE_X_IRMC_N = "X-IRMC-N";
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,11 +15,7 @@
|
||||
*/
|
||||
package android.pim.vcard;
|
||||
|
||||
import android.content.AbstractSyncableContentProvider;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.IContentProvider;
|
||||
import android.provider.Contacts;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
@@ -27,62 +23,26 @@ import android.util.Log;
|
||||
*/
|
||||
public class EntryCommitter implements EntryHandler {
|
||||
public static String LOG_TAG = "vcard.EntryComitter";
|
||||
|
||||
|
||||
private ContentResolver mContentResolver;
|
||||
|
||||
// Ideally, this should be ContactsProvider but it seems Class loader cannot find it,
|
||||
// even when it is subclass of ContactsProvider...
|
||||
private AbstractSyncableContentProvider mProvider;
|
||||
private long mMyContactsGroupId;
|
||||
|
||||
private long mTimeToCommit;
|
||||
|
||||
public EntryCommitter(ContentResolver resolver) {
|
||||
mContentResolver = resolver;
|
||||
|
||||
tryGetOriginalProvider();
|
||||
}
|
||||
|
||||
public void onFinal() {
|
||||
if (VCardConfig.showPerformanceLog()) {
|
||||
Log.d(LOG_TAG,
|
||||
String.format("time to commit entries: %ld ms", mTimeToCommit));
|
||||
}
|
||||
}
|
||||
|
||||
private void tryGetOriginalProvider() {
|
||||
final ContentResolver resolver = mContentResolver;
|
||||
|
||||
if ((mMyContactsGroupId = Contacts.People.tryGetMyContactsGroupId(resolver)) == 0) {
|
||||
Log.e(LOG_TAG, "Could not get group id of MyContact");
|
||||
return;
|
||||
}
|
||||
|
||||
IContentProvider iProviderForName = resolver.acquireProvider(Contacts.CONTENT_URI);
|
||||
ContentProvider contentProvider =
|
||||
ContentProvider.coerceToLocalContentProvider(iProviderForName);
|
||||
if (contentProvider == null) {
|
||||
Log.e(LOG_TAG, "Fail to get ContentProvider object.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(contentProvider instanceof AbstractSyncableContentProvider)) {
|
||||
Log.e(LOG_TAG,
|
||||
"Acquired ContentProvider object is not AbstractSyncableContentProvider.");
|
||||
return;
|
||||
}
|
||||
|
||||
mProvider = (AbstractSyncableContentProvider)contentProvider;
|
||||
public void onParsingStart() {
|
||||
}
|
||||
|
||||
public void onParsingEnd() {
|
||||
if (VCardConfig.showPerformanceLog()) {
|
||||
Log.d(LOG_TAG, String.format("time to commit entries: %d ms", mTimeToCommit));
|
||||
}
|
||||
}
|
||||
|
||||
public void onEntryCreated(final ContactStruct contactStruct) {
|
||||
long start = System.currentTimeMillis();
|
||||
if (mProvider != null) {
|
||||
contactStruct.pushIntoAbstractSyncableContentProvider(
|
||||
mProvider, mMyContactsGroupId);
|
||||
} else {
|
||||
contactStruct.pushIntoContentResolver(mContentResolver);
|
||||
}
|
||||
contactStruct.pushIntoContentResolver(mContentResolver);
|
||||
mTimeToCommit += System.currentTimeMillis() - start;
|
||||
}
|
||||
}
|
||||
@@ -16,18 +16,23 @@
|
||||
package android.pim.vcard;
|
||||
|
||||
/**
|
||||
* Unlike VCardBuilderBase, this (and VCardDataBuilder) assumes
|
||||
* Unlike {@link VCardBuilder}, this (and {@link VCardDataBuilder}) assumes
|
||||
* "each VCard entry should be correctly parsed and passed to each EntryHandler object",
|
||||
*/
|
||||
public interface EntryHandler {
|
||||
/**
|
||||
* Able to be use this method for showing performance log, etc.
|
||||
* TODO: better name?
|
||||
* Called when the parsing started.
|
||||
*/
|
||||
public void onFinal();
|
||||
public void onParsingStart();
|
||||
|
||||
/**
|
||||
* The method called when one VCard entry is successfully created
|
||||
*/
|
||||
public void onEntryCreated(final ContactStruct entry);
|
||||
|
||||
/**
|
||||
* Called when the parsing ended.
|
||||
* Able to be use this method for showing performance log, etc.
|
||||
*/
|
||||
public void onParsingEnd();
|
||||
}
|
||||
|
||||
1433
core/java/android/pim/vcard/VCardComposer.java
Normal file
1433
core/java/android/pim/vcard/VCardComposer.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -15,43 +15,267 @@
|
||||
*/
|
||||
package android.pim.vcard;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The class representing VCard related configurations
|
||||
* The class representing VCard related configurations. Useful static methods are not in this class
|
||||
* but in VCardUtils.
|
||||
*/
|
||||
public class VCardConfig {
|
||||
static final int LOG_LEVEL_NONE = 0;
|
||||
static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1;
|
||||
static final int LOG_LEVEL_SHOW_WARNING = 0x2;
|
||||
static final int LOG_LEVEL_VERBOSE =
|
||||
// TODO: may be better to make the instance of this available and stop using static methods and
|
||||
// one integer.
|
||||
|
||||
/* package */ static final int LOG_LEVEL_NONE = 0;
|
||||
/* package */ static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1;
|
||||
/* package */ static final int LOG_LEVEL_SHOW_WARNING = 0x2;
|
||||
/* package */ static final int LOG_LEVEL_VERBOSE =
|
||||
LOG_LEVEL_PERFORMANCE_MEASUREMENT | LOG_LEVEL_SHOW_WARNING;
|
||||
|
||||
|
||||
/* package */ static final int LOG_LEVEL = LOG_LEVEL_PERFORMANCE_MEASUREMENT;
|
||||
|
||||
// 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";
|
||||
|
||||
// TODO: use this flag
|
||||
public static boolean IGNORE_CASE_EXCEPT_VALUE = true;
|
||||
// TODO: make the other codes use this flag
|
||||
public static final boolean IGNORE_CASE_EXCEPT_VALUE = true;
|
||||
|
||||
protected static final int LOG_LEVEL = LOG_LEVEL_PERFORMANCE_MEASUREMENT;
|
||||
private static final int FLAG_V21 = 0;
|
||||
private static final int FLAG_V30 = 1;
|
||||
|
||||
// 0x2 is reserved for the future use ...
|
||||
|
||||
public static final int NAME_ORDER_DEFAULT = 0;
|
||||
public static final int NAME_ORDER_EUROPE = 0x4;
|
||||
public static final int NAME_ORDER_JAPANESE = 0x8;
|
||||
private static final int NAME_ORDER_MASK = 0xC;
|
||||
|
||||
// 0x10 is reserved for safety
|
||||
|
||||
// Note: phonetic name probably should be "LAST FIRST MIDDLE" for European languages, and
|
||||
// space should be added between each element while it should not be in Japanese.
|
||||
// But unfortunately, we currently do not have the data and are not sure whether we should
|
||||
// support European version of name ordering.
|
||||
//
|
||||
// TODO: Implement the logic described above if we really need European version of
|
||||
// phonetic name handling. Also, adding the appropriate test case of vCard would be
|
||||
// highly appreciated.
|
||||
public static final int NAME_ORDER_TYPE_ENGLISH = 0;
|
||||
public static final int NAME_ORDER_TYPE_JAPANESE = 1;
|
||||
|
||||
public static final int NAME_ORDER_TYPE_DEFAULT = NAME_ORDER_TYPE_ENGLISH;
|
||||
private static final int FLAG_CHARSET_UTF8 = 0;
|
||||
private static final int FLAG_CHARSET_SHIFT_JIS = 0x20;
|
||||
|
||||
/**
|
||||
* @hide temporal. may be deleted
|
||||
* The flag indicating the vCard composer will add some "X-" properties used only in Android
|
||||
* when the formal vCard specification does not have appropriate fields for that data.
|
||||
*
|
||||
* For example, Android accepts nickname information while vCard 2.1 does not.
|
||||
* When this flag is on, vCard composer emits alternative "X-" property (like "X-NICKNAME")
|
||||
* instead of just dropping it.
|
||||
*
|
||||
* vCard parser code automatically parses the field emitted even when this flag is off.
|
||||
*
|
||||
* Note that this flag does not assure all the information must be hold in the emitted vCard.
|
||||
*/
|
||||
private static final int FLAG_USE_ANDROID_PROPERTY = 0x80000000;
|
||||
|
||||
/**
|
||||
* The flag indicating the vCard composer will add some "X-" properties seen in the
|
||||
* vCard data emitted by the other softwares/devices when the formal vCard specification
|
||||
* does not have appropriate field(s) for that data.
|
||||
*
|
||||
* One example is X-PHONETIC-FIRST-NAME/X-PHONETIC-MIDDLE-NAME/X-PHONETIC-LAST-NAME, which are
|
||||
* for phonetic name (how the name is pronounced), seen in the vCard emitted by some other
|
||||
* non-Android devices/softwares. We chose to enable the vCard composer to use those
|
||||
* defact properties since they are also useful for Android devices.
|
||||
*
|
||||
* Note for developers: only "X-" properties should be added with this flag. vCard 2.1/3.0
|
||||
* allows any kind of "X-" properties but does not allow non-"X-" properties (except IANA tokens
|
||||
* in vCard 3.0). Some external parsers may get confused with non-valid, non-"X-" properties.
|
||||
*/
|
||||
private static final int FLAG_USE_DEFACT_PROPERTY = 0x40000000;
|
||||
|
||||
/**
|
||||
* The flag indicating some specific dialect seen in vcard of DoCoMo (one of Japanese
|
||||
* mobile careers) should be used. This flag does not include any other information like
|
||||
* that "the vCard is for Japanese". So it is "possible" that "the vCard should have DoCoMo's
|
||||
* dialect but the name order should be European", but it is not recommended.
|
||||
*/
|
||||
private static final int FLAG_DOCOMO = 0x20000000;
|
||||
|
||||
|
||||
// VCard types
|
||||
|
||||
|
||||
/**
|
||||
* General vCard format with the version 2.1. Uses UTF-8 for the charset.
|
||||
* When composing a vCard entry, the US convension will be used.
|
||||
*
|
||||
* e.g. The order of the display name would be "Prefix Given Middle Family Suffix",
|
||||
* while in Japan, it should be "Prefix Family Middle Given Suffix".
|
||||
*/
|
||||
public static final int VCARD_TYPE_V21_GENERIC =
|
||||
(FLAG_V21 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
|
||||
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static String VCARD_TYPE_V21_GENERIC_STR = "v21_generic";
|
||||
|
||||
/**
|
||||
* General vCard format with the version 3.0. Uses UTF-8 for the charset.
|
||||
*
|
||||
* Note that this type is not fully implemented, so probably some bugs remain especially
|
||||
* in parsing part.
|
||||
*
|
||||
* TODO: implement this type.
|
||||
*/
|
||||
public static final int VCARD_TYPE_V30_GENERIC =
|
||||
(FLAG_V30 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
|
||||
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V30_GENERIC_STR = "v30_generic";
|
||||
|
||||
/**
|
||||
* General vCard format with the version 2.1 with some Europe convension. Uses Utf-8.
|
||||
* Currently, only name order is considered ("Prefix Middle Given Family Suffix")
|
||||
*/
|
||||
public static final int VCARD_TYPE_V21_EUROPE =
|
||||
(FLAG_V21 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
|
||||
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V21_EUROPE_STR = "v21_europe";
|
||||
|
||||
/**
|
||||
* General vCard format with the version 3.0 with some Europe convension. Uses UTF-8
|
||||
*/
|
||||
public static final int VCARD_TYPE_V30_EUROPE =
|
||||
(FLAG_V30 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
|
||||
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V30_EUROPE_STR = "v30_europe";
|
||||
|
||||
/**
|
||||
* vCard 2.1 format for miscellaneous Japanese devices. Shift_Jis is used for
|
||||
* parsing/composing the vCard data.
|
||||
*/
|
||||
public static final int VCARD_TYPE_V21_JAPANESE =
|
||||
(FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
|
||||
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V21_JAPANESE_STR = "v21_japanese";
|
||||
|
||||
/**
|
||||
* vCard 2.1 format for miscellaneous Japanese devices, using UTF-8 as default charset.
|
||||
*/
|
||||
public static final int VCARD_TYPE_V21_JAPANESE_UTF8 =
|
||||
(FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
|
||||
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V21_JAPANESE_UTF8_STR = "v21_japanese_utf8";
|
||||
|
||||
/**
|
||||
* vCard format for miscellaneous Japanese devices, using Shift_Jis for
|
||||
* parsing/composing the vCard data.
|
||||
*/
|
||||
public static final int VCARD_TYPE_V30_JAPANESE =
|
||||
(FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
|
||||
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V30_JAPANESE_STR = "v30_japanese";
|
||||
|
||||
/**
|
||||
* vCard 3.0 format for miscellaneous Japanese devices, using UTF-8 as default charset.
|
||||
*/
|
||||
public static final int VCARD_TYPE_V30_JAPANESE_UTF8 =
|
||||
(FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
|
||||
FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
|
||||
|
||||
/* package */ static final String VCARD_TYPE_V30_JAPANESE_UTF8_STR = "v30_japanese_utf8";
|
||||
|
||||
/**
|
||||
* VCard format used in DoCoMo, which is one of Japanese mobile phone careers.
|
||||
* Base version is vCard 2.1, but the data has several DoCoMo-specific convensions.
|
||||
* No Android-specific property nor defact property is included.
|
||||
*/
|
||||
public static final int VCARD_TYPE_DOCOMO =
|
||||
(FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS | FLAG_DOCOMO);
|
||||
|
||||
private static final String VCARD_TYPE_DOCOMO_STR = "docomo";
|
||||
|
||||
public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC;
|
||||
|
||||
private static final Map<String, Integer> VCARD_TYPES_MAP;
|
||||
|
||||
static {
|
||||
VCARD_TYPES_MAP = new HashMap<String, Integer>();
|
||||
VCARD_TYPES_MAP.put(VCARD_TYPE_V21_GENERIC_STR, VCARD_TYPE_V21_GENERIC);
|
||||
VCARD_TYPES_MAP.put(VCARD_TYPE_V30_GENERIC_STR, VCARD_TYPE_V30_GENERIC);
|
||||
VCARD_TYPES_MAP.put(VCARD_TYPE_V21_EUROPE_STR, VCARD_TYPE_V21_EUROPE);
|
||||
VCARD_TYPES_MAP.put(VCARD_TYPE_V30_EUROPE_STR, VCARD_TYPE_V30_EUROPE);
|
||||
VCARD_TYPES_MAP.put(VCARD_TYPE_V21_JAPANESE_STR, VCARD_TYPE_V21_JAPANESE);
|
||||
VCARD_TYPES_MAP.put(VCARD_TYPE_V21_JAPANESE_UTF8_STR, VCARD_TYPE_V21_JAPANESE_UTF8);
|
||||
VCARD_TYPES_MAP.put(VCARD_TYPE_V30_JAPANESE_STR, VCARD_TYPE_V30_JAPANESE);
|
||||
VCARD_TYPES_MAP.put(VCARD_TYPE_V30_JAPANESE_UTF8_STR, VCARD_TYPE_V30_JAPANESE_UTF8);
|
||||
VCARD_TYPES_MAP.put(VCARD_TYPE_DOCOMO_STR, VCARD_TYPE_DOCOMO);
|
||||
}
|
||||
|
||||
public static int getVCardTypeFromString(String vcardTypeString) {
|
||||
String loweredKey = vcardTypeString.toLowerCase();
|
||||
if (VCARD_TYPES_MAP.containsKey(loweredKey)) {
|
||||
return VCARD_TYPES_MAP.get(loweredKey);
|
||||
} else {
|
||||
// XXX: should return the value indicating the input is invalid?
|
||||
return VCARD_TYPE_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isV30(int vcardType) {
|
||||
return ((vcardType & FLAG_V30) != 0);
|
||||
}
|
||||
|
||||
public static boolean usesQuotedPrintable(int vcardType) {
|
||||
return !isV30(vcardType);
|
||||
}
|
||||
|
||||
public static boolean isDoCoMo(int vcardType) {
|
||||
return ((vcardType & FLAG_DOCOMO) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the device is Japanese and some Japanese convension is
|
||||
* applied to creating "formatted" something like FORMATTED_ADDRESS.
|
||||
*/
|
||||
public static boolean isJapaneseDevice(int vcardType) {
|
||||
return ((vcardType == VCARD_TYPE_V21_JAPANESE) ||
|
||||
(vcardType == VCARD_TYPE_V21_JAPANESE_UTF8) ||
|
||||
(vcardType == VCARD_TYPE_V30_JAPANESE) ||
|
||||
(vcardType == VCARD_TYPE_V30_JAPANESE_UTF8) ||
|
||||
(vcardType == VCARD_TYPE_DOCOMO));
|
||||
}
|
||||
|
||||
public static boolean usesShiftJis(int vcardType) {
|
||||
return ((vcardType & FLAG_CHARSET_SHIFT_JIS) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true when Japanese phonetic string must be converted to a string
|
||||
* containing only half-width katakana. This method exists since Japanese mobile
|
||||
* phones usually use only half-width katakana for expressing phonetic names and
|
||||
* some devices are not ready for parsing other phonetic strings like hiragana and
|
||||
* full-width katakana.
|
||||
*/
|
||||
public static boolean needsToConvertPhoneticString(int vcardType) {
|
||||
return (vcardType == VCARD_TYPE_DOCOMO);
|
||||
}
|
||||
|
||||
public static int getNameOrderType(int vcardType) {
|
||||
return vcardType & NAME_ORDER_MASK;
|
||||
}
|
||||
|
||||
public static boolean usesAndroidSpecificProperty(int vcardType) {
|
||||
return ((vcardType & FLAG_USE_ANDROID_PROPERTY) != 0);
|
||||
}
|
||||
|
||||
public static boolean usesDefactProperty(int vcardType) {
|
||||
return ((vcardType & FLAG_USE_DEFACT_PROPERTY) != 0);
|
||||
}
|
||||
|
||||
public static boolean onlyOneNoteFieldIsAvailable(int vcardType) {
|
||||
return vcardType == VCARD_TYPE_DOCOMO;
|
||||
}
|
||||
|
||||
public static boolean showPerformanceLog() {
|
||||
return (LOG_LEVEL & LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0;
|
||||
return (VCardConfig.LOG_LEVEL & VCardConfig.LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0;
|
||||
}
|
||||
|
||||
private VCardConfig() {
|
||||
|
||||
@@ -59,7 +59,7 @@ public class VCardDataBuilder implements VCardBuilder {
|
||||
private String mTargetCharset;
|
||||
private boolean mStrictLineBreakParsing;
|
||||
|
||||
private int mNameOrderType;
|
||||
private int mVCardType;
|
||||
|
||||
// Just for testing.
|
||||
private long mTimePushIntoContentResolver;
|
||||
@@ -67,23 +67,21 @@ public class VCardDataBuilder implements VCardBuilder {
|
||||
private List<EntryHandler> mEntryHandlers = new ArrayList<EntryHandler>();
|
||||
|
||||
public VCardDataBuilder() {
|
||||
this(null, null, false, VCardConfig.NAME_ORDER_TYPE_DEFAULT);
|
||||
this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public VCardDataBuilder(int nameOrderType) {
|
||||
this(null, null, false, nameOrderType);
|
||||
public VCardDataBuilder(int vcardType) {
|
||||
this(null, null, false, vcardType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public VCardDataBuilder(String charset,
|
||||
boolean strictLineBreakParsing,
|
||||
int nameOrderType) {
|
||||
this(null, charset, strictLineBreakParsing, nameOrderType);
|
||||
public VCardDataBuilder(String charset, boolean strictLineBreakParsing, int vcardType) {
|
||||
this(null, charset, strictLineBreakParsing, vcardType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +90,7 @@ public class VCardDataBuilder implements VCardBuilder {
|
||||
public VCardDataBuilder(String sourceCharset,
|
||||
String targetCharset,
|
||||
boolean strictLineBreakParsing,
|
||||
int nameOrderType) {
|
||||
int vcardType) {
|
||||
if (sourceCharset != null) {
|
||||
mSourceCharset = sourceCharset;
|
||||
} else {
|
||||
@@ -104,7 +102,7 @@ public class VCardDataBuilder implements VCardBuilder {
|
||||
mTargetCharset = TARGET_CHARSET;
|
||||
}
|
||||
mStrictLineBreakParsing = strictLineBreakParsing;
|
||||
mNameOrderType = nameOrderType;
|
||||
mVCardType = vcardType;
|
||||
}
|
||||
|
||||
public void addEntryHandler(EntryHandler entryHandler) {
|
||||
@@ -112,11 +110,14 @@ public class VCardDataBuilder implements VCardBuilder {
|
||||
}
|
||||
|
||||
public void start() {
|
||||
for (EntryHandler entryHandler : mEntryHandlers) {
|
||||
entryHandler.onParsingStart();
|
||||
}
|
||||
}
|
||||
|
||||
public void end() {
|
||||
for (EntryHandler entryHandler : mEntryHandlers) {
|
||||
entryHandler.onFinal();
|
||||
entryHandler.onParsingEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +136,7 @@ public class VCardDataBuilder implements VCardBuilder {
|
||||
Log.e(LOG_TAG, "This is not VCARD!");
|
||||
}
|
||||
|
||||
mCurrentContactStruct = new ContactStruct(mNameOrderType);
|
||||
mCurrentContactStruct = new ContactStruct(mVCardType);
|
||||
}
|
||||
|
||||
public void endRecord() {
|
||||
@@ -164,8 +165,7 @@ public class VCardDataBuilder implements VCardBuilder {
|
||||
|
||||
public void propertyParamType(String type) {
|
||||
if (mParamType != null) {
|
||||
Log.e(LOG_TAG,
|
||||
"propertyParamType() is called more than once " +
|
||||
Log.e(LOG_TAG, "propertyParamType() is called more than once " +
|
||||
"before propertyParamValue() is called");
|
||||
}
|
||||
mParamType = type;
|
||||
@@ -173,6 +173,7 @@ public class VCardDataBuilder implements VCardBuilder {
|
||||
|
||||
public void propertyParamValue(String value) {
|
||||
if (mParamType == null) {
|
||||
// From vCard 2.1 specification. vCard 3.0 formally does not allow this case.
|
||||
mParamType = "TYPE";
|
||||
}
|
||||
mCurrentProperty.addParameter(mParamType, value);
|
||||
@@ -297,7 +298,7 @@ public class VCardDataBuilder implements VCardBuilder {
|
||||
String charset =
|
||||
((charsetCollection != null) ? charsetCollection.iterator().next() : null);
|
||||
String targetCharset = CharsetUtils.nameForDefaultVendor(charset);
|
||||
|
||||
|
||||
final Collection<String> encodingCollection = mCurrentProperty.getParameters("ENCODING");
|
||||
String encoding =
|
||||
((encodingCollection != null) ? encodingCollection.iterator().next() : null);
|
||||
|
||||
@@ -34,7 +34,7 @@ import java.util.HashSet;
|
||||
* This class is used to parse vcard. Please refer to vCard Specification 2.1.
|
||||
*/
|
||||
public class VCardParser_V21 extends VCardParser {
|
||||
private static final String LOG_TAG = "VCardParser_V21";
|
||||
private static final String LOG_TAG = "vcard.VCardParser_V21";
|
||||
|
||||
/** Store the known-type */
|
||||
private static final HashSet<String> sKnownTypeSet = new HashSet<String>(
|
||||
@@ -58,8 +58,10 @@ public class VCardParser_V21 extends VCardParser {
|
||||
"VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
|
||||
"BDAY", "ROLE", "REV", "UID", "KEY", "MAILER"));
|
||||
|
||||
// Though vCard 2.1 specification does not allow "B" encoding, some data may have it.
|
||||
// We allow it for safety...
|
||||
/**
|
||||
* Though vCard 2.1 specification does not allow "B" encoding, some data may have it.
|
||||
* We allow it for safety...
|
||||
*/
|
||||
private static final HashSet<String> sAvailableEncodingV21 =
|
||||
new HashSet<String>(Arrays.asList(
|
||||
"7BIT", "8BIT", "QUOTED-PRINTABLE", "BASE64", "B"));
|
||||
@@ -70,7 +72,10 @@ public class VCardParser_V21 extends VCardParser {
|
||||
/** The builder to build parsed data */
|
||||
protected VCardBuilder mBuilder = null;
|
||||
|
||||
/** The encoding type */
|
||||
/**
|
||||
* The encoding type. "Encoding" in vCard is different from "Charset".
|
||||
* e.g. 7BIT, 8BIT, QUOTED-PRINTABLE.
|
||||
*/
|
||||
protected String mEncoding = null;
|
||||
|
||||
protected final String sDefaultEncoding = "8BIT";
|
||||
@@ -88,17 +93,17 @@ public class VCardParser_V21 extends VCardParser {
|
||||
|
||||
// Just for debugging
|
||||
private long mTimeTotal;
|
||||
private long mTimeStartRecord;
|
||||
private long mTimeEndRecord;
|
||||
private long mTimeReadStartRecord;
|
||||
private long mTimeReadEndRecord;
|
||||
private long mTimeStartProperty;
|
||||
private long mTimeEndProperty;
|
||||
private long mTimeParseItems;
|
||||
private long mTimeParseItem1;
|
||||
private long mTimeParseItem2;
|
||||
private long mTimeParseItem3;
|
||||
private long mTimeHandlePropertyValue1;
|
||||
private long mTimeHandlePropertyValue2;
|
||||
private long mTimeHandlePropertyValue3;
|
||||
private long mTimeParseLineAndHandleGroup;
|
||||
private long mTimeParsePropertyValues;
|
||||
private long mTimeParseAdrOrgN;
|
||||
private long mTimeHandleMiscPropertyValue;
|
||||
private long mTimeHandleQuotedPrintable;
|
||||
private long mTimeHandleBase64;
|
||||
|
||||
/**
|
||||
* Create a new VCard parser.
|
||||
@@ -213,7 +218,7 @@ public class VCardParser_V21 extends VCardParser {
|
||||
if (mBuilder != null) {
|
||||
start = System.currentTimeMillis();
|
||||
mBuilder.startRecord("VCARD");
|
||||
mTimeStartRecord += System.currentTimeMillis() - start;
|
||||
mTimeReadStartRecord += System.currentTimeMillis() - start;
|
||||
}
|
||||
start = System.currentTimeMillis();
|
||||
parseItems();
|
||||
@@ -222,7 +227,7 @@ public class VCardParser_V21 extends VCardParser {
|
||||
if (mBuilder != null) {
|
||||
start = System.currentTimeMillis();
|
||||
mBuilder.endRecord();
|
||||
mTimeEndRecord += System.currentTimeMillis() - start;
|
||||
mTimeReadEndRecord += System.currentTimeMillis() - start;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -250,26 +255,6 @@ public class VCardParser_V21 extends VCardParser {
|
||||
// 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).
|
||||
//
|
||||
// TODO: ignore non vCard entry (e.g. vcalendar).
|
||||
// XXX: Not sure, but according to VDataBuilder.java, vcalendar
|
||||
// entry
|
||||
// may be nested. Just seeking "END:SOMETHING" may not be enough.
|
||||
// e.g.
|
||||
// BEGIN:VCARD
|
||||
// ... (Valid. Must parse this)
|
||||
// END:VCARD
|
||||
// BEGIN:VSOMETHING
|
||||
// ... (Must ignore this)
|
||||
// BEGIN:VSOMETHING2
|
||||
// ... (Must ignore this)
|
||||
// END:VSOMETHING2
|
||||
// ... (Must ignore this!)
|
||||
// END:VSOMETHING
|
||||
// BEGIN:VCARD
|
||||
// ... (Valid. Must parse this)
|
||||
// END:VCARD
|
||||
// INVALID_STRING (VCardException should be thrown)
|
||||
if (length == 2 &&
|
||||
strArray[0].trim().equalsIgnoreCase("BEGIN") &&
|
||||
strArray[1].trim().equalsIgnoreCase("VCARD")) {
|
||||
@@ -367,11 +352,11 @@ public class VCardParser_V21 extends VCardParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* item = [groups "."] name [params] ":" value CRLF
|
||||
* / [groups "."] "ADR" [params] ":" addressparts CRLF
|
||||
* / [groups "."] "ORG" [params] ":" orgparts CRLF
|
||||
* / [groups "."] "N" [params] ":" nameparts CRLF
|
||||
* / [groups "."] "AGENT" [params] ":" vcard CRLF
|
||||
* item = [groups "."] name [params] ":" value CRLF
|
||||
* / [groups "."] "ADR" [params] ":" addressparts CRLF
|
||||
* / [groups "."] "ORG" [params] ":" orgparts CRLF
|
||||
* / [groups "."] "N" [params] ":" nameparts CRLF
|
||||
* / [groups "."] "AGENT" [params] ":" vcard CRLF
|
||||
*/
|
||||
protected boolean parseItem() throws IOException, VCardException {
|
||||
mEncoding = sDefaultEncoding;
|
||||
@@ -389,14 +374,13 @@ public class VCardParser_V21 extends VCardParser {
|
||||
String propertyName = propertyNameAndValue[0].toUpperCase();
|
||||
String propertyValue = propertyNameAndValue[1];
|
||||
|
||||
mTimeParseItem1 += System.currentTimeMillis() - start;
|
||||
mTimeParseLineAndHandleGroup += System.currentTimeMillis() - start;
|
||||
|
||||
if (propertyName.equals("ADR") ||
|
||||
propertyName.equals("ORG") ||
|
||||
if (propertyName.equals("ADR") || propertyName.equals("ORG") ||
|
||||
propertyName.equals("N")) {
|
||||
start = System.currentTimeMillis();
|
||||
handleMultiplePropertyValue(propertyName, propertyValue);
|
||||
mTimeParseItem3 += System.currentTimeMillis() - start;
|
||||
mTimeParseAdrOrgN += System.currentTimeMillis() - start;
|
||||
return false;
|
||||
} else if (propertyName.equals("AGENT")) {
|
||||
handleAgent(propertyValue);
|
||||
@@ -408,14 +392,13 @@ public class VCardParser_V21 extends VCardParser {
|
||||
} else {
|
||||
throw new VCardException("Unknown BEGIN type: " + propertyValue);
|
||||
}
|
||||
} else if (propertyName.equals("VERSION") &&
|
||||
!propertyValue.equals(getVersion())) {
|
||||
} else if (propertyName.equals("VERSION") && !propertyValue.equals(getVersion())) {
|
||||
throw new VCardVersionException("Incompatible version: " +
|
||||
propertyValue + " != " + getVersion());
|
||||
}
|
||||
start = System.currentTimeMillis();
|
||||
handlePropertyValue(propertyName, propertyValue);
|
||||
mTimeParseItem2 += System.currentTimeMillis() - start;
|
||||
mTimeParsePropertyValues += System.currentTimeMillis() - start;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -542,7 +525,7 @@ public class VCardParser_V21 extends VCardParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* ptypeval = knowntype / "X-" word
|
||||
* ptypeval = knowntype / "X-" word
|
||||
*/
|
||||
protected void handleType(String ptypeval) {
|
||||
String upperTypeValue = ptypeval;
|
||||
@@ -637,8 +620,7 @@ public class VCardParser_V21 extends VCardParser {
|
||||
}
|
||||
}
|
||||
|
||||
protected void handlePropertyValue(
|
||||
String propertyName, String propertyValue) throws
|
||||
protected void handlePropertyValue(String propertyName, String propertyValue) throws
|
||||
IOException, VCardException {
|
||||
if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
|
||||
long start = System.currentTimeMillis();
|
||||
@@ -648,7 +630,7 @@ public class VCardParser_V21 extends VCardParser {
|
||||
v.add(result);
|
||||
mBuilder.propertyValues(v);
|
||||
}
|
||||
mTimeHandlePropertyValue2 += System.currentTimeMillis() - start;
|
||||
mTimeHandleQuotedPrintable += System.currentTimeMillis() - start;
|
||||
} else if (mEncoding.equalsIgnoreCase("BASE64") ||
|
||||
mEncoding.equalsIgnoreCase("B")) {
|
||||
long start = System.currentTimeMillis();
|
||||
@@ -667,7 +649,7 @@ public class VCardParser_V21 extends VCardParser {
|
||||
mBuilder.propertyValues(null);
|
||||
}
|
||||
}
|
||||
mTimeHandlePropertyValue3 += System.currentTimeMillis() - start;
|
||||
mTimeHandleBase64 += System.currentTimeMillis() - start;
|
||||
} else {
|
||||
if (!(mEncoding == null || mEncoding.equalsIgnoreCase("7BIT")
|
||||
|| mEncoding.equalsIgnoreCase("8BIT")
|
||||
@@ -681,7 +663,7 @@ public class VCardParser_V21 extends VCardParser {
|
||||
v.add(maybeUnescapeText(propertyValue));
|
||||
mBuilder.propertyValues(v);
|
||||
}
|
||||
mTimeHandlePropertyValue1 += System.currentTimeMillis() - start;
|
||||
mTimeHandleMiscPropertyValue += System.currentTimeMillis() - start;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -770,15 +752,15 @@ public class VCardParser_V21 extends VCardParser {
|
||||
* We are not sure whether we should add "\" CRLF to each value.
|
||||
* For now, we exclude them.
|
||||
*/
|
||||
protected void handleMultiplePropertyValue(
|
||||
String propertyName, String propertyValue) throws IOException, VCardException {
|
||||
// vCard 2.1 does not allow QUOTED-PRINTABLE here, but some data have it.
|
||||
protected void handleMultiplePropertyValue(String propertyName, String propertyValue)
|
||||
throws IOException, VCardException {
|
||||
// vCard 2.1 does not allow QUOTED-PRINTABLE here,
|
||||
// but some softwares/devices emit such data.
|
||||
if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
|
||||
propertyValue = getQuotedPrintable(propertyValue);
|
||||
}
|
||||
|
||||
if (mBuilder != null) {
|
||||
// TODO: limit should be set in accordance with propertyName?
|
||||
StringBuilder builder = new StringBuilder();
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
int length = propertyValue.length();
|
||||
@@ -786,7 +768,7 @@ public class VCardParser_V21 extends VCardParser {
|
||||
char ch = propertyValue.charAt(i);
|
||||
if (ch == '\\' && i < length - 1) {
|
||||
char nextCh = propertyValue.charAt(i + 1);
|
||||
String unescapedString = maybeUnescape(nextCh);
|
||||
String unescapedString = maybeUnescapeCharacter(nextCh);
|
||||
if (unescapedString != null) {
|
||||
builder.append(unescapedString);
|
||||
i++;
|
||||
@@ -819,7 +801,6 @@ public class VCardParser_V21 extends VCardParser {
|
||||
throw new VCardNotSupportedException("AGENT Property is not supported now.");
|
||||
/* This is insufficient support. Also, AGENT Property is very rare.
|
||||
Ignore it for now.
|
||||
TODO: fix this.
|
||||
|
||||
String[] strArray = propertyValue.split(":", 2);
|
||||
if (!(strArray.length == 2 ||
|
||||
@@ -843,7 +824,7 @@ public class VCardParser_V21 extends VCardParser {
|
||||
* Returns unescaped String if the character should be unescaped. Return null otherwise.
|
||||
* e.g. In vCard 2.1, "\;" should be unescaped into ";" while "\x" should not be.
|
||||
*/
|
||||
protected String maybeUnescape(char ch) {
|
||||
protected String maybeUnescapeCharacter(char ch) {
|
||||
// Original vCard 2.1 specification does not allow transformation
|
||||
// "\:" -> ":", "\," -> ",", and "\\" -> "\", but previous implementation of
|
||||
// this class allowed them, so keep it as is.
|
||||
@@ -863,17 +844,11 @@ public class VCardParser_V21 extends VCardParser {
|
||||
@Override
|
||||
public boolean parse(InputStream is, String charset, VCardBuilder builder)
|
||||
throws IOException, VCardException {
|
||||
// TODO: make this count error entries instead of just throwing VCardException.
|
||||
|
||||
{
|
||||
// TODO: If we really need to allow only CRLF as line break,
|
||||
// we will have to develop our own BufferedReader().
|
||||
final InputStreamReader tmpReader = new InputStreamReader(is, charset);
|
||||
if (VCardConfig.showPerformanceLog()) {
|
||||
mReader = new CustomBufferedReader(tmpReader);
|
||||
} else {
|
||||
mReader = new BufferedReader(tmpReader);
|
||||
}
|
||||
final InputStreamReader tmpReader = new InputStreamReader(is, charset);
|
||||
if (VCardConfig.showPerformanceLog()) {
|
||||
mReader = new CustomBufferedReader(tmpReader);
|
||||
} else {
|
||||
mReader = new BufferedReader(tmpReader);
|
||||
}
|
||||
|
||||
mBuilder = builder;
|
||||
@@ -903,21 +878,26 @@ public class VCardParser_V21 extends VCardParser {
|
||||
}
|
||||
|
||||
private void showPerformanceInfo() {
|
||||
Log.d(LOG_TAG, "total parsing time: " + mTimeTotal + " ms");
|
||||
Log.d(LOG_TAG, "Total parsing time: " + mTimeTotal + " ms");
|
||||
if (mReader instanceof CustomBufferedReader) {
|
||||
Log.d(LOG_TAG, "total readLine time: " +
|
||||
Log.d(LOG_TAG, "Total readLine time: " +
|
||||
((CustomBufferedReader)mReader).getTotalmillisecond() + " ms");
|
||||
}
|
||||
Log.d(LOG_TAG, "mTimeStartRecord: " + mTimeStartRecord + " ms");
|
||||
Log.d(LOG_TAG, "mTimeEndRecord: " + mTimeEndRecord + " ms");
|
||||
Log.d(LOG_TAG, "mTimeParseItem1: " + mTimeParseItem1 + " ms");
|
||||
Log.d(LOG_TAG, "mTimeParseItem2: " + mTimeParseItem2 + " ms");
|
||||
Log.d(LOG_TAG, "mTimeParseItem3: " + mTimeParseItem3 + " ms");
|
||||
Log.d(LOG_TAG, "mTimeHandlePropertyValue1: " + mTimeHandlePropertyValue1 + " ms");
|
||||
Log.d(LOG_TAG, "mTimeHandlePropertyValue2: " + mTimeHandlePropertyValue2 + " ms");
|
||||
Log.d(LOG_TAG, "mTimeHandlePropertyValue3: " + mTimeHandlePropertyValue3 + " ms");
|
||||
Log.d(LOG_TAG, "Time for handling the beggining of the record: " +
|
||||
mTimeReadStartRecord + " ms");
|
||||
Log.d(LOG_TAG, "Time for handling the end of the record: " +
|
||||
mTimeReadEndRecord + " ms");
|
||||
Log.d(LOG_TAG, "Time for parsing line, and handling group: " +
|
||||
mTimeParseLineAndHandleGroup + " ms");
|
||||
Log.d(LOG_TAG, "Time for parsing ADR, ORG, and N fields:" + mTimeParseAdrOrgN + " ms");
|
||||
Log.d(LOG_TAG, "Time for parsing property values: " + mTimeParsePropertyValues + " ms");
|
||||
Log.d(LOG_TAG, "Time for handling normal property values: " +
|
||||
mTimeHandleMiscPropertyValue + " ms");
|
||||
Log.d(LOG_TAG, "Time for handling Quoted-Printable: " +
|
||||
mTimeHandleQuotedPrintable + " ms");
|
||||
Log.d(LOG_TAG, "Time for handling Base64: " + mTimeHandleBase64 + " ms");
|
||||
}
|
||||
|
||||
|
||||
private boolean isLetter(char ch) {
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
|
||||
return true;
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.HashSet;
|
||||
* 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 = "VCardParser_V30";
|
||||
private static final String LOG_TAG = "vcard.VCardParser_V30";
|
||||
|
||||
private static final HashSet<String> sAcceptablePropsWithParam = new HashSet<String>(
|
||||
Arrays.asList(
|
||||
@@ -49,7 +49,7 @@ public class VCardParser_V30 extends VCardParser_V21 {
|
||||
|
||||
@Override
|
||||
protected String getVersion() {
|
||||
return "3.0";
|
||||
return Constants.VERSION_V30;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -284,7 +284,7 @@ public class VCardParser_V30 extends VCardParser_V21 {
|
||||
if (ch == '\\' && i < length - 1) {
|
||||
char next_ch = text.charAt(++i);
|
||||
if (next_ch == 'n' || next_ch == 'N') {
|
||||
builder.append("\r\n");
|
||||
builder.append("\n");
|
||||
} else {
|
||||
builder.append(next_ch);
|
||||
}
|
||||
@@ -296,9 +296,9 @@ public class VCardParser_V30 extends VCardParser_V21 {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String maybeUnescape(char ch) {
|
||||
protected String maybeUnescapeCharacter(char ch) {
|
||||
if (ch == 'n' || ch == 'N') {
|
||||
return "\r\n";
|
||||
return "\n";
|
||||
} else {
|
||||
return String.valueOf(ch);
|
||||
}
|
||||
|
||||
764
core/java/android/pim/vcard/VCardUtils.java
Normal file
764
core/java/android/pim/vcard/VCardUtils.java
Normal file
@@ -0,0 +1,764 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.pim.vcard;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentValues;
|
||||
import android.provider.ContactsContract.Data;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utilities for VCard handling codes.
|
||||
*/
|
||||
public class VCardUtils {
|
||||
/*
|
||||
* TODO: some of methods in this class should be placed to the more appropriate place...
|
||||
*/
|
||||
|
||||
// Note that not all types are included in this map/set, since, for example, TYPE_HOME_FAX is
|
||||
// converted to two attribute Strings. These only contain some minor fields valid in both
|
||||
// vCard and current (as of 2009-08-07) Contacts structure.
|
||||
private static final Map<Integer, String> sKnownPhoneTypesMap_ItoS;
|
||||
private static final Set<String> sPhoneTypesSetUnknownToContacts;
|
||||
|
||||
private static final Map<String, Integer> sKnownPhoneTypesMap_StoI;
|
||||
|
||||
static {
|
||||
sKnownPhoneTypesMap_ItoS = new HashMap<Integer, String>();
|
||||
sKnownPhoneTypesMap_StoI = new HashMap<String, Integer>();
|
||||
|
||||
sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_CAR, Constants.ATTR_TYPE_CAR);
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_CAR, Phone.TYPE_CAR);
|
||||
sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_PAGER, Constants.ATTR_TYPE_PAGER);
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PAGER, Phone.TYPE_PAGER);
|
||||
sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_ISDN, Constants.ATTR_TYPE_ISDN);
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_ISDN, Phone.TYPE_ISDN);
|
||||
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_HOME, Phone.TYPE_HOME);
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_WORK, Phone.TYPE_WORK);
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_CELL, Phone.TYPE_MOBILE);
|
||||
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_OTHER, Phone.TYPE_OTHER);
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_CALLBACK, Phone.TYPE_CALLBACK);
|
||||
sKnownPhoneTypesMap_StoI.put(
|
||||
Constants.ATTR_TYPE_PHONE_EXTRA_COMPANY_MAIN, Phone.TYPE_COMPANY_MAIN);
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_RADIO, Phone.TYPE_RADIO);
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_TELEX, Phone.TYPE_TELEX);
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_TTY_TDD, Phone.TYPE_TTY_TDD);
|
||||
sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_ASSISTANT, Phone.TYPE_ASSISTANT);
|
||||
|
||||
sPhoneTypesSetUnknownToContacts = new HashSet<String>();
|
||||
sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_MODEM);
|
||||
sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_MSG);
|
||||
sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_BBS);
|
||||
sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_VIDEO);
|
||||
}
|
||||
|
||||
public static String getPhoneAttributeString(int type) {
|
||||
return sKnownPhoneTypesMap_ItoS.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Interger when the given types can be parsed as known type. Returns String object
|
||||
* when not, which should be set to label.
|
||||
*/
|
||||
public static Object getPhoneTypeFromStrings(Collection<String> types) {
|
||||
int type = -1;
|
||||
String label = null;
|
||||
boolean isFax = false;
|
||||
boolean hasPref = false;
|
||||
|
||||
if (types != null) {
|
||||
for (String typeString : types) {
|
||||
typeString = typeString.toUpperCase();
|
||||
if (typeString.equals(Constants.ATTR_TYPE_PREF)) {
|
||||
hasPref = true;
|
||||
} else if (typeString.equals(Constants.ATTR_TYPE_FAX)) {
|
||||
isFax = true;
|
||||
} else {
|
||||
if (typeString.startsWith("X-") && type < 0) {
|
||||
typeString = typeString.substring(2);
|
||||
}
|
||||
Integer tmp = sKnownPhoneTypesMap_StoI.get(typeString);
|
||||
if (tmp != null) {
|
||||
type = tmp;
|
||||
} else if (type < 0) {
|
||||
type = Phone.TYPE_CUSTOM;
|
||||
label = typeString;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type < 0) {
|
||||
if (hasPref) {
|
||||
type = Phone.TYPE_MAIN;
|
||||
} else {
|
||||
// default to TYPE_HOME
|
||||
type = Phone.TYPE_HOME;
|
||||
}
|
||||
}
|
||||
if (isFax) {
|
||||
if (type == Phone.TYPE_HOME) {
|
||||
type = Phone.TYPE_FAX_HOME;
|
||||
} else if (type == Phone.TYPE_WORK) {
|
||||
type = Phone.TYPE_FAX_WORK;
|
||||
} else if (type == Phone.TYPE_OTHER) {
|
||||
type = Phone.TYPE_OTHER_FAX;
|
||||
}
|
||||
}
|
||||
if (type == Phone.TYPE_CUSTOM) {
|
||||
return label;
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isValidPhoneAttribute(String phoneAttribute, int vcardType) {
|
||||
// TODO: check the following.
|
||||
// - it may violate vCard spec
|
||||
// - it may contain non-ASCII characters
|
||||
//
|
||||
// TODO: use vcardType
|
||||
return (phoneAttribute.startsWith("X-") || phoneAttribute.startsWith("x-") ||
|
||||
sPhoneTypesSetUnknownToContacts.contains(phoneAttribute));
|
||||
}
|
||||
|
||||
public static String[] sortNameElements(int vcardType,
|
||||
String familyName, String middleName, String givenName) {
|
||||
String[] list = new String[3];
|
||||
switch (VCardConfig.getNameOrderType(vcardType)) {
|
||||
case VCardConfig.NAME_ORDER_JAPANESE:
|
||||
// TODO: Should handle Ascii case?
|
||||
list[0] = familyName;
|
||||
list[1] = middleName;
|
||||
list[2] = givenName;
|
||||
break;
|
||||
case VCardConfig.NAME_ORDER_EUROPE:
|
||||
list[0] = middleName;
|
||||
list[1] = givenName;
|
||||
list[2] = familyName;
|
||||
break;
|
||||
default:
|
||||
list[0] = givenName;
|
||||
list[1] = middleName;
|
||||
list[2] = familyName;
|
||||
break;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts postal data into the builder object.
|
||||
*
|
||||
* Note that the data structure of ContactsContract is different from that defined in vCard.
|
||||
* So some conversion may be performed in this method. See also
|
||||
* {{@link #getVCardPostalElements(ContentValues)}
|
||||
*/
|
||||
public static void insertStructuredPostalDataUsingContactsStruct(int vcardType,
|
||||
final ContentProviderOperation.Builder builder,
|
||||
final ContactStruct.PostalData postalData) {
|
||||
builder.withValueBackReference(StructuredPostal.RAW_CONTACT_ID, 0);
|
||||
builder.withValue(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
|
||||
|
||||
builder.withValue(StructuredPostal.TYPE, postalData.type);
|
||||
if (postalData.type == StructuredPostal.TYPE_CUSTOM) {
|
||||
builder.withValue(StructuredPostal.LABEL, postalData.label);
|
||||
}
|
||||
|
||||
builder.withValue(StructuredPostal.POBOX, postalData.pobox);
|
||||
// Extended address is dropped since there's no relevant entry in ContactsContract.
|
||||
builder.withValue(StructuredPostal.STREET, postalData.street);
|
||||
builder.withValue(StructuredPostal.CITY, postalData.localty);
|
||||
builder.withValue(StructuredPostal.REGION, postalData.region);
|
||||
builder.withValue(StructuredPostal.POSTCODE, postalData.postalCode);
|
||||
builder.withValue(StructuredPostal.COUNTRY, postalData.country);
|
||||
|
||||
builder.withValue(StructuredPostal.FORMATTED_ADDRESS,
|
||||
postalData.getFormattedAddress(vcardType));
|
||||
if (postalData.isPrimary) {
|
||||
builder.withValue(Data.IS_PRIMARY, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns String[] containing address information based on vCard spec
|
||||
* (PO Box, Extended Address, Street, Locality, Region, Postal Code, Country Name).
|
||||
* All String objects are non-null ("" is used when the relevant data is empty).
|
||||
*
|
||||
* Note that the data structure of ContactsContract is different from that defined in vCard.
|
||||
* So some conversion may be performed in this method. See also
|
||||
* {{@link #insertStructuredPostalDataUsingContactsStruct(int,
|
||||
* android.content.ContentProviderOperation.Builder,
|
||||
* android.pim.vcard.ContactStruct.PostalData)}
|
||||
*/
|
||||
public static String[] getVCardPostalElements(ContentValues contentValues) {
|
||||
String[] dataArray = new String[7];
|
||||
dataArray[0] = contentValues.getAsString(StructuredPostal.POBOX);
|
||||
if (dataArray[0] == null) {
|
||||
dataArray[0] = "";
|
||||
}
|
||||
// Extended addr. There's no relevant data in ContactsContract.
|
||||
dataArray[1] = "";
|
||||
dataArray[2] = contentValues.getAsString(StructuredPostal.STREET);
|
||||
if (dataArray[2] == null) {
|
||||
dataArray[2] = "";
|
||||
}
|
||||
// Assume that localty == city
|
||||
dataArray[3] = contentValues.getAsString(StructuredPostal.CITY);
|
||||
if (dataArray[3] == null) {
|
||||
dataArray[3] = "";
|
||||
}
|
||||
String region = contentValues.getAsString(StructuredPostal.REGION);
|
||||
if (!TextUtils.isEmpty(region)) {
|
||||
dataArray[4] = region;
|
||||
} else {
|
||||
dataArray[4] = "";
|
||||
}
|
||||
dataArray[5] = contentValues.getAsString(StructuredPostal.POSTCODE);
|
||||
if (dataArray[5] == null) {
|
||||
dataArray[5] = "";
|
||||
}
|
||||
dataArray[6] = contentValues.getAsString(StructuredPostal.COUNTRY);
|
||||
if (dataArray[6] == null) {
|
||||
dataArray[6] = "";
|
||||
}
|
||||
|
||||
return dataArray;
|
||||
}
|
||||
|
||||
public static String constructNameFromElements(int nameOrderType,
|
||||
String familyName, String middleName, String givenName) {
|
||||
return constructNameFromElements(nameOrderType, familyName, middleName, givenName,
|
||||
null, null);
|
||||
}
|
||||
|
||||
public static String constructNameFromElements(int nameOrderType,
|
||||
String familyName, String middleName, String givenName,
|
||||
String prefix, String suffix) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String[] nameList = sortNameElements(nameOrderType,
|
||||
familyName, middleName, givenName);
|
||||
boolean first = true;
|
||||
if (!TextUtils.isEmpty(prefix)) {
|
||||
first = false;
|
||||
builder.append(prefix);
|
||||
}
|
||||
for (String namePart : nameList) {
|
||||
if (!TextUtils.isEmpty(namePart)) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
builder.append(' ');
|
||||
}
|
||||
builder.append(namePart);
|
||||
}
|
||||
}
|
||||
if (!TextUtils.isEmpty(suffix)) {
|
||||
if (!first) {
|
||||
builder.append(' ');
|
||||
}
|
||||
builder.append(suffix);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static boolean containsOnlyAscii(String str) {
|
||||
if (TextUtils.isEmpty(str)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final int length = str.length();
|
||||
final int asciiFirst = 0x20;
|
||||
final int asciiLast = 0x126;
|
||||
for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
|
||||
int c = str.codePointAt(i);
|
||||
if (c < asciiFirst || asciiLast < c) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is useful since vCard 3.0 often requires the ("X-") properties and groups
|
||||
* should contain only alphabets, digits, and hyphen.
|
||||
*
|
||||
* Note: It is already known some devices (wrongly) outputs properties with characters
|
||||
* which should not be in the field. One example is "X-GOOGLE TALK". We appreciate
|
||||
* such kind of input but must never output it unless the target is very specific
|
||||
* to the device which is able to parse the malformed input.
|
||||
*/
|
||||
public static boolean containsOnlyAlphaDigitHyphen(String str) {
|
||||
if (TextUtils.isEmpty(str)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final int lowerAlphabetFirst = 0x41; // included ('A')
|
||||
final int lowerAlphabetLast = 0x5b; // not included ('[')
|
||||
final int upperAlphabetFirst = 0x61; // included ('a')
|
||||
final int upperAlphabetLast = 0x7b; // included ('{')
|
||||
final int digitFirst = 0x30; // included ('0')
|
||||
final int digitLast = 0x39; // included ('9')
|
||||
final int hyphen = '-';
|
||||
final int length = str.length();
|
||||
for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
|
||||
int codepoint = str.codePointAt(i);
|
||||
if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetLast) ||
|
||||
(upperAlphabetFirst <= codepoint && codepoint < upperAlphabetLast) ||
|
||||
(digitFirst <= codepoint && codepoint < digitLast) ||
|
||||
(codepoint == hyphen))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Replace wth the method in Base64 class.
|
||||
private static char PAD = '=';
|
||||
private static final char[] ENCODE64 = {
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
||||
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
|
||||
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
|
||||
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
|
||||
};
|
||||
|
||||
static public String encodeBase64(byte[] data) {
|
||||
if (data == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
char[] charBuffer = new char[(data.length + 2) / 3 * 4];
|
||||
int position = 0;
|
||||
int _3byte = 0;
|
||||
for (int i=0; i<data.length-2; i+=3) {
|
||||
_3byte = ((data[i] & 0xFF) << 16) + ((data[i+1] & 0xFF) << 8) + (data[i+2] & 0xFF);
|
||||
charBuffer[position++] = ENCODE64[_3byte >> 18];
|
||||
charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
|
||||
charBuffer[position++] = ENCODE64[(_3byte >> 6) & 0x3F];
|
||||
charBuffer[position++] = ENCODE64[_3byte & 0x3F];
|
||||
}
|
||||
switch(data.length % 3) {
|
||||
case 1: // [111111][11 0000][0000 00][000000]
|
||||
_3byte = ((data[data.length-1] & 0xFF) << 16);
|
||||
charBuffer[position++] = ENCODE64[_3byte >> 18];
|
||||
charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
|
||||
charBuffer[position++] = PAD;
|
||||
charBuffer[position++] = PAD;
|
||||
break;
|
||||
case 2: // [111111][11 1111][1111 00][000000]
|
||||
_3byte = ((data[data.length-2] & 0xFF) << 16) + ((data[data.length-1] & 0xFF) << 8);
|
||||
charBuffer[position++] = ENCODE64[_3byte >> 18];
|
||||
charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
|
||||
charBuffer[position++] = ENCODE64[(_3byte >> 6) & 0x3F];
|
||||
charBuffer[position++] = PAD;
|
||||
break;
|
||||
}
|
||||
|
||||
return new String(charBuffer);
|
||||
}
|
||||
|
||||
static public String toHalfWidthString(String orgString) {
|
||||
if (TextUtils.isEmpty(orgString)) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int length = orgString.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
// All Japanese character is able to be expressed by char.
|
||||
// Do not need to use String#codepPointAt().
|
||||
char ch = orgString.charAt(i);
|
||||
CharSequence halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch);
|
||||
if (halfWidthText != null) {
|
||||
builder.append(halfWidthText);
|
||||
} else {
|
||||
builder.append(ch);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private VCardUtils() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TextUtils especially for Japanese.
|
||||
* TODO: make this in android.text in the future
|
||||
*/
|
||||
class JapaneseUtils {
|
||||
static private final Map<Character, String> sHalfWidthMap =
|
||||
new HashMap<Character, String>();
|
||||
|
||||
static {
|
||||
// There's no logical mapping rule in Unicode. Sigh.
|
||||
sHalfWidthMap.put('\u3001', "\uFF64");
|
||||
sHalfWidthMap.put('\u3002', "\uFF61");
|
||||
sHalfWidthMap.put('\u300C', "\uFF62");
|
||||
sHalfWidthMap.put('\u300D', "\uFF63");
|
||||
sHalfWidthMap.put('\u301C', "~");
|
||||
sHalfWidthMap.put('\u3041', "\uFF67");
|
||||
sHalfWidthMap.put('\u3042', "\uFF71");
|
||||
sHalfWidthMap.put('\u3043', "\uFF68");
|
||||
sHalfWidthMap.put('\u3044', "\uFF72");
|
||||
sHalfWidthMap.put('\u3045', "\uFF69");
|
||||
sHalfWidthMap.put('\u3046', "\uFF73");
|
||||
sHalfWidthMap.put('\u3047', "\uFF6A");
|
||||
sHalfWidthMap.put('\u3048', "\uFF74");
|
||||
sHalfWidthMap.put('\u3049', "\uFF6B");
|
||||
sHalfWidthMap.put('\u304A', "\uFF75");
|
||||
sHalfWidthMap.put('\u304B', "\uFF76");
|
||||
sHalfWidthMap.put('\u304C', "\uFF76\uFF9E");
|
||||
sHalfWidthMap.put('\u304D', "\uFF77");
|
||||
sHalfWidthMap.put('\u304E', "\uFF77\uFF9E");
|
||||
sHalfWidthMap.put('\u304F', "\uFF78");
|
||||
sHalfWidthMap.put('\u3050', "\uFF78\uFF9E");
|
||||
sHalfWidthMap.put('\u3051', "\uFF79");
|
||||
sHalfWidthMap.put('\u3052', "\uFF79\uFF9E");
|
||||
sHalfWidthMap.put('\u3053', "\uFF7A");
|
||||
sHalfWidthMap.put('\u3054', "\uFF7A\uFF9E");
|
||||
sHalfWidthMap.put('\u3055', "\uFF7B");
|
||||
sHalfWidthMap.put('\u3056', "\uFF7B\uFF9E");
|
||||
sHalfWidthMap.put('\u3057', "\uFF7C");
|
||||
sHalfWidthMap.put('\u3058', "\uFF7C\uFF9E");
|
||||
sHalfWidthMap.put('\u3059', "\uFF7D");
|
||||
sHalfWidthMap.put('\u305A', "\uFF7D\uFF9E");
|
||||
sHalfWidthMap.put('\u305B', "\uFF7E");
|
||||
sHalfWidthMap.put('\u305C', "\uFF7E\uFF9E");
|
||||
sHalfWidthMap.put('\u305D', "\uFF7F");
|
||||
sHalfWidthMap.put('\u305E', "\uFF7F\uFF9E");
|
||||
sHalfWidthMap.put('\u305F', "\uFF80");
|
||||
sHalfWidthMap.put('\u3060', "\uFF80\uFF9E");
|
||||
sHalfWidthMap.put('\u3061', "\uFF81");
|
||||
sHalfWidthMap.put('\u3062', "\uFF81\uFF9E");
|
||||
sHalfWidthMap.put('\u3063', "\uFF6F");
|
||||
sHalfWidthMap.put('\u3064', "\uFF82");
|
||||
sHalfWidthMap.put('\u3065', "\uFF82\uFF9E");
|
||||
sHalfWidthMap.put('\u3066', "\uFF83");
|
||||
sHalfWidthMap.put('\u3067', "\uFF83\uFF9E");
|
||||
sHalfWidthMap.put('\u3068', "\uFF84");
|
||||
sHalfWidthMap.put('\u3069', "\uFF84\uFF9E");
|
||||
sHalfWidthMap.put('\u306A', "\uFF85");
|
||||
sHalfWidthMap.put('\u306B', "\uFF86");
|
||||
sHalfWidthMap.put('\u306C', "\uFF87");
|
||||
sHalfWidthMap.put('\u306D', "\uFF88");
|
||||
sHalfWidthMap.put('\u306E', "\uFF89");
|
||||
sHalfWidthMap.put('\u306F', "\uFF8A");
|
||||
sHalfWidthMap.put('\u3070', "\uFF8A\uFF9E");
|
||||
sHalfWidthMap.put('\u3071', "\uFF8A\uFF9F");
|
||||
sHalfWidthMap.put('\u3072', "\uFF8B");
|
||||
sHalfWidthMap.put('\u3073', "\uFF8B\uFF9E");
|
||||
sHalfWidthMap.put('\u3074', "\uFF8B\uFF9F");
|
||||
sHalfWidthMap.put('\u3075', "\uFF8C");
|
||||
sHalfWidthMap.put('\u3076', "\uFF8C\uFF9E");
|
||||
sHalfWidthMap.put('\u3077', "\uFF8C\uFF9F");
|
||||
sHalfWidthMap.put('\u3078', "\uFF8D");
|
||||
sHalfWidthMap.put('\u3079', "\uFF8D\uFF9E");
|
||||
sHalfWidthMap.put('\u307A', "\uFF8D\uFF9F");
|
||||
sHalfWidthMap.put('\u307B', "\uFF8E");
|
||||
sHalfWidthMap.put('\u307C', "\uFF8E\uFF9E");
|
||||
sHalfWidthMap.put('\u307D', "\uFF8E\uFF9F");
|
||||
sHalfWidthMap.put('\u307E', "\uFF8F");
|
||||
sHalfWidthMap.put('\u307F', "\uFF90");
|
||||
sHalfWidthMap.put('\u3080', "\uFF91");
|
||||
sHalfWidthMap.put('\u3081', "\uFF92");
|
||||
sHalfWidthMap.put('\u3082', "\uFF93");
|
||||
sHalfWidthMap.put('\u3083', "\uFF6C");
|
||||
sHalfWidthMap.put('\u3084', "\uFF94");
|
||||
sHalfWidthMap.put('\u3085', "\uFF6D");
|
||||
sHalfWidthMap.put('\u3086', "\uFF95");
|
||||
sHalfWidthMap.put('\u3087', "\uFF6E");
|
||||
sHalfWidthMap.put('\u3088', "\uFF96");
|
||||
sHalfWidthMap.put('\u3089', "\uFF97");
|
||||
sHalfWidthMap.put('\u308A', "\uFF98");
|
||||
sHalfWidthMap.put('\u308B', "\uFF99");
|
||||
sHalfWidthMap.put('\u308C', "\uFF9A");
|
||||
sHalfWidthMap.put('\u308D', "\uFF9B");
|
||||
sHalfWidthMap.put('\u308E', "\uFF9C");
|
||||
sHalfWidthMap.put('\u308F', "\uFF9C");
|
||||
sHalfWidthMap.put('\u3090', "\uFF72");
|
||||
sHalfWidthMap.put('\u3091', "\uFF74");
|
||||
sHalfWidthMap.put('\u3092', "\uFF66");
|
||||
sHalfWidthMap.put('\u3093', "\uFF9D");
|
||||
sHalfWidthMap.put('\u309B', "\uFF9E");
|
||||
sHalfWidthMap.put('\u309C', "\uFF9F");
|
||||
sHalfWidthMap.put('\u30A1', "\uFF67");
|
||||
sHalfWidthMap.put('\u30A2', "\uFF71");
|
||||
sHalfWidthMap.put('\u30A3', "\uFF68");
|
||||
sHalfWidthMap.put('\u30A4', "\uFF72");
|
||||
sHalfWidthMap.put('\u30A5', "\uFF69");
|
||||
sHalfWidthMap.put('\u30A6', "\uFF73");
|
||||
sHalfWidthMap.put('\u30A7', "\uFF6A");
|
||||
sHalfWidthMap.put('\u30A8', "\uFF74");
|
||||
sHalfWidthMap.put('\u30A9', "\uFF6B");
|
||||
sHalfWidthMap.put('\u30AA', "\uFF75");
|
||||
sHalfWidthMap.put('\u30AB', "\uFF76");
|
||||
sHalfWidthMap.put('\u30AC', "\uFF76\uFF9E");
|
||||
sHalfWidthMap.put('\u30AD', "\uFF77");
|
||||
sHalfWidthMap.put('\u30AE', "\uFF77\uFF9E");
|
||||
sHalfWidthMap.put('\u30AF', "\uFF78");
|
||||
sHalfWidthMap.put('\u30B0', "\uFF78\uFF9E");
|
||||
sHalfWidthMap.put('\u30B1', "\uFF79");
|
||||
sHalfWidthMap.put('\u30B2', "\uFF79\uFF9E");
|
||||
sHalfWidthMap.put('\u30B3', "\uFF7A");
|
||||
sHalfWidthMap.put('\u30B4', "\uFF7A\uFF9E");
|
||||
sHalfWidthMap.put('\u30B5', "\uFF7B");
|
||||
sHalfWidthMap.put('\u30B6', "\uFF7B\uFF9E");
|
||||
sHalfWidthMap.put('\u30B7', "\uFF7C");
|
||||
sHalfWidthMap.put('\u30B8', "\uFF7C\uFF9E");
|
||||
sHalfWidthMap.put('\u30B9', "\uFF7D");
|
||||
sHalfWidthMap.put('\u30BA', "\uFF7D\uFF9E");
|
||||
sHalfWidthMap.put('\u30BB', "\uFF7E");
|
||||
sHalfWidthMap.put('\u30BC', "\uFF7E\uFF9E");
|
||||
sHalfWidthMap.put('\u30BD', "\uFF7F");
|
||||
sHalfWidthMap.put('\u30BE', "\uFF7F\uFF9E");
|
||||
sHalfWidthMap.put('\u30BF', "\uFF80");
|
||||
sHalfWidthMap.put('\u30C0', "\uFF80\uFF9E");
|
||||
sHalfWidthMap.put('\u30C1', "\uFF81");
|
||||
sHalfWidthMap.put('\u30C2', "\uFF81\uFF9E");
|
||||
sHalfWidthMap.put('\u30C3', "\uFF6F");
|
||||
sHalfWidthMap.put('\u30C4', "\uFF82");
|
||||
sHalfWidthMap.put('\u30C5', "\uFF82\uFF9E");
|
||||
sHalfWidthMap.put('\u30C6', "\uFF83");
|
||||
sHalfWidthMap.put('\u30C7', "\uFF83\uFF9E");
|
||||
sHalfWidthMap.put('\u30C8', "\uFF84");
|
||||
sHalfWidthMap.put('\u30C9', "\uFF84\uFF9E");
|
||||
sHalfWidthMap.put('\u30CA', "\uFF85");
|
||||
sHalfWidthMap.put('\u30CB', "\uFF86");
|
||||
sHalfWidthMap.put('\u30CC', "\uFF87");
|
||||
sHalfWidthMap.put('\u30CD', "\uFF88");
|
||||
sHalfWidthMap.put('\u30CE', "\uFF89");
|
||||
sHalfWidthMap.put('\u30CF', "\uFF8A");
|
||||
sHalfWidthMap.put('\u30D0', "\uFF8A\uFF9E");
|
||||
sHalfWidthMap.put('\u30D1', "\uFF8A\uFF9F");
|
||||
sHalfWidthMap.put('\u30D2', "\uFF8B");
|
||||
sHalfWidthMap.put('\u30D3', "\uFF8B\uFF9E");
|
||||
sHalfWidthMap.put('\u30D4', "\uFF8B\uFF9F");
|
||||
sHalfWidthMap.put('\u30D5', "\uFF8C");
|
||||
sHalfWidthMap.put('\u30D6', "\uFF8C\uFF9E");
|
||||
sHalfWidthMap.put('\u30D7', "\uFF8C\uFF9F");
|
||||
sHalfWidthMap.put('\u30D8', "\uFF8D");
|
||||
sHalfWidthMap.put('\u30D9', "\uFF8D\uFF9E");
|
||||
sHalfWidthMap.put('\u30DA', "\uFF8D\uFF9F");
|
||||
sHalfWidthMap.put('\u30DB', "\uFF8E");
|
||||
sHalfWidthMap.put('\u30DC', "\uFF8E\uFF9E");
|
||||
sHalfWidthMap.put('\u30DD', "\uFF8E\uFF9F");
|
||||
sHalfWidthMap.put('\u30DE', "\uFF8F");
|
||||
sHalfWidthMap.put('\u30DF', "\uFF90");
|
||||
sHalfWidthMap.put('\u30E0', "\uFF91");
|
||||
sHalfWidthMap.put('\u30E1', "\uFF92");
|
||||
sHalfWidthMap.put('\u30E2', "\uFF93");
|
||||
sHalfWidthMap.put('\u30E3', "\uFF6C");
|
||||
sHalfWidthMap.put('\u30E4', "\uFF94");
|
||||
sHalfWidthMap.put('\u30E5', "\uFF6D");
|
||||
sHalfWidthMap.put('\u30E6', "\uFF95");
|
||||
sHalfWidthMap.put('\u30E7', "\uFF6E");
|
||||
sHalfWidthMap.put('\u30E8', "\uFF96");
|
||||
sHalfWidthMap.put('\u30E9', "\uFF97");
|
||||
sHalfWidthMap.put('\u30EA', "\uFF98");
|
||||
sHalfWidthMap.put('\u30EB', "\uFF99");
|
||||
sHalfWidthMap.put('\u30EC', "\uFF9A");
|
||||
sHalfWidthMap.put('\u30ED', "\uFF9B");
|
||||
sHalfWidthMap.put('\u30EE', "\uFF9C");
|
||||
sHalfWidthMap.put('\u30EF', "\uFF9C");
|
||||
sHalfWidthMap.put('\u30F0', "\uFF72");
|
||||
sHalfWidthMap.put('\u30F1', "\uFF74");
|
||||
sHalfWidthMap.put('\u30F2', "\uFF66");
|
||||
sHalfWidthMap.put('\u30F3', "\uFF9D");
|
||||
sHalfWidthMap.put('\u30F4', "\uFF73\uFF9E");
|
||||
sHalfWidthMap.put('\u30F5', "\uFF76");
|
||||
sHalfWidthMap.put('\u30F6', "\uFF79");
|
||||
sHalfWidthMap.put('\u30FB', "\uFF65");
|
||||
sHalfWidthMap.put('\u30FC', "\uFF70");
|
||||
sHalfWidthMap.put('\uFF01', "!");
|
||||
sHalfWidthMap.put('\uFF02', "\"");
|
||||
sHalfWidthMap.put('\uFF03', "#");
|
||||
sHalfWidthMap.put('\uFF04', "$");
|
||||
sHalfWidthMap.put('\uFF05', "%");
|
||||
sHalfWidthMap.put('\uFF06', "&");
|
||||
sHalfWidthMap.put('\uFF07', "'");
|
||||
sHalfWidthMap.put('\uFF08', "(");
|
||||
sHalfWidthMap.put('\uFF09', ")");
|
||||
sHalfWidthMap.put('\uFF0A', "*");
|
||||
sHalfWidthMap.put('\uFF0B', "+");
|
||||
sHalfWidthMap.put('\uFF0C', ",");
|
||||
sHalfWidthMap.put('\uFF0D', "-");
|
||||
sHalfWidthMap.put('\uFF0E', ".");
|
||||
sHalfWidthMap.put('\uFF0F', "/");
|
||||
sHalfWidthMap.put('\uFF10', "0");
|
||||
sHalfWidthMap.put('\uFF11', "1");
|
||||
sHalfWidthMap.put('\uFF12', "2");
|
||||
sHalfWidthMap.put('\uFF13', "3");
|
||||
sHalfWidthMap.put('\uFF14', "4");
|
||||
sHalfWidthMap.put('\uFF15', "5");
|
||||
sHalfWidthMap.put('\uFF16', "6");
|
||||
sHalfWidthMap.put('\uFF17', "7");
|
||||
sHalfWidthMap.put('\uFF18', "8");
|
||||
sHalfWidthMap.put('\uFF19', "9");
|
||||
sHalfWidthMap.put('\uFF1A', ":");
|
||||
sHalfWidthMap.put('\uFF1B', ";");
|
||||
sHalfWidthMap.put('\uFF1C', "<");
|
||||
sHalfWidthMap.put('\uFF1D', "=");
|
||||
sHalfWidthMap.put('\uFF1E', ">");
|
||||
sHalfWidthMap.put('\uFF1F', "?");
|
||||
sHalfWidthMap.put('\uFF20', "@");
|
||||
sHalfWidthMap.put('\uFF21', "A");
|
||||
sHalfWidthMap.put('\uFF22', "B");
|
||||
sHalfWidthMap.put('\uFF23', "C");
|
||||
sHalfWidthMap.put('\uFF24', "D");
|
||||
sHalfWidthMap.put('\uFF25', "E");
|
||||
sHalfWidthMap.put('\uFF26', "F");
|
||||
sHalfWidthMap.put('\uFF27', "G");
|
||||
sHalfWidthMap.put('\uFF28', "H");
|
||||
sHalfWidthMap.put('\uFF29', "I");
|
||||
sHalfWidthMap.put('\uFF2A', "J");
|
||||
sHalfWidthMap.put('\uFF2B', "K");
|
||||
sHalfWidthMap.put('\uFF2C', "L");
|
||||
sHalfWidthMap.put('\uFF2D', "M");
|
||||
sHalfWidthMap.put('\uFF2E', "N");
|
||||
sHalfWidthMap.put('\uFF2F', "O");
|
||||
sHalfWidthMap.put('\uFF30', "P");
|
||||
sHalfWidthMap.put('\uFF31', "Q");
|
||||
sHalfWidthMap.put('\uFF32', "R");
|
||||
sHalfWidthMap.put('\uFF33', "S");
|
||||
sHalfWidthMap.put('\uFF34', "T");
|
||||
sHalfWidthMap.put('\uFF35', "U");
|
||||
sHalfWidthMap.put('\uFF36', "V");
|
||||
sHalfWidthMap.put('\uFF37', "W");
|
||||
sHalfWidthMap.put('\uFF38', "X");
|
||||
sHalfWidthMap.put('\uFF39', "Y");
|
||||
sHalfWidthMap.put('\uFF3A', "Z");
|
||||
sHalfWidthMap.put('\uFF3B', "[");
|
||||
sHalfWidthMap.put('\uFF3C', "\\");
|
||||
sHalfWidthMap.put('\uFF3D', "]");
|
||||
sHalfWidthMap.put('\uFF3E', "^");
|
||||
sHalfWidthMap.put('\uFF3F', "_");
|
||||
sHalfWidthMap.put('\uFF41', "a");
|
||||
sHalfWidthMap.put('\uFF42', "b");
|
||||
sHalfWidthMap.put('\uFF43', "c");
|
||||
sHalfWidthMap.put('\uFF44', "d");
|
||||
sHalfWidthMap.put('\uFF45', "e");
|
||||
sHalfWidthMap.put('\uFF46', "f");
|
||||
sHalfWidthMap.put('\uFF47', "g");
|
||||
sHalfWidthMap.put('\uFF48', "h");
|
||||
sHalfWidthMap.put('\uFF49', "i");
|
||||
sHalfWidthMap.put('\uFF4A', "j");
|
||||
sHalfWidthMap.put('\uFF4B', "k");
|
||||
sHalfWidthMap.put('\uFF4C', "l");
|
||||
sHalfWidthMap.put('\uFF4D', "m");
|
||||
sHalfWidthMap.put('\uFF4E', "n");
|
||||
sHalfWidthMap.put('\uFF4F', "o");
|
||||
sHalfWidthMap.put('\uFF50', "p");
|
||||
sHalfWidthMap.put('\uFF51', "q");
|
||||
sHalfWidthMap.put('\uFF52', "r");
|
||||
sHalfWidthMap.put('\uFF53', "s");
|
||||
sHalfWidthMap.put('\uFF54', "t");
|
||||
sHalfWidthMap.put('\uFF55', "u");
|
||||
sHalfWidthMap.put('\uFF56', "v");
|
||||
sHalfWidthMap.put('\uFF57', "w");
|
||||
sHalfWidthMap.put('\uFF58', "x");
|
||||
sHalfWidthMap.put('\uFF59', "y");
|
||||
sHalfWidthMap.put('\uFF5A', "z");
|
||||
sHalfWidthMap.put('\uFF5B', "{");
|
||||
sHalfWidthMap.put('\uFF5C', "|");
|
||||
sHalfWidthMap.put('\uFF5D', "}");
|
||||
sHalfWidthMap.put('\uFF5E', "~");
|
||||
sHalfWidthMap.put('\uFF61', "\uFF61");
|
||||
sHalfWidthMap.put('\uFF62', "\uFF62");
|
||||
sHalfWidthMap.put('\uFF63', "\uFF63");
|
||||
sHalfWidthMap.put('\uFF64', "\uFF64");
|
||||
sHalfWidthMap.put('\uFF65', "\uFF65");
|
||||
sHalfWidthMap.put('\uFF66', "\uFF66");
|
||||
sHalfWidthMap.put('\uFF67', "\uFF67");
|
||||
sHalfWidthMap.put('\uFF68', "\uFF68");
|
||||
sHalfWidthMap.put('\uFF69', "\uFF69");
|
||||
sHalfWidthMap.put('\uFF6A', "\uFF6A");
|
||||
sHalfWidthMap.put('\uFF6B', "\uFF6B");
|
||||
sHalfWidthMap.put('\uFF6C', "\uFF6C");
|
||||
sHalfWidthMap.put('\uFF6D', "\uFF6D");
|
||||
sHalfWidthMap.put('\uFF6E', "\uFF6E");
|
||||
sHalfWidthMap.put('\uFF6F', "\uFF6F");
|
||||
sHalfWidthMap.put('\uFF70', "\uFF70");
|
||||
sHalfWidthMap.put('\uFF71', "\uFF71");
|
||||
sHalfWidthMap.put('\uFF72', "\uFF72");
|
||||
sHalfWidthMap.put('\uFF73', "\uFF73");
|
||||
sHalfWidthMap.put('\uFF74', "\uFF74");
|
||||
sHalfWidthMap.put('\uFF75', "\uFF75");
|
||||
sHalfWidthMap.put('\uFF76', "\uFF76");
|
||||
sHalfWidthMap.put('\uFF77', "\uFF77");
|
||||
sHalfWidthMap.put('\uFF78', "\uFF78");
|
||||
sHalfWidthMap.put('\uFF79', "\uFF79");
|
||||
sHalfWidthMap.put('\uFF7A', "\uFF7A");
|
||||
sHalfWidthMap.put('\uFF7B', "\uFF7B");
|
||||
sHalfWidthMap.put('\uFF7C', "\uFF7C");
|
||||
sHalfWidthMap.put('\uFF7D', "\uFF7D");
|
||||
sHalfWidthMap.put('\uFF7E', "\uFF7E");
|
||||
sHalfWidthMap.put('\uFF7F', "\uFF7F");
|
||||
sHalfWidthMap.put('\uFF80', "\uFF80");
|
||||
sHalfWidthMap.put('\uFF81', "\uFF81");
|
||||
sHalfWidthMap.put('\uFF82', "\uFF82");
|
||||
sHalfWidthMap.put('\uFF83', "\uFF83");
|
||||
sHalfWidthMap.put('\uFF84', "\uFF84");
|
||||
sHalfWidthMap.put('\uFF85', "\uFF85");
|
||||
sHalfWidthMap.put('\uFF86', "\uFF86");
|
||||
sHalfWidthMap.put('\uFF87', "\uFF87");
|
||||
sHalfWidthMap.put('\uFF88', "\uFF88");
|
||||
sHalfWidthMap.put('\uFF89', "\uFF89");
|
||||
sHalfWidthMap.put('\uFF8A', "\uFF8A");
|
||||
sHalfWidthMap.put('\uFF8B', "\uFF8B");
|
||||
sHalfWidthMap.put('\uFF8C', "\uFF8C");
|
||||
sHalfWidthMap.put('\uFF8D', "\uFF8D");
|
||||
sHalfWidthMap.put('\uFF8E', "\uFF8E");
|
||||
sHalfWidthMap.put('\uFF8F', "\uFF8F");
|
||||
sHalfWidthMap.put('\uFF90', "\uFF90");
|
||||
sHalfWidthMap.put('\uFF91', "\uFF91");
|
||||
sHalfWidthMap.put('\uFF92', "\uFF92");
|
||||
sHalfWidthMap.put('\uFF93', "\uFF93");
|
||||
sHalfWidthMap.put('\uFF94', "\uFF94");
|
||||
sHalfWidthMap.put('\uFF95', "\uFF95");
|
||||
sHalfWidthMap.put('\uFF96', "\uFF96");
|
||||
sHalfWidthMap.put('\uFF97', "\uFF97");
|
||||
sHalfWidthMap.put('\uFF98', "\uFF98");
|
||||
sHalfWidthMap.put('\uFF99', "\uFF99");
|
||||
sHalfWidthMap.put('\uFF9A', "\uFF9A");
|
||||
sHalfWidthMap.put('\uFF9B', "\uFF9B");
|
||||
sHalfWidthMap.put('\uFF9C', "\uFF9C");
|
||||
sHalfWidthMap.put('\uFF9D', "\uFF9D");
|
||||
sHalfWidthMap.put('\uFF9E', "\uFF9E");
|
||||
sHalfWidthMap.put('\uFF9F', "\uFF9F");
|
||||
sHalfWidthMap.put('\uFFE5', "\u005C\u005C");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return half-width version of that character if possible. Return null if not possible
|
||||
* @param ch input character
|
||||
* @return CharSequence object if the mapping for ch exists. Return null otherwise.
|
||||
*/
|
||||
public static CharSequence tryGetHalfWidthText(char ch) {
|
||||
if (sHalfWidthMap.containsKey(ch)) {
|
||||
return sHalfWidthMap.get(ch);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import android.syncml.pim.PropertyNode;
|
||||
import android.syncml.pim.VBuilder;
|
||||
import android.syncml.pim.VNode;
|
||||
import android.syncml.pim.VParser;
|
||||
import android.text.TextUtils;
|
||||
import android.util.CharsetUtils;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -403,7 +404,10 @@ public class VCardDataBuilder implements VBuilder {
|
||||
String targetCharset = CharsetUtils.nameForDefaultVendor(paramMap.getAsString("CHARSET"));
|
||||
String encoding = paramMap.getAsString("ENCODING");
|
||||
|
||||
if (targetCharset == null || targetCharset.length() == 0) {
|
||||
Log.d("@@@", String.format("targetCharset: \"%s\", encoding: \"%s\"",
|
||||
targetCharset, encoding));
|
||||
|
||||
if (TextUtils.isEmpty(targetCharset)) {
|
||||
targetCharset = mTargetCharset;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package android.syncml.pim.vcard;
|
||||
|
||||
import android.syncml.pim.VDataBuilder;
|
||||
import android.syncml.pim.VParser;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
@@ -35,10 +35,6 @@
|
||||
<!-- The duration (in milliseconds) of a long animation. -->
|
||||
<integer name="config_longAnimTime">300</integer>
|
||||
|
||||
<!-- Flag indicating whether Last Name comes before First Name.
|
||||
This becomes true in Japan, for example.-->
|
||||
<bool name="config_lastname_comes_before_firstname">false</bool>
|
||||
|
||||
<!-- This string array should be overridden by the device to present a list of network attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardward -->
|
||||
<!-- An Array of "[type-name],[associated radio-name],[priority] -->
|
||||
<string-array translatable="false" name="networkAttributes">
|
||||
|
||||
@@ -19,11 +19,6 @@ package com.android.unit_tests.vcard;
|
||||
import android.content.ContentValues;
|
||||
import android.pim.vcard.ContactStruct;
|
||||
import android.pim.vcard.EntryHandler;
|
||||
import android.pim.vcard.VCardBuilder;
|
||||
import android.pim.vcard.VCardBuilderCollection;
|
||||
import android.pim.vcard.VCardConfig;
|
||||
import android.pim.vcard.VCardDataBuilder;
|
||||
import android.pim.vcard.VCardParser;
|
||||
import android.pim.vcard.VCardParser_V21;
|
||||
import android.pim.vcard.VCardParser_V30;
|
||||
import android.pim.vcard.exception.VCardException;
|
||||
@@ -38,20 +33,21 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class VCardTests extends AndroidTestCase {
|
||||
|
||||
// TODO: Use EntityIterator, which is added in Eclair.
|
||||
private static class EntryHolder implements EntryHandler {
|
||||
public List<ContactStruct> contacts = new ArrayList<ContactStruct>();
|
||||
public void onParsingStart() {
|
||||
}
|
||||
public void onEntryCreated(ContactStruct contactStruct) {
|
||||
contacts.add(contactStruct);
|
||||
}
|
||||
public void onFinal() {
|
||||
public void onParsingEnd() {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static void verify(ContactStruct expected, ContactStruct actual) {
|
||||
if (!equalsString(expected.getName(), actual.getName())) {
|
||||
fail(String.format("Names do not equal: \"%s\" != \"%s\"",
|
||||
@@ -128,7 +124,7 @@ public class VCardTests extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
private class PropertyNodesVerifier {
|
||||
private HashMap<String, ArrayList<PropertyNode>> mPropertyNodeMap;
|
||||
@@ -189,6 +185,7 @@ public class VCardTests extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public void testV21SimpleCase1_1() throws IOException, VCardException {
|
||||
VCardParser parser = new VCardParser_V21();
|
||||
VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH);
|
||||
@@ -260,7 +257,7 @@ public class VCardTests extends AndroidTestCase {
|
||||
verify(new ContactStruct("Ando Roid", null,
|
||||
null, null, null, null, null, null),
|
||||
actual);
|
||||
}
|
||||
}*/
|
||||
|
||||
public void testV21BackslashCase() throws IOException, VCardException {
|
||||
VCardParser_V21 parser = new VCardParser_V21();
|
||||
|
||||
Reference in New Issue
Block a user