Add SIP support for vCard 3.0.

Change-Id: I48b7057dc802c37936e31fbe95798af6b2c06a5b
diff --git a/java/com/android/vcard/VCardConstants.java b/java/com/android/vcard/VCardConstants.java
index ef0f7e3..98fe6c5 100644
--- a/java/com/android/vcard/VCardConstants.java
+++ b/java/com/android/vcard/VCardConstants.java
@@ -45,6 +45,7 @@
     public static final String PROPERTY_NAME = "NAME";  // (3.0, 4,0)
     public static final String PROPERTY_NICKNAME = "NICKNAME";  // (3.0, 4.0)
     public static final String PROPERTY_SORT_STRING = "SORT-STRING";  // (3.0, 4.0)
+    public static final String PROPERTY_IMPP = "IMPP";  // RFC 4770 (for 3.0 only)
     public static final String PROPERTY_END = "END";
 
     // Valid property names not supported (not appropriately handled) by our importer.
diff --git a/java/com/android/vcard/VCardEntry.java b/java/com/android/vcard/VCardEntry.java
index 35dc9a0..1f28de5 100644
--- a/java/com/android/vcard/VCardEntry.java
+++ b/java/com/android/vcard/VCardEntry.java
@@ -23,9 +23,6 @@
 import android.net.Uri;
 import android.os.RemoteException;
 import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Event;
 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
@@ -35,9 +32,13 @@
 import android.provider.ContactsContract.CommonDataKinds.Organization;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.util.Log;
@@ -469,6 +470,7 @@
     private List<ImData> mImList;
     private List<PhotoData> mPhotoList;
     private List<String> mWebsiteList;
+    private List<String> mSipList;
     private List<List<String>> mAndroidCustomPropertyList;
 
     private final int mVCardType;
@@ -1045,6 +1047,14 @@
             mPhoneticMiddleName = propValue;
         } else if (propName.equals(VCardConstants.PROPERTY_X_PHONETIC_LAST_NAME)) {
             mPhoneticFamilyName = propValue;
+        } else if (propName.equals(VCardConstants.PROPERTY_IMPP)) {
+            // See also RFC 4770 (for vCard 3.0)
+            if (propValue.startsWith("sip:") && propValue.length() > 4) {
+                if (mSipList == null) {
+                    mSipList = new ArrayList<String>();
+                }
+                mSipList.add(propValue.substring(4));
+            }
         } else if (propName.equals(VCardConstants.PROPERTY_X_ANDROID_CUSTOM)) {
             final List<String> customPropertyList =
                 VCardUtils.constructListFromValue(propValue, mVCardType);
@@ -1295,6 +1305,15 @@
             operationList.add(builder.build());
         }
 
+        if (mSipList != null && !mSipList.isEmpty()) {
+            for (String sipAddress : mSipList) {
+                builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+                builder.withValue(Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE);
+                builder.withValue(SipAddress.SIP_ADDRESS, sipAddress);
+                operationList.add(builder.build());
+            }
+        }
+
         if (mAndroidCustomPropertyList != null) {
             for (List<String> customPropertyList : mAndroidCustomPropertyList) {
                 int size = customPropertyList.size();
diff --git a/tests/res/raw/v30_sip.vcf b/tests/res/raw/v30_sip.vcf
new file mode 100644
index 0000000..11a63e4
--- /dev/null
+++ b/tests/res/raw/v30_sip.vcf
@@ -0,0 +1,5 @@
+BEGIN:VCARD

+VERSION:3.0

+FN:Android

+IMPP;TYPE=personal:sip:android@android.example.com

+END:VCARD

diff --git a/tests/src/com/android/vcard/tests/VCardImporterTests.java b/tests/src/com/android/vcard/tests/VCardImporterTests.java
index a8dcc52..1220a63 100644
--- a/tests/src/com/android/vcard/tests/VCardImporterTests.java
+++ b/tests/src/com/android/vcard/tests/VCardImporterTests.java
@@ -15,6 +15,12 @@
  */
 package com.android.vcard.tests;
 
+import com.android.vcard.VCardConfig;
+import com.android.vcard.tests.test_utils.ContentValuesVerifier;
+import com.android.vcard.tests.test_utils.ContentValuesVerifierElem;
+import com.android.vcard.tests.test_utils.PropertyNodesVerifierElem.TypeSet;
+import com.android.vcard.tests.test_utils.VCardTestsBase;
+
 import android.content.ContentValues;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Event;
@@ -24,17 +30,12 @@
 import android.provider.ContactsContract.CommonDataKinds.Organization;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.CommonDataKinds.Website;
 import android.provider.ContactsContract.Data;
 
-import com.android.vcard.VCardConfig;
-import com.android.vcard.tests.test_utils.ContentValuesVerifier;
-import com.android.vcard.tests.test_utils.ContentValuesVerifierElem;
-import com.android.vcard.tests.test_utils.PropertyNodesVerifierElem.TypeSet;
-import com.android.vcard.tests.test_utils.VCardTestsBase;
-
 import java.util.Arrays;
 
 public class VCardImporterTests extends VCardTestsBase {
@@ -1105,4 +1106,22 @@
                 .put(Im.TYPE, Im.TYPE_HOME)
                 .put(Im.DATA, "hhh@gmail.com");
     }
+
+    public void testSipV30_Parse() {
+        mVerifier.initForImportTest(V30, R.raw.v30_sip);
+        mVerifier.addPropertyNodesVerifierElem()
+                .addExpectedNodeWithOrder("FN", "Android")
+                .addExpectedNodeWithOrder("IMPP", "sip:android@android.example.com",
+                        new TypeSet("personal"));
+    }
+
+    public void testSipV30() {
+        mVerifier.initForImportTest(V30, R.raw.v30_sip);
+        final ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
+                .put(StructuredName.DISPLAY_NAME, "Android");
+        // Type is ignored silently.
+        elem.addExpected(SipAddress.CONTENT_ITEM_TYPE)
+                .put(SipAddress.SIP_ADDRESS, "android@android.example.com");
+    }
 }
diff --git a/tests/src/com/android/vcard/tests/test_utils/ImportTestProvider.java b/tests/src/com/android/vcard/tests/test_utils/ImportTestProvider.java
index 8d6fa12..ea18e24 100644
--- a/tests/src/com/android/vcard/tests/test_utils/ImportTestProvider.java
+++ b/tests/src/com/android/vcard/tests/test_utils/ImportTestProvider.java
@@ -29,6 +29,7 @@
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
 import android.provider.ContactsContract.CommonDataKinds.Relation;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.CommonDataKinds.Website;
@@ -60,7 +61,7 @@
                 Event.CONTENT_ITEM_TYPE, Photo.CONTENT_ITEM_TYPE,
                 Note.CONTENT_ITEM_TYPE, Website.CONTENT_ITEM_TYPE,
                 Relation.CONTENT_ITEM_TYPE, Event.CONTENT_ITEM_TYPE,
-                GroupMembership.CONTENT_ITEM_TYPE));
+                GroupMembership.CONTENT_ITEM_TYPE, SipAddress.CONTENT_ITEM_TYPE));
 
     final Map<String, Collection<ContentValues>> mMimeTypeToExpectedContentValues;
 
@@ -120,8 +121,10 @@
                 final String mimeType = actualContentValues.getAsString(Data.MIMETYPE);
                 if (!sKnownMimeTypeSet.contains(mimeType)) {
                     TestCase.fail(String.format(
-                            "Unknown MimeType %s. Probably added after developing this test",
-                            mimeType));
+                            "Unknown MimeType %s. " +
+                            "(Maybe the MimeType is added after developing this test suite." +
+                            "Please look into %s if you strongly believe the type is regitimate)",
+                            ImportTestProvider.class.getSimpleName(), mimeType));
                 }
                 // Remove data meaningless in this unit tests.
                 // Specifically, Data.DATA1 - DATA7 are set to null or empty String