Merge "Change the permission labels to lowercase."
diff --git a/src/com/android/settings/search/DatabaseIndexingManager.java b/src/com/android/settings/search/DatabaseIndexingManager.java
index a0f47d1..9c79885 100644
--- a/src/com/android/settings/search/DatabaseIndexingManager.java
+++ b/src/com/android/settings/search/DatabaseIndexingManager.java
@@ -22,68 +22,33 @@
         .COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE;
 import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_KEY;
 import static com.android.settings.search.DatabaseResultLoader.SELECT_COLUMNS;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.CLASS_NAME;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_ENTRIES;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_KEY_REF;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_RANK;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns
-        .DATA_SUMMARY_OFF_NORMALIZED;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns
-        .DATA_SUMMARY_ON_NORMALIZED;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED;
 import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DOCID;
 import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ENABLED;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ICON;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_ACTION;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.LOCALE;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.PAYLOAD;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.SCREEN_TITLE;
-import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.USER_ID;
 import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX;
 
-import android.content.ComponentName;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
-import android.content.res.XmlResourceParser;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
 import android.os.AsyncTask;
 import android.os.Build;
-import android.provider.SearchIndexableData;
 import android.provider.SearchIndexableResource;
 import android.provider.SearchIndexablesContract;
-import android.support.annotation.DrawableRes;
 import android.support.annotation.VisibleForTesting;
-import android.text.TextUtils;
-import android.util.AttributeSet;
 import android.util.Log;
-import android.util.Xml;
 
-import com.android.settings.SettingsActivity;
-import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.overlay.FeatureFactory;
 
-import com.android.settings.search.indexing.IndexableDataCollector;
+import com.android.settings.search.indexing.IndexDataConverter;
 import com.android.settings.search.indexing.PreIndexData;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import com.android.settings.search.indexing.PreIndexDataCollector;
 
-import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -91,7 +56,7 @@
  * Consumes the SearchIndexableProvider content providers.
  * Updates the Resource, Raw Data and non-indexable data for Search.
  *
- * TODO this class needs to be refactored by moving most of its methods into controllers
+ * TODO(b/33577327) this class needs to be refactored by moving most of its methods into controllers
  */
 public class DatabaseIndexingManager {
 
@@ -103,14 +68,10 @@
     public static final String FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER =
             "SEARCH_INDEX_DATA_PROVIDER";
 
-    private static final String NODE_NAME_PREFERENCE_SCREEN = "PreferenceScreen";
-    private static final String NODE_NAME_CHECK_BOX_PREFERENCE = "CheckBoxPreference";
-    private static final String NODE_NAME_LIST_PREFERENCE = "ListPreference";
-
     @VisibleForTesting
     final AtomicBoolean mIsIndexingComplete = new AtomicBoolean(false);
 
-    private IndexableDataCollector mCollector;
+    private PreIndexDataCollector mCollector;
 
     private Context mContext;
 
@@ -143,8 +104,8 @@
         final String providerVersionedNames =
                 IndexDatabaseHelper.buildProviderVersionedNames(providers);
 
-        final boolean isFullIndex = isFullIndex(mContext, localeStr,
-                fingerprint, providerVersionedNames);
+        final boolean isFullIndex = isFullIndex(mContext, localeStr, fingerprint,
+                providerVersionedNames);
 
         if (isFullIndex) {
             rebuildDatabase();
@@ -174,7 +135,7 @@
     @VisibleForTesting
     PreIndexData getIndexDataFromProviders(List<ResolveInfo> providers, boolean isFullIndex) {
         if (mCollector == null) {
-            mCollector = new IndexableDataCollector(mContext);
+            mCollector = new PreIndexDataCollector(mContext);
         }
         return mCollector.collectIndexableData(providers, isFullIndex);
     }
@@ -191,7 +152,7 @@
      */
     @VisibleForTesting
     boolean isFullIndex(Context context, String locale, String fingerprint,
-                               String providerVersionedNames) {
+            String providerVersionedNames) {
         final boolean isLocaleIndexed = IndexDatabaseHelper.isLocaleAlreadyIndexed(context, locale);
         final boolean isBuildIndexed = IndexDatabaseHelper.isBuildIndexed(context, fingerprint);
         final boolean areProvidersIndexed = IndexDatabaseHelper
@@ -222,7 +183,6 @@
      */
     @VisibleForTesting
     void updateDatabase(PreIndexData indexData, boolean needsReindexing, String localeStr) {
-        final List<SearchIndexableData> dataToUpdate = indexData.dataToUpdate;
         final Map<String, Set<String>> nonIndexableKeys = indexData.nonIndexableKeys;
 
         final SQLiteDatabase database = getWritableDatabase();
@@ -235,9 +195,7 @@
             database.beginTransaction();
 
             // Add new data from Providers at initial index time, or inserted later.
-            if (dataToUpdate.size() > 0) {
-                addDataToDatabase(database, localeStr, dataToUpdate, nonIndexableKeys);
-            }
+            addIndaxebleDataToDatabase(database, localeStr, indexData);
 
             // Only check for non-indexable key updates after initial index.
             // Enabled state with non-indexable keys is checked when items are first inserted.
@@ -251,32 +209,14 @@
         }
     }
 
-    /**
-     * Inserts {@link SearchIndexableData} into the database.
-     *
-     * @param database         where the data will be inserted.
-     * @param localeStr        is the locale of the data to be inserted.
-     * @param dataToUpdate     is a {@link List} of the data to be inserted.
-     * @param nonIndexableKeys is a {@link Map} from Package Name to a {@link Set} of keys which
-     *                         identify search results which should not be surfaced.
-     */
+
     @VisibleForTesting
-    void addDataToDatabase(SQLiteDatabase database, String localeStr,
-            List<SearchIndexableData> dataToUpdate, Map<String, Set<String>> nonIndexableKeys) {
-        final long current = System.currentTimeMillis();
-
-        for (SearchIndexableData data : dataToUpdate) {
-            try {
-                indexOneSearchIndexableData(database, localeStr, data, nonIndexableKeys);
-            } catch (Exception e) {
-                Log.e(LOG_TAG, "Cannot index: " + (data != null ? data.className : data)
-                        + " for locale: " + localeStr, e);
-            }
+    void addIndaxebleDataToDatabase(SQLiteDatabase database, String locale, PreIndexData data) {
+        if (data.dataToUpdate.size() == 0) {
+            return;
         }
-
-        final long now = System.currentTimeMillis();
-        Log.d(LOG_TAG, "Indexing locale '" + localeStr + "' took " +
-                (now - current) + " millis");
+        IndexDataConverter manager = new IndexDataConverter(mContext, database);
+        manager.addDataToDatabase(locale, data.dataToUpdate, data.nonIndexableKeys);
     }
 
     /**
@@ -388,646 +328,6 @@
         }
     }
 
-
-    @VisibleForTesting
-    void indexOneSearchIndexableData(SQLiteDatabase database, String localeStr,
-            SearchIndexableData data, Map<String, Set<String>> nonIndexableKeys) {
-        if (data instanceof SearchIndexableResource) {
-            indexOneResource(database, localeStr, (SearchIndexableResource) data, nonIndexableKeys);
-        } else if (data instanceof SearchIndexableRaw) {
-            indexOneRaw(database, localeStr, (SearchIndexableRaw) data, nonIndexableKeys);
-        }
-    }
-
-    private void indexOneRaw(SQLiteDatabase database, String localeStr,
-            SearchIndexableRaw raw, Map<String, Set<String>> nonIndexableKeysFromResource) {
-        // Should be the same locale as the one we are processing
-        if (!raw.locale.toString().equalsIgnoreCase(localeStr)) {
-            return;
-        }
-
-        Set<String> packageKeys = nonIndexableKeysFromResource.get(raw.intentTargetPackage);
-        boolean enabled = raw.enabled;
-
-        if (packageKeys != null && packageKeys.contains(raw.key)) {
-            enabled = false;
-        }
-
-        DatabaseRow.Builder builder = new DatabaseRow.Builder();
-        builder.setLocale(localeStr)
-                .setEntries(raw.entries)
-                .setClassName(raw.className)
-                .setScreenTitle(raw.screenTitle)
-                .setIconResId(raw.iconResId)
-                .setRank(raw.rank)
-                .setIntentAction(raw.intentAction)
-                .setIntentTargetPackage(raw.intentTargetPackage)
-                .setIntentTargetClass(raw.intentTargetClass)
-                .setEnabled(enabled)
-                .setKey(raw.key)
-                .setUserId(raw.userId);
-
-        updateOneRowWithFilteredData(database, builder, raw.title, raw.summaryOn, raw.summaryOff,
-                raw.keywords);
-    }
-
-    private void indexOneResource(SQLiteDatabase database, String localeStr,
-            SearchIndexableResource sir, Map<String, Set<String>> nonIndexableKeysFromResource) {
-
-        if (sir == null) {
-            Log.e(LOG_TAG, "Cannot index a null resource!");
-            return;
-        }
-
-        final List<String> nonIndexableKeys = new ArrayList<String>();
-
-        if (sir.xmlResId > SearchIndexableResources.NO_DATA_RES_ID) {
-            Set<String> resNonIndexableKeys = nonIndexableKeysFromResource.get(sir.packageName);
-            if (resNonIndexableKeys != null && resNonIndexableKeys.size() > 0) {
-                nonIndexableKeys.addAll(resNonIndexableKeys);
-            }
-
-            indexFromResource(database, localeStr, sir, nonIndexableKeys);
-        } else {
-            if (TextUtils.isEmpty(sir.className)) {
-                Log.w(LOG_TAG, "Cannot index an empty Search Provider name!");
-                return;
-            }
-
-            final Class<?> clazz = DatabaseIndexingUtils.getIndexableClass(sir.className);
-            if (clazz == null) {
-                Log.d(LOG_TAG, "SearchIndexableResource '" + sir.className +
-                        "' should implement the " + Indexable.class.getName() + " interface!");
-                return;
-            }
-
-            // Will be non null only for a Local provider implementing a
-            // SEARCH_INDEX_DATA_PROVIDER field
-            final Indexable.SearchIndexProvider provider =
-                    DatabaseIndexingUtils.getSearchIndexProvider(clazz);
-            if (provider != null) {
-                List<String> providerNonIndexableKeys = provider.getNonIndexableKeys(sir.context);
-                if (providerNonIndexableKeys != null && providerNonIndexableKeys.size() > 0) {
-                    nonIndexableKeys.addAll(providerNonIndexableKeys);
-                }
-
-                indexFromProvider(database, localeStr, provider, sir, nonIndexableKeys);
-            }
-        }
-    }
-
-    @VisibleForTesting
-    void indexFromResource(SQLiteDatabase database, String localeStr,
-            SearchIndexableResource sir, List<String> nonIndexableKeys) {
-        final Context context = sir.context;
-        XmlResourceParser parser = null;
-        try {
-            parser = context.getResources().getXml(sir.xmlResId);
-
-            int type;
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                    && type != XmlPullParser.START_TAG) {
-                // Parse next until start tag is found
-            }
-
-            String nodeName = parser.getName();
-            if (!NODE_NAME_PREFERENCE_SCREEN.equals(nodeName)) {
-                throw new RuntimeException(
-                        "XML document must start with <PreferenceScreen> tag; found"
-                                + nodeName + " at " + parser.getPositionDescription());
-            }
-
-            final int outerDepth = parser.getDepth();
-            final AttributeSet attrs = Xml.asAttributeSet(parser);
-
-            final String screenTitle = XmlParserUtils.getDataTitle(context, attrs);
-            String key = XmlParserUtils.getDataKey(context, attrs);
-
-            String title;
-            String headerTitle;
-            String summary;
-            String headerSummary;
-            String keywords;
-            String headerKeywords;
-            String childFragment;
-            @DrawableRes
-            int iconResId;
-            ResultPayload payload;
-            boolean enabled;
-            final String fragmentName = sir.className;
-            final int rank = sir.rank;
-            final String intentAction = sir.intentAction;
-            final String intentTargetPackage = sir.intentTargetPackage;
-            final String intentTargetClass = sir.intentTargetClass;
-
-            Map<String, PreferenceControllerMixin> controllerUriMap = null;
-
-            if (fragmentName != null) {
-                controllerUriMap = DatabaseIndexingUtils
-                        .getPreferenceControllerUriMap(fragmentName, context);
-            }
-
-            // Insert rows for the main PreferenceScreen node. Rewrite the data for removing
-            // hyphens.
-
-            headerTitle = XmlParserUtils.getDataTitle(context, attrs);
-            headerSummary = XmlParserUtils.getDataSummary(context, attrs);
-            headerKeywords = XmlParserUtils.getDataKeywords(context, attrs);
-            enabled = !nonIndexableKeys.contains(key);
-
-            // TODO: Set payload type for header results
-            DatabaseRow.Builder headerBuilder = new DatabaseRow.Builder();
-            headerBuilder.setLocale(localeStr)
-                    .setEntries(null)
-                    .setClassName(fragmentName)
-                    .setScreenTitle(screenTitle)
-                    .setRank(rank)
-                    .setIntentAction(intentAction)
-                    .setIntentTargetPackage(intentTargetPackage)
-                    .setIntentTargetClass(intentTargetClass)
-                    .setEnabled(enabled)
-                    .setKey(key)
-                    .setUserId(-1 /* default user id */);
-
-            // Flag for XML headers which a child element's title.
-            boolean isHeaderUnique = true;
-            DatabaseRow.Builder builder;
-
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                    continue;
-                }
-
-                nodeName = parser.getName();
-
-                title = XmlParserUtils.getDataTitle(context, attrs);
-                key = XmlParserUtils.getDataKey(context, attrs);
-                enabled = !nonIndexableKeys.contains(key);
-                keywords = XmlParserUtils.getDataKeywords(context, attrs);
-                iconResId = XmlParserUtils.getDataIcon(context, attrs);
-
-                if (isHeaderUnique && TextUtils.equals(headerTitle, title)) {
-                    isHeaderUnique = false;
-                }
-
-                builder = new DatabaseRow.Builder();
-                builder.setLocale(localeStr)
-                        .setClassName(fragmentName)
-                        .setScreenTitle(screenTitle)
-                        .setIconResId(iconResId)
-                        .setRank(rank)
-                        .setIntentAction(intentAction)
-                        .setIntentTargetPackage(intentTargetPackage)
-                        .setIntentTargetClass(intentTargetClass)
-                        .setEnabled(enabled)
-                        .setKey(key)
-                        .setUserId(-1 /* default user id */);
-
-                if (!nodeName.equals(NODE_NAME_CHECK_BOX_PREFERENCE)) {
-                    summary = XmlParserUtils.getDataSummary(context, attrs);
-
-                    String entries = null;
-
-                    if (nodeName.endsWith(NODE_NAME_LIST_PREFERENCE)) {
-                        entries = XmlParserUtils.getDataEntries(context, attrs);
-                    }
-
-                    // TODO (b/62254931) index primitives instead of payload
-                    payload = DatabaseIndexingUtils.getPayloadFromUriMap(controllerUriMap, key);
-                    childFragment = XmlParserUtils.getDataChildFragment(context, attrs);
-
-                    builder.setEntries(entries)
-                            .setChildClassName(childFragment)
-                            .setPayload(payload);
-
-                    // Insert rows for the child nodes of PreferenceScreen
-                    updateOneRowWithFilteredData(database, builder, title, summary,
-                            null /* summary off */, keywords);
-                } else {
-                    String summaryOn = XmlParserUtils.getDataSummaryOn(context, attrs);
-                    String summaryOff = XmlParserUtils.getDataSummaryOff(context, attrs);
-
-                    if (TextUtils.isEmpty(summaryOn) && TextUtils.isEmpty(summaryOff)) {
-                        summaryOn = XmlParserUtils.getDataSummary(context, attrs);
-                    }
-
-                    updateOneRowWithFilteredData(database, builder, title, summaryOn, summaryOff,
-                            keywords);
-                }
-            }
-
-            // The xml header's title does not match the title of one of the child settings.
-            if (isHeaderUnique) {
-                updateOneRowWithFilteredData(database, headerBuilder, headerTitle, headerSummary,
-                        null /* summary off */, headerKeywords);
-            }
-        } catch (XmlPullParserException e) {
-            throw new RuntimeException("Error parsing PreferenceScreen", e);
-        } catch (IOException e) {
-            throw new RuntimeException("Error parsing PreferenceScreen", e);
-        } finally {
-            if (parser != null) parser.close();
-        }
-    }
-
-    private void indexFromProvider(SQLiteDatabase database, String localeStr,
-            Indexable.SearchIndexProvider provider, SearchIndexableResource sir,
-            List<String> nonIndexableKeys) {
-
-        final String className = sir.className;
-        final String intentAction = sir.intentAction;
-        final String intentTargetPackage = sir.intentTargetPackage;
-
-        if (provider == null) {
-            Log.w(LOG_TAG, "Cannot find provider: " + className);
-            return;
-        }
-
-        final List<SearchIndexableRaw> rawList = provider.getRawDataToIndex(mContext,
-                true /* enabled */);
-
-        if (rawList != null) {
-
-            final int rawSize = rawList.size();
-            for (int i = 0; i < rawSize; i++) {
-                SearchIndexableRaw raw = rawList.get(i);
-
-                // Should be the same locale as the one we are processing
-                if (!raw.locale.toString().equalsIgnoreCase(localeStr)) {
-                    continue;
-                }
-                boolean enabled = !nonIndexableKeys.contains(raw.key);
-
-                DatabaseRow.Builder builder = new DatabaseRow.Builder();
-                builder.setLocale(localeStr)
-                        .setEntries(raw.entries)
-                        .setClassName(className)
-                        .setScreenTitle(raw.screenTitle)
-                        .setIconResId(raw.iconResId)
-                        .setIntentAction(raw.intentAction)
-                        .setIntentTargetPackage(raw.intentTargetPackage)
-                        .setIntentTargetClass(raw.intentTargetClass)
-                        .setEnabled(enabled)
-                        .setKey(raw.key)
-                        .setUserId(raw.userId);
-
-                updateOneRowWithFilteredData(database, builder, raw.title, raw.summaryOn,
-                        raw.summaryOff, raw.keywords);
-            }
-        }
-
-        final List<SearchIndexableResource> resList =
-                provider.getXmlResourcesToIndex(mContext, true);
-        if (resList != null) {
-            final int resSize = resList.size();
-            for (int i = 0; i < resSize; i++) {
-                SearchIndexableResource item = resList.get(i);
-
-                // Should be the same locale as the one we are processing
-                if (!item.locale.toString().equalsIgnoreCase(localeStr)) {
-                    continue;
-                }
-
-                item.className = TextUtils.isEmpty(item.className)
-                        ? className
-                        : item.className;
-                item.intentAction = TextUtils.isEmpty(item.intentAction)
-                        ? intentAction
-                        : item.intentAction;
-                item.intentTargetPackage = TextUtils.isEmpty(item.intentTargetPackage)
-                        ? intentTargetPackage
-                        : item.intentTargetPackage;
-
-                indexFromResource(database, localeStr, item, nonIndexableKeys);
-            }
-        }
-    }
-
-    private void updateOneRowWithFilteredData(SQLiteDatabase database, DatabaseRow.Builder builder,
-            String title, String summaryOn, String summaryOff, String keywords) {
-
-        final String updatedTitle = DatabaseIndexingUtils.normalizeHyphen(title);
-        final String updatedSummaryOn = DatabaseIndexingUtils.normalizeHyphen(summaryOn);
-        final String updatedSummaryOff = DatabaseIndexingUtils.normalizeHyphen(summaryOff);
-
-        final String normalizedTitle = DatabaseIndexingUtils.normalizeString(updatedTitle);
-        final String normalizedSummaryOn = DatabaseIndexingUtils.normalizeString(updatedSummaryOn);
-        final String normalizedSummaryOff = DatabaseIndexingUtils
-                .normalizeString(updatedSummaryOff);
-
-        final String spaceDelimitedKeywords = DatabaseIndexingUtils.normalizeKeywords(keywords);
-
-        builder.setUpdatedTitle(updatedTitle)
-                .setUpdatedSummaryOn(updatedSummaryOn)
-                .setUpdatedSummaryOff(updatedSummaryOff)
-                .setNormalizedTitle(normalizedTitle)
-                .setNormalizedSummaryOn(normalizedSummaryOn)
-                .setNormalizedSummaryOff(normalizedSummaryOff)
-                .setSpaceDelimitedKeywords(spaceDelimitedKeywords);
-
-        updateOneRow(database, builder.build(mContext));
-    }
-
-    private void updateOneRow(SQLiteDatabase database, DatabaseRow row) {
-
-        if (TextUtils.isEmpty(row.updatedTitle)) {
-            return;
-        }
-
-        ContentValues values = new ContentValues();
-        values.put(IndexDatabaseHelper.IndexColumns.DOCID, row.getDocId());
-        values.put(LOCALE, row.locale);
-        values.put(DATA_RANK, row.rank);
-        values.put(DATA_TITLE, row.updatedTitle);
-        values.put(DATA_TITLE_NORMALIZED, row.normalizedTitle);
-        values.put(DATA_SUMMARY_ON, row.updatedSummaryOn);
-        values.put(DATA_SUMMARY_ON_NORMALIZED, row.normalizedSummaryOn);
-        values.put(DATA_SUMMARY_OFF, row.updatedSummaryOff);
-        values.put(DATA_SUMMARY_OFF_NORMALIZED, row.normalizedSummaryOff);
-        values.put(DATA_ENTRIES, row.entries);
-        values.put(DATA_KEYWORDS, row.spaceDelimitedKeywords);
-        values.put(CLASS_NAME, row.className);
-        values.put(SCREEN_TITLE, row.screenTitle);
-        values.put(INTENT_ACTION, row.intentAction);
-        values.put(INTENT_TARGET_PACKAGE, row.intentTargetPackage);
-        values.put(INTENT_TARGET_CLASS, row.intentTargetClass);
-        values.put(ICON, row.iconResId);
-        values.put(ENABLED, row.enabled);
-        values.put(DATA_KEY_REF, row.key);
-        values.put(USER_ID, row.userId);
-        values.put(PAYLOAD_TYPE, row.payloadType);
-        values.put(PAYLOAD, row.payload);
-
-        database.replaceOrThrow(TABLE_PREFS_INDEX, null, values);
-
-        if (!TextUtils.isEmpty(row.className) && !TextUtils.isEmpty(row.childClassName)) {
-            ContentValues siteMapPair = new ContentValues();
-            final int pairDocId = Objects.hash(row.className, row.childClassName);
-            siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.DOCID, pairDocId);
-            siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.PARENT_CLASS, row.className);
-            siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.PARENT_TITLE, row.screenTitle);
-            siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.CHILD_CLASS, row.childClassName);
-            siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.CHILD_TITLE, row.updatedTitle);
-
-            database.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, null, siteMapPair);
-        }
-    }
-
-    public static class DatabaseRow {
-        public final String locale;
-        public final String updatedTitle;
-        public final String normalizedTitle;
-        public final String updatedSummaryOn;
-        public final String normalizedSummaryOn;
-        public final String updatedSummaryOff;
-        public final String normalizedSummaryOff;
-        public final String entries;
-        public final String className;
-        public final String childClassName;
-        public final String screenTitle;
-        public final int iconResId;
-        public final int rank;
-        public final String spaceDelimitedKeywords;
-        public final String intentAction;
-        public final String intentTargetPackage;
-        public final String intentTargetClass;
-        public final boolean enabled;
-        public final String key;
-        public final int userId;
-        public final int payloadType;
-        public final byte[] payload;
-
-        private DatabaseRow(Builder builder) {
-            locale = builder.mLocale;
-            updatedTitle = builder.mUpdatedTitle;
-            normalizedTitle = builder.mNormalizedTitle;
-            updatedSummaryOn = builder.mUpdatedSummaryOn;
-            normalizedSummaryOn = builder.mNormalizedSummaryOn;
-            updatedSummaryOff = builder.mUpdatedSummaryOff;
-            normalizedSummaryOff = builder.mNormalizedSummaryOff;
-            entries = builder.mEntries;
-            className = builder.mClassName;
-            childClassName = builder.mChildClassName;
-            screenTitle = builder.mScreenTitle;
-            iconResId = builder.mIconResId;
-            rank = builder.mRank;
-            spaceDelimitedKeywords = builder.mSpaceDelimitedKeywords;
-            intentAction = builder.mIntentAction;
-            intentTargetPackage = builder.mIntentTargetPackage;
-            intentTargetClass = builder.mIntentTargetClass;
-            enabled = builder.mEnabled;
-            key = builder.mKey;
-            userId = builder.mUserId;
-            payloadType = builder.mPayloadType;
-            payload = builder.mPayload != null ? ResultPayloadUtils.marshall(builder.mPayload)
-                    : null;
-        }
-
-        /**
-         * Returns the doc id for this row.
-         */
-        public int getDocId() {
-            // Eventually we want all DocIds to be the data_reference key. For settings values,
-            // this will be preference keys, and for non-settings they should be unique.
-            return TextUtils.isEmpty(key)
-                    ? Objects.hash(updatedTitle, className, screenTitle, intentTargetClass)
-                    : key.hashCode();
-        }
-
-        public static class Builder {
-            private String mLocale;
-            private String mUpdatedTitle;
-            private String mNormalizedTitle;
-            private String mUpdatedSummaryOn;
-            private String mNormalizedSummaryOn;
-            private String mUpdatedSummaryOff;
-            private String mNormalizedSummaryOff;
-            private String mEntries;
-            private String mClassName;
-            private String mChildClassName;
-            private String mScreenTitle;
-            private int mIconResId;
-            private int mRank;
-            private String mSpaceDelimitedKeywords;
-            private String mIntentAction;
-            private String mIntentTargetPackage;
-            private String mIntentTargetClass;
-            private boolean mEnabled;
-            private String mKey;
-            private int mUserId;
-            @ResultPayload.PayloadType
-            private int mPayloadType;
-            private ResultPayload mPayload;
-
-            public Builder setLocale(String locale) {
-                mLocale = locale;
-                return this;
-            }
-
-            public Builder setUpdatedTitle(String updatedTitle) {
-                mUpdatedTitle = updatedTitle;
-                return this;
-            }
-
-            public Builder setNormalizedTitle(String normalizedTitle) {
-                mNormalizedTitle = normalizedTitle;
-                return this;
-            }
-
-            public Builder setUpdatedSummaryOn(String updatedSummaryOn) {
-                mUpdatedSummaryOn = updatedSummaryOn;
-                return this;
-            }
-
-            public Builder setNormalizedSummaryOn(String normalizedSummaryOn) {
-                mNormalizedSummaryOn = normalizedSummaryOn;
-                return this;
-            }
-
-            public Builder setUpdatedSummaryOff(String updatedSummaryOff) {
-                mUpdatedSummaryOff = updatedSummaryOff;
-                return this;
-            }
-
-            public Builder setNormalizedSummaryOff(String normalizedSummaryOff) {
-                this.mNormalizedSummaryOff = normalizedSummaryOff;
-                return this;
-            }
-
-            public Builder setEntries(String entries) {
-                mEntries = entries;
-                return this;
-            }
-
-            public Builder setClassName(String className) {
-                mClassName = className;
-                return this;
-            }
-
-            public Builder setChildClassName(String childClassName) {
-                mChildClassName = childClassName;
-                return this;
-            }
-
-            public Builder setScreenTitle(String screenTitle) {
-                mScreenTitle = screenTitle;
-                return this;
-            }
-
-            public Builder setIconResId(int iconResId) {
-                mIconResId = iconResId;
-                return this;
-            }
-
-            public Builder setRank(int rank) {
-                mRank = rank;
-                return this;
-            }
-
-            public Builder setSpaceDelimitedKeywords(String spaceDelimitedKeywords) {
-                mSpaceDelimitedKeywords = spaceDelimitedKeywords;
-                return this;
-            }
-
-            public Builder setIntentAction(String intentAction) {
-                mIntentAction = intentAction;
-                return this;
-            }
-
-            public Builder setIntentTargetPackage(String intentTargetPackage) {
-                mIntentTargetPackage = intentTargetPackage;
-                return this;
-            }
-
-            public Builder setIntentTargetClass(String intentTargetClass) {
-                mIntentTargetClass = intentTargetClass;
-                return this;
-            }
-
-            public Builder setEnabled(boolean enabled) {
-                mEnabled = enabled;
-                return this;
-            }
-
-            public Builder setKey(String key) {
-                mKey = key;
-                return this;
-            }
-
-            public Builder setUserId(int userId) {
-                mUserId = userId;
-                return this;
-            }
-
-            public Builder setPayload(ResultPayload payload) {
-                mPayload = payload;
-
-                if (mPayload != null) {
-                    setPayloadType(mPayload.getType());
-                }
-                return this;
-            }
-
-            /**
-             * Payload type is added when a Payload is added to the Builder in {setPayload}
-             *
-             * @param payloadType PayloadType
-             * @return The Builder
-             */
-            private Builder setPayloadType(@ResultPayload.PayloadType int payloadType) {
-                mPayloadType = payloadType;
-                return this;
-            }
-
-            /**
-             * Adds intent to inline payloads, or creates an Intent Payload as a fallback if the
-             * payload is null.
-             */
-            private void setIntent(Context context) {
-                if (mPayload != null) {
-                    return;
-                }
-                final Intent intent = buildIntent(context);
-                mPayload = new ResultPayload(intent);
-                mPayloadType = ResultPayload.PayloadType.INTENT;
-            }
-
-            /**
-             * Adds Intent payload to builder.
-             */
-            private Intent buildIntent(Context context) {
-                final Intent intent;
-
-                boolean isEmptyIntentAction = TextUtils.isEmpty(mIntentAction);
-                // No intent action is set, or the intent action is for a subsetting.
-                if (isEmptyIntentAction
-                        || (!isEmptyIntentAction && TextUtils.equals(mIntentTargetPackage,
-                        SearchIndexableResources.SUBSETTING_TARGET_PACKAGE))) {
-                    // Action is null, we will launch it as a sub-setting
-                    intent = DatabaseIndexingUtils.buildSubsettingIntent(context, mClassName, mKey,
-                            mScreenTitle);
-                } else {
-                    intent = new Intent(mIntentAction);
-                    final String targetClass = mIntentTargetClass;
-                    if (!TextUtils.isEmpty(mIntentTargetPackage)
-                            && !TextUtils.isEmpty(targetClass)) {
-                        final ComponentName component = new ComponentName(mIntentTargetPackage,
-                                targetClass);
-                        intent.setComponent(component);
-                    }
-                    intent.putExtra(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, mKey);
-                }
-                return intent;
-            }
-
-            public DatabaseRow build(Context context) {
-                setIntent(context);
-                return new DatabaseRow(this);
-            }
-        }
-    }
-
     public class IndexingTask extends AsyncTask<Void, Void, Void> {
 
         @VisibleForTesting
diff --git a/src/com/android/settings/search/DatabaseIndexingUtils.java b/src/com/android/settings/search/DatabaseIndexingUtils.java
index 7093134..f43f210 100644
--- a/src/com/android/settings/search/DatabaseIndexingUtils.java
+++ b/src/com/android/settings/search/DatabaseIndexingUtils.java
@@ -174,18 +174,18 @@
         return null;
     }
 
-    static String normalizeHyphen(String input) {
+    public static String normalizeHyphen(String input) {
         return (input != null) ? input.replaceAll(NON_BREAKING_HYPHEN, HYPHEN) : EMPTY;
     }
 
-    static String normalizeString(String input) {
+    public static String normalizeString(String input) {
         final String nohyphen = (input != null) ? input.replaceAll(HYPHEN, EMPTY) : EMPTY;
         final String normalized = Normalizer.normalize(nohyphen, Normalizer.Form.NFD);
 
         return REMOVE_DIACRITICALS_PATTERN.matcher(normalized).replaceAll("").toLowerCase();
     }
 
-    static String normalizeKeywords(String input) {
+    public static String normalizeKeywords(String input) {
         return (input != null) ? input.replaceAll(LIST_DELIMITERS, SPACE) : EMPTY;
     }
 }
diff --git a/src/com/android/settings/search/InlinePayload.java b/src/com/android/settings/search/InlinePayload.java
index 03b8828..1cb694a 100644
--- a/src/com/android/settings/search/InlinePayload.java
+++ b/src/com/android/settings/search/InlinePayload.java
@@ -35,8 +35,7 @@
     /**
      * Defines the key to access and store the Setting the inline result represents.
      */
-    @VisibleForTesting
-    final String mSettingKey;
+    private final String mSettingKey;
 
     /**
      * Defines where the Setting is stored.
@@ -154,4 +153,8 @@
 
         return false;
     }
+
+    public String getKey() {
+        return mSettingKey;
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/search/indexing/IndexData.java b/src/com/android/settings/search/indexing/IndexData.java
new file mode 100644
index 0000000..b0c79f3
--- /dev/null
+++ b/src/com/android/settings/search/indexing/IndexData.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.settings.search.indexing;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+import com.android.settings.SettingsActivity;
+import com.android.settings.search.DatabaseIndexingUtils;
+import com.android.settings.search.ResultPayload;
+import com.android.settings.search.ResultPayloadUtils;
+import com.android.settings.search.SearchIndexableResources;
+
+import java.util.Objects;
+
+/**
+ * Data class representing a single row in the Setting Search results database.
+ */
+public class IndexData {
+    public final String locale;
+    public final String updatedTitle;
+    public final String normalizedTitle;
+    public final String updatedSummaryOn;
+    public final String normalizedSummaryOn;
+    public final String updatedSummaryOff;
+    public final String normalizedSummaryOff;
+    public final String entries;
+    public final String className;
+    public final String childClassName;
+    public final String screenTitle;
+    public final int iconResId;
+    public final int rank;
+    public final String spaceDelimitedKeywords;
+    public final String intentAction;
+    public final String intentTargetPackage;
+    public final String intentTargetClass;
+    public final boolean enabled;
+    public final String key;
+    public final int userId;
+    public final int payloadType;
+    public final byte[] payload;
+
+    private IndexData(Builder builder) {
+        locale = builder.mLocale;
+        updatedTitle = builder.mUpdatedTitle;
+        normalizedTitle = builder.mNormalizedTitle;
+        updatedSummaryOn = builder.mUpdatedSummaryOn;
+        normalizedSummaryOn = builder.mNormalizedSummaryOn;
+        updatedSummaryOff = builder.mUpdatedSummaryOff;
+        normalizedSummaryOff = builder.mNormalizedSummaryOff;
+        entries = builder.mEntries;
+        className = builder.mClassName;
+        childClassName = builder.mChildClassName;
+        screenTitle = builder.mScreenTitle;
+        iconResId = builder.mIconResId;
+        rank = builder.mRank;
+        spaceDelimitedKeywords = builder.mSpaceDelimitedKeywords;
+        intentAction = builder.mIntentAction;
+        intentTargetPackage = builder.mIntentTargetPackage;
+        intentTargetClass = builder.mIntentTargetClass;
+        enabled = builder.mEnabled;
+        key = builder.mKey;
+        userId = builder.mUserId;
+        payloadType = builder.mPayloadType;
+        payload = builder.mPayload != null ? ResultPayloadUtils.marshall(builder.mPayload)
+                : null;
+    }
+
+    /**
+     * Returns the doc id for this row.
+     */
+    public int getDocId() {
+        // Eventually we want all DocIds to be the data_reference key. For settings values,
+        // this will be preference keys, and for non-settings they should be unique.
+        return TextUtils.isEmpty(key)
+                ? Objects.hash(updatedTitle, className, screenTitle, intentTargetClass)
+                : key.hashCode();
+    }
+
+    public static class Builder {
+        private String mLocale;
+        private String mUpdatedTitle;
+        private String mNormalizedTitle;
+        private String mUpdatedSummaryOn;
+        private String mNormalizedSummaryOn;
+        private String mUpdatedSummaryOff;
+        private String mNormalizedSummaryOff;
+        private String mEntries;
+        private String mClassName;
+        private String mChildClassName;
+        private String mScreenTitle;
+        private int mIconResId;
+        private int mRank;
+        private String mSpaceDelimitedKeywords;
+        private String mIntentAction;
+        private String mIntentTargetPackage;
+        private String mIntentTargetClass;
+        private boolean mEnabled;
+        private String mKey;
+        private int mUserId;
+        @ResultPayload.PayloadType
+        private int mPayloadType;
+        private ResultPayload mPayload;
+
+        public Builder setLocale(String locale) {
+            mLocale = locale;
+            return this;
+        }
+
+        public Builder setUpdatedTitle(String updatedTitle) {
+            mUpdatedTitle = updatedTitle;
+            return this;
+        }
+
+        public Builder setNormalizedTitle(String normalizedTitle) {
+            mNormalizedTitle = normalizedTitle;
+            return this;
+        }
+
+        public Builder setUpdatedSummaryOn(String updatedSummaryOn) {
+            mUpdatedSummaryOn = updatedSummaryOn;
+            return this;
+        }
+
+        public Builder setNormalizedSummaryOn(String normalizedSummaryOn) {
+            mNormalizedSummaryOn = normalizedSummaryOn;
+            return this;
+        }
+
+        public Builder setUpdatedSummaryOff(String updatedSummaryOff) {
+            mUpdatedSummaryOff = updatedSummaryOff;
+            return this;
+        }
+
+        public Builder setNormalizedSummaryOff(String normalizedSummaryOff) {
+            this.mNormalizedSummaryOff = normalizedSummaryOff;
+            return this;
+        }
+
+        public Builder setEntries(String entries) {
+            mEntries = entries;
+            return this;
+        }
+
+        public Builder setClassName(String className) {
+            mClassName = className;
+            return this;
+        }
+
+        public Builder setChildClassName(String childClassName) {
+            mChildClassName = childClassName;
+            return this;
+        }
+
+        public Builder setScreenTitle(String screenTitle) {
+            mScreenTitle = screenTitle;
+            return this;
+        }
+
+        public Builder setIconResId(int iconResId) {
+            mIconResId = iconResId;
+            return this;
+        }
+
+        public Builder setRank(int rank) {
+            mRank = rank;
+            return this;
+        }
+
+        public Builder setSpaceDelimitedKeywords(String spaceDelimitedKeywords) {
+            mSpaceDelimitedKeywords = spaceDelimitedKeywords;
+            return this;
+        }
+
+        public Builder setIntentAction(String intentAction) {
+            mIntentAction = intentAction;
+            return this;
+        }
+
+        public Builder setIntentTargetPackage(String intentTargetPackage) {
+            mIntentTargetPackage = intentTargetPackage;
+            return this;
+        }
+
+        public Builder setIntentTargetClass(String intentTargetClass) {
+            mIntentTargetClass = intentTargetClass;
+            return this;
+        }
+
+        public Builder setEnabled(boolean enabled) {
+            mEnabled = enabled;
+            return this;
+        }
+
+        public Builder setKey(String key) {
+            mKey = key;
+            return this;
+        }
+
+        public Builder setUserId(int userId) {
+            mUserId = userId;
+            return this;
+        }
+
+        public Builder setPayload(ResultPayload payload) {
+            mPayload = payload;
+
+            if (mPayload != null) {
+                setPayloadType(mPayload.getType());
+            }
+            return this;
+        }
+
+        /**
+         * Payload type is added when a Payload is added to the Builder in {setPayload}
+         *
+         * @param payloadType PayloadType
+         * @return The Builder
+         */
+        private Builder setPayloadType(@ResultPayload.PayloadType int payloadType) {
+            mPayloadType = payloadType;
+            return this;
+        }
+
+        /**
+         * Adds intent to inline payloads, or creates an Intent Payload as a fallback if the
+         * payload is null.
+         */
+        private void setIntent(Context context) {
+            if (mPayload != null) {
+                return;
+            }
+            final Intent intent = buildIntent(context);
+            mPayload = new ResultPayload(intent);
+            mPayloadType = ResultPayload.PayloadType.INTENT;
+        }
+
+        /**
+         * Adds Intent payload to builder.
+         */
+        private Intent buildIntent(Context context) {
+            final Intent intent;
+
+            boolean isEmptyIntentAction = TextUtils.isEmpty(mIntentAction);
+            // No intent action is set, or the intent action is for a subsetting.
+            if (isEmptyIntentAction
+                    || (!isEmptyIntentAction && TextUtils.equals(mIntentTargetPackage,
+                    SearchIndexableResources.SUBSETTING_TARGET_PACKAGE))) {
+                // Action is null, we will launch it as a sub-setting
+                intent = DatabaseIndexingUtils.buildSubsettingIntent(context, mClassName, mKey,
+                        mScreenTitle);
+            } else {
+                intent = new Intent(mIntentAction);
+                final String targetClass = mIntentTargetClass;
+                if (!TextUtils.isEmpty(mIntentTargetPackage)
+                        && !TextUtils.isEmpty(targetClass)) {
+                    final ComponentName component = new ComponentName(mIntentTargetPackage,
+                            targetClass);
+                    intent.setComponent(component);
+                }
+                intent.putExtra(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, mKey);
+            }
+            return intent;
+        }
+
+        public IndexData build(Context context) {
+            setIntent(context);
+            return new IndexData(this);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/search/indexing/IndexDataConverter.java b/src/com/android/settings/search/indexing/IndexDataConverter.java
new file mode 100644
index 0000000..3c602f6
--- /dev/null
+++ b/src/com/android/settings/search/indexing/IndexDataConverter.java
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.settings.search.indexing;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.XmlResourceParser;
+import android.database.sqlite.SQLiteDatabase;
+import android.provider.SearchIndexableData;
+import android.provider.SearchIndexableResource;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+import com.android.settings.core.PreferenceControllerMixin;
+
+import com.android.settings.search.DatabaseIndexingUtils;
+import com.android.settings.search.IndexDatabaseHelper;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.ResultPayload;
+import com.android.settings.search.SearchIndexableRaw;
+import com.android.settings.search.SearchIndexableResources;
+import com.android.settings.search.XmlParserUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.CLASS_NAME;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_ENTRIES;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_KEY_REF;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_RANK;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ENABLED;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ICON;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_ACTION;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.LOCALE;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.PAYLOAD;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.SCREEN_TITLE;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.USER_ID;
+import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX;
+
+/**
+ * Helper class to convert {@link PreIndexData} to {@link IndexData}.
+ *
+ * TODO (b/33577327) This is just copied straight from DatabaseIndexingManager. But it's still ugly.
+ * TODO              This is currently a long chain of method calls. It needs to be broken up.
+ * TODO              but for the sake of easy code reviews, that will happen later.
+ */
+public class IndexDataConverter {
+
+    private static final String LOG_TAG = "IndexDataConverter";
+
+    private static final String NODE_NAME_PREFERENCE_SCREEN = "PreferenceScreen";
+    private static final String NODE_NAME_CHECK_BOX_PREFERENCE = "CheckBoxPreference";
+    private static final String NODE_NAME_LIST_PREFERENCE = "ListPreference";
+
+    private Context mContext;
+
+    private SQLiteDatabase mDb;
+
+    public IndexDataConverter(Context context, SQLiteDatabase database) {
+        mContext = context;
+        mDb = database;
+    }
+
+    /**
+     * Inserts {@link SearchIndexableData} into the database.
+     *
+     * @param localeStr        is the locale of the data to be inserted.
+     * @param dataToUpdate     is a {@link List} of the data to be inserted.
+     * @param nonIndexableKeys is a {@link Map} from Package Name to a {@link Set} of keys which
+     *                         identify search results which should not be surfaced.
+     */
+    public void addDataToDatabase(String localeStr, List<SearchIndexableData> dataToUpdate,
+            Map<String, Set<String>> nonIndexableKeys) {
+        final long current = System.currentTimeMillis();
+
+        for (SearchIndexableData data : dataToUpdate) {
+            try {
+                indexOneSearchIndexableData(localeStr, data, nonIndexableKeys);
+            } catch (Exception e) {
+                Log.e(LOG_TAG, "Cannot index: " + (data != null ? data.className : data)
+                        + " for locale: " + localeStr, e);
+            }
+        }
+
+        final long now = System.currentTimeMillis();
+        Log.d(LOG_TAG, "Indexing locale '" + localeStr + "' took " +
+                (now - current) + " millis");
+    }
+
+    @VisibleForTesting
+    void indexOneSearchIndexableData(String localeStr, SearchIndexableData data,
+            Map<String, Set<String>> nonIndexableKeys) {
+        if (data instanceof SearchIndexableResource) {
+            indexOneResource(localeStr, (SearchIndexableResource) data, nonIndexableKeys);
+        } else if (data instanceof SearchIndexableRaw) {
+            indexOneRaw(localeStr, (SearchIndexableRaw) data, nonIndexableKeys);
+        }
+    }
+
+    @VisibleForTesting
+    void indexOneRaw(String localeStr, SearchIndexableRaw raw, Map<String,
+            Set<String>> nonIndexableKeysFromResource) {
+        // Should be the same locale as the one we are processing
+        if (!raw.locale.toString().equalsIgnoreCase(localeStr)) {
+            return;
+        }
+
+        Set<String> packageKeys = nonIndexableKeysFromResource.get(raw.intentTargetPackage);
+        boolean enabled = raw.enabled;
+
+        if (packageKeys != null && packageKeys.contains(raw.key)) {
+            enabled = false;
+        }
+
+        IndexData.Builder builder = new IndexData.Builder();
+        builder.setLocale(localeStr)
+                .setEntries(raw.entries)
+                .setClassName(raw.className)
+                .setScreenTitle(raw.screenTitle)
+                .setIconResId(raw.iconResId)
+                .setRank(raw.rank)
+                .setIntentAction(raw.intentAction)
+                .setIntentTargetPackage(raw.intentTargetPackage)
+                .setIntentTargetClass(raw.intentTargetClass)
+                .setEnabled(enabled)
+                .setKey(raw.key)
+                .setUserId(raw.userId);
+
+        updateOneRowWithFilteredData(builder, raw.title, raw.summaryOn, raw.summaryOff,
+                raw.keywords);
+    }
+
+    @VisibleForTesting
+    void indexOneResource(String localeStr, SearchIndexableResource sir,
+            Map<String, Set<String>> nonIndexableKeysFromResource) {
+
+        if (sir == null) {
+            Log.e(LOG_TAG, "Cannot index a null resource!");
+            return;
+        }
+
+        final List<String> nonIndexableKeys = new ArrayList<>();
+
+        if (sir.xmlResId > SearchIndexableResources.NO_DATA_RES_ID) {
+            Set<String> resNonIndexableKeys = nonIndexableKeysFromResource.get(sir.packageName);
+            if (resNonIndexableKeys != null && resNonIndexableKeys.size() > 0) {
+                nonIndexableKeys.addAll(resNonIndexableKeys);
+            }
+
+            indexFromResource(localeStr, sir, nonIndexableKeys);
+        } else {
+            if (TextUtils.isEmpty(sir.className)) {
+                Log.w(LOG_TAG, "Cannot index an empty Search Provider name!");
+                return;
+            }
+
+            final Class<?> clazz = DatabaseIndexingUtils.getIndexableClass(sir.className);
+            if (clazz == null) {
+                Log.d(LOG_TAG, "SearchIndexableResource '" + sir.className +
+                        "' should implement the " + Indexable.class.getName() + " interface!");
+                return;
+            }
+
+            // Will be non null only for a Local provider implementing a
+            // SEARCH_INDEX_DATA_PROVIDER field
+            final Indexable.SearchIndexProvider provider =
+                    DatabaseIndexingUtils.getSearchIndexProvider(clazz);
+            if (provider != null) {
+                List<String> providerNonIndexableKeys = provider.getNonIndexableKeys(sir.context);
+                if (providerNonIndexableKeys != null && providerNonIndexableKeys.size() > 0) {
+                    nonIndexableKeys.addAll(providerNonIndexableKeys);
+                }
+
+                indexFromProvider(localeStr, provider, sir, nonIndexableKeys);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    void indexFromResource(String localeStr, SearchIndexableResource sir,
+            List<String> nonIndexableKeys) {
+        final Context context = sir.context;
+        XmlResourceParser parser = null;
+        try {
+            parser = context.getResources().getXml(sir.xmlResId);
+
+            int type;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+                // Parse next until start tag is found
+            }
+
+            String nodeName = parser.getName();
+            if (!NODE_NAME_PREFERENCE_SCREEN.equals(nodeName)) {
+                throw new RuntimeException(
+                        "XML document must start with <PreferenceScreen> tag; found"
+                                + nodeName + " at " + parser.getPositionDescription());
+            }
+
+            final int outerDepth = parser.getDepth();
+            final AttributeSet attrs = Xml.asAttributeSet(parser);
+
+            final String screenTitle = XmlParserUtils.getDataTitle(context, attrs);
+            String key = XmlParserUtils.getDataKey(context, attrs);
+
+            String title;
+            String headerTitle;
+            String summary;
+            String headerSummary;
+            String keywords;
+            String headerKeywords;
+            String childFragment;
+            @DrawableRes
+            int iconResId;
+            ResultPayload payload;
+            boolean enabled;
+            final String fragmentName = sir.className;
+            final int rank = sir.rank;
+            final String intentAction = sir.intentAction;
+            final String intentTargetPackage = sir.intentTargetPackage;
+            final String intentTargetClass = sir.intentTargetClass;
+
+            Map<String, PreferenceControllerMixin> controllerUriMap = null;
+
+            if (fragmentName != null) {
+                controllerUriMap = DatabaseIndexingUtils
+                        .getPreferenceControllerUriMap(fragmentName, context);
+            }
+
+            // Insert rows for the main PreferenceScreen node. Rewrite the data for removing
+            // hyphens.
+
+            headerTitle = XmlParserUtils.getDataTitle(context, attrs);
+            headerSummary = XmlParserUtils.getDataSummary(context, attrs);
+            headerKeywords = XmlParserUtils.getDataKeywords(context, attrs);
+            enabled = !nonIndexableKeys.contains(key);
+
+            // TODO: Set payload type for header results
+            IndexData.Builder headerBuilder = new IndexData.Builder();
+            headerBuilder.setLocale(localeStr)
+                    .setEntries(null)
+                    .setClassName(fragmentName)
+                    .setScreenTitle(screenTitle)
+                    .setRank(rank)
+                    .setIntentAction(intentAction)
+                    .setIntentTargetPackage(intentTargetPackage)
+                    .setIntentTargetClass(intentTargetClass)
+                    .setEnabled(enabled)
+                    .setKey(key)
+                    .setUserId(-1 /* default user id */);
+
+            // Flag for XML headers which a child element's title.
+            boolean isHeaderUnique = true;
+            IndexData.Builder builder;
+
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+
+                nodeName = parser.getName();
+
+                title = XmlParserUtils.getDataTitle(context, attrs);
+                key = XmlParserUtils.getDataKey(context, attrs);
+                enabled = !nonIndexableKeys.contains(key);
+                keywords = XmlParserUtils.getDataKeywords(context, attrs);
+                iconResId = XmlParserUtils.getDataIcon(context, attrs);
+
+                if (isHeaderUnique && TextUtils.equals(headerTitle, title)) {
+                    isHeaderUnique = false;
+                }
+
+                builder = new IndexData.Builder();
+                builder.setLocale(localeStr)
+                        .setClassName(fragmentName)
+                        .setScreenTitle(screenTitle)
+                        .setIconResId(iconResId)
+                        .setRank(rank)
+                        .setIntentAction(intentAction)
+                        .setIntentTargetPackage(intentTargetPackage)
+                        .setIntentTargetClass(intentTargetClass)
+                        .setEnabled(enabled)
+                        .setKey(key)
+                        .setUserId(-1 /* default user id */);
+
+                if (!nodeName.equals(NODE_NAME_CHECK_BOX_PREFERENCE)) {
+                    summary = XmlParserUtils.getDataSummary(context, attrs);
+
+                    String entries = null;
+
+                    if (nodeName.endsWith(NODE_NAME_LIST_PREFERENCE)) {
+                        entries = XmlParserUtils.getDataEntries(context, attrs);
+                    }
+
+                    // TODO (b/62254931) index primitives instead of payload
+                    payload = DatabaseIndexingUtils.getPayloadFromUriMap(controllerUriMap, key);
+                    childFragment = XmlParserUtils.getDataChildFragment(context, attrs);
+
+                    builder.setEntries(entries)
+                            .setChildClassName(childFragment)
+                            .setPayload(payload);
+
+                    // Insert rows for the child nodes of PreferenceScreen
+                    updateOneRowWithFilteredData(builder, title, summary,
+                            null /* summary off */, keywords);
+                } else {
+                    String summaryOn = XmlParserUtils.getDataSummaryOn(context, attrs);
+                    String summaryOff = XmlParserUtils.getDataSummaryOff(context, attrs);
+
+                    if (TextUtils.isEmpty(summaryOn) && TextUtils.isEmpty(summaryOff)) {
+                        summaryOn = XmlParserUtils.getDataSummary(context, attrs);
+                    }
+
+                    updateOneRowWithFilteredData(builder, title, summaryOn, summaryOff,
+                            keywords);
+                }
+            }
+
+            // The xml header's title does not match the title of one of the child settings.
+            if (isHeaderUnique) {
+                updateOneRowWithFilteredData(headerBuilder, headerTitle, headerSummary,
+                        null /* summary off */, headerKeywords);
+            }
+        } catch (XmlPullParserException e) {
+            throw new RuntimeException("Error parsing PreferenceScreen", e);
+        } catch (IOException e) {
+            throw new RuntimeException("Error parsing PreferenceScreen", e);
+        } finally {
+            if (parser != null) parser.close();
+        }
+    }
+
+    @VisibleForTesting
+    void indexFromProvider(String localeStr, Indexable.SearchIndexProvider provider,
+            SearchIndexableResource sir, List<String> nonIndexableKeys) {
+
+        final String className = sir.className;
+        final String intentAction = sir.intentAction;
+        final String intentTargetPackage = sir.intentTargetPackage;
+
+        if (provider == null) {
+            Log.w(LOG_TAG, "Cannot find provider: " + className);
+            return;
+        }
+
+        final List<SearchIndexableRaw> rawList = provider.getRawDataToIndex(mContext,
+                true /* enabled */);
+
+        if (rawList != null) {
+
+            final int rawSize = rawList.size();
+            for (int i = 0; i < rawSize; i++) {
+                SearchIndexableRaw raw = rawList.get(i);
+
+                // Should be the same locale as the one we are processing
+                if (!raw.locale.toString().equalsIgnoreCase(localeStr)) {
+                    continue;
+                }
+                boolean enabled = !nonIndexableKeys.contains(raw.key);
+
+                IndexData.Builder builder = new IndexData.Builder();
+                builder.setLocale(localeStr)
+                        .setEntries(raw.entries)
+                        .setClassName(className)
+                        .setScreenTitle(raw.screenTitle)
+                        .setIconResId(raw.iconResId)
+                        .setIntentAction(raw.intentAction)
+                        .setIntentTargetPackage(raw.intentTargetPackage)
+                        .setIntentTargetClass(raw.intentTargetClass)
+                        .setEnabled(enabled)
+                        .setKey(raw.key)
+                        .setUserId(raw.userId);
+
+                updateOneRowWithFilteredData(builder, raw.title, raw.summaryOn, raw.summaryOff,
+                        raw.keywords);
+            }
+        }
+
+        final List<SearchIndexableResource> resList =
+                provider.getXmlResourcesToIndex(mContext, true);
+        if (resList != null) {
+            final int resSize = resList.size();
+            for (int i = 0; i < resSize; i++) {
+                SearchIndexableResource item = resList.get(i);
+
+                // Should be the same locale as the one we are processing
+                if (!item.locale.toString().equalsIgnoreCase(localeStr)) {
+                    continue;
+                }
+
+                item.className = TextUtils.isEmpty(item.className)
+                        ? className
+                        : item.className;
+                item.intentAction = TextUtils.isEmpty(item.intentAction)
+                        ? intentAction
+                        : item.intentAction;
+                item.intentTargetPackage = TextUtils.isEmpty(item.intentTargetPackage)
+                        ? intentTargetPackage
+                        : item.intentTargetPackage;
+
+                indexFromResource(localeStr, item, nonIndexableKeys);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    void updateOneRowWithFilteredData(IndexData.Builder builder,
+            String title, String summaryOn, String summaryOff, String keywords) {
+
+        final String updatedTitle = DatabaseIndexingUtils.normalizeHyphen(title);
+        final String updatedSummaryOn = DatabaseIndexingUtils.normalizeHyphen(summaryOn);
+        final String updatedSummaryOff = DatabaseIndexingUtils.normalizeHyphen(summaryOff);
+
+        final String normalizedTitle = DatabaseIndexingUtils.normalizeString(updatedTitle);
+        final String normalizedSummaryOn = DatabaseIndexingUtils.normalizeString(updatedSummaryOn);
+        final String normalizedSummaryOff = DatabaseIndexingUtils
+                .normalizeString(updatedSummaryOff);
+
+        final String spaceDelimitedKeywords = DatabaseIndexingUtils.normalizeKeywords(keywords);
+
+        builder.setUpdatedTitle(updatedTitle)
+                .setUpdatedSummaryOn(updatedSummaryOn)
+                .setUpdatedSummaryOff(updatedSummaryOff)
+                .setNormalizedTitle(normalizedTitle)
+                .setNormalizedSummaryOn(normalizedSummaryOn)
+                .setNormalizedSummaryOff(normalizedSummaryOff)
+                .setSpaceDelimitedKeywords(spaceDelimitedKeywords);
+
+        updateOneRow(builder.build(mContext));
+    }
+
+    private void updateOneRow(IndexData row) {
+        if (TextUtils.isEmpty(row.updatedTitle)) {
+            return;
+        }
+
+        ContentValues values = new ContentValues();
+        values.put(IndexDatabaseHelper.IndexColumns.DOCID, row.getDocId());
+        values.put(LOCALE, row.locale);
+        values.put(DATA_RANK, row.rank);
+        values.put(DATA_TITLE, row.updatedTitle);
+        values.put(DATA_TITLE_NORMALIZED, row.normalizedTitle);
+        values.put(DATA_SUMMARY_ON, row.updatedSummaryOn);
+        values.put(DATA_SUMMARY_ON_NORMALIZED, row.normalizedSummaryOn);
+        values.put(DATA_SUMMARY_OFF, row.updatedSummaryOff);
+        values.put(DATA_SUMMARY_OFF_NORMALIZED, row.normalizedSummaryOff);
+        values.put(DATA_ENTRIES, row.entries);
+        values.put(DATA_KEYWORDS, row.spaceDelimitedKeywords);
+        values.put(CLASS_NAME, row.className);
+        values.put(SCREEN_TITLE, row.screenTitle);
+        values.put(INTENT_ACTION, row.intentAction);
+        values.put(INTENT_TARGET_PACKAGE, row.intentTargetPackage);
+        values.put(INTENT_TARGET_CLASS, row.intentTargetClass);
+        values.put(ICON, row.iconResId);
+        values.put(ENABLED, row.enabled);
+        values.put(DATA_KEY_REF, row.key);
+        values.put(USER_ID, row.userId);
+        values.put(PAYLOAD_TYPE, row.payloadType);
+        values.put(PAYLOAD, row.payload);
+
+        mDb.replaceOrThrow(TABLE_PREFS_INDEX, null, values);
+
+        if (!TextUtils.isEmpty(row.className) && !TextUtils.isEmpty(row.childClassName)) {
+            ContentValues siteMapPair = new ContentValues();
+            final int pairDocId = Objects.hash(row.className, row.childClassName);
+            siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.DOCID, pairDocId);
+            siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.PARENT_CLASS, row.className);
+            siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.PARENT_TITLE, row.screenTitle);
+            siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.CHILD_CLASS, row.childClassName);
+            siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.CHILD_TITLE, row.updatedTitle);
+
+            mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, null, siteMapPair);
+        }
+    }
+}
diff --git a/src/com/android/settings/search/indexing/IndexableDataCollector.java b/src/com/android/settings/search/indexing/PreIndexDataCollector.java
similarity index 99%
rename from src/com/android/settings/search/indexing/IndexableDataCollector.java
rename to src/com/android/settings/search/indexing/PreIndexDataCollector.java
index cd6b9bb..7186df8 100644
--- a/src/com/android/settings/search/indexing/IndexableDataCollector.java
+++ b/src/com/android/settings/search/indexing/PreIndexDataCollector.java
@@ -65,7 +65,7 @@
 /**
  * Collects all data from {@link android.provider.SearchIndexablesProvider} to be indexed.
  */
-public class IndexableDataCollector {
+public class PreIndexDataCollector {
 
     private static final String TAG = "IndexableDataCollector";
 
@@ -78,7 +78,7 @@
 
     private PreIndexData mIndexData;
 
-    public IndexableDataCollector(Context context) {
+    public PreIndexDataCollector(Context context) {
         mContext = context;
     }
 
diff --git a/tests/robotests/src/com/android/settings/search/CursorToSearchResultConverterTest.java b/tests/robotests/src/com/android/settings/search/CursorToSearchResultConverterTest.java
index a15a449..47d5287 100644
--- a/tests/robotests/src/com/android/settings/search/CursorToSearchResultConverterTest.java
+++ b/tests/robotests/src/com/android/settings/search/CursorToSearchResultConverterTest.java
@@ -243,7 +243,7 @@
         for (SearchResult result : results) {
             final InlineSwitchPayload newPayload = (InlineSwitchPayload) result.payload;
             final Intent rebuiltIntent = newPayload.getIntent();
-            assertThat(newPayload.mSettingKey).isEqualTo(uri);
+            assertThat(newPayload.getKey()).isEqualTo(uri);
             assertThat(newPayload.getType()).isEqualTo(type);
             assertThat(newPayload.mSettingSource).isEqualTo(source);
             assertThat(newPayload.isStandard()).isTrue();
diff --git a/tests/robotests/src/com/android/settings/search/DatabaseIndexingManagerTest.java b/tests/robotests/src/com/android/settings/search/DatabaseIndexingManagerTest.java
index fff38c5..db4aff7 100644
--- a/tests/robotests/src/com/android/settings/search/DatabaseIndexingManagerTest.java
+++ b/tests/robotests/src/com/android/settings/search/DatabaseIndexingManagerTest.java
@@ -21,7 +21,6 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyList;
-import static org.mockito.Matchers.anyMap;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Mockito.doNothing;
@@ -42,10 +41,8 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.os.Build;
 import android.provider.SearchIndexableData;
-import android.provider.SearchIndexableResource;
 import android.util.ArrayMap;
 
-import com.android.settings.R;
 import com.android.settings.TestConfig;
 import com.android.settings.search.indexing.PreIndexData;
 import com.android.settings.testutils.DatabaseTestUtils;
@@ -65,7 +62,6 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
@@ -149,7 +145,7 @@
         Cursor dbCursor = mDb.query("prefs_index", null, null, null, null, null, null);
         List<String> columnNames = new ArrayList<>(Arrays.asList(dbCursor.getColumnNames()));
         // Note that docid is not included.
-        List<String> expColumnNames = new ArrayList<>(Arrays.asList(new String[]{
+        List<String> expColumnNames = Arrays.asList(
                 "locale",
                 "data_rank",
                 "data_title",
@@ -171,7 +167,7 @@
                 "user_id",
                 "payload_type",
                 "payload"
-        }));
+        );
         // Prevent database schema regressions
         assertThat(columnNames).containsAllIn(expColumnNames);
     }
@@ -179,180 +175,6 @@
     // Tests for the flow: IndexOneRaw -> UpdateOneRowWithFilteredData -> UpdateOneRow
 
     @Test
-    public void testInsertRawColumn_rowInserted() {
-        SearchIndexableRaw raw = getFakeRaw();
-        mManager.indexOneSearchIndexableData(mDb, localeStr, raw,
-                new HashMap<>()/* Non-indexable keys */);
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
-        assertThat(cursor.getCount()).isEqualTo(1);
-    }
-
-    @Test
-    public void testInsertRawColumn_nonIndexableKey_resultIsDisabled() {
-        SearchIndexableRaw raw = getFakeRaw();
-        Map<String, Set<String>> niks = new HashMap<>();
-        Set<String> keys = new HashSet<>();
-        keys.add(raw.key);
-        niks.put(raw.intentTargetPackage, keys);
-
-        mManager.indexOneSearchIndexableData(mDb, localeStr, raw, niks);
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
-        assertThat(cursor.getCount()).isEqualTo(1);
-    }
-
-    @Test
-    public void testInsertRawColumn_rowMatches() {
-        SearchIndexableRaw raw = getFakeRaw();
-        mManager.indexOneSearchIndexableData(mDb, localeStr, raw,
-                new HashMap<>()/* Non-indexable keys */);
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
-        cursor.moveToPosition(0);
-
-        // Locale
-        assertThat(cursor.getString(0)).isEqualTo(localeStr);
-        // Data Rank
-        assertThat(cursor.getInt(1)).isEqualTo(raw.rank);
-        // Data Title
-        assertThat(cursor.getString(2)).isEqualTo(updatedTitle);
-        // Normalized Title
-        assertThat(cursor.getString(3)).isEqualTo(normalizedTitle);
-        // Summary On
-        assertThat(cursor.getString(4)).isEqualTo(updatedSummaryOn);
-        // Summary On Normalized
-        assertThat(cursor.getString(5)).isEqualTo(normalizedSummaryOn);
-        // Summary Off
-        assertThat(cursor.getString(6)).isEqualTo(updatedSummaryOff);
-        // Summary off normalized
-        assertThat(cursor.getString(7)).isEqualTo(normalizedSummaryOff);
-        // Entries
-        assertThat(cursor.getString(8)).isEqualTo(raw.entries);
-        // Keywords
-        assertThat(cursor.getString(9)).isEqualTo(spaceDelimittedKeywords);
-        // Screen Title
-        assertThat(cursor.getString(10)).isEqualTo(raw.screenTitle);
-        // Class Name
-        assertThat(cursor.getString(11)).isEqualTo(raw.className);
-        // Icon
-        assertThat(cursor.getInt(12)).isEqualTo(raw.iconResId);
-        // Intent Action
-        assertThat(cursor.getString(13)).isEqualTo(raw.intentAction);
-        // Target Package
-        assertThat(cursor.getString(14)).isEqualTo(raw.intentTargetPackage);
-        // Target Class
-        assertThat(cursor.getString(15)).isEqualTo(raw.intentTargetClass);
-        // Enabled
-        assertThat(cursor.getInt(16) == 1).isEqualTo(raw.enabled);
-        // Data ref key
-        assertThat(cursor.getString(17)).isNotNull();
-        // User Id
-        assertThat(cursor.getInt(18)).isEqualTo(raw.userId);
-        // Payload Type - default is 0
-        assertThat(cursor.getInt(19)).isEqualTo(0);
-        // Payload
-        byte[] payload = cursor.getBlob(20);
-        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
-                ResultPayload.CREATOR);
-        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
-    }
-
-    @Test
-    public void testInsertRawColumn_mismatchedLocale_noRowInserted() {
-        SearchIndexableRaw raw = getFakeRaw("ca-fr");
-        mManager.indexOneSearchIndexableData(mDb, localeStr, raw, null /* Non-indexable keys */);
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
-        assertThat(cursor.getCount()).isEqualTo(0);
-    }
-
-    // Tests for the flow: IndexOneResource -> IndexFromResource ->
-    //                     UpdateOneRowWithFilteredData -> UpdateOneRow
-
-    @Test
-    public void testNullResource_NothingInserted() {
-        mManager.indexOneSearchIndexableData(mDb, localeStr, null /* searchIndexableResource */,
-                new HashMap<>());
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
-        assertThat(cursor.getCount()).isEqualTo(0);
-    }
-
-    @Test
-    public void testAddResource_RowsInserted() {
-        SearchIndexableResource resource = getFakeResource(R.xml.display_settings);
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
-        assertThat(cursor.getCount()).isEqualTo(17);
-    }
-
-    @Test
-    public void testAddResource_withNIKs_rowsInsertedDisabled() {
-        SearchIndexableResource resource = getFakeResource(R.xml.display_settings);
-        // Only add 2 of 16 items to be disabled.
-        String[] keys = {"brightness", "wallpaper"};
-        Map<String, Set<String>> niks = getNonIndexableKeys(keys);
-
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, niks);
-
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
-        assertThat(cursor.getCount()).isEqualTo(2);
-        cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
-        assertThat(cursor.getCount()).isEqualTo(15);
-    }
-
-    @Test
-    public void testAddResourceHeader_rowsMatch() {
-        SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
-
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
-        cursor.moveToPosition(1);
-
-        // Locale
-        assertThat(cursor.getString(0)).isEqualTo(localeStr);
-        // Data Rank
-        assertThat(cursor.getInt(1)).isEqualTo(rank);
-        // Data Title
-        assertThat(cursor.getString(2)).isEqualTo("App info");
-        // Normalized Title
-        assertThat(cursor.getString(3)).isEqualTo("app info");
-        // Summary On
-        assertThat(cursor.getString(4)).isEqualTo("Manage apps, set up quick launch shortcuts");
-        // Summary On Normalized
-        assertThat(cursor.getString(5)).isEqualTo("manage apps, set up quick launch shortcuts");
-        // Summary Off - only on for checkbox preferences
-        assertThat(cursor.getString(6)).isEmpty();
-        // Summary off normalized - only on for checkbox preferences
-        assertThat(cursor.getString(7)).isEmpty();
-        // Entries - only on for list preferences
-        assertThat(cursor.getString(8)).isNull();
-        // Keywords
-        assertThat(cursor.getString(9)).isEmpty();
-        // Screen Title
-        assertThat(cursor.getString(10)).isEqualTo("App info");
-        // Class Name
-        assertThat(cursor.getString(11)).isEqualTo(className);
-        // Icon
-        assertThat(cursor.getInt(12)).isEqualTo(0);
-        // Intent Action
-        assertThat(cursor.getString(13)).isEqualTo(action);
-        // Target Package
-        assertThat(cursor.getString(14)).isEqualTo(targetPackage);
-        // Target Class
-        assertThat(cursor.getString(15)).isEqualTo(targetClass);
-        // Enabled
-        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
-        // Data ref key
-        assertThat(cursor.getString(17)).isEqualTo("applications_settings");
-        // User Id
-        assertThat(cursor.getInt(18)).isEqualTo(userId);
-        // Payload Type - default is 0
-        assertThat(cursor.getInt(19)).isEqualTo(0);
-        // Payload - should be updated to real payloads as controllers are added
-        byte[] payload = cursor.getBlob(20);
-        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
-                ResultPayload.CREATOR);
-        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
-    }
-
-    @Test
     public void testAddResource_withChildFragment_shouldUpdateSiteMapDb() {
         // FIXME: This test was failing. (count = 6 at the end)
 
@@ -377,376 +199,6 @@
 //        assertThat(count).isEqualTo(5);
     }
 
-    @Test
-    public void testAddResource_customSetting_rowsMatch() {
-        SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
-        final String prefTitle =
-                mContext.getString(R.string.fingerprint_swipe_for_notifications_title);
-        final String prefSummary =
-                mContext.getString(R.string.fingerprint_swipe_for_notifications_summary);
-        final String keywords = mContext.getString(R.string.keywords_gesture);
-        Cursor cursor = mDb.rawQuery(
-                "SELECT * FROM prefs_index where data_title='" + prefTitle + "'", null);
-        cursor.moveToFirst();
-
-        // Locale
-        assertThat(cursor.getString(0)).isEqualTo(localeStr);
-        // Data Rank
-        assertThat(cursor.getInt(1)).isEqualTo(rank);
-        // Data Title
-        assertThat(cursor.getString(2)).isEqualTo(prefTitle);
-        // Normalized Title
-        assertThat(cursor.getString(3)).isEqualTo(prefTitle.toLowerCase());
-        // Summary On
-        assertThat(cursor.getString(4)).isEqualTo(prefSummary);
-        // Summary On Normalized
-        assertThat(cursor.getString(5)).isEqualTo(prefSummary.toLowerCase());
-        // Summary Off - only on for checkbox preferences
-        assertThat(cursor.getString(6)).isEmpty();
-        // Summary off normalized - only on for checkbox preferences
-        assertThat(cursor.getString(7)).isEmpty();
-        // Entries - only on for list preferences
-        assertThat(cursor.getString(8)).isNull();
-        // Keywords
-        assertThat(cursor.getString(9)).isEqualTo(keywords);
-        // Screen Title
-        assertThat(cursor.getString(10)).isEqualTo(
-                mContext.getString(R.string.fingerprint_swipe_for_notifications_title));
-        // Class Name
-        assertThat(cursor.getString(11)).isEqualTo(className);
-        // Icon
-        assertThat(cursor.getInt(12)).isEqualTo(noIcon);
-        // Intent Action
-        assertThat(cursor.getString(13)).isEqualTo(action);
-        // Target Package
-        assertThat(cursor.getString(14)).isEqualTo(targetPackage);
-        // Target Class
-        assertThat(cursor.getString(15)).isEqualTo(targetClass);
-        // Enabled
-        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
-        // Data ref key
-        assertThat(cursor.getString(17)).isEqualTo("gesture_swipe_down_fingerprint");
-        // User Id
-        assertThat(cursor.getInt(18)).isEqualTo(userId);
-        // Payload Type - default is 0
-        assertThat(cursor.getInt(19)).isEqualTo(0);
-        // Payload - should be updated to real payloads as controllers are added
-        byte[] payload = cursor.getBlob(20);
-        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
-                ResultPayload.CREATOR);
-        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
-    }
-
-    @Test
-    public void testAddResource_checkboxPreference_rowsMatch() {
-        SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
-
-        /* Should return 6 results, with the following titles:
-         * Advanced Settings, Apps, Manage Apps, Preferred install location, Running Services
-         */
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
-        cursor.moveToPosition(0);
-        // Locale
-        assertThat(cursor.getString(0)).isEqualTo(localeStr);
-        // Data Rank
-        assertThat(cursor.getInt(1)).isEqualTo(rank);
-        // Data Title
-        assertThat(cursor.getString(2)).isEqualTo("Advanced settings");
-        // Normalized Title
-        assertThat(cursor.getString(3)).isEqualTo("advanced settings");
-        // Summary On
-        assertThat(cursor.getString(4)).isEqualTo("Enable more settings options");
-        // Summary On Normalized
-        assertThat(cursor.getString(5)).isEqualTo("enable more settings options");
-        // Summary Off
-        assertThat(cursor.getString(6)).isEqualTo("Enable more settings options");
-        // Summary Off
-        assertThat(cursor.getString(7)).isEqualTo("enable more settings options");
-        // Entries - only on for list preferences
-        assertThat(cursor.getString(8)).isNull();
-        // Keywords
-        assertThat(cursor.getString(9)).isEmpty();
-        // Screen Title
-        assertThat(cursor.getString(10)).isEqualTo("App info");
-        // Class Name
-        assertThat(cursor.getString(11)).isEqualTo(className);
-        // Icon
-        assertThat(cursor.getInt(12)).isEqualTo(noIcon);
-        // Intent Action
-        assertThat(cursor.getString(13)).isEqualTo(action);
-        // Target Package
-        assertThat(cursor.getString(14)).isEqualTo(targetPackage);
-        // Target Class
-        assertThat(cursor.getString(15)).isEqualTo(targetClass);
-        // Enabled
-        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
-        // Data ref key
-        assertThat(cursor.getString(17)).isEqualTo("toggle_advanced_settings");
-        // User Id
-        assertThat(cursor.getInt(18)).isEqualTo(userId);
-        // Payload Type - default is 0
-        assertThat(cursor.getInt(19)).isEqualTo(0);
-        // Payload - should be updated to real payloads as controllers are added
-        byte[] payload = cursor.getBlob(20);
-        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
-                ResultPayload.CREATOR);
-        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
-    }
-
-    @Test
-    public void testAddResource_listPreference_rowsMatch() {
-        SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
-
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
-        cursor.moveToPosition(3);
-        // Locale
-        assertThat(cursor.getString(0)).isEqualTo(localeStr);
-        // Data Rank
-        assertThat(cursor.getInt(1)).isEqualTo(rank);
-        // Data Title
-        assertThat(cursor.getString(2)).isEqualTo("Preferred install location");
-        // Normalized Title
-        assertThat(cursor.getString(3)).isEqualTo("preferred install location");
-        // Summary On
-        assertThat(cursor.getString(4)).isEqualTo(
-                "Change the preferred installation location for new apps");
-        // Summary On Normalized
-        assertThat(cursor.getString(5)).isEqualTo(
-                "change the preferred installation location for new apps");
-        // Summary Off - only on for checkbox preferences
-        assertThat(cursor.getString(6)).isEmpty();
-        // Summary off normalized - only on for checkbox preferences
-        assertThat(cursor.getString(7)).isEmpty();
-        // Entries - only on for list preferences
-        assertThat(cursor.getString(8)).isEqualTo("Internal device storage|Removable SD card|" +
-                "Let the system decide|");
-        // Keywords
-        assertThat(cursor.getString(9)).isEmpty();
-        // Screen Title
-        assertThat(cursor.getString(10)).isEqualTo("App info");
-        // Class Name
-        assertThat(cursor.getString(11)).isEqualTo(className);
-        // Icon
-        assertThat(cursor.getInt(12)).isEqualTo(noIcon);
-        // Intent Action
-        assertThat(cursor.getString(13)).isEqualTo(action);
-        // Target Package
-        assertThat(cursor.getString(14)).isEqualTo(targetPackage);
-        // Target Class
-        assertThat(cursor.getString(15)).isEqualTo(targetClass);
-        // Enabled
-        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
-        // Data ref key
-        assertThat(cursor.getString(17)).isEqualTo("app_install_location");
-        // User Id
-        assertThat(cursor.getInt(18)).isEqualTo(userId);
-        // Payload Type - default is 0
-        assertThat(cursor.getInt(19)).isEqualTo(0);
-        // Payload - should be updated to real payloads as controllers are added
-        byte[] payload = cursor.getBlob(20);
-        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
-                ResultPayload.CREATOR);
-        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
-    }
-
-    @Test
-    public void testAddResource_iconAddedFromXml() {
-        SearchIndexableResource resource = getFakeResource(R.xml.connected_devices);
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
-
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
-        cursor.moveToPosition(0);
-
-        // Icon
-        assertThat(cursor.getInt(12)).isNotEqualTo(noIcon);
-    }
-
-    // Tests for the flow: IndexOneResource -> IndexFromProvider -> IndexFromResource ->
-    //                     UpdateOneRowWithFilteredData -> UpdateOneRow
-
-    @Test
-    public void testResourceProvider_rowInserted() {
-        SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
-        resource.xmlResId = 0;
-        resource.className = "com.android.settings.display.ScreenZoomSettings";
-
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
-        assertThat(cursor.getCount()).isEqualTo(1);
-    }
-
-    @Test
-    public void testResourceProvider_rowMatches() {
-        SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
-        resource.xmlResId = 0;
-        resource.className = "com.android.settings.display.ScreenZoomSettings";
-
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
-        cursor.moveToPosition(0);
-
-        // Locale
-        assertThat(cursor.getString(0)).isEqualTo(localeStr);
-        // Data Rank
-        assertThat(cursor.getInt(1)).isEqualTo(0);
-        // Data Title
-        assertThat(cursor.getString(2)).isEqualTo("Display size");
-        // Normalized Title
-        assertThat(cursor.getString(3)).isEqualTo("display size");
-        // Summary On
-        assertThat(cursor.getString(4)).isEmpty();
-        // Summary On Normalized
-        assertThat(cursor.getString(5)).isEmpty();
-        // Summary Off - only on for checkbox preferences
-        assertThat(cursor.getString(6)).isEmpty();
-        // Summary off normalized - only on for checkbox preferences
-        assertThat(cursor.getString(7)).isEmpty();
-        // Entries - only on for list preferences
-        assertThat(cursor.getString(8)).isNull();
-        // Keywords
-        assertThat(cursor.getString(9)).isEqualTo("display density screen zoom scale scaling");
-        // Screen Title
-        assertThat(cursor.getString(10)).isEqualTo("Display size");
-        // Class Name
-        assertThat(cursor.getString(11))
-                .isEqualTo("com.android.settings.display.ScreenZoomSettings");
-        // Icon
-        assertThat(cursor.getInt(12)).isEqualTo(noIcon);
-        // Intent Action
-        assertThat(cursor.getString(13)).isNull();
-        // Target Package
-        assertThat(cursor.getString(14)).isNull();
-        // Target Class
-        assertThat(cursor.getString(15)).isNull();
-        // Enabled
-        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
-        // Data ref key
-        assertThat(cursor.getString(17)).isNull();
-        // User Id
-        assertThat(cursor.getInt(18)).isEqualTo(userId);
-        // Payload Type - default is 0
-        assertThat(cursor.getInt(19)).isEqualTo(0);
-        // Payload - should be updated to real payloads as controllers are added
-        byte[] payload = cursor.getBlob(20);
-        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
-                ResultPayload.CREATOR);
-        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
-    }
-
-    @Test
-    public void testResourceProvider_resourceRowInserted() {
-        SearchIndexableResource resource = getFakeResource(0);
-        resource.className = "com.android.settings.LegalSettings";
-
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
-        assertThat(cursor.getCount()).isEqualTo(6);
-    }
-
-    @Test
-    public void testResourceProvider_resourceRowMatches() {
-        SearchIndexableResource resource = getFakeResource(0 /* xml */);
-        resource.className = "com.android.settings.display.ScreenZoomSettings";
-
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
-        cursor.moveToPosition(0);
-
-        // Locale
-        assertThat(cursor.getString(0)).isEqualTo(localeStr);
-        // Data Rank
-        assertThat(cursor.getInt(1)).isEqualTo(0);
-        // Data Title
-        assertThat(cursor.getString(2)).isEqualTo("Display size");
-        // Normalized Title
-        assertThat(cursor.getString(3)).isEqualTo("display size");
-        // Summary On
-        assertThat(cursor.getString(4)).isEmpty();
-        // Summary On Normalized
-        assertThat(cursor.getString(5)).isEmpty();
-        // Summary Off - only on for checkbox preferences
-        assertThat(cursor.getString(6)).isEmpty();
-        // Summary off normalized - only on for checkbox preferences
-        assertThat(cursor.getString(7)).isEmpty();
-        // Entries - only on for list preferences
-        assertThat(cursor.getString(8)).isNull();
-        // Keywords
-        assertThat(cursor.getString(9)).isEqualTo(
-                "display density screen zoom scale scaling");
-        // Screen Title
-        assertThat(cursor.getString(10)).isEqualTo("Display size");
-        // Class Name
-        assertThat(cursor.getString(11))
-                .isEqualTo("com.android.settings.display.ScreenZoomSettings");
-        // Icon
-        assertThat(cursor.getInt(12)).isEqualTo(noIcon);
-        // Intent Action
-        assertThat(cursor.getString(13)).isNull();
-        // Target Package
-        assertThat(cursor.getString(14)).isNull();
-        // Target Class
-        assertThat(cursor.getString(15)).isNull();
-        // Enabled
-        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
-        // Data ref key
-        assertThat(cursor.getString(17)).isNull();
-        // User Id
-        assertThat(cursor.getInt(18)).isEqualTo(userId);
-        // Payload Type - default is 0
-        assertThat(cursor.getInt(19)).isEqualTo(0);
-        // Payload - should be updated to real payloads as controllers are added
-        byte[] payload = cursor.getBlob(20);
-        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
-                ResultPayload.CREATOR);
-        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
-    }
-
-    @Test
-    public void testResourceProvider_disabledResource_rowsInserted() {
-        SearchIndexableResource resource = getFakeResource(0 /* xml */);
-        resource.className = "com.android.settings.LegalSettings";
-
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
-                new HashMap<String, Set<String>>());
-
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
-        assertThat(cursor.getCount()).isEqualTo(1);
-        cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
-        assertThat(cursor.getCount()).isEqualTo(5);
-    }
-
-    @Test
-    public void testResource_withTitleAndSettingName_titleNotInserted() {
-        SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
-        mManager.indexFromResource(mDb, localeStr, resource, new ArrayList<String>());
-
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE" +
-                " enabled = 1", null);
-        assertThat(cursor.getCount()).isEqualTo(1);
-    }
-
-    @Test
-    public void testResourceProvider_nonSubsettingIntent() {
-        SearchIndexableResource resource = getFakeResource(0 /* xml */);
-        String fakeAction = "fake_action";
-        resource.className = "com.android.settings.LegalSettings";
-        resource.intentAction = fakeAction;
-        resource.intentTargetPackage = SearchIndexableResources.SUBSETTING_TARGET_PACKAGE;
-
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
-        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
-        cursor.moveToPosition(0);
-
-        // Intent Action
-        assertThat(cursor.getString(13)).isEqualTo(fakeAction);
-        // Target Package
-        assertThat(cursor.getString(14))
-                .isEqualTo(SearchIndexableResources.SUBSETTING_TARGET_PACKAGE);
-    }
-
     // Test new public indexing flow
 
     @Test
@@ -825,14 +277,6 @@
     }
 
     @Test
-    public void testFullUpdatedDatabase_noData_addDataToDatabaseNotCalled() {
-        PreIndexData emptydata = new PreIndexData();
-        mManager.updateDatabase(emptydata, true /* isFullIndex */, localeStr);
-        verify(mManager, times(0)).addDataToDatabase(any(SQLiteDatabase.class), anyString(),
-                anyList(), anyMap());
-    }
-
-    @Test
     public void testLocaleUpdated_afterIndexing_localeNotAdded() {
         PreIndexData emptydata = new PreIndexData();
         mManager.updateDatabase(emptydata, true /* isFullIndex */, localeStr);
@@ -1013,28 +457,6 @@
         return data;
     }
 
-    private SearchIndexableResource getFakeResource(int xml) {
-        SearchIndexableResource sir = new SearchIndexableResource(mContext);
-        sir.rank = rank;
-        sir.xmlResId = xml;
-        sir.className = className;
-        sir.packageName = packageName;
-        sir.iconResId = iconResId;
-        sir.intentAction = action;
-        sir.intentTargetPackage = targetPackage;
-        sir.intentTargetClass = targetClass;
-        sir.enabled = enabled;
-        return sir;
-    }
-
-    private Map<String, Set<String>> getNonIndexableKeys(String[] keys) {
-        Map<String, Set<String>> niks = new HashMap<>();
-        Set<String> keysList = new HashSet<>();
-        keysList.addAll(Arrays.asList(keys));
-        niks.put(packageName, keysList);
-        return niks;
-    }
-
     private void insertSpecialCase(String specialCase, boolean enabled, String key) {
         ContentValues values = new ContentValues();
         values.put(IndexDatabaseHelper.IndexColumns.DOCID, specialCase.hashCode());
diff --git a/tests/robotests/src/com/android/settings/search/InlineListPayloadTest.java b/tests/robotests/src/com/android/settings/search/InlineListPayloadTest.java
index bee8d93..fc15205 100644
--- a/tests/robotests/src/com/android/settings/search/InlineListPayloadTest.java
+++ b/tests/robotests/src/com/android/settings/search/InlineListPayloadTest.java
@@ -40,7 +40,7 @@
                 intent, true /* isAvailable */, 1 /* numOptions */, 1 /* default */);
 
         final Intent retainedIntent = payload.getIntent();
-        assertThat(payload.mSettingKey).isEqualTo(uri);
+        assertThat(payload.getKey()).isEqualTo(uri);
         assertThat(payload.getType()).isEqualTo(type);
         assertThat(payload.mSettingSource).isEqualTo(source);
         assertThat(payload.getAvailability()).isEqualTo(ResultPayload.Availability.AVAILABLE);
@@ -69,7 +69,7 @@
                 .CREATOR.createFromParcel(parcel);
 
         final Intent builtIntent = payload.getIntent();
-        assertThat(payload.mSettingKey).isEqualTo(uri);
+        assertThat(payload.getKey()).isEqualTo(uri);
         assertThat(payload.getType()).isEqualTo(type);
         assertThat(payload.mSettingSource).isEqualTo(source);
         assertThat(payload.getAvailability()).isEqualTo(ResultPayload.Availability.AVAILABLE);
diff --git a/tests/robotests/src/com/android/settings/search/InlineSwitchPayloadTest.java b/tests/robotests/src/com/android/settings/search/InlineSwitchPayloadTest.java
index b067ea6..64778a0 100644
--- a/tests/robotests/src/com/android/settings/search/InlineSwitchPayloadTest.java
+++ b/tests/robotests/src/com/android/settings/search/InlineSwitchPayloadTest.java
@@ -64,7 +64,7 @@
         InlineSwitchPayload payload = new InlineSwitchPayload(uri, source, 1, intent, true,
                 1 /* default */);
         final Intent retainedIntent = payload.getIntent();
-        assertThat(payload.mSettingKey).isEqualTo(uri);
+        assertThat(payload.getKey()).isEqualTo(uri);
         assertThat(payload.getType()).isEqualTo(type);
         assertThat(payload.mSettingSource).isEqualTo(source);
         assertThat(payload.isStandard()).isTrue();
@@ -93,7 +93,7 @@
         InlineSwitchPayload payload = InlineSwitchPayload.CREATOR.createFromParcel(parcel);
 
         final Intent builtIntent = payload.getIntent();
-        assertThat(payload.mSettingKey).isEqualTo(uri);
+        assertThat(payload.getKey()).isEqualTo(uri);
         assertThat(payload.getType()).isEqualTo(type);
         assertThat(payload.mSettingSource).isEqualTo(source);
         assertThat(payload.isStandard()).isTrue();
diff --git a/tests/robotests/src/com/android/settings/search/indexing/IndexDataConverterTest.java b/tests/robotests/src/com/android/settings/search/indexing/IndexDataConverterTest.java
new file mode 100644
index 0000000..89aa62e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/search/indexing/IndexDataConverterTest.java
@@ -0,0 +1,689 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.settings.search.indexing;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.provider.SearchIndexableResource;
+import com.android.settings.TestConfig;
+import com.android.settings.search.IndexDatabaseHelper;
+import com.android.settings.search.ResultPayload;
+import com.android.settings.search.ResultPayloadUtils;
+import com.android.settings.search.SearchIndexableRaw;
+import com.android.settings.search.SearchIndexableResources;
+import com.android.settings.testutils.DatabaseTestUtils;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import static com.android.settings.R.*;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class IndexDataConverterTest {
+
+    private final String localeStr = "en_US";
+
+    private final int rank = 8;
+    private final String title = "title\u2011title";
+    private final String updatedTitle = "title-title";
+    private final String normalizedTitle = "titletitle";
+    private final String summaryOn = "summary\u2011on";
+    private final String updatedSummaryOn = "summary-on";
+    private final String normalizedSummaryOn = "summaryon";
+    private final String summaryOff = "summary\u2011off";
+    private final String updatedSummaryOff = "summary-off";
+    private final String normalizedSummaryOff = "summaryoff";
+    private final String entries = "entries";
+    private final String keywords = "keywords, keywordss, keywordsss";
+    private final String spaceDelimittedKeywords = "keywords keywordss keywordsss";
+    private final String screenTitle = "screen title";
+    private final String className = "class name";
+    private final int iconResId = 0xff;
+    private final int noIcon = 0;
+    private final String action = "action";
+    private final String targetPackage = "target package";
+    private final String targetClass = "target class";
+    private final String packageName = "package name";
+    private final String key = "key";
+    private final int userId = -1;
+    private final boolean enabled = true;
+
+    private Context mContext;
+
+    private IndexDataConverter mConverter;
+    private SQLiteDatabase mDb;
+
+    @Before
+    public void setUp() {
+        mContext = spy(RuntimeEnvironment.application);
+        mDb = IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
+        mConverter = spy(new IndexDataConverter(mContext, mDb));
+    }
+
+    @After
+    public void cleanUp() {
+        DatabaseTestUtils.clearDb(mContext);
+    }
+
+    @Test
+    public void testInsertRawColumn_rowInserted() {
+        SearchIndexableRaw raw = getFakeRaw();
+        mConverter.indexOneSearchIndexableData(localeStr, raw,
+                new HashMap<>()/* Non-indexable keys */);
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+        assertThat(cursor.getCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void testInsertRawColumn_nonIndexableKey_resultIsDisabled() {
+        SearchIndexableRaw raw = getFakeRaw();
+        Map<String, Set<String>> niks = new HashMap<>();
+        Set<String> keys = new HashSet<>();
+        keys.add(raw.key);
+        niks.put(raw.intentTargetPackage, keys);
+
+        mConverter.indexOneSearchIndexableData(localeStr, raw, niks);
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
+        assertThat(cursor.getCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void testInsertRawColumn_rowMatches() {
+        SearchIndexableRaw raw = getFakeRaw();
+        mConverter.indexOneSearchIndexableData(localeStr, raw,
+                new HashMap<>()/* Non-indexable keys */);
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+        cursor.moveToPosition(0);
+
+        // Locale
+        assertThat(cursor.getString(0)).isEqualTo(localeStr);
+        // Data Rank
+        assertThat(cursor.getInt(1)).isEqualTo(raw.rank);
+        // Data Title
+        assertThat(cursor.getString(2)).isEqualTo(updatedTitle);
+        // Normalized Title
+        assertThat(cursor.getString(3)).isEqualTo(normalizedTitle);
+        // Summary On
+        assertThat(cursor.getString(4)).isEqualTo(updatedSummaryOn);
+        // Summary On Normalized
+        assertThat(cursor.getString(5)).isEqualTo(normalizedSummaryOn);
+        // Summary Off
+        assertThat(cursor.getString(6)).isEqualTo(updatedSummaryOff);
+        // Summary off normalized
+        assertThat(cursor.getString(7)).isEqualTo(normalizedSummaryOff);
+        // Entries
+        assertThat(cursor.getString(8)).isEqualTo(raw.entries);
+        // Keywords
+        assertThat(cursor.getString(9)).isEqualTo(spaceDelimittedKeywords);
+        // Screen Title
+        assertThat(cursor.getString(10)).isEqualTo(raw.screenTitle);
+        // Class Name
+        assertThat(cursor.getString(11)).isEqualTo(raw.className);
+        // Icon
+        assertThat(cursor.getInt(12)).isEqualTo(raw.iconResId);
+        // Intent Action
+        assertThat(cursor.getString(13)).isEqualTo(raw.intentAction);
+        // Target Package
+        assertThat(cursor.getString(14)).isEqualTo(raw.intentTargetPackage);
+        // Target Class
+        assertThat(cursor.getString(15)).isEqualTo(raw.intentTargetClass);
+        // Enabled
+        assertThat(cursor.getInt(16) == 1).isEqualTo(raw.enabled);
+        // Data ref key
+        assertThat(cursor.getString(17)).isNotNull();
+        // User Id
+        assertThat(cursor.getInt(18)).isEqualTo(raw.userId);
+        // Payload Type - default is 0
+        assertThat(cursor.getInt(19)).isEqualTo(0);
+        // Payload
+        byte[] payload = cursor.getBlob(20);
+        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
+                ResultPayload.CREATOR);
+        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
+    }
+
+    @Test
+    public void testInsertRawColumn_mismatchedLocale_noRowInserted() {
+        SearchIndexableRaw raw = getFakeRaw("ca-fr");
+        mConverter.indexOneSearchIndexableData(localeStr, raw, null /* Non-indexable keys */);
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+        assertThat(cursor.getCount()).isEqualTo(0);
+    }
+
+    // Tests for the flow: IndexOneResource -> IndexFromResource ->
+    //                     UpdateOneRowWithFilteredData -> UpdateOneRow
+
+    @Test
+    public void testNullResource_NothingInserted() {
+        mConverter.indexOneSearchIndexableData(localeStr, null /* searchIndexableResource */,
+                new HashMap<>());
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+        assertThat(cursor.getCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void testAddResource_RowsInserted() {
+        SearchIndexableResource resource = getFakeResource(xml.display_settings);
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+        assertThat(cursor.getCount()).isEqualTo(17);
+    }
+
+    @Test
+    public void testAddResource_withNIKs_rowsInsertedDisabled() {
+        SearchIndexableResource resource = getFakeResource(xml.display_settings);
+        // Only add 2 of 16 items to be disabled.
+        String[] keys = {"brightness", "wallpaper"};
+        Map<String, Set<String>> niks = getNonIndexableKeys(keys);
+
+        mConverter.indexOneSearchIndexableData(localeStr, resource, niks);
+
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
+        assertThat(cursor.getCount()).isEqualTo(2);
+        cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
+        assertThat(cursor.getCount()).isEqualTo(15);
+    }
+
+    @Test
+    public void testAddResourceHeader_rowsMatch() {
+        SearchIndexableResource resource = getFakeResource(xml.application_settings);
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
+        cursor.moveToPosition(1);
+
+        // Locale
+        assertThat(cursor.getString(0)).isEqualTo(localeStr);
+        // Data Rank
+        assertThat(cursor.getInt(1)).isEqualTo(rank);
+        // Data Title
+        assertThat(cursor.getString(2)).isEqualTo("App info");
+        // Normalized Title
+        assertThat(cursor.getString(3)).isEqualTo("app info");
+        // Summary On
+        assertThat(cursor.getString(4)).isEqualTo("Manage apps, set up quick launch shortcuts");
+        // Summary On Normalized
+        assertThat(cursor.getString(5)).isEqualTo("manage apps, set up quick launch shortcuts");
+        // Summary Off - only on for checkbox preferences
+        assertThat(cursor.getString(6)).isEmpty();
+        // Summary off normalized - only on for checkbox preferences
+        assertThat(cursor.getString(7)).isEmpty();
+        // Entries - only on for list preferences
+        assertThat(cursor.getString(8)).isNull();
+        // Keywords
+        assertThat(cursor.getString(9)).isEmpty();
+        // Screen Title
+        assertThat(cursor.getString(10)).isEqualTo("App info");
+        // Class Name
+        assertThat(cursor.getString(11)).isEqualTo(className);
+        // Icon
+        assertThat(cursor.getInt(12)).isEqualTo(0);
+        // Intent Action
+        assertThat(cursor.getString(13)).isEqualTo(action);
+        // Target Package
+        assertThat(cursor.getString(14)).isEqualTo(targetPackage);
+        // Target Class
+        assertThat(cursor.getString(15)).isEqualTo(targetClass);
+        // Enabled
+        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
+        // Data ref key
+        assertThat(cursor.getString(17)).isEqualTo("applications_settings");
+        // User Id
+        assertThat(cursor.getInt(18)).isEqualTo(userId);
+        // Payload Type - default is 0
+        assertThat(cursor.getInt(19)).isEqualTo(0);
+        // Payload - should be updated to real payloads as controllers are added
+        byte[] payload = cursor.getBlob(20);
+        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
+                ResultPayload.CREATOR);
+        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
+    }
+
+    @Test
+    public void testAddResource_customSetting_rowsMatch() {
+        SearchIndexableResource resource = getFakeResource(xml.swipe_to_notification_settings);
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+        final String prefTitle =
+                mContext.getString(string.fingerprint_swipe_for_notifications_title);
+        final String prefSummary =
+                mContext.getString(string.fingerprint_swipe_for_notifications_summary);
+        final String keywords = mContext.getString(string.keywords_gesture);
+        Cursor cursor = mDb.rawQuery(
+                "SELECT * FROM prefs_index where data_title='" + prefTitle + "'", null);
+        cursor.moveToFirst();
+
+        // Locale
+        assertThat(cursor.getString(0)).isEqualTo(localeStr);
+        // Data Rank
+        assertThat(cursor.getInt(1)).isEqualTo(rank);
+        // Data Title
+        assertThat(cursor.getString(2)).isEqualTo(prefTitle);
+        // Normalized Title
+        assertThat(cursor.getString(3)).isEqualTo(prefTitle.toLowerCase());
+        // Summary On
+        assertThat(cursor.getString(4)).isEqualTo(prefSummary);
+        // Summary On Normalized
+        assertThat(cursor.getString(5)).isEqualTo(prefSummary.toLowerCase());
+        // Summary Off - only on for checkbox preferences
+        assertThat(cursor.getString(6)).isEmpty();
+        // Summary off normalized - only on for checkbox preferences
+        assertThat(cursor.getString(7)).isEmpty();
+        // Entries - only on for list preferences
+        assertThat(cursor.getString(8)).isNull();
+        // Keywords
+        assertThat(cursor.getString(9)).isEqualTo(keywords);
+        // Screen Title
+        assertThat(cursor.getString(10)).isEqualTo(
+                mContext.getString(string.fingerprint_swipe_for_notifications_title));
+        // Class Name
+        assertThat(cursor.getString(11)).isEqualTo(className);
+        // Icon
+        assertThat(cursor.getInt(12)).isEqualTo(noIcon);
+        // Intent Action
+        assertThat(cursor.getString(13)).isEqualTo(action);
+        // Target Package
+        assertThat(cursor.getString(14)).isEqualTo(targetPackage);
+        // Target Class
+        assertThat(cursor.getString(15)).isEqualTo(targetClass);
+        // Enabled
+        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
+        // Data ref key
+        assertThat(cursor.getString(17)).isEqualTo("gesture_swipe_down_fingerprint");
+        // User Id
+        assertThat(cursor.getInt(18)).isEqualTo(userId);
+        // Payload Type - default is 0
+        assertThat(cursor.getInt(19)).isEqualTo(0);
+        // Payload - should be updated to real payloads as controllers are added
+        byte[] payload = cursor.getBlob(20);
+        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
+                ResultPayload.CREATOR);
+        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
+    }
+
+    @Test
+    public void testAddResource_checkboxPreference_rowsMatch() {
+        SearchIndexableResource resource = getFakeResource(xml.application_settings);
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+
+        /* Should return 6 results, with the following titles:
+         * Advanced Settings, Apps, Manage Apps, Preferred install location, Running Services
+         */
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
+        cursor.moveToPosition(0);
+        // Locale
+        assertThat(cursor.getString(0)).isEqualTo(localeStr);
+        // Data Rank
+        assertThat(cursor.getInt(1)).isEqualTo(rank);
+        // Data Title
+        assertThat(cursor.getString(2)).isEqualTo("Advanced settings");
+        // Normalized Title
+        assertThat(cursor.getString(3)).isEqualTo("advanced settings");
+        // Summary On
+        assertThat(cursor.getString(4)).isEqualTo("Enable more settings options");
+        // Summary On Normalized
+        assertThat(cursor.getString(5)).isEqualTo("enable more settings options");
+        // Summary Off
+        assertThat(cursor.getString(6)).isEqualTo("Enable more settings options");
+        // Summary Off
+        assertThat(cursor.getString(7)).isEqualTo("enable more settings options");
+        // Entries - only on for list preferences
+        assertThat(cursor.getString(8)).isNull();
+        // Keywords
+        assertThat(cursor.getString(9)).isEmpty();
+        // Screen Title
+        assertThat(cursor.getString(10)).isEqualTo("App info");
+        // Class Name
+        assertThat(cursor.getString(11)).isEqualTo(className);
+        // Icon
+        assertThat(cursor.getInt(12)).isEqualTo(noIcon);
+        // Intent Action
+        assertThat(cursor.getString(13)).isEqualTo(action);
+        // Target Package
+        assertThat(cursor.getString(14)).isEqualTo(targetPackage);
+        // Target Class
+        assertThat(cursor.getString(15)).isEqualTo(targetClass);
+        // Enabled
+        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
+        // Data ref key
+        assertThat(cursor.getString(17)).isEqualTo("toggle_advanced_settings");
+        // User Id
+        assertThat(cursor.getInt(18)).isEqualTo(userId);
+        // Payload Type - default is 0
+        assertThat(cursor.getInt(19)).isEqualTo(0);
+        // Payload - should be updated to real payloads as controllers are added
+        byte[] payload = cursor.getBlob(20);
+        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
+                ResultPayload.CREATOR);
+        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
+    }
+
+    @Test
+    public void testAddResource_listPreference_rowsMatch() {
+        SearchIndexableResource resource = getFakeResource(xml.application_settings);
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
+        cursor.moveToPosition(3);
+        // Locale
+        assertThat(cursor.getString(0)).isEqualTo(localeStr);
+        // Data Rank
+        assertThat(cursor.getInt(1)).isEqualTo(rank);
+        // Data Title
+        assertThat(cursor.getString(2)).isEqualTo("Preferred install location");
+        // Normalized Title
+        assertThat(cursor.getString(3)).isEqualTo("preferred install location");
+        // Summary On
+        assertThat(cursor.getString(4)).isEqualTo(
+                "Change the preferred installation location for new apps");
+        // Summary On Normalized
+        assertThat(cursor.getString(5)).isEqualTo(
+                "change the preferred installation location for new apps");
+        // Summary Off - only on for checkbox preferences
+        assertThat(cursor.getString(6)).isEmpty();
+        // Summary off normalized - only on for checkbox preferences
+        assertThat(cursor.getString(7)).isEmpty();
+        // Entries - only on for list preferences
+        assertThat(cursor.getString(8)).isEqualTo("Internal device storage|Removable SD card|" +
+                "Let the system decide|");
+        // Keywords
+        assertThat(cursor.getString(9)).isEmpty();
+        // Screen Title
+        assertThat(cursor.getString(10)).isEqualTo("App info");
+        // Class Name
+        assertThat(cursor.getString(11)).isEqualTo(className);
+        // Icon
+        assertThat(cursor.getInt(12)).isEqualTo(noIcon);
+        // Intent Action
+        assertThat(cursor.getString(13)).isEqualTo(action);
+        // Target Package
+        assertThat(cursor.getString(14)).isEqualTo(targetPackage);
+        // Target Class
+        assertThat(cursor.getString(15)).isEqualTo(targetClass);
+        // Enabled
+        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
+        // Data ref key
+        assertThat(cursor.getString(17)).isEqualTo("app_install_location");
+        // User Id
+        assertThat(cursor.getInt(18)).isEqualTo(userId);
+        // Payload Type - default is 0
+        assertThat(cursor.getInt(19)).isEqualTo(0);
+        // Payload - should be updated to real payloads as controllers are added
+        byte[] payload = cursor.getBlob(20);
+        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
+                ResultPayload.CREATOR);
+        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
+    }
+
+    @Test
+    public void testAddResource_iconAddedFromXml() {
+        SearchIndexableResource resource = getFakeResource(xml.connected_devices);
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
+        cursor.moveToPosition(0);
+
+        // Icon
+        assertThat(cursor.getInt(12)).isNotEqualTo(noIcon);
+    }
+
+    // Tests for the flow: IndexOneResource -> IndexFromProvider -> IndexFromResource ->
+    //                     UpdateOneRowWithFilteredData -> UpdateOneRow
+
+    @Test
+    public void testResourceProvider_rowInserted() {
+        SearchIndexableResource resource = getFakeResource(xml.swipe_to_notification_settings);
+        resource.xmlResId = 0;
+        resource.className = "com.android.settings.display.ScreenZoomSettings";
+
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+        assertThat(cursor.getCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void testResourceProvider_rowMatches() {
+        SearchIndexableResource resource = getFakeResource(xml.swipe_to_notification_settings);
+        resource.xmlResId = 0;
+        resource.className = "com.android.settings.display.ScreenZoomSettings";
+
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+        cursor.moveToPosition(0);
+
+        // Locale
+        assertThat(cursor.getString(0)).isEqualTo(localeStr);
+        // Data Rank
+        assertThat(cursor.getInt(1)).isEqualTo(0);
+        // Data Title
+        assertThat(cursor.getString(2)).isEqualTo("Display size");
+        // Normalized Title
+        assertThat(cursor.getString(3)).isEqualTo("display size");
+        // Summary On
+        assertThat(cursor.getString(4)).isEmpty();
+        // Summary On Normalized
+        assertThat(cursor.getString(5)).isEmpty();
+        // Summary Off - only on for checkbox preferences
+        assertThat(cursor.getString(6)).isEmpty();
+        // Summary off normalized - only on for checkbox preferences
+        assertThat(cursor.getString(7)).isEmpty();
+        // Entries - only on for list preferences
+        assertThat(cursor.getString(8)).isNull();
+        // Keywords
+        assertThat(cursor.getString(9)).isEqualTo("display density screen zoom scale scaling");
+        // Screen Title
+        assertThat(cursor.getString(10)).isEqualTo("Display size");
+        // Class Name
+        assertThat(cursor.getString(11))
+                .isEqualTo("com.android.settings.display.ScreenZoomSettings");
+        // Icon
+        assertThat(cursor.getInt(12)).isEqualTo(noIcon);
+        // Intent Action
+        assertThat(cursor.getString(13)).isNull();
+        // Target Package
+        assertThat(cursor.getString(14)).isNull();
+        // Target Class
+        assertThat(cursor.getString(15)).isNull();
+        // Enabled
+        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
+        // Data ref key
+        assertThat(cursor.getString(17)).isNull();
+        // User Id
+        assertThat(cursor.getInt(18)).isEqualTo(userId);
+        // Payload Type - default is 0
+        assertThat(cursor.getInt(19)).isEqualTo(0);
+        // Payload - should be updated to real payloads as controllers are added
+        byte[] payload = cursor.getBlob(20);
+        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
+                ResultPayload.CREATOR);
+        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
+    }
+
+    @Test
+    public void testResourceProvider_resourceRowInserted() {
+        SearchIndexableResource resource = getFakeResource(0);
+        resource.className = "com.android.settings.LegalSettings";
+
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+        assertThat(cursor.getCount()).isEqualTo(6);
+    }
+
+    @Test
+    public void testResourceProvider_resourceRowMatches() {
+        SearchIndexableResource resource = getFakeResource(0 /* xml */);
+        resource.className = "com.android.settings.display.ScreenZoomSettings";
+
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
+        cursor.moveToPosition(0);
+
+        // Locale
+        assertThat(cursor.getString(0)).isEqualTo(localeStr);
+        // Data Rank
+        assertThat(cursor.getInt(1)).isEqualTo(0);
+        // Data Title
+        assertThat(cursor.getString(2)).isEqualTo("Display size");
+        // Normalized Title
+        assertThat(cursor.getString(3)).isEqualTo("display size");
+        // Summary On
+        assertThat(cursor.getString(4)).isEmpty();
+        // Summary On Normalized
+        assertThat(cursor.getString(5)).isEmpty();
+        // Summary Off - only on for checkbox preferences
+        assertThat(cursor.getString(6)).isEmpty();
+        // Summary off normalized - only on for checkbox preferences
+        assertThat(cursor.getString(7)).isEmpty();
+        // Entries - only on for list preferences
+        assertThat(cursor.getString(8)).isNull();
+        // Keywords
+        assertThat(cursor.getString(9)).isEqualTo(
+                "display density screen zoom scale scaling");
+        // Screen Title
+        assertThat(cursor.getString(10)).isEqualTo("Display size");
+        // Class Name
+        assertThat(cursor.getString(11))
+                .isEqualTo("com.android.settings.display.ScreenZoomSettings");
+        // Icon
+        assertThat(cursor.getInt(12)).isEqualTo(noIcon);
+        // Intent Action
+        assertThat(cursor.getString(13)).isNull();
+        // Target Package
+        assertThat(cursor.getString(14)).isNull();
+        // Target Class
+        assertThat(cursor.getString(15)).isNull();
+        // Enabled
+        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
+        // Data ref key
+        assertThat(cursor.getString(17)).isNull();
+        // User Id
+        assertThat(cursor.getInt(18)).isEqualTo(userId);
+        // Payload Type - default is 0
+        assertThat(cursor.getInt(19)).isEqualTo(0);
+        // Payload - should be updated to real payloads as controllers are added
+        byte[] payload = cursor.getBlob(20);
+        ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
+                ResultPayload.CREATOR);
+        assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
+    }
+
+    @Test
+    public void testResourceProvider_disabledResource_rowsInserted() {
+        SearchIndexableResource resource = getFakeResource(0 /* xml */);
+        resource.className = "com.android.settings.LegalSettings";
+
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
+        assertThat(cursor.getCount()).isEqualTo(1);
+        cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
+        assertThat(cursor.getCount()).isEqualTo(5);
+    }
+
+    @Test
+    public void testResource_withTitleAndSettingName_titleNotInserted() {
+        SearchIndexableResource resource = getFakeResource(xml.swipe_to_notification_settings);
+        mConverter.indexFromResource(localeStr, resource, new ArrayList<>());
+
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE" +
+                " enabled = 1", null);
+        assertThat(cursor.getCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void testResourceProvider_nonSubsettingIntent() {
+        SearchIndexableResource resource = getFakeResource(0 /* xml */);
+        String fakeAction = "fake_action";
+        resource.className = "com.android.settings.LegalSettings";
+        resource.intentAction = fakeAction;
+        resource.intentTargetPackage = SearchIndexableResources.SUBSETTING_TARGET_PACKAGE;
+
+        mConverter.indexOneSearchIndexableData(localeStr, resource, new HashMap<>());
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+        cursor.moveToPosition(0);
+
+        // Intent Action
+        assertThat(cursor.getString(13)).isEqualTo(fakeAction);
+        // Target Package
+        assertThat(cursor.getString(14))
+                .isEqualTo(SearchIndexableResources.SUBSETTING_TARGET_PACKAGE);
+    }
+
+    private SearchIndexableRaw getFakeRaw() {
+        return getFakeRaw(localeStr);
+    }
+
+    private SearchIndexableRaw getFakeRaw(String localeStr) {
+        SearchIndexableRaw data = new SearchIndexableRaw(mContext);
+        data.locale = new Locale(localeStr);
+        data.rank = rank;
+        data.title = title;
+        data.summaryOn = summaryOn;
+        data.summaryOff = summaryOff;
+        data.entries = entries;
+        data.keywords = keywords;
+        data.screenTitle = screenTitle;
+        data.className = className;
+        data.packageName = packageName;
+        data.iconResId = iconResId;
+        data.intentAction = action;
+        data.intentTargetPackage = targetPackage;
+        data.intentTargetClass = targetClass;
+        data.key = key;
+        data.userId = userId;
+        data.enabled = enabled;
+        return data;
+    }
+
+    private SearchIndexableResource getFakeResource(int xml) {
+        SearchIndexableResource sir = new SearchIndexableResource(mContext);
+        sir.rank = rank;
+        sir.xmlResId = xml;
+        sir.className = className;
+        sir.packageName = packageName;
+        sir.iconResId = iconResId;
+        sir.intentAction = action;
+        sir.intentTargetPackage = targetPackage;
+        sir.intentTargetClass = targetClass;
+        sir.enabled = enabled;
+        return sir;
+    }
+
+    private Map<String, Set<String>> getNonIndexableKeys(String[] keys) {
+        Map<String, Set<String>> niks = new HashMap<>();
+        Set<String> keysList = new HashSet<>();
+        keysList.addAll(Arrays.asList(keys));
+        niks.put(packageName, keysList);
+        return niks;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/search/DatabaseRowTest.java b/tests/robotests/src/com/android/settings/search/indexing/IndexDataTest.java
similarity index 90%
rename from tests/robotests/src/com/android/settings/search/DatabaseRowTest.java
rename to tests/robotests/src/com/android/settings/search/indexing/IndexDataTest.java
index a0d3163..40be4f2 100644
--- a/tests/robotests/src/com/android/settings/search/DatabaseRowTest.java
+++ b/tests/robotests/src/com/android/settings/search/indexing/IndexDataTest.java
@@ -15,16 +15,17 @@
  *
  */
 
-package com.android.settings.search;
+package com.android.settings.search.indexing;
 
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.Context;
 
+import com.android.settings.search.InlineSwitchPayload;
+import com.android.settings.search.ResultPayload;
+import com.android.settings.search.ResultPayloadUtils;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
-import com.android.settings.search.DatabaseIndexingManager.DatabaseRow;
-import com.android.settings.search.DatabaseIndexingManager.DatabaseRow.Builder;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -36,8 +37,8 @@
 
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class DatabaseRowTest {
-    private Builder mBuilder;
+public class IndexDataTest {
+    private IndexData.Builder mBuilder;
 
     private static final String LOCALE = "locale";
     private static final String UPDATED_TITLE = "updated title";
@@ -69,13 +70,13 @@
 
     @Test
     public void testFullRowBuild_nonNull() {
-        DatabaseRow row = generateRow();
+        IndexData row = generateRow();
         assertThat(row).isNotNull();
     }
 
     @Test
     public void testPrimitivesBuild_noDataLoss() {
-        DatabaseRow row = generateRow();
+        IndexData row = generateRow();
 
         assertThat(row.locale).isEqualTo(LOCALE);
         assertThat(row.updatedTitle).isEqualTo(UPDATED_TITLE);
@@ -102,7 +103,7 @@
 
     @Test
     public void testGenericIntent_addedToPayload() {
-        final DatabaseRow row = generateRow();
+        final IndexData row = generateRow();
         final ResultPayload payload = ResultPayloadUtils.unmarshall(row.payload,
                 ResultPayload.CREATOR);
         final ComponentName name = payload.getIntent().getComponent();
@@ -116,12 +117,12 @@
         final InlineSwitchPayload payload = new InlineSwitchPayload(URI, 0 /* mSettingSource */,
                 1 /* onValue */, null /* intent */, true /* isDeviceSupported */, 1 /* default */);
         mBuilder.setPayload(payload);
-        final DatabaseRow row = generateRow();
+        final IndexData row = generateRow();
         final InlineSwitchPayload unmarshalledPayload = ResultPayloadUtils
                 .unmarshall(row.payload, InlineSwitchPayload.CREATOR);
 
         assertThat(row.payloadType).isEqualTo(ResultPayload.PayloadType.INLINE_SWITCH);
-        assertThat(unmarshalledPayload.mSettingKey).isEqualTo(URI);
+        assertThat(unmarshalledPayload.getKey()).isEqualTo(URI);
     }
 
     @Test
@@ -135,7 +136,7 @@
         final InlineSwitchPayload payload = new InlineSwitchPayload(URI, 0 /* mSettingSource */,
                 1 /* onValue */, intent, true /* isDeviceSupported */, 1 /* default */);
         mBuilder.setPayload(payload);
-        final DatabaseRow row = generateRow();
+        final IndexData row = generateRow();
         final InlineSwitchPayload unmarshalledPayload = ResultPayloadUtils
                 .unmarshall(row.payload, InlineSwitchPayload.CREATOR);
         final ComponentName name = unmarshalledPayload.getIntent().getComponent();
@@ -145,12 +146,12 @@
     }
 
 
-    private DatabaseRow generateRow() {
+    private IndexData generateRow() {
         return mBuilder.build(mContext);
     }
 
-    private DatabaseRow.Builder createBuilder() {
-        mBuilder = new DatabaseRow.Builder();
+    private IndexData.Builder createBuilder() {
+        mBuilder = new IndexData.Builder();
         mBuilder.setLocale(LOCALE)
                 .setUpdatedTitle(UPDATED_TITLE)
                 .setNormalizedTitle(NORMALIZED_TITLE)
diff --git a/tests/robotests/src/com/android/settings/search/indexing/IndexableDataCollectorTest.java b/tests/robotests/src/com/android/settings/search/indexing/PreIndexDataCollectorTest.java
similarity index 97%
rename from tests/robotests/src/com/android/settings/search/indexing/IndexableDataCollectorTest.java
rename to tests/robotests/src/com/android/settings/search/indexing/PreIndexDataCollectorTest.java
index 0f1f345..2bb03cb 100644
--- a/tests/robotests/src/com/android/settings/search/indexing/IndexableDataCollectorTest.java
+++ b/tests/robotests/src/com/android/settings/search/indexing/PreIndexDataCollectorTest.java
@@ -47,7 +47,7 @@
 
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class IndexableDataCollectorTest {
+public class PreIndexDataCollectorTest {
 
     private final String AUTHORITY_ONE = "authority";
     private final String PACKAGE_ONE = "com.android.settings";
@@ -57,7 +57,7 @@
 
     Context mContext;
 
-    IndexableDataCollector mDataCollector;
+    PreIndexDataCollector mDataCollector;
 
     @Before
     public void setUp() {
@@ -66,7 +66,7 @@
         doReturn(mResolver).when(mContext).getContentResolver();
         //doReturn(mPackageManager).when(mContext).getPackageManager();
 
-        mDataCollector = spy(new IndexableDataCollector(mContext));
+        mDataCollector = spy(new PreIndexDataCollector(mContext));
     }
 
     @Test