- create a Uri for and expose the contacts entities uri
- change the EntityIterator to use that Uri
- fix the column naming in the entities view
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index 20d0b2a..e9720c3 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -61,7 +61,7 @@
 /* package */ class ContactsDatabaseHelper extends SQLiteOpenHelper {
     private static final String TAG = "ContactsDatabaseHelper";
 
-    private static final int DATABASE_VERSION = 99;
+    private static final int DATABASE_VERSION = 100;
 
     private static final String DATABASE_NAME = "contacts2.db";
     private static final String DATABASE_PRESENCE = "presence_db";
@@ -1002,62 +1002,7 @@
                 StatusUpdates.STATUS_ICON + " INTEGER" +
         ");");
 
-        String contactEntitiesSelect = "SELECT "
-                + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AS " + RawContacts.ACCOUNT_NAME + ","
-                + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AS " + RawContacts.ACCOUNT_TYPE + ","
-                + RawContactsColumns.CONCRETE_SOURCE_ID + " AS " + RawContacts.SOURCE_ID + ","
-                + RawContactsColumns.CONCRETE_VERSION + " AS " + RawContacts.VERSION + ","
-                + RawContactsColumns.CONCRETE_DIRTY + " AS " + RawContacts.DIRTY + ","
-                + RawContactsColumns.CONCRETE_DELETED + " AS " + RawContacts.DELETED + ","
-                + PackagesColumns.PACKAGE + " AS " + Data.RES_PACKAGE + ","
-                + RawContacts.CONTACT_ID + ", "
-                + RawContactsColumns.CONCRETE_SYNC1 + " AS " + RawContacts.SYNC1 + ", "
-                + RawContactsColumns.CONCRETE_SYNC2 + " AS " + RawContacts.SYNC2 + ", "
-                + RawContactsColumns.CONCRETE_SYNC3 + " AS " + RawContacts.SYNC3 + ", "
-                + RawContactsColumns.CONCRETE_SYNC4 + " AS " + RawContacts.SYNC4 + ", "
-                + Data.MIMETYPE + ", "
-                + Data.DATA1 + ", "
-                + Data.DATA2 + ", "
-                + Data.DATA3 + ", "
-                + Data.DATA4 + ", "
-                + Data.DATA5 + ", "
-                + Data.DATA6 + ", "
-                + Data.DATA7 + ", "
-                + Data.DATA8 + ", "
-                + Data.DATA9 + ", "
-                + Data.DATA10 + ", "
-                + Data.DATA11 + ", "
-                + Data.DATA12 + ", "
-                + Data.DATA13 + ", "
-                + Data.DATA14 + ", "
-                + Data.DATA15 + ", "
-                + Data.SYNC1 + ", "
-                + Data.SYNC2 + ", "
-                + Data.SYNC3 + ", "
-                + Data.SYNC4 + ", "
-                + RawContactsColumns.CONCRETE_ID + " AS " + Data.RAW_CONTACT_ID + ", "
-                + Data.IS_PRIMARY + ", "
-                + Data.IS_SUPER_PRIMARY + ", "
-                + Data.DATA_VERSION + ", "
-                + DataColumns.CONCRETE_ID + " AS " + RawContacts._ID + ","
-                + RawContactsColumns.CONCRETE_STARRED + " AS " + RawContacts.STARRED + ","
-                + Tables.GROUPS + "." + Groups.SOURCE_ID + " AS " + GroupMembership.GROUP_SOURCE_ID
-                + " FROM " + Tables.RAW_CONTACTS
-                + " LEFT OUTER JOIN " + Tables.DATA + " ON ("
-                +   DataColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID + ")"
-                + " LEFT OUTER JOIN " + Tables.PACKAGES + " ON ("
-                +   DataColumns.CONCRETE_PACKAGE_ID + "=" + PackagesColumns.CONCRETE_ID + ")"
-                + " LEFT OUTER JOIN " + Tables.MIMETYPES + " ON ("
-                +   DataColumns.CONCRETE_MIMETYPE_ID + "=" + MimetypesColumns.CONCRETE_ID + ")"
-                + " LEFT OUTER JOIN " + Tables.GROUPS + " ON ("
-                +   MimetypesColumns.CONCRETE_MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE
-                +   "' AND " + GroupsColumns.CONCRETE_ID + "="
-                + Tables.DATA + "." + GroupMembership.GROUP_ROW_ID + ")";
-
-        db.execSQL("CREATE VIEW " + Tables.CONTACT_ENTITIES + " AS "
-                + contactEntitiesSelect);
-        db.execSQL("CREATE VIEW " + Tables.CONTACT_ENTITIES_RESTRICTED + " AS "
-                + contactEntitiesSelect + " WHERE " + RawContacts.IS_RESTRICTED + "=0");
+        createContactEntitiesView(db);
 
         String dataColumns =
                 Data.IS_PRIMARY + ", "
@@ -1236,42 +1181,117 @@
                 ContactsContract.AUTHORITY, new Bundle());
     }
 
+    private static void createContactEntitiesView(SQLiteDatabase db) {
+        String contactEntitiesSelect = "SELECT "
+                + RawContactsColumns.CONCRETE_ACCOUNT_NAME + " AS " + RawContacts.ACCOUNT_NAME + ","
+                + RawContactsColumns.CONCRETE_ACCOUNT_TYPE + " AS " + RawContacts.ACCOUNT_TYPE + ","
+                + RawContactsColumns.CONCRETE_SOURCE_ID + " AS " + RawContacts.SOURCE_ID + ","
+                + RawContactsColumns.CONCRETE_VERSION + " AS " + RawContacts.VERSION + ","
+                + RawContactsColumns.CONCRETE_DIRTY + " AS " + RawContacts.DIRTY + ","
+                + RawContactsColumns.CONCRETE_DELETED + " AS " + RawContacts.DELETED + ","
+                + PackagesColumns.PACKAGE + " AS " + Data.RES_PACKAGE + ","
+                + RawContacts.CONTACT_ID + ", "
+                + RawContactsColumns.CONCRETE_SYNC1 + " AS " + RawContacts.SYNC1 + ", "
+                + RawContactsColumns.CONCRETE_SYNC2 + " AS " + RawContacts.SYNC2 + ", "
+                + RawContactsColumns.CONCRETE_SYNC3 + " AS " + RawContacts.SYNC3 + ", "
+                + RawContactsColumns.CONCRETE_SYNC4 + " AS " + RawContacts.SYNC4 + ", "
+                + Data.MIMETYPE + ", "
+                + Data.DATA1 + ", "
+                + Data.DATA2 + ", "
+                + Data.DATA3 + ", "
+                + Data.DATA4 + ", "
+                + Data.DATA5 + ", "
+                + Data.DATA6 + ", "
+                + Data.DATA7 + ", "
+                + Data.DATA8 + ", "
+                + Data.DATA9 + ", "
+                + Data.DATA10 + ", "
+                + Data.DATA11 + ", "
+                + Data.DATA12 + ", "
+                + Data.DATA13 + ", "
+                + Data.DATA14 + ", "
+                + Data.DATA15 + ", "
+                + Data.SYNC1 + ", "
+                + Data.SYNC2 + ", "
+                + Data.SYNC3 + ", "
+                + Data.SYNC4 + ", "
+                + RawContactsColumns.CONCRETE_ID + " AS " + RawContacts._ID + ", "
+                + Data.IS_PRIMARY + ", "
+                + Data.IS_SUPER_PRIMARY + ", "
+                + Data.DATA_VERSION + ", "
+                + DataColumns.CONCRETE_ID + " AS " + RawContacts.Entity.DATA_ID + ","
+                + RawContactsColumns.CONCRETE_STARRED + " AS " + RawContacts.STARRED + ","
+                + Tables.GROUPS + "." + Groups.SOURCE_ID + " AS " + GroupMembership.GROUP_SOURCE_ID
+                + " FROM " + Tables.RAW_CONTACTS
+                + " LEFT OUTER JOIN " + Tables.DATA + " ON ("
+                +   DataColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID + ")"
+                + " LEFT OUTER JOIN " + Tables.PACKAGES + " ON ("
+                +   DataColumns.CONCRETE_PACKAGE_ID + "=" + PackagesColumns.CONCRETE_ID + ")"
+                + " LEFT OUTER JOIN " + Tables.MIMETYPES + " ON ("
+                +   DataColumns.CONCRETE_MIMETYPE_ID + "=" + MimetypesColumns.CONCRETE_ID + ")"
+                + " LEFT OUTER JOIN " + Tables.GROUPS + " ON ("
+                +   MimetypesColumns.CONCRETE_MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE
+                +   "' AND " + GroupsColumns.CONCRETE_ID + "="
+                + Tables.DATA + "." + GroupMembership.GROUP_ROW_ID + ")";
+
+        db.execSQL("CREATE VIEW " + Tables.CONTACT_ENTITIES + " AS "
+                + contactEntitiesSelect);
+        db.execSQL("CREATE VIEW " + Tables.CONTACT_ENTITIES_RESTRICTED + " AS "
+                + contactEntitiesSelect + " WHERE " + RawContacts.IS_RESTRICTED + "=0");
+    }
+
     @Override
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        if (oldVersion < 99) {
+            Log.i(TAG, "Upgrading from version " + oldVersion + " to " + newVersion
+                    + ", data will be lost!");
 
-        Log.i(TAG, "Upgrading from version " + oldVersion + " to " + newVersion
-                + ", data will be lost!");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.CONTACTS + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.RAW_CONTACTS + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.PACKAGES + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.MIMETYPES + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.DATA + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.PHONE_LOOKUP + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.NAME_LOOKUP + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.NICKNAME_LOOKUP + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.GROUPS + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.ACTIVITIES + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.CALLS + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.SETTINGS + ";");
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.STATUS_UPDATES + ";");
 
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.CONTACTS + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.RAW_CONTACTS + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.PACKAGES + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.MIMETYPES + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.DATA + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.PHONE_LOOKUP + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.NAME_LOOKUP + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.NICKNAME_LOOKUP + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.GROUPS + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.ACTIVITIES + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.CALLS + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.SETTINGS + ";");
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.STATUS_UPDATES + ";");
+            db.execSQL("DROP VIEW IF EXISTS " + Tables.CONTACT_ENTITIES + ";");
+            db.execSQL("DROP VIEW IF EXISTS " + Tables.CONTACT_ENTITIES_RESTRICTED + ";");
+            db.execSQL("DROP VIEW IF EXISTS " + Views.CONTACTS_ALL + ";");
+            db.execSQL("DROP VIEW IF EXISTS " + Views.CONTACTS_RESTRICTED + ";");
+            db.execSQL("DROP VIEW IF EXISTS " + Views.DATA_ALL + ";");
+            db.execSQL("DROP VIEW IF EXISTS " + Views.DATA_RESTRICTED + ";");
+            db.execSQL("DROP VIEW IF EXISTS " + Views.RAW_CONTACTS_ALL + ";");
+            db.execSQL("DROP VIEW IF EXISTS " + Views.RAW_CONTACTS_RESTRICTED + ";");
+            db.execSQL("DROP VIEW IF EXISTS " + Views.GROUPS_ALL + ";");
 
-        db.execSQL("DROP VIEW IF EXISTS " + Tables.CONTACT_ENTITIES + ";");
-        db.execSQL("DROP VIEW IF EXISTS " + Tables.CONTACT_ENTITIES_RESTRICTED + ";");
-        db.execSQL("DROP VIEW IF EXISTS " + Views.CONTACTS_ALL + ";");
-        db.execSQL("DROP VIEW IF EXISTS " + Views.CONTACTS_RESTRICTED + ";");
-        db.execSQL("DROP VIEW IF EXISTS " + Views.DATA_ALL + ";");
-        db.execSQL("DROP VIEW IF EXISTS " + Views.DATA_RESTRICTED + ";");
-        db.execSQL("DROP VIEW IF EXISTS " + Views.RAW_CONTACTS_ALL + ";");
-        db.execSQL("DROP VIEW IF EXISTS " + Views.RAW_CONTACTS_RESTRICTED + ";");
-        db.execSQL("DROP VIEW IF EXISTS " + Views.GROUPS_ALL + ";");
+            // TODO: we should not be dropping agg_exceptions and contact_options. In case that
+            // table's schema changes, we should try to preserve the data, because it was entered
+            // by the user and has never been synched to the server.
+            db.execSQL("DROP TABLE IF EXISTS " + Tables.AGGREGATION_EXCEPTIONS + ";");
 
-        // TODO: we should not be dropping agg_exceptions and contact_options. In case that table's
-        // schema changes, we should try to preserve the data, because it was entered by the user
-        // and has never been synched to the server.
-        db.execSQL("DROP TABLE IF EXISTS " + Tables.AGGREGATION_EXCEPTIONS + ";");
+            onCreate(db);
+            return;
+        }
 
-        onCreate(db);
+        Log.i(TAG, "Upgrading from version " + oldVersion + " to " + newVersion);
+        
+        if (oldVersion == 99) {
+            db.execSQL("DROP VIEW IF EXISTS " + Tables.CONTACT_ENTITIES + ";");
+            db.execSQL("DROP VIEW IF EXISTS " + Tables.CONTACT_ENTITIES_RESTRICTED + ";");
+            createContactEntitiesView(db);
+            oldVersion++;
+        }
+
+        if (oldVersion != newVersion) {
+            throw new IllegalStateException(
+                    "error upgrading the database to version " + newVersion);
+        }
     }
 
     /**
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 3496a18..e1d26c5 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -167,6 +167,7 @@
     private static final int RAW_CONTACTS = 2002;
     private static final int RAW_CONTACTS_ID = 2003;
     private static final int RAW_CONTACTS_DATA = 2004;
+    private static final int RAW_CONTACT_ENTITY_ID = 2005;
 
     private static final int DATA = 3000;
     private static final int DATA_ID = 3001;
@@ -207,6 +208,8 @@
     private static final int LIVE_FOLDERS_CONTACTS_FAVORITES = 14002;
     private static final int LIVE_FOLDERS_CONTACTS_GROUP_NAME = 14003;
 
+    private static final int RAW_CONTACT_ENTITIES = 15001;
+
     private interface ContactsQuery {
         public static final String TABLE = Tables.RAW_CONTACTS;
 
@@ -348,6 +351,8 @@
     private static final HashMap<String, String> sContactsVCardProjectionMap;
     /** Contains just the raw contacts columns */
     private static final HashMap<String, String> sRawContactsProjectionMap;
+    /** Contains the columns from the raw contacts entity view*/
+    private static final HashMap<String, String> sRawContactsEntityProjectionMap;
     /** Contains columns from the data view */
     private static final HashMap<String, String> sDataProjectionMap;
     /** Contains columns from the data view */
@@ -414,6 +419,9 @@
         matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
         matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID);
         matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA);
+        matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ENTITY_ID);
+
+        matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES);
 
         matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);
         matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID);
@@ -565,6 +573,49 @@
         sDataProjectionMap.put(Contacts.PHOTO_ID, Contacts.PHOTO_ID);
         sDataProjectionMap.put(GroupMembership.GROUP_SOURCE_ID, GroupMembership.GROUP_SOURCE_ID);
 
+        HashMap<String, String> columns;
+        columns = new HashMap<String, String>();
+        columns.put(RawContacts._ID, RawContacts._ID);
+        columns.put(RawContacts.CONTACT_ID, RawContacts.CONTACT_ID);
+        columns.put(RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_NAME);
+        columns.put(RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_TYPE);
+        columns.put(RawContacts.SOURCE_ID, RawContacts.SOURCE_ID);
+        columns.put(RawContacts.VERSION, RawContacts.VERSION);
+        columns.put(RawContacts.DIRTY, RawContacts.DIRTY);
+        columns.put(RawContacts.DELETED, RawContacts.DELETED);
+        columns.put(RawContacts.SYNC1, RawContacts.SYNC1);
+        columns.put(RawContacts.SYNC2, RawContacts.SYNC2);
+        columns.put(RawContacts.SYNC3, RawContacts.SYNC3);
+        columns.put(RawContacts.SYNC4, RawContacts.SYNC4);
+        columns.put(Data.RES_PACKAGE, Data.RES_PACKAGE);
+        columns.put(Data.MIMETYPE, Data.MIMETYPE);
+        columns.put(Data.DATA1, Data.DATA1);
+        columns.put(Data.DATA2, Data.DATA2);
+        columns.put(Data.DATA3, Data.DATA3);
+        columns.put(Data.DATA4, Data.DATA4);
+        columns.put(Data.DATA5, Data.DATA5);
+        columns.put(Data.DATA6, Data.DATA6);
+        columns.put(Data.DATA7, Data.DATA7);
+        columns.put(Data.DATA8, Data.DATA8);
+        columns.put(Data.DATA9, Data.DATA9);
+        columns.put(Data.DATA10, Data.DATA10);
+        columns.put(Data.DATA11, Data.DATA11);
+        columns.put(Data.DATA12, Data.DATA12);
+        columns.put(Data.DATA13, Data.DATA13);
+        columns.put(Data.DATA14, Data.DATA14);
+        columns.put(Data.DATA15, Data.DATA15);
+        columns.put(Data.SYNC1, Data.SYNC1);
+        columns.put(Data.SYNC2, Data.SYNC2);
+        columns.put(Data.SYNC3, Data.SYNC3);
+        columns.put(Data.SYNC4, Data.SYNC4);
+        columns.put(RawContacts.Entity.DATA_ID, RawContacts.Entity.DATA_ID);
+        columns.put(Data.STARRED, Data.STARRED);
+        columns.put(Data.DATA_VERSION, Data.DATA_VERSION);
+        columns.put(Data.IS_PRIMARY, Data.IS_PRIMARY);
+        columns.put(Data.IS_SUPER_PRIMARY, Data.IS_SUPER_PRIMARY);
+        columns.put(GroupMembership.GROUP_SOURCE_ID, GroupMembership.GROUP_SOURCE_ID);
+        sRawContactsEntityProjectionMap = columns;
+
         // Handle projections for Contacts-level statuses
         addProjection(sDataProjectionMap, Contacts.CONTACT_PRESENCE,
                 Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE);
@@ -693,8 +744,6 @@
         sPhoneLookupProjectionMap.put(PhoneLookup.LABEL,
                 Phone.LABEL + " AS " + PhoneLookup.LABEL);
 
-        HashMap<String, String> columns;
-
         // Groups projection map
         columns = new HashMap<String, String>();
         columns.put(Groups._ID, Groups._ID);
@@ -2648,7 +2697,7 @@
         }
     }
 
-    private boolean readBooleanQueryParameter(Uri uri, String name, boolean defaultValue) {
+    private static boolean readBooleanQueryParameter(Uri uri, String name, boolean defaultValue) {
         final String flag = uri.getQueryParameter(name);
         return flag == null
                 ? defaultValue
@@ -3632,6 +3681,18 @@
                 selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
                 break;
 
+            case RAW_CONTACT_ENTITIES: {
+                setTablesAndProjectionMapForRawContactsEntities(qb, uri);
+                break;
+            }
+
+            case RAW_CONTACT_ENTITY_ID: {
+                long rawContactId = Long.parseLong(uri.getPathSegments().get(1));
+                setTablesAndProjectionMapForRawContactsEntities(qb, uri);
+                qb.appendWhere(" AND " + RawContacts._ID + "=" + rawContactId);
+                break;
+            }
+
             default:
                 return mLegacyApiSupport.query(uri, projection, selection, selectionArgs,
                         sortOrder, limit);
@@ -3883,6 +3944,22 @@
         appendAccountFromParameter(qb, uri);
     }
 
+    private void setTablesAndProjectionMapForRawContactsEntities(SQLiteQueryBuilder qb, Uri uri) {
+        // Note: currently, "export only" equals to "restricted", but may not in the future.
+        boolean excludeRestrictedData = readBooleanQueryParameter(uri,
+                Data.FOR_EXPORT_ONLY, false);
+
+        String requestingPackage = uri.getQueryParameter(
+                ContactsContract.REQUESTING_PACKAGE_PARAM_KEY);
+        if (requestingPackage != null) {
+            excludeRestrictedData = excludeRestrictedData
+                    || !mDbHelper.hasAccessToRestrictedData(requestingPackage);
+        }
+        qb.setTables(mDbHelper.getContactEntitiesView(excludeRestrictedData));
+        qb.setProjectionMap(sRawContactsEntityProjectionMap);
+        appendAccountFromParameter(qb, uri);
+    }
+
     private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri,
             String[] projection, boolean distinct) {
         StringBuilder sb = new StringBuilder();
@@ -4200,13 +4277,13 @@
                 Data.SYNC3,
                 Data.SYNC4};
 
-        private static final String[] PROJECTION = new String[]{
+        public static final String[] PROJECTION = new String[]{
                 RawContacts.ACCOUNT_NAME,
                 RawContacts.ACCOUNT_TYPE,
                 RawContacts.SOURCE_ID,
                 RawContacts.VERSION,
                 RawContacts.DIRTY,
-                Data._ID,
+                RawContacts.Entity.DATA_ID,
                 Data.RES_PACKAGE,
                 Data.MIMETYPE,
                 Data.DATA1,
@@ -4228,7 +4305,7 @@
                 Data.SYNC2,
                 Data.SYNC3,
                 Data.SYNC4,
-                Data.RAW_CONTACT_ID,
+                RawContacts._ID,
                 Data.IS_PRIMARY,
                 Data.IS_SUPER_PRIMARY,
                 Data.DATA_VERSION,
@@ -4263,35 +4340,22 @@
         private static final int COLUMN_CONTACT_ID = 37;
         private static final int COLUMN_STARRED = 38;
 
-        public RawContactsEntityIterator(ContactsProvider2 provider, String contactsIdString,
-                Uri uri, String selection, String[] selectionArgs, String sortOrder) {
+        public RawContactsEntityIterator(ContactsProvider2 provider, Uri entityUri,
+                String contactsIdString,
+                String selection, String[] selectionArgs, String sortOrder) {
             mIsClosed = false;
-
-            final String updatedSortOrder = (sortOrder == null)
-                    ? Data.RAW_CONTACT_ID
-                    : (Data.RAW_CONTACT_ID + "," + sortOrder);
-
-            final SQLiteDatabase db = provider.mDbHelper.getReadableDatabase();
-            final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
-            final boolean excludeRestrictedData =
-                provider.readBooleanQueryParameter(uri, Data.FOR_EXPORT_ONLY, false);
-            qb.setTables(provider.mDbHelper.getContactEntitiesView(excludeRestrictedData));
+            Uri uri;
             if (contactsIdString != null) {
-                qb.appendWhere(Data.RAW_CONTACT_ID + "=" + contactsIdString);
+                uri = Uri.withAppendedPath(RawContacts.CONTENT_URI, contactsIdString);
+                uri = Uri.withAppendedPath(uri, RawContacts.Entity.CONTENT_DIRECTORY);
+            } else {
+                uri = ContactsContract.RawContactsEntity.CONTENT_URI;
             }
-            final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
-            final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
-            if (!TextUtils.isEmpty(accountName)) {
-                if (contactsIdString != null) {
-                    qb.appendWhere(" AND ");
-                }
-                qb.appendWhere(RawContacts.ACCOUNT_NAME + "="
-                        + DatabaseUtils.sqlEscapeString(accountName) + " AND "
-                        + RawContacts.ACCOUNT_TYPE + "="
-                        + DatabaseUtils.sqlEscapeString(accountType));
-            }
-            mEntityCursor = qb.query(db, PROJECTION, selection, selectionArgs,
-                    null, null, updatedSortOrder);
+            final Uri.Builder builder = uri.buildUpon();
+            String query = entityUri.getQuery();
+            builder.encodedQuery(query);
+            mEntityCursor = provider.query(builder.build(),
+                    PROJECTION, selection, selectionArgs, sortOrder);
             mEntityCursor.moveToFirst();
         }
 
@@ -4542,8 +4606,8 @@
                     contactsIdString = uri.getPathSegments().get(1);
                 }
 
-                return new RawContactsEntityIterator(this, contactsIdString,
-                        uri, selection, selectionArgs, sortOrder);
+                return new RawContactsEntityIterator(this, uri, contactsIdString,
+                        selection, selectionArgs, sortOrder);
             case GROUPS:
             case GROUPS_ID:
                 String idString = null;