Can't send my wife's vcard between devices

Bug 13751984

If X-ANDROID-CUSTOM follows a photo's hex data, that line will get included
as part of the photo data and will cause Base64.decode() to throw an
exception. The code that gathers the hex data needs to finish if it sees
X-ANDROID-CUSTOM. Added a test case to test this "bad" vcard.

Change-Id: Ie60a1d09354a9c8a9dab603da01e9c7aff5eb070
diff --git a/java/com/android/vcard/VCardParserImpl_V21.java b/java/com/android/vcard/VCardParserImpl_V21.java
index 34dc6a3..aaf442f 100644
--- a/java/com/android/vcard/VCardParserImpl_V21.java
+++ b/java/com/android/vcard/VCardParserImpl_V21.java
@@ -847,7 +847,8 @@
             // or
             //      END:VCARD
             String propertyName = getPropertyNameUpperCase(line);
-            if (getKnownPropertyNameSet().contains(propertyName)) {
+            if (getKnownPropertyNameSet().contains(propertyName) ||
+                    VCardConstants.PROPERTY_X_ANDROID_CUSTOM.equals(propertyName)) {
                 Log.w(LOG_TAG, "Found a next property during parsing a BASE64 string, " +
                         "which must not contain semi-colon or colon. Treat the line as next "
                         + "property.");
diff --git a/tests/res/raw/v21_x_android_custom_after_photo.vcf b/tests/res/raw/v21_x_android_custom_after_photo.vcf
new file mode 100644
index 0000000..5fd7db1
--- /dev/null
+++ b/tests/res/raw/v21_x_android_custom_after_photo.vcf
@@ -0,0 +1,42 @@
+BEGIN:VCARD
+VERSION:2.1
+N:Ando;Roid;
+PHOTO;ENCODING=BASE64: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
+ fGh4i/V4q4YNEfoiwAAAABJRU5ErkJggg==
+X-ANDROID-CUSTOM:vnd.android.cursor.item/contact_event;1999-07-10;1;;;;;;;;;;;;;
+BDAY:1975-08-20
+END:VCARD
\ No newline at end of file
diff --git a/tests/src/com/android/vcard/tests/VCardImporterTests.java b/tests/src/com/android/vcard/tests/VCardImporterTests.java
index bcf2a8a..12addd6 100644
--- a/tests/src/com/android/vcard/tests/VCardImporterTests.java
+++ b/tests/src/com/android/vcard/tests/VCardImporterTests.java
@@ -1301,4 +1301,36 @@
                 .put(Phone.TYPE, Phone.TYPE_HOME)
                 .put(Phone.NUMBER, ",1234,5678;9");
     }
+
+    // We ran into a case where a 2.1 vcard was sent with a 3.0+ property,
+    // X-ANDROID-CUSTOM. If that property followed photo data without a blank line,
+    // getBase64() would append the X-ANDROID-CUSTOM data line to the photo data.
+    // When Base64.decode() was called with this data, it would throw an exception.
+    // Besides looking for the normal 2.1 properties, we need to look for
+    // X-ANDROID-CUSTOM as well. Here's an example of a bad vcard that would cause
+    // this problem (This vcard was generated by a KLP MR2 Nexus 5 or a KLP Moto X):
+    // ...
+    //  LHnTW/l/wB9f+PV2UcFyfGeVis3qVPch7pWjs/s+m/2Zpdp5f8Ayy/df6uPZWNcR9dRzWoZPb
+    //  /l4/xpotvtH2vj/l39f8/99f8AxFdvKjwD/9k=
+    // X-ANDROID-CUSTOM:vnd.android.cursor.item/contact_event;1999-07-10;1;;;;;;;;;;;;;
+    // BDAY:1975-08-20
+    // END:VCARD
+    //
+    // Here's how to build and run the tests in this file:
+    //   mmm frameworks/opt/vcard
+    //   adb install -r -d out/target/product/hammerhead/data/app/AndroidVCardTests.apk
+    //   adb shell am instrument -w com.android.vcard.tests/android.test.InstrumentationTestRunner
+    //
+    public void testV21XAndroidCustomAfterPhoto() {
+        mVerifier.initForImportTest(V21, R.raw.v21_x_android_custom_after_photo);
+        mVerifier.addPropertyNodesVerifierElem()
+                .addExpectedNodeWithOrder("N", "Ando;Roid;", Arrays.asList("Ando", "Roid", ""))
+                .addExpectedNodeWithOrder("PHOTO", null,
+                        null, sPhotoByteArrayForComplicatedCase, mContentValuesForBase64V21,
+                        null, null)
+                .addExpectedNodeWithOrder("X-ANDROID-CUSTOM",
+                        "vnd.android.cursor.item/contact_event;1999-07-10;1;;;;;;;;;;;;;")
+                .addExpectedNodeWithOrder("BDAY", "1975-08-20");
+    }
+
 }