Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80e54df8 authored by Matthew Fritze's avatar Matthew Fritze
Browse files

Move the indexing back into DatabaseIndexingManager

For the sake of incremental updates, we moved all of the
conversion from PreIndexData to IndexData, and the
insertion of the rows into the SQLite DB into a new class,
IndexDataConverter. However, it's real role is just to
convert PreIndexData into IndexData.

So this CL moves the insertion of the rows back into
DatabaseIndexingManager.

Again, for the sake of simplicity, I did not change the
conversion flow. Rather, instead of inserting a row at the
end of the conversion, I just put it into a list which is
then returned. This lets me move the tests to appropriate
locations, without having to change them too much.

In the tests, the references to real xml layouts are
changed to fake references. Hooray for being less brittle.
IndexDataConverter now just tests that the IndexData
has the appropriate data from PreIndexdData.

Independently, we test that IndexData gets inserted in
DatabaseIndexingManager.

In the next CL, I'll refactor the conversion
flow for readability.

Bug: 33577327
Test: make RunSettingsRoboTests
Test: Took a database dump before and after change,
      and they were the same. Cool.

Change-Id: I39cc812d1f736e13a0a51af50984c239961ecf7a
parent c1b9a8e5
Loading
Loading
Loading
Loading
+81 −10
Original line number Diff line number Diff line
@@ -23,7 +23,24 @@ import static com.android.settings.search.DatabaseResultLoader
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.DOCID;
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_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;

import android.content.ContentValues;
@@ -38,10 +55,12 @@ import android.os.Build;
import android.provider.SearchIndexableResource;
import android.provider.SearchIndexablesContract;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;

import com.android.settings.overlay.FeatureFactory;

import com.android.settings.search.indexing.IndexData;
import com.android.settings.search.indexing.IndexDataConverter;
import com.android.settings.search.indexing.PreIndexData;
import com.android.settings.search.indexing.PreIndexDataCollector;
@@ -49,6 +68,7 @@ import com.android.settings.search.indexing.PreIndexDataCollector;
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;

@@ -72,6 +92,7 @@ public class DatabaseIndexingManager {
    final AtomicBoolean mIsIndexingComplete = new AtomicBoolean(false);

    private PreIndexDataCollector mCollector;
    private IndexDataConverter mConverter;

    private Context mContext;

@@ -182,8 +203,8 @@ public class DatabaseIndexingManager {
     * @param localeStr       the default locale for the device.
     */
    @VisibleForTesting
    void updateDatabase(PreIndexData indexData, boolean needsReindexing, String localeStr) {
        final Map<String, Set<String>> nonIndexableKeys = indexData.nonIndexableKeys;
    void updateDatabase(PreIndexData preIndexData, boolean needsReindexing, String localeStr) {
        final Map<String, Set<String>> nonIndexableKeys = preIndexData.nonIndexableKeys;

        final SQLiteDatabase database = getWritableDatabase();
        if (database == null) {
@@ -194,8 +215,9 @@ public class DatabaseIndexingManager {
        try {
            database.beginTransaction();

            // Add new data from Providers at initial index time, or inserted later.
            addIndaxebleDataToDatabase(database, localeStr, indexData);
            // Convert all Pre-index data to Index data.
            List<IndexData> indexData = getIndexData(localeStr, preIndexData);
            insertIndexData(database, indexData);

            // Only check for non-indexable key updates after initial index.
            // Enabled state with non-indexable keys is checked when items are first inserted.
@@ -209,14 +231,64 @@ public class DatabaseIndexingManager {
        }
    }

    @VisibleForTesting
    List<IndexData> getIndexData(String locale, PreIndexData data) {
        if (mConverter == null) {
            mConverter = new IndexDataConverter(mContext);
        }
        return mConverter.convertPreIndexDataToIndexData(data, locale);
    }

    /**
     * Inserts all of the entries in {@param indexData} into the {@param database}
     * as Search Data and as part of the Information Hierarchy.
     */
    @VisibleForTesting
    void addIndaxebleDataToDatabase(SQLiteDatabase database, String locale, PreIndexData data) {
        if (data.dataToUpdate.size() == 0) {
            return;
    void insertIndexData(SQLiteDatabase database, List<IndexData> indexData) {
        ContentValues values;

        for (IndexData dataRow : indexData) {
            values = new ContentValues();
            values.put(IndexDatabaseHelper.IndexColumns.DOCID, dataRow.getDocId());
            values.put(LOCALE, dataRow.locale);
            values.put(DATA_TITLE, dataRow.updatedTitle);
            values.put(DATA_TITLE_NORMALIZED, dataRow.normalizedTitle);
            values.put(DATA_SUMMARY_ON, dataRow.updatedSummaryOn);
            values.put(DATA_SUMMARY_ON_NORMALIZED, dataRow.normalizedSummaryOn);
            values.put(DATA_ENTRIES, dataRow.entries);
            values.put(DATA_KEYWORDS, dataRow.spaceDelimitedKeywords);
            values.put(CLASS_NAME, dataRow.className);
            values.put(SCREEN_TITLE, dataRow.screenTitle);
            values.put(INTENT_ACTION, dataRow.intentAction);
            values.put(INTENT_TARGET_PACKAGE, dataRow.intentTargetPackage);
            values.put(INTENT_TARGET_CLASS, dataRow.intentTargetClass);
            values.put(ICON, dataRow.iconResId);
            values.put(ENABLED, dataRow.enabled);
            values.put(DATA_KEY_REF, dataRow.key);
            values.put(USER_ID, dataRow.userId);
            values.put(PAYLOAD_TYPE, dataRow.payloadType);
            values.put(PAYLOAD, dataRow.payload);

            database.replaceOrThrow(TABLE_PREFS_INDEX, null, values);

            if (!TextUtils.isEmpty(dataRow.className)
                    && !TextUtils.isEmpty(dataRow.childClassName)) {
                ContentValues siteMapPair = new ContentValues();
                final int pairDocId = Objects.hash(dataRow.className, dataRow.childClassName);
                siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.DOCID, pairDocId);
                siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.PARENT_CLASS,
                        dataRow.className);
                siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.PARENT_TITLE,
                        dataRow.screenTitle);
                siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.CHILD_CLASS,
                        dataRow.childClassName);
                siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.CHILD_TITLE,
                        dataRow.updatedTitle);

                database.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_SITE_MAP,
                        null /* nullColumnHack */, siteMapPair);
            }
        }
        IndexDataConverter manager = new IndexDataConverter(mContext, database);
        manager.addDataToDatabase(locale, data.dataToUpdate, data.nonIndexableKeys);
    }

    /**
@@ -288,7 +360,6 @@ public class DatabaseIndexingManager {
        disabledResults.close();
    }


    /**
     * TODO (b/64951285): Deprecate this method
     *
+47 −100
Original line number Diff line number Diff line
@@ -17,10 +17,8 @@

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;
@@ -32,7 +30,6 @@ 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;
@@ -44,33 +41,10 @@ import org.xmlpull.v1.XmlPullParserException;
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 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}.
 *
@@ -86,56 +60,65 @@ public class IndexDataConverter {
    private static final String NODE_NAME_CHECK_BOX_PREFERENCE = "CheckBoxPreference";
    private static final String NODE_NAME_LIST_PREFERENCE = "ListPreference";

    private Context mContext;
    private final Context mContext;

    private String mLocale;

    private SQLiteDatabase mDb;
    private List<IndexData> mIndexData;

    public IndexDataConverter(Context context, SQLiteDatabase database) {
    public IndexDataConverter(Context context) {
        mContext = context;
        mDb = database;
        mLocale = Locale.getDefault().toString();
    }

    public List<IndexData> convertPreIndexDataToIndexData(PreIndexData preIndexData,
            String locale) {
        mLocale = locale;
        mIndexData = new ArrayList<>();
        List<SearchIndexableData> dataToUpdate = preIndexData.dataToUpdate;
        Map<String, Set<String>> nonIndexableKeys = preIndexData.nonIndexableKeys;
        parsePreIndexData(dataToUpdate, nonIndexableKeys);
        return mIndexData;
    }

    /**
     * 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,
    private void parsePreIndexData(List<SearchIndexableData> dataToUpdate,
            Map<String, Set<String>> nonIndexableKeys) {
        final long current = System.currentTimeMillis();

        for (SearchIndexableData data : dataToUpdate) {
            try {
                indexOneSearchIndexableData(localeStr, data, nonIndexableKeys);
                addOneIndexData(data, nonIndexableKeys);
            } catch (Exception e) {
                Log.e(LOG_TAG, "Cannot index: " + (data != null ? data.className : data)
                        + " for locale: " + localeStr, e);
                        + " for locale: " + mLocale, e);
            }
        }

        final long now = System.currentTimeMillis();
        Log.d(LOG_TAG, "Indexing locale '" + localeStr + "' took " +
        Log.d(LOG_TAG, "Indexing locale '" + mLocale + "' took " +
                (now - current) + " millis");
    }

    @VisibleForTesting
    void indexOneSearchIndexableData(String localeStr, SearchIndexableData data,
    private void addOneIndexData(SearchIndexableData data,
            Map<String, Set<String>> nonIndexableKeys) {
        if (data instanceof SearchIndexableResource) {
            indexOneResource(localeStr, (SearchIndexableResource) data, nonIndexableKeys);
            addOneResource((SearchIndexableResource) data, nonIndexableKeys);
        } else if (data instanceof SearchIndexableRaw) {
            indexOneRaw(localeStr, (SearchIndexableRaw) data, nonIndexableKeys);
            addOneRaw((SearchIndexableRaw) data, nonIndexableKeys);
        }
    }

    @VisibleForTesting
    void indexOneRaw(String localeStr, SearchIndexableRaw raw, Map<String,
    private void addOneRaw(SearchIndexableRaw raw, Map<String,
            Set<String>> nonIndexableKeysFromResource) {
        // Should be the same locale as the one we are processing
        if (!raw.locale.toString().equalsIgnoreCase(localeStr)) {
        if (!raw.locale.toString().equalsIgnoreCase(mLocale)) {
            return;
        }

@@ -149,7 +132,7 @@ public class IndexDataConverter {
        IndexData.Builder builder = new IndexData.Builder();
        builder.setTitle(raw.title)
                .setSummaryOn(raw.summaryOn)
                .setLocale(localeStr)
                .setLocale(mLocale)
                .setEntries(raw.entries)
                .setKeywords(raw.keywords)
                .setClassName(raw.className)
@@ -162,11 +145,10 @@ public class IndexDataConverter {
                .setKey(raw.key)
                .setUserId(raw.userId);

        updateOneRow(builder.build(mContext));
        addRowToData(builder.build(mContext));
    }

    @VisibleForTesting
    void indexOneResource(String localeStr, SearchIndexableResource sir,
    private void addOneResource(SearchIndexableResource sir,
        Map<String, Set<String>> nonIndexableKeysFromResource) {

        if (sir == null) {
@@ -182,7 +164,7 @@ public class IndexDataConverter {
                nonIndexableKeys.addAll(resNonIndexableKeys);
            }

            indexFromResource(localeStr, sir, nonIndexableKeys);
            addIndexDataFromResource(sir, nonIndexableKeys);
        } else {
            if (TextUtils.isEmpty(sir.className)) {
                Log.w(LOG_TAG, "Cannot index an empty Search Provider name!");
@@ -202,17 +184,16 @@ public class IndexDataConverter {
                    DatabaseIndexingUtils.getSearchIndexProvider(clazz);
            if (provider != null) {
                List<String> providerNonIndexableKeys = provider.getNonIndexableKeys(sir.context);
                if (providerNonIndexableKeys != null && providerNonIndexableKeys.size() > 0) {
                if (providerNonIndexableKeys != null) {
                    nonIndexableKeys.addAll(providerNonIndexableKeys);
                }

                indexFromProvider(localeStr, provider, sir, nonIndexableKeys);
                addIndexDataFromProvider(provider, sir, nonIndexableKeys);
            }
        }
    }

    @VisibleForTesting
    void indexFromResource(String localeStr, SearchIndexableResource sir,
    private void addIndexDataFromResource(SearchIndexableResource sir,
            List<String> nonIndexableKeys) {
        final Context context = sir.context;
        XmlResourceParser parser = null;
@@ -274,7 +255,7 @@ public class IndexDataConverter {
            headerBuilder.setTitle(headerTitle)
                    .setSummaryOn(headerSummary)
                    .setKeywords(headerKeywords)
                    .setLocale(localeStr)
                    .setLocale(mLocale)
                    .setClassName(fragmentName)
                    .setScreenTitle(screenTitle)
                    .setIntentAction(intentAction)
@@ -308,7 +289,7 @@ public class IndexDataConverter {

                builder = new IndexData.Builder();
                builder.setTitle(title)
                        .setLocale(localeStr)
                        .setLocale(mLocale)
                        .setKeywords(keywords)
                        .setClassName(fragmentName)
                        .setScreenTitle(screenTitle)
@@ -339,7 +320,7 @@ public class IndexDataConverter {
                            .setPayload(payload);

                    // Insert rows for the child nodes of PreferenceScreen
                    updateOneRow(builder.build(mContext));
                    addRowToData(builder.build(mContext));
                } else {
                    // TODO (b/33577327) We removed summary off here. We should check if we can
                    // merge this 'else' section with the one above. Put a break point to
@@ -353,13 +334,13 @@ public class IndexDataConverter {

                    builder.setSummaryOn(summaryOn);

                    updateOneRow(builder.build(mContext));
                    addRowToData(builder.build(mContext));
                }
            }

            // The xml header's title does not match the title of one of the child settings.
            if (isHeaderUnique) {
                updateOneRow(headerBuilder.build(mContext));
                addRowToData(headerBuilder.build(mContext));
            }
        } catch (XmlPullParserException e) {
            throw new RuntimeException("Error parsing PreferenceScreen", e);
@@ -370,8 +351,7 @@ public class IndexDataConverter {
        }
    }

    @VisibleForTesting
    void indexFromProvider(String localeStr, Indexable.SearchIndexProvider provider,
    private void addIndexDataFromProvider(Indexable.SearchIndexProvider provider,
            SearchIndexableResource sir, List<String> nonIndexableKeys) {

        final String className = sir.className;
@@ -393,7 +373,7 @@ public class IndexDataConverter {
                SearchIndexableRaw raw = rawList.get(i);

                // Should be the same locale as the one we are processing
                if (!raw.locale.toString().equalsIgnoreCase(localeStr)) {
                if (!raw.locale.toString().equalsIgnoreCase(mLocale)) {
                    continue;
                }
                boolean enabled = !nonIndexableKeys.contains(raw.key);
@@ -401,7 +381,7 @@ public class IndexDataConverter {
                IndexData.Builder builder = new IndexData.Builder();
                builder.setTitle(raw.title)
                        .setSummaryOn(raw.summaryOn)
                        .setLocale(localeStr)
                        .setLocale(mLocale)
                        .setEntries(raw.entries)
                        .setKeywords(raw.keywords)
                        .setClassName(className)
@@ -414,7 +394,7 @@ public class IndexDataConverter {
                        .setKey(raw.key)
                        .setUserId(raw.userId);

                updateOneRow(builder.build(mContext));
                addRowToData(builder.build(mContext));
            }
        }

@@ -426,7 +406,7 @@ public class IndexDataConverter {
                SearchIndexableResource item = resList.get(i);

                // Should be the same locale as the one we are processing
                if (!item.locale.toString().equalsIgnoreCase(localeStr)) {
                if (!item.locale.toString().equalsIgnoreCase(mLocale)) {
                    continue;
                }

@@ -440,49 +420,16 @@ public class IndexDataConverter {
                        ? intentTargetPackage
                        : item.intentTargetPackage;

                indexFromResource(localeStr, item, nonIndexableKeys);
                addIndexDataFromResource(item, nonIndexableKeys);
            }
        }
    }

    private void updateOneRow(IndexData row) {
    private void addRowToData(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_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_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);
        }
        mIndexData.add(row);
    }
}
+1 −0
Original line number Diff line number Diff line
com.android.settings.development.DevelopmentSettingsDashboardFragment
com.android.settings.display.ScreenZoomPreferenceFragmentForSetupWizard
com.android.settings.search.indexing.FakeSettingsFragment
+34 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  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.

  -->

<!--
    WARNING: This resource file is used to test Settings Search indexing.
    If you change something in here, please run the settings robotests and
    make sure they still pass.
 -->

<PreferenceScreen
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
        android:title="bears_bears_bears"
        settings:keywords="keywords">

    <Preference
            android:key="pref_key_1"
            android:title="bears_bears_bears"/>
</PreferenceScreen>
 No newline at end of file
+61 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading