am a3dbee32: Merge change I919c20bb into eclair-mr2

Merge commit 'a3dbee32d1deab72e5bbf17ab34b961fb7ab4182' into eclair-mr2-plus-aosp

* commit 'a3dbee32d1deab72e5bbf17ab34b961fb7ab4182':
  Code clean up.
diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java
index 377e201..51701c6 100644
--- a/core/java/android/pim/vcard/VCardBuilder.java
+++ b/core/java/android/pim/vcard/VCardBuilder.java
@@ -95,7 +95,7 @@
     private final boolean mUsesUtf8;
     private final boolean mUsesShiftJis;
     private final boolean mAppendTypeParamName;
-    private final boolean mRefrainsQPToPrimaryProperties;
+    private final boolean mRefrainsQPToNameProperties;
     private final boolean mNeedsToConvertPhoneticString;
 
     private final boolean mShouldAppendCharsetParam;
@@ -118,7 +118,7 @@
         mUsesDefactProperty = VCardConfig.usesDefactProperty(vcardType);
         mUsesUtf8 = VCardConfig.usesUtf8(vcardType);
         mUsesShiftJis = VCardConfig.usesShiftJis(vcardType);
-        mRefrainsQPToPrimaryProperties = VCardConfig.refrainsQPToPrimaryProperties(vcardType);
+        mRefrainsQPToNameProperties = VCardConfig.shouldRefrainQPToNameProperties(vcardType);
         mAppendTypeParamName = VCardConfig.appendTypeParamName(vcardType);
         mNeedsToConvertPhoneticString = VCardConfig.needsToConvertPhoneticString(vcardType);
 
@@ -255,7 +255,7 @@
             final boolean reallyAppendCharsetParameterToName =
                     shouldAppendCharsetParam(familyName, givenName, middleName, prefix, suffix);
             final boolean reallyUseQuotedPrintableToName =
-                    (!mRefrainsQPToPrimaryProperties &&
+                    (!mRefrainsQPToNameProperties &&
                             !(VCardUtils.containsOnlyNonCrLfPrintableAscii(familyName) &&
                                     VCardUtils.containsOnlyNonCrLfPrintableAscii(givenName) &&
                                     VCardUtils.containsOnlyNonCrLfPrintableAscii(middleName) &&
@@ -273,7 +273,7 @@
             final boolean reallyAppendCharsetParameterToFN =
                     shouldAppendCharsetParam(formattedName);
             final boolean reallyUseQuotedPrintableToFN =
-                    !mRefrainsQPToPrimaryProperties &&
+                    !mRefrainsQPToNameProperties &&
                     !VCardUtils.containsOnlyNonCrLfPrintableAscii(formattedName);
 
             final String encodedFamily;
@@ -353,7 +353,7 @@
             mBuilder.append(VCARD_END_OF_LINE);
         } else if (!TextUtils.isEmpty(displayName)) {
             final boolean reallyUseQuotedPrintableToDisplayName =
-                (!mRefrainsQPToPrimaryProperties &&
+                (!mRefrainsQPToNameProperties &&
                         !VCardUtils.containsOnlyNonCrLfPrintableAscii(displayName));
             final String encodedDisplayName =
                     reallyUseQuotedPrintableToDisplayName ?
@@ -471,7 +471,7 @@
             mBuilder.append(VCardConstants.PARAM_TYPE_X_IRMC_N);
 
             boolean reallyUseQuotedPrintable =
-                (!mRefrainsQPToPrimaryProperties
+                (!mRefrainsQPToNameProperties
                         && !(VCardUtils.containsOnlyNonCrLfPrintableAscii(
                                 phoneticFamilyName)
                                 && VCardUtils.containsOnlyNonCrLfPrintableAscii(
@@ -976,12 +976,8 @@
 
                 // Note: vCard 3.0 does not allow any parameter addition toward "URL"
                 //       property, while there's no document in vCard 2.1.
-                //
-                // TODO: Should we allow adding it when appropriate?
-                //       (Actually, we drop some data. Using "group.X-URL-TYPE" or something
-                //        may help)
                 if (!TextUtils.isEmpty(website)) {
-                    appendLine(VCardConstants.PROPERTY_URL, website);
+                    appendLineWithCharsetAndQPDetection(VCardConstants.PROPERTY_URL, website);
                 }
             }
         }
@@ -1041,23 +1037,9 @@
                 if (data == null) {
                     continue;
                 }
-                final String photoType;
-                // Use some heuristics for guessing the format of the image.
-                // TODO: there should be some general API for detecting the file format.
-                if (data.length >= 3 && data[0] == 'G' && data[1] == 'I'
-                        && data[2] == 'F') {
-                    photoType = "GIF";
-                } else if (data.length >= 4 && data[0] == (byte) 0x89
-                        && data[1] == 'P' && data[2] == 'N' && data[3] == 'G') {
-                    // Note: vCard 2.1 officially does not support PNG, but we may have it and
-                    //       using X- word like "X-PNG" may not let importers know it is PNG.
-                    //       So we use the String "PNG" as is...
-                    photoType = "PNG";
-                } else if (data.length >= 2 && data[0] == (byte) 0xff
-                        && data[1] == (byte) 0xd8) {
-                    photoType = "JPEG";
-                } else {
-                    Log.d(LOG_TAG, "Unknown photo type. Ignore.");
+                final String photoType = VCardUtils.guessImageType(data);
+                if (photoType == null) {
+                    Log.d(LOG_TAG, "Unknown photo type. Ignored.");
                     continue;
                 }
                 final String photoString = new String(Base64.encodeBase64(data));
@@ -1762,7 +1744,6 @@
         return builder.toString();
     }
 
-
     /**
      * Append '\' to the characters which should be escaped. The character set is different
      * not only between vCard 2.1 and vCard 3.0 but also among each device.
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index c2d628f..2037bc3 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -144,11 +144,6 @@
     private static final Uri sDataRequestUri;
     private static final Map<Integer, String> sImMap;
 
-    /**
-     * See the comment in {@link VCardConfig#FLAG_REFRAIN_QP_TO_PRIMARY_PROPERTIES}.
-     */
-    private static final Set<String> sPrimaryPropertyNameSet;
-
     static {
         Uri.Builder builder = RawContacts.CONTENT_URI.buildUpon();
         builder.appendQueryParameter(Data.FOR_EXPORT_ONLY, "1");
@@ -161,12 +156,6 @@
         sImMap.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER);
         sImMap.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME);
         // Google talk is a special case.
-
-        // TODO: incomplete. Implement properly
-        sPrimaryPropertyNameSet = new HashSet<String>();
-        sPrimaryPropertyNameSet.add(VCardConstants.PROPERTY_N);
-        sPrimaryPropertyNameSet.add(VCardConstants.PROPERTY_FN);
-        sPrimaryPropertyNameSet.add(VCardConstants.PROPERTY_SOUND);
     }
 
     public static interface OneEntryHandler {
diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java
index ff150a4..ecd089a 100644
--- a/core/java/android/pim/vcard/VCardConfig.java
+++ b/core/java/android/pim/vcard/VCardConfig.java
@@ -37,6 +37,12 @@
 
     /* package */ static final int LOG_LEVEL = LOG_LEVEL_NONE;
 
+    /* package */ static final int PARSE_TYPE_UNKNOWN = 0;
+    /* package */ static final int PARSE_TYPE_APPLE = 1;
+    /* package */ static final int PARSE_TYPE_MOBILE_PHONE_JP = 2;  // For Japanese mobile phones.
+    /* package */ static final int PARSE_TYPE_FOMA = 3;  // For Japanese FOMA mobile phones.
+    /* package */ static final int PARSE_TYPE_WINDOWS_MOBILE_JP = 4;
+
     // Assumes that "iso-8859-1" is able to map "all" 8bit characters to some unicode and
     // decode the unicode to the original charset. If not, this setting will cause some bug. 
     public static final String DEFAULT_CHARSET = "iso-8859-1";
@@ -108,31 +114,26 @@
      * </P>
      * <P>
      * We added this Android-specific notion since some (incomplete) vCard exporters for vCard 2.1
-     * do NOT use Quoted-Printable encoding toward some properties like "N", "FN", etc. even when
-     * their values contain non-ascii or/and CR/LF, while they use the encoding in the other
-     * properties like "ADR", "ORG", etc.
+     * do NOT use Quoted-Printable encoding toward some properties related names like "N", "FN", etc.
+     * even when their values contain non-ascii or/and CR/LF, while they use the encoding in the
+     * other properties like "ADR", "ORG", etc.
      * <P>
      * We are afraid of the case where some vCard importer also forget handling QP presuming QP is
      * not used in such fields.
      * </P>
      * <P>
      * This flag is useful when some target importer you are going to focus on does not accept
-     * such "primary" property values with Quoted-Printable encoding.
+     * such properties with Quoted-Printable encoding.
      * </P>
      * <P>
      * Again, we should not use this flag at all for complying vCard 2.1 spec.
      * </P>
      * <P>
-     * We will change the behavior around this flag in the future, after understanding the other
-     * real vCard cases around this problem. Please use this flag with extreme caution even when
-     * needed.
-     * </P>
-     * <P>
      * In vCard 3.0, Quoted-Printable is explicitly "prohibitted", so we don't need to care this
      * kind of problem (hopefully).
      * </P>
      */
-    public static final int FLAG_REFRAIN_QP_TO_PRIMARY_PROPERTIES = 0x10000000;
+    public static final int FLAG_REFRAIN_QP_TO_NAME_PROPERTIES = 0x10000000;
 
     /**
      * <P>
@@ -311,7 +312,7 @@
     public static final int VCARD_TYPE_V21_JAPANESE_MOBILE =
         (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
                 FLAG_CONVERT_PHONETIC_NAME_STRINGS |
-                FLAG_REFRAIN_QP_TO_PRIMARY_PROPERTIES);
+                FLAG_REFRAIN_QP_TO_NAME_PROPERTIES);
 
     /* package */ static final String VCARD_TYPE_V21_JAPANESE_MOBILE_STR = "v21_japanese_mobile";
 
@@ -400,9 +401,9 @@
         return (VCardConfig.LOG_LEVEL & VCardConfig.LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0;
     }
 
-    public static boolean refrainsQPToPrimaryProperties(final int vcardType) {
+    public static boolean shouldRefrainQPToNameProperties(final int vcardType) {
        return (!shouldUseQuotedPrintable(vcardType) ||
-               ((vcardType & FLAG_REFRAIN_QP_TO_PRIMARY_PROPERTIES) != 0));
+               ((vcardType & FLAG_REFRAIN_QP_TO_NAME_PROPERTIES) != 0));
     }
 
     public static boolean appendTypeParamName(final int vcardType) {
diff --git a/core/java/android/pim/vcard/VCardParser.java b/core/java/android/pim/vcard/VCardParser.java
index 6afb95e..57c52a6 100644
--- a/core/java/android/pim/vcard/VCardParser.java
+++ b/core/java/android/pim/vcard/VCardParser.java
@@ -21,21 +21,15 @@
 import java.io.InputStream;
 
 public abstract class VCardParser {
-    public static final int PARSER_MODE_DEFAULT = 0;
-    /**
-     * The parser should ignore "AGENT" properties and nested vCard structure.
-     */
-    public static final int PARSER_MODE_SCAN = 1;
-
-    protected final int mParserMode;
+    protected final int mParseType;
     protected boolean mCanceled;
 
     public VCardParser() {
-        mParserMode = PARSER_MODE_DEFAULT;
+        this(VCardConfig.PARSE_TYPE_UNKNOWN);
     }
 
-    public VCardParser(int parserMode) {
-        mParserMode = parserMode;
+    public VCardParser(int parseType) {
+        mParseType = parseType;
     }
 
     /**
diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java
index ef3fb8d..ec569d4 100644
--- a/core/java/android/pim/vcard/VCardParser_V21.java
+++ b/core/java/android/pim/vcard/VCardParser_V21.java
@@ -95,12 +95,6 @@
     protected Set<String> mUnknownTypeMap = new HashSet<String>();
     protected Set<String> mUnknownValueMap = new HashSet<String>();
 
-    // It seems Windows Mobile 6.5 uses "AGENT" property with completely wrong usage.
-    // We should just ignore just one line.
-    // e.g.
-    // "AGENT;CHARSET=SHIFT_JIS:some text"
-    private boolean mIgnoreInvalidAgentLine = false;
-
     // For measuring performance.
     private long mTimeTotal;
     private long mTimeReadStartRecord;
@@ -116,33 +110,20 @@
     private long mTimeHandleBase64;
 
     public VCardParser_V21() {
-        this(null, PARSER_MODE_DEFAULT);
-    }
-
-    public VCardParser_V21(int parserMode) {
-        this(null, parserMode);
+        this(VCardConfig.PARSE_TYPE_UNKNOWN);
     }
 
     public VCardParser_V21(VCardSourceDetector detector) {
-        this(detector, PARSER_MODE_DEFAULT);
+        this(detector.getEstimatedType());
     }
 
     /**
      * TODO: Merge detector and parser mode.
      */
-    public VCardParser_V21(VCardSourceDetector detector, int parserMode) {
-        super(parserMode);
-        if (detector != null) {
-            final int type = detector.getType();
-            if (type == VCardSourceDetector.TYPE_FOMA) {
-                mNestCount = 1;
-            } else if (type == VCardSourceDetector.TYPE_JAPANESE_MOBILE_PHONE) {
-                mIgnoreInvalidAgentLine = true;
-            }
-        }
-
-        if (parserMode == PARSER_MODE_SCAN) {
-            mIgnoreInvalidAgentLine = true;
+    public VCardParser_V21(int parseType) {
+        super(parseType);
+        if (parseType == VCardConfig.PARSE_TYPE_FOMA) {
+            mNestCount = 1;
         }
     }
 
@@ -827,24 +808,13 @@
      *         items *CRLF "END" [ws] ":" [ws] "VCARD"
      */
     protected void handleAgent(final String propertyValue) throws VCardException {
-        if (mIgnoreInvalidAgentLine && !propertyValue.toUpperCase().contains("BEGIN:VCARD")) {
+        if (!propertyValue.toUpperCase().contains("BEGIN:VCARD")) {
+            // Apparently invalid line seen in Windows Mobile 6.5. Ignore them.
             return;
         } else {
             throw new VCardAgentNotSupportedException("AGENT Property is not supported now.");
         }
-        /* This is insufficient support. Also, AGENT Property is very rare and really hard to
-           understand the content.
-           Ignore it for now.
-
-        String[] strArray = propertyValue.split(":", 2);
-        if (!(strArray.length == 2 ||
-                strArray[0].trim().equalsIgnoreCase("BEGIN") && 
-                strArray[1].trim().equalsIgnoreCase("VCARD"))) {
-            throw new VCardException("BEGIN:VCARD != \"" + propertyValue + "\"");
-        }
-        parseItems();
-        readEndVCard();
-        */
+        // TODO: Support AGENT property.
     }
     
     /**
diff --git a/core/java/android/pim/vcard/VCardSourceDetector.java b/core/java/android/pim/vcard/VCardSourceDetector.java
index d3f451c..7297c50 100644
--- a/core/java/android/pim/vcard/VCardSourceDetector.java
+++ b/core/java/android/pim/vcard/VCardSourceDetector.java
@@ -26,14 +26,6 @@
  * @hide
  */
 public class VCardSourceDetector implements VCardInterpreter {
-    // Should only be used in package. 
-    static final int TYPE_UNKNOWN = 0;
-    static final int TYPE_APPLE = 1;
-    static final int TYPE_JAPANESE_MOBILE_PHONE = 2;  // Used in Japanese mobile phones.
-    static final int TYPE_FOMA = 3;  // Used in some Japanese FOMA mobile phones.
-    static final int TYPE_WINDOWS_MOBILE_JP = 4;
-    // TODO: Excel, etc.
-
     private static Set<String> APPLE_SIGNS = new HashSet<String>(Arrays.asList(
             "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", "X-PHONETIC-LAST-NAME",
             "X-ABADR", "X-ABUID"));
@@ -51,7 +43,7 @@
             "X-SD-DESCRIPTION"));
     private static String TYPE_FOMA_CHARSET_SIGN = "X-SD-CHAR_CODE";
     
-    private int mType = TYPE_UNKNOWN;
+    private int mType = VCardConfig.PARSE_TYPE_UNKNOWN;
     // Some mobile phones (like FOMA) tells us the charset of the data.
     private boolean mNeedParseSpecifiedCharset;
     private String mSpecifiedCharset;
@@ -80,21 +72,21 @@
     
     public void propertyName(String name) {
         if (name.equalsIgnoreCase(TYPE_FOMA_CHARSET_SIGN)) {
-            mType = TYPE_FOMA;
+            mType = VCardConfig.PARSE_TYPE_FOMA;
             mNeedParseSpecifiedCharset = true;
             return;
         }
-        if (mType != TYPE_UNKNOWN) {
+        if (mType != VCardConfig.PARSE_TYPE_UNKNOWN) {
             return;
         }
         if (WINDOWS_MOBILE_PHONE_SIGNS.contains(name)) {
-            mType = TYPE_WINDOWS_MOBILE_JP;
+            mType = VCardConfig.PARSE_TYPE_WINDOWS_MOBILE_JP;
         } else if (FOMA_SIGNS.contains(name)) {
-            mType = TYPE_FOMA;
+            mType = VCardConfig.PARSE_TYPE_FOMA;
         } else if (JAPANESE_MOBILE_PHONE_SIGNS.contains(name)) {
-            mType = TYPE_JAPANESE_MOBILE_PHONE;
+            mType = VCardConfig.PARSE_TYPE_MOBILE_PHONE_JP;
         } else if (APPLE_SIGNS.contains(name)) {
-            mType = TYPE_APPLE;
+            mType = VCardConfig.PARSE_TYPE_APPLE;
         }
     }
 
@@ -110,7 +102,7 @@
         }
     }
 
-    int getType() {
+    /* package */ int getEstimatedType() {
         return mType;
     }
     
@@ -124,14 +116,14 @@
             return mSpecifiedCharset;
         }
         switch (mType) {
-        case TYPE_WINDOWS_MOBILE_JP:
-        case TYPE_FOMA:
-        case TYPE_JAPANESE_MOBILE_PHONE:
-            return "SHIFT_JIS";
-        case TYPE_APPLE:
-            return "UTF-8";
-        default:
-            return null;
+            case VCardConfig.PARSE_TYPE_WINDOWS_MOBILE_JP:
+            case VCardConfig.PARSE_TYPE_FOMA:
+            case VCardConfig.PARSE_TYPE_MOBILE_PHONE_JP:
+                return "SHIFT_JIS";
+            case VCardConfig.PARSE_TYPE_APPLE:
+                return "UTF-8";
+            default:
+                return null;
         }
     }
 }
diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java
index 36f9006..8404da0 100644
--- a/core/java/android/pim/vcard/VCardUtils.java
+++ b/core/java/android/pim/vcard/VCardUtils.java
@@ -23,6 +23,7 @@
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -466,7 +467,7 @@
         return true;
     }
     
-    static public String toHalfWidthString(String orgString) {
+    public static String toHalfWidthString(String orgString) {
         if (TextUtils.isEmpty(orgString)) {
             return null;
         }
@@ -485,7 +486,31 @@
         }
         return builder.toString();
     }
-    
+
+    /**
+     * Guesses the format of input image. Currently just the first few bytes are used.
+     * The type "GIF", "PNG", or "JPEG" is returned when possible. Returns null when
+     * the guess failed.
+     * @param input Image as byte array.
+     * @return The image type or null when the type cannot be determined.
+     */
+    public static String guessImageType(final byte[] input) {
+        if (input.length >= 3 && input[0] == 'G' && input[1] == 'I' && input[2] == 'F') {
+            return "GIF";
+        } else if (input.length >= 4 && input[0] == (byte) 0x89
+                && input[1] == 'P' && input[2] == 'N' && input[3] == 'G') {
+            // Note: vCard 2.1 officially does not support PNG, but we may have it and
+            //       using X- word like "X-PNG" may not let importers know it is PNG.
+            //       So we use the String "PNG" as is...
+            return "PNG";
+        } else if (input.length >= 2 && input[0] == (byte) 0xff
+                && input[1] == (byte) 0xd8) {
+            return "JPEG";
+        } else {
+            return null;
+        }
+    }
+
     private VCardUtils() {
     }
 }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
index 36cc966..eeb7cc4 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
@@ -1017,8 +1017,7 @@
                 .addNodeWithOrder("X-NO", "");
 
         // Only scan mode lets vCard parser accepts invalid AGENT lines like above.
-        verifier.verify(R.raw.v21_winmo_65, V21,
-                new VCardParser_V21(VCardParser.PARSER_MODE_SCAN));
+        verifier.verify(R.raw.v21_winmo_65, V21, new VCardParser_V21());
     }
 
     public void testIgnoreAgentV21()  throws IOException, VCardException {
@@ -1027,8 +1026,7 @@
         elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "Example")
                 .put(StructuredName.DISPLAY_NAME, "Example");
-        verifier.verify(R.raw.v21_winmo_65, V21,
-                new VCardParser_V21(VCardParser.PARSER_MODE_SCAN));
+        verifier.verify(R.raw.v21_winmo_65, V21, new VCardParser_V21());
     }
 
     public void testTolerateInvalidCommentLikeLineV21() throws IOException, VCardException {