Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6994f311 authored by Daisuke Miyakawa's avatar Daisuke Miyakawa Committed by Android (Google) Code Review
Browse files

Merge "vCard refactoring."

parents ef08207b 56374c43
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ import java.util.Map;
        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");
+15 −18
Original line number Diff line number Diff line
@@ -91,13 +91,13 @@ import java.util.Map;
 *         composer.terminate();
 *     }
 * }</pre>
 * <P>
 * <p>
 * Users have to manually take care of memory efficiency. Even one vCard may contain
 * image of non-trivial size for mobile devices.
 * </P>
 * <P>
 * In default, Default {@link VCardBuilder} class is used to build each vCard.
 * </P>
 * </p>
 * <p>
 * {@link VCardBuilder} is used to build each vCard.
 * </p>
 */
public class VCardComposer {
    private static final String LOG_TAG = "VCardComposer";
@@ -161,14 +161,14 @@ public class VCardComposer {
     * Must not close the stream outside this class.
     * </p>
     */
    public class HandlerForOutputStream implements OneEntryHandler {
    public final class HandlerForOutputStream implements OneEntryHandler {
        @SuppressWarnings("hiding")
        private static final String LOG_TAG = "vcard.VCardComposer.HandlerForOutputStream";
        private static final String LOG_TAG = "VCardComposer.HandlerForOutputStream";

        private boolean mOnTerminateIsCalled = false;

        final private OutputStream mOutputStream; // mWriter will close this.
        protected Writer mWriter;
        private final OutputStream mOutputStream; // mWriter will close this.
        private Writer mWriter;

        /**
         * Input stream will be closed on the detruction of this object.
@@ -177,7 +177,7 @@ public class VCardComposer {
            mOutputStream = outputStream;
        }

        public final boolean onInit(final Context context) {
        public boolean onInit(final Context context) {
            try {
                mWriter = new BufferedWriter(new OutputStreamWriter(
                        mOutputStream, mCharset));
@@ -207,7 +207,7 @@ public class VCardComposer {
            return true;
        }

        public final boolean onEntryCreated(String vcard) {
        public boolean onEntryCreated(String vcard) {
            try {
                mWriter.write(vcard);
            } catch (IOException e) {
@@ -220,7 +220,7 @@ public class VCardComposer {
            return true;
        }

        public final void onTerminate() {
        public void onTerminate() {
            mOnTerminateIsCalled = true;
            if (mWriter != null) {
                try {
@@ -242,8 +242,6 @@ public class VCardComposer {
            }
        }

        // Users can override this if they want to (e.g. if they don't want to close the stream).
        // TODO: Should expose bare OutputStream instead?
        public void closeOutputStream() {
            try {
                mWriter.close();
@@ -312,8 +310,7 @@ public class VCardComposer {
     * a Handler object given via {{@link #addHandler(OneEntryHandler)} returns false.
     * If false, this ignores those errors.
     */
    public VCardComposer(final Context context, final int vcardType,
            String charset,
    public VCardComposer(final Context context, final int vcardType, String charset,
            final boolean careHandlerErrors) {
        mContext = context;
        mVCardType = vcardType;
@@ -380,6 +377,7 @@ public class VCardComposer {
                mCharset = charset;
            }
        }

        Log.d(LOG_TAG, "Use the charset \"" + mCharset + "\"");
    }

@@ -602,7 +600,6 @@ public class VCardComposer {
            return "";
        } else {
            final VCardBuilder builder = new VCardBuilder(mVCardType, mCharset);
            // TODO: Android-specific X attributes?
            builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
                    .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
                    .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE))
+10 −11
Original line number Diff line number Diff line
@@ -153,6 +153,7 @@ public class VCardConfig {
     * In vCard 3.0, Quoted-Printable is explicitly "prohibitted", so we don't need to care this
     * kind of problem (hopefully).
     * </p>
     * @hide
     */
    public static final int FLAG_REFRAIN_QP_TO_NAME_PROPERTIES = 0x10000000;

@@ -171,7 +172,7 @@ public class VCardConfig {
     * able to parse them as we expect.
     * </p>
     */
    public static final int FLAG_CONVERT_PHONETIC_NAME_STRINGS = 0x0800000;
    public static final int FLAG_CONVERT_PHONETIC_NAME_STRINGS = 0x08000000;

    /**
     * <p>
@@ -184,21 +185,20 @@ public class VCardConfig {
     * How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0.
     * </p>
     * <p>
     * e.g.<BR />
     * 1) Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..."<BR />
     * 2) Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..."<BR />
     * 3) Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..."<BR />
     * </p>
     * <p>
     * 2) had been the default of VCard exporter/importer in Android, but it is found that
     * some external exporter is not able to parse the type format like 2) but only 3).
     * e.g.
     * </p>
     * <ol>
     * <li>Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..."</li>
     * <li>Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..."</li>
     * <li>Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..."</li>
     * </ol>
     * <p>
     * If you are targeting to the importer which cannot accept TYPE params without "TYPE="
     * strings (which should be rare though), please use this flag.
     * </p>
     * <p>
     * Example usage: int vcardType = (VCARD_TYPE_V21_GENERIC | FLAG_APPEND_TYPE_PARAM);
     * Example usage:
     * <pre class="prettyprint">int type = (VCARD_TYPE_V21_GENERIC | FLAG_APPEND_TYPE_PARAM);</pre>
     * </p>
     */
    public static final int FLAG_APPEND_TYPE_PARAM = 0x04000000;
@@ -261,7 +261,6 @@ public class VCardConfig {
     */
    public static final int VCARD_TYPE_UNKNOWN = 0;


    /**
     * <p>
     * Generic vCard format with the vCard 2.1. When composing a vCard entry,
+19 −21
Original line number Diff line number Diff line
@@ -78,12 +78,12 @@ public class VCardEntry {
                Im.PROTOCOL_GOOGLE_TALK);
    }

    static public class PhoneData {
    public static class PhoneData {
        public final int type;
        public final String data;
        public final String label;
        // isPrimary is changable only when there's no appropriate one existing in
        // the original VCard.
        // isPrimary is (not final but) changable, only when there's no appropriate one existing
        // in the original VCard.
        public boolean isPrimary;
        public PhoneData(int type, String data, String label, boolean isPrimary) {
            this.type = type;
@@ -109,13 +109,11 @@ public class VCardEntry {
        }
    }

    static public class EmailData {
    public static class EmailData {
        public final int type;
        public final String data;
        // Used only when TYPE is TYPE_CUSTOM.
        public final String label;
        // isPrimary is changable only when there's no appropriate one existing in
        // the original VCard.
        public boolean isPrimary;
        public EmailData(int type, String data, String label, boolean isPrimary) {
            this.type = type;
@@ -141,9 +139,9 @@ public class VCardEntry {
        }
    }

    static public class PostalData {
        // Determined by vCard spec.
        // PO Box, Extended Addr, Street, Locality, Region, Postal Code, Country Name
    public static class PostalData {
        // Determined by vCard specification.
        // - PO Box, Extended Addr, Street, Locality, Region, Postal Code, Country Name
        public static final int ADDR_MAX_DATA_SIZE = 7;
        private final String[] dataArray;
        public final String pobox;
@@ -248,10 +246,11 @@ public class VCardEntry {
        }
    }

    static public class OrganizationData {
    public static class OrganizationData {
        public final int type;
        // non-final is Intentional: we may change the values since this info is separated into
        // two parts in vCard: "ORG" + "TITLE".
        // two parts in vCard: "ORG" + "TITLE", and we have to cope with each field in
        // different timing.
        public String companyName;
        public String departmentName;
        public String titleName;
@@ -313,7 +312,7 @@ public class VCardEntry {
        }
    }

    static public class ImData {
    public static class ImData {
        public final int protocol;
        public final String customProtocol;
        public final int type;
@@ -441,7 +440,7 @@ public class VCardEntry {
    private String mSuffix;

    // Used only when no family nor given name is found.
    private String mFullName;
    private String mFormattedName;

    private String mPhoneticFamilyName;
    private String mPhoneticGivenName;
@@ -499,7 +498,6 @@ public class VCardEntry {
                }
            }

            // Use NANP in default when there's no information about locale.
            final int formattingType = VCardUtils.getPhoneNumberFormat(mVCardType);
            formattedNumber = PhoneNumberUtils.formatNumber(builder.toString(), formattingType);
        }
@@ -754,11 +752,11 @@ public class VCardEntry {
        if (propName.equals(VCardConstants.PROPERTY_VERSION)) {
            // vCard version. Ignore this.
        } else if (propName.equals(VCardConstants.PROPERTY_FN)) {
            mFullName = propValue;
        } else if (propName.equals(VCardConstants.PROPERTY_NAME) && mFullName == null) {
            mFormattedName = propValue;
        } else if (propName.equals(VCardConstants.PROPERTY_NAME) && mFormattedName == null) {
            // Only in vCard 3.0. Use this if FN, which must exist in vCard 3.0 but may not
            // actually exist in the real vCard data, does not exist.
            mFullName = propValue;
            mFormattedName = propValue;
        } else if (propName.equals(VCardConstants.PROPERTY_N)) {
            handleNProperty(propValueList);
        } else if (propName.equals(VCardConstants.PROPERTY_SORT_STRING)) {
@@ -1016,8 +1014,8 @@ public class VCardEntry {
     */
    private void constructDisplayName() {
        // FullName (created via "FN" or "NAME" field) is prefered.
        if (!TextUtils.isEmpty(mFullName)) {
            mDisplayName = mFullName;
        if (!TextUtils.isEmpty(mFormattedName)) {
            mDisplayName = mFormattedName;
        } else if (!(TextUtils.isEmpty(mFamilyName) && TextUtils.isEmpty(mGivenName))) {
            mDisplayName = VCardUtils.constructNameFromElements(mVCardType,
                    mFamilyName, mMiddleName, mGivenName, mPrefix, mSuffix);
@@ -1320,7 +1318,7 @@ public class VCardEntry {
                && TextUtils.isEmpty(mGivenName)
                && TextUtils.isEmpty(mPrefix)
                && TextUtils.isEmpty(mSuffix)
                && TextUtils.isEmpty(mFullName)
                && TextUtils.isEmpty(mFormattedName)
                && TextUtils.isEmpty(mPhoneticFamilyName)
                && TextUtils.isEmpty(mPhoneticMiddleName)
                && TextUtils.isEmpty(mPhoneticGivenName)
@@ -1379,7 +1377,7 @@ public class VCardEntry {
    }

    public String getFullName() {
        return mFullName;
        return mFormattedName;
    }

    public String getPhoneticFamilyName() {
+36 −18
Original line number Diff line number Diff line
@@ -20,9 +20,7 @@ import android.text.TextUtils;
import android.util.CharsetUtils;
import android.util.Log;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.net.QuotedPrintableCodec;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
@@ -31,6 +29,23 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * <p>
 * The {@link VCardInterpreter} implementation which enables {@link VCardEntryHandler} objects
 * to easily handle each vCard entry.
 * </p>
 * <p>
 * This class understand details inside vCard and translates it to {@link VCardEntry}.
 * Then the class throw it to {@link VCardEntryHandler} registered via
 * {@link #addEntryHandler(VCardEntryHandler)}, so that all those registered objects
 * are able to handle the {@link VCardEntry} object.
 * </p>
 * <p>
 * If you want to know the detail inside vCard, it would be better to implement
 * {@link VCardInterpreter} directly, instead of relying on this class and
 * {@link VCardEntry} created by the object.
 * </p>
 */
public class VCardEntryConstructor implements VCardInterpreter {
    private static String LOG_TAG = "VCardEntryConstructor";

@@ -48,27 +63,33 @@ public class VCardEntryConstructor implements VCardInterpreter {
    private final int mVCardType;
    private final Account mAccount;
    
    /** For measuring performance. */
    // For measuring performance.
    private long mTimePushIntoContentResolver;

    final private List<VCardEntryHandler> mEntryHandlers = new ArrayList<VCardEntryHandler>();
    private final List<VCardEntryHandler> mEntryHandlers = new ArrayList<VCardEntryHandler>();

    public VCardEntryConstructor() {
        this(null, false, VCardConfig.VCARD_TYPE_V21_GENERIC, null);
        this(VCardConfig.VCARD_TYPE_V21_GENERIC, null, null, false);
    }

    public VCardEntryConstructor(final int vcardType) {
        this(null, false, vcardType, null);
        this(vcardType, null, null, false);
    }

    public VCardEntryConstructor(final int vcardType, final Account account) {
        this(vcardType, account, null, false);
    }

    public VCardEntryConstructor(final String inputCharset,
            final int vcardType, final Account account) {
        this(inputCharset, false, vcardType, account);
    public VCardEntryConstructor(final int vcardType, final Account account,
            final String inputCharset) {
        this(vcardType, account, inputCharset, false);
    }

    public VCardEntryConstructor(final String inputCharset,
            final boolean strictLineBreakParsing, final int vcardType,
            final Account account) {
    /**
     * @hide
     */
    public VCardEntryConstructor(final int vcardType, final Account account,
            final String inputCharset, final boolean strictLineBreakParsing) {
        if (inputCharset != null) {
            mSourceCharset = inputCharset;
        } else {
@@ -95,17 +116,11 @@ public class VCardEntryConstructor implements VCardInterpreter {
        }
    }

    /**
     * Called when the parse failed between {@link #startEntry()} and {@link #endEntry()}.
     */
    public void clear() {
        mCurrentVCardEntry = null;
        mCurrentProperty = new VCardEntry.Property();
    }

    /**
     * Assume that VCard is not nested. In other words, this code does not accept 
     */
    public void startEntry() {
        if (mCurrentVCardEntry != null) {
            Log.e(LOG_TAG, "Nested VCard code is not supported now.");
@@ -211,6 +226,9 @@ public class VCardEntryConstructor implements VCardInterpreter {
        }
    }

    /**
     * @hide
     */
    public void showPerformanceInfo() {
        Log.d(LOG_TAG, "time for insert ContactStruct to database: " + 
                mTimePushIntoContentResolver + " ms");
Loading