VCardEntryConstructor.java revision 2bf85a1a15a3175119ab8415fc590fd5fe3d0752
14199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/*
24199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Copyright (C) 2009 The Android Open Source Project
34199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *
44199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Licensed under the Apache License, Version 2.0 (the "License");
54199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * you may not use this file except in compliance with the License.
64199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * You may obtain a copy of the License at
74199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *
84199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *      http://www.apache.org/licenses/LICENSE-2.0
94199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa *
104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Unless required by applicable law or agreed to in writing, software
114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * distributed under the License is distributed on an "AS IS" BASIS,
124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * See the License for the specific language governing permissions and
144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * limitations under the License.
154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */
164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawapackage com.android.vcard;
174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.accounts.Account;
194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.text.TextUtils;
204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.util.Base64;
214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.util.CharsetUtils;
224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.util.Log;
234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.UnsupportedEncodingException;
254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.nio.ByteBuffer;
264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.nio.charset.Charset;
274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.ArrayList;
284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Collection;
294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.List;
304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/**
324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p>
334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * The {@link VCardInterpreter} implementation which enables {@link VCardEntryHandler} objects
344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * to easily handle each vCard entry.
354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p>
364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p>
374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * This class understand details inside vCard and translates it to {@link VCardEntry}.
384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Then the class throw it to {@link VCardEntryHandler} registered via
394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * {@link #addEntryHandler(VCardEntryHandler)}, so that all those registered objects
404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * are able to handle the {@link VCardEntry} object.
414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p>
424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p>
434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * If you want to know the detail inside vCard, it would be better to implement
444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * {@link VCardInterpreter} directly, instead of relying on this class and
454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * {@link VCardEntry} created by the object.
464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p>
474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */
484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawapublic class VCardEntryConstructor implements VCardInterpreter {
494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static String LOG_TAG = "VCardEntryConstructor";
504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private VCardEntry.Property mCurrentProperty = new VCardEntry.Property();
524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private VCardEntry mCurrentVCardEntry;
534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private String mParamType;
544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    // The charset using which {@link VCardInterpreter} parses the text.
564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    // Each String is first decoded into binary stream with this charset, and encoded back
574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    // to "target charset", which may be explicitly specified by the vCard with "CHARSET"
584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    // property or implicitly mentioned by its version (e.g. vCard 3.0 recommends UTF-8).
594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final String mSourceCharset;
604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final boolean mStrictLineBreaking;
624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final int mVCardType;
634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final Account mAccount;
644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    // For measuring performance.
664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private long mTimePushIntoContentResolver;
674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private final List<VCardEntryHandler> mEntryHandlers = new ArrayList<VCardEntryHandler>();
694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardEntryConstructor() {
714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(VCardConfig.VCARD_TYPE_V21_GENERIC, null);
724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardEntryConstructor(final int vcardType) {
754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(vcardType, null, null, false);
764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardEntryConstructor(final int vcardType, final Account account) {
794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(vcardType, account, null, false);
804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardEntryConstructor(final int vcardType, final Account account,
834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final String inputCharset) {
844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        this(vcardType, account, inputCharset, false);
854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @hide Just for testing.
894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public VCardEntryConstructor(final int vcardType, final Account account,
914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            final String inputCharset, final boolean strictLineBreakParsing) {
924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (inputCharset != null) {
934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mSourceCharset = inputCharset;
944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } else {
954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mSourceCharset = VCardConfig.DEFAULT_INTERMEDIATE_CHARSET;
964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mStrictLineBreaking = strictLineBreakParsing;
984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mVCardType = vcardType;
994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mAccount = account;
1004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void addEntryHandler(VCardEntryHandler entryHandler) {
1034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mEntryHandlers.add(entryHandler);
1044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1052bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa
1062bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa    @Override
1074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void start() {
1084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        for (VCardEntryHandler entryHandler : mEntryHandlers) {
1094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            entryHandler.onStart();
1104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
1114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1132bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa    @Override
1144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void end() {
1154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        for (VCardEntryHandler entryHandler : mEntryHandlers) {
1164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            entryHandler.onEnd();
1174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
1184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void clear() {
1214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCurrentVCardEntry = null;
1224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCurrentProperty = new VCardEntry.Property();
1234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1252bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa    @Override
1264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void startEntry() {
1274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mCurrentVCardEntry != null) {
1284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.e(LOG_TAG, "Nested VCard code is not supported now.");
1294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
1304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCurrentVCardEntry = new VCardEntry(mVCardType, mAccount);
1314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1332bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa    @Override
1344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void endEntry() {
1354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCurrentVCardEntry.consolidateFields();
1364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        for (VCardEntryHandler entryHandler : mEntryHandlers) {
1374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            entryHandler.onEntryCreated(mCurrentVCardEntry);
1384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
1394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCurrentVCardEntry = null;
1404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1422bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa    @Override
1434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void startProperty() {
1444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCurrentProperty.clear();
1454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1472bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa    @Override
1484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void endProperty() {
1494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCurrentVCardEntry.addProperty(mCurrentProperty);
1504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1522bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa    @Override
1534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void propertyName(String name) {
1544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCurrentProperty.setPropertyName(name);
1554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1572bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa    @Override
1584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void propertyGroup(String group) {
1594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1612bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa    @Override
1624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void propertyParamType(String type) {
1634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mParamType != null) {
1644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.e(LOG_TAG, "propertyParamType() is called more than once " +
1654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    "before propertyParamValue() is called");
1664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
1674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mParamType = type;
1684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1702bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa    @Override
1714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void propertyParamValue(String value) {
1724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (mParamType == null) {
1734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            // From vCard 2.1 specification. vCard 3.0 formally does not allow this case.
1744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mParamType = "TYPE";
1754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
1762bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa        if (!VCardUtils.containsOnlyAlphaDigitHyphen(value)) {
1772bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa            value = encodeToSystemCharset(
1782bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa                    value, mSourceCharset, VCardConfig.DEFAULT_IMPORT_CHARSET);
1792bf85a1a15a3175119ab8415fc590fd5fe3d0752Daisuke Miyakawa        }
1804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mCurrentProperty.addParameter(mParamType, value);
1814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        mParamType = null;
1824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
1834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
1844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private static String encodeToSystemCharset(String originalString,
1854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            String sourceCharset, String targetCharset) {
1864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (sourceCharset.equalsIgnoreCase(targetCharset)) {
1874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return originalString;
1884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
1894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        final Charset charset = Charset.forName(sourceCharset);
1904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        final ByteBuffer byteBuffer = charset.encode(originalString);
1914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // byteBuffer.array() "may" return byte array which is larger than
1924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // byteBuffer.remaining(). Here, we keep on the safe side.
1934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        final byte[] bytes = new byte[byteBuffer.remaining()];
1944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        byteBuffer.get(bytes);
1954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        try {
1964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            String ret = new String(bytes, targetCharset);
1974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return ret;
1984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        } catch (UnsupportedEncodingException e) {
1994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
2004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return null;
2014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
2024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    private String handleOneValue(String value,
2054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            String sourceCharset, String targetCharset, String encoding) {
20658610106ce61adad9b1caa1fe9f7925c3e938babDaisuke Miyakawa        // It is possible when some of multiple values are empty.
20758610106ce61adad9b1caa1fe9f7925c3e938babDaisuke Miyakawa        // e.g. N:;a;;; -> values are "", "a", "", "", and "".
20858610106ce61adad9b1caa1fe9f7925c3e938babDaisuke Miyakawa        if (TextUtils.isEmpty(value)) {
20958610106ce61adad9b1caa1fe9f7925c3e938babDaisuke Miyakawa            return "";
2104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
2114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (encoding != null) {
2134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            if (encoding.equals("BASE64") || encoding.equals("B")) {
2144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mCurrentProperty.setPropertyBytes(Base64.decode(value.getBytes(), Base64.DEFAULT));
2154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                return value;
2164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            } else if (encoding.equals("QUOTED-PRINTABLE")) {
2174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                return VCardUtils.parseQuotedPrintable(
2184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                        value, mStrictLineBreaking, sourceCharset, targetCharset);
2194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            }
2204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            Log.w(LOG_TAG, "Unknown encoding. Fall back to default.");
2214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
2224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        // Just translate the charset of a given String from inputCharset to a system one.
2244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        return encodeToSystemCharset(value, sourceCharset, targetCharset);
2254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void propertyValues(List<String> values) {
2284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (values == null || values.isEmpty()) {
2294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            return;
2304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
2314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
232d5a8fc2a35c69fc34df35fd545ccf83d548ba50cDaisuke Miyakawa        final Collection<String> charsetCollection =
233d5a8fc2a35c69fc34df35fd545ccf83d548ba50cDaisuke Miyakawa                mCurrentProperty.getParameters(VCardConstants.PARAM_CHARSET);
234d5a8fc2a35c69fc34df35fd545ccf83d548ba50cDaisuke Miyakawa        final Collection<String> encodingCollection =
235d5a8fc2a35c69fc34df35fd545ccf83d548ba50cDaisuke Miyakawa                mCurrentProperty.getParameters(VCardConstants.PARAM_ENCODING);
2364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        final String encoding =
2374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            ((encodingCollection != null) ? encodingCollection.iterator().next() : null);
2384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        String targetCharset = CharsetUtils.nameForDefaultVendor(
2394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                ((charsetCollection != null) ? charsetCollection.iterator().next() : null));
2404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        if (TextUtils.isEmpty(targetCharset)) {
2414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            targetCharset = VCardConfig.DEFAULT_IMPORT_CHARSET;
2424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
2434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        for (final String value : values) {
2454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa            mCurrentProperty.addToPropertyValueList(
2464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                    handleOneValue(value, mSourceCharset, targetCharset, encoding));
2474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        }
2484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa
2504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    /**
2514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     * @hide
2524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa     */
2534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    public void showPerformanceInfo() {
2544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa        Log.d(LOG_TAG, "time for insert ContactStruct to database: " +
2554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa                mTimePushIntoContentResolver + " ms");
2564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa    }
2574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa}
258