Loading core/java/android/pim/vcard/VCardComposer.java +42 −10 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import java.io.OutputStream; 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; Loading Loading @@ -197,7 +198,7 @@ public class VCardComposer { 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: " Loading Loading @@ -428,6 +429,14 @@ public class VCardComposer { } 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; Loading @@ -439,7 +448,8 @@ public class VCardComposer { 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; Loading Loading @@ -475,7 +485,8 @@ public class VCardComposer { 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. Loading @@ -484,6 +495,20 @@ public class VCardComposer { boolean dataExists = false; EntityIterator entityIterator = null; try { 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) Loading @@ -491,6 +516,13 @@ public class VCardComposer { .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(); Loading tests/AndroidTests/src/com/android/unit_tests/vcard/ExportTestResolver.java +34 −1 Original line number Diff line number Diff line Loading @@ -110,6 +110,39 @@ import java.util.List; 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, String selection, String[] selectionArgs, String sortOrder) { Loading tests/AndroidTests/src/com/android/unit_tests/vcard/VCardVerifier.java +29 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -32,6 +35,7 @@ import android.test.mock.MockContext; 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 { Loading Loading @@ -259,8 +263,24 @@ import java.util.Arrays; } } 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); Loading @@ -270,7 +290,14 @@ import java.util.Arrays; 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(); Loading Loading
core/java/android/pim/vcard/VCardComposer.java +42 −10 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import java.io.OutputStream; 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; Loading Loading @@ -197,7 +198,7 @@ public class VCardComposer { 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: " Loading Loading @@ -428,6 +429,14 @@ public class VCardComposer { } 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; Loading @@ -439,7 +448,8 @@ public class VCardComposer { 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; Loading Loading @@ -475,7 +485,8 @@ public class VCardComposer { 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. Loading @@ -484,6 +495,20 @@ public class VCardComposer { boolean dataExists = false; EntityIterator entityIterator = null; try { 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) Loading @@ -491,6 +516,13 @@ public class VCardComposer { .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(); Loading
tests/AndroidTests/src/com/android/unit_tests/vcard/ExportTestResolver.java +34 −1 Original line number Diff line number Diff line Loading @@ -110,6 +110,39 @@ import java.util.List; 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, String selection, String[] selectionArgs, String sortOrder) { Loading
tests/AndroidTests/src/com/android/unit_tests/vcard/VCardVerifier.java +29 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -32,6 +35,7 @@ import android.test.mock.MockContext; 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 { Loading Loading @@ -259,8 +263,24 @@ import java.util.Arrays; } } 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); Loading @@ -270,7 +290,14 @@ import java.util.Arrays; 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(); Loading