Fix test breakage in vCard exporter.

Due to the change Iae8dbac1, all tests for vCard exporeter has failed.
This change fixes the breakage by using a kind of dirty Dependency Injection.

Current test framework for vCard exporter strongly depends on the assumption that
ContentValues objects are able to be directly passed to objects which use
ContentResolver, while the change above disabled the feature by removing
queryEntities().

This change makes VCardComposer forcibly uses queryEntities() via Reflection.
I agree that this change is not so clean, but works fine for now.
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index 4eaea6a..389c9f4 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -54,6 +54,7 @@
 import java.io.OutputStreamWriter;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
+import java.lang.reflect.Method;
 import java.nio.charset.UnsupportedCharsetException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -197,7 +198,7 @@
             if (mIsDoCoMo) {
                 try {
                     // Create one empty entry.
-                    mWriter.write(createOneEntryInternal("-1"));
+                    mWriter.write(createOneEntryInternal("-1", null));
                 } catch (IOException e) {
                     Log.e(LOG_TAG,
                             "IOException occurred during exportOneContactData: "
@@ -428,6 +429,14 @@
     }
 
     public boolean createOneEntry() {
+        return createOneEntry(null);
+    }
+
+    /**
+     * @param getEntityIteratorMethod For Dependency Injection.
+     * @hide just for testing.
+     */
+    public boolean createOneEntry(Method getEntityIteratorMethod) {
         if (mCursor == null || mCursor.isAfterLast()) {
             mErrorReason = FAILURE_REASON_NOT_INITIALIZED;
             return false;
@@ -439,7 +448,8 @@
                 vcard = createOneCallLogEntryInternal();
             } else {
                 if (mIdColumn >= 0) {
-                    vcard = createOneEntryInternal(mCursor.getString(mIdColumn));
+                    vcard = createOneEntryInternal(mCursor.getString(mIdColumn),
+                            getEntityIteratorMethod);
                 } else {
                     Log.e(LOG_TAG, "Incorrect mIdColumn: " + mIdColumn);
                     return true;
@@ -475,7 +485,8 @@
         return true;
     }
 
-    private String createOneEntryInternal(final String contactId) {
+    private String createOneEntryInternal(final String contactId,
+            Method getEntityIteratorMethod) {
         final Map<String, List<ContentValues>> contentValuesListMap =
                 new HashMap<String, List<ContentValues>>();
         // The resolver may return the entity iterator with no data. It is possiible.
@@ -484,13 +495,34 @@
         boolean dataExists = false;
         EntityIterator entityIterator = null;
         try {
-            final Uri uri = RawContacts.CONTENT_URI.buildUpon()
-                    .appendEncodedPath(contactId)
-                    .appendEncodedPath(RawContacts.Entity.CONTENT_DIRECTORY)
-                    .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
-                    .build();
-            entityIterator = RawContacts.newEntityIterator(mContentResolver.query(
-                    uri, null, null, null, null));
+
+            if (getEntityIteratorMethod != null) {
+                try {
+                    final Uri uri = RawContacts.CONTENT_URI.buildUpon()
+                            .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
+                            .build();
+                    final String selection = Data.CONTACT_ID + "=?";
+                    final String[] selectionArgs = new String[] {contactId};
+                    entityIterator = (EntityIterator)getEntityIteratorMethod.invoke(null,
+                            mContentResolver, uri, selection, selectionArgs, null);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } else {
+                final Uri uri = RawContacts.CONTENT_URI.buildUpon()
+                        .appendEncodedPath(contactId)
+                        .appendEncodedPath(RawContacts.Entity.CONTENT_DIRECTORY)
+                        .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1")
+                        .build();
+                entityIterator = RawContacts.newEntityIterator(mContentResolver.query(
+                        uri, null, null, null, null));
+            }
+
+            if (entityIterator == null) {
+                Log.e(LOG_TAG, "EntityIterator is null");
+                return "";
+            }
+
             dataExists = entityIterator.hasNext();
             while (entityIterator.hasNext()) {
                 Entity entity = entityIterator.next();
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/ExportTestResolver.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/ExportTestResolver.java
index 38aed6f..a76dfd8 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/ExportTestResolver.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/ExportTestResolver.java
@@ -110,8 +110,41 @@
         return contactEntry;
     }
 
+    /**
+     * <p>
+     * An old method which had existed but was removed from ContentResolver.
+     * </p>
+     * <p>
+     * We still keep using this method since we don't have a propeer way to know
+     * which value in the ContentValue corresponds to the entry in Contacts database.
+     * </p>
+     * <p>
+     * Detail:
+     * There's an easy way to know which index "family name" corresponds to, via
+     * {@link android.provider.ContactsContract}.
+     * FAMILY_NAME equals DATA3, so the corresponding index
+     * for "family name" should be 2 (note that index is 0-origin).
+     * However, we cannot know what the index 2 corresponds to; it may be "family name",
+     * "label" for now, but may be the other some column in the future. We don't have
+     * convenient way to know the original data structure.
+     * </p>
+     */
+    public EntityIterator queryEntities(Uri uri,
+            String selection, String[] selectionArgs, String sortOrder) {
+        mTestCase.assertTrue(uri != null);
+        mTestCase.assertTrue(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()));
+        final String authority = uri.getAuthority();
+        mTestCase.assertTrue(RawContacts.CONTENT_URI.getAuthority().equals(authority));
+        mTestCase.assertTrue((Data.CONTACT_ID + "=?").equals(selection));
+        mTestCase.assertEquals(1, selectionArgs.length);
+        final int id = Integer.parseInt(selectionArgs[0]);
+        mTestCase.assertTrue(id >= 0 && id < mContactEntryList.size());
+
+        return new MockEntityIterator(mContactEntryList.get(id).getList());
+    }
+
     @Override
-    public Cursor query(Uri uri, String[] projection,
+    public Cursor query(Uri uri,String[] projection,
             String selection, String[] selectionArgs, String sortOrder) {
         mTestCase.assertTrue(VCardComposer.CONTACTS_TEST_CONTENT_URI.equals(uri));
         // In this test, following arguments are not supported.
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardVerifier.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardVerifier.java
index e5cdf63..4b97750 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardVerifier.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardVerifier.java
@@ -15,8 +15,11 @@
  */
 package com.android.unit_tests.vcard;
 
+import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.EntityIterator;
+import android.net.Uri;
 import android.pim.vcard.VCardComposer;
 import android.pim.vcard.VCardConfig;
 import android.pim.vcard.VCardEntryConstructor;
@@ -32,6 +35,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.Method;
 import java.util.Arrays;
 
 /* package */ class CustomMockContext extends MockContext {
@@ -259,8 +263,24 @@
         }
     }
 
+    public static EntityIterator mockGetEntityIteratorMethod(
+            final ContentResolver resolver,
+            final Uri uri, final String selection,
+            final String[] selectionArgs, final String sortOrder) {
+        final ContentProvider provider =
+            resolver.acquireContentProviderClient(uri).getLocalContentProvider();
+        return ((ExportTestProvider)provider).queryEntities(
+                uri, selection, selectionArgs, sortOrder);
+    }
+
+    private Method getMockGetEntityIteratorMethod()
+            throws SecurityException, NoSuchMethodException {
+        return this.getClass().getMethod("mockGetEntityIteratorMethod",
+                ContentResolver.class, Uri.class, String.class, String[].class, String.class);
+    }
+
     private void verifyForExportTest() {
-        VCardComposer composer =
+       final VCardComposer composer =
             new VCardComposer(new CustomMockContext(mExportTestResolver), mVCardType);
         composer.addHandler(mLineVerifier);
         composer.addHandler(mVCardVerifierInternal);
@@ -270,7 +290,14 @@
         mTestCase.assertFalse(composer.isAfterLast());
         try {
             while (!composer.isAfterLast()) {
-                mTestCase.assertTrue(composer.createOneEntry());
+                try {
+                    final Method mockGetEntityIteratorMethod = getMockGetEntityIteratorMethod();
+                    mTestCase.assertTrue(
+                            composer.createOneEntry(getMockGetEntityIteratorMethod()));
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    mTestCase.fail();
+                }
             }
         } finally {
             composer.terminate();