diff --git a/src/com/android/settings/search2/CursorToSearchResultConverter.java b/src/com/android/settings/search2/CursorToSearchResultConverter.java index 3d293233007..3255c0c0e5e 100644 --- a/src/com/android/settings/search2/CursorToSearchResultConverter.java +++ b/src/com/android/settings/search2/CursorToSearchResultConverter.java @@ -35,10 +35,12 @@ import com.android.settings.search.Index; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; -import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_RANK; +import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_ID; import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_TITLE; import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_SUMMARY_ON; import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_CLASS_NAME; @@ -63,21 +65,28 @@ class CursorToSearchResultConverter { private final String TAG = "CursorConverter"; + private final String mQueryText; + private final Context mContext; - public CursorToSearchResultConverter(Context context) { + private final Set mKeys; + + public CursorToSearchResultConverter(Context context, String queryText) { mContext = context; + mKeys = new HashSet<>(); + mQueryText = queryText; } - public List convertCursor(Cursor cursorResults) { + public List convertCursor(Cursor cursorResults, int baseRank) { if (cursorResults == null) { return null; } final Map contextMap = new HashMap<>(); - final ArrayList results = new ArrayList<>(); + final List results = new ArrayList<>(); while (cursorResults.moveToNext()) { - SearchResult result = buildSingleSearchResultFromCursor(contextMap, cursorResults); + SearchResult result = buildSingleSearchResultFromCursor(contextMap, cursorResults, + baseRank); if (result != null) { results.add(result); } @@ -87,13 +96,22 @@ class CursorToSearchResultConverter { } private SearchResult buildSingleSearchResultFromCursor(Map contextMap, - Cursor cursor) { + Cursor cursor, int baseRank) { + final String docId = cursor.getString(COLUMN_INDEX_ID); + /* Make sure that this result has not yet been added as a result. Checking the docID + covers the case of multiple queries matching the same row, but we need to also to check + for potentially the same named or slightly varied names pointing to the same page. + */ + if (mKeys.contains(docId)) { + return null; + } + mKeys.add(docId); + final String pkgName = cursor.getString(COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE); final String action = cursor.getString(COLUMN_INDEX_INTENT_ACTION); final String title = cursor.getString(COLUMN_INDEX_TITLE); final String summaryOn = cursor.getString(COLUMN_INDEX_SUMMARY_ON); final String className = cursor.getString(COLUMN_INDEX_CLASS_NAME); - final int rank = cursor.getInt(COLUMN_INDEX_RANK); final String key = cursor.getString(COLUMN_INDEX_KEY); final String iconResStr = cursor.getString(COLUMN_INDEX_ICON); final int payloadType = cursor.getInt(COLUMN_INDEX_PAYLOAD_TYPE); @@ -109,9 +127,13 @@ class CursorToSearchResultConverter { return null; } + final List breadcrumbs = getBreadcrumbs(cursor); + final int rank = getRank(breadcrumbs, baseRank); + final SearchResult.Builder builder = new SearchResult.Builder(); builder.addTitle(title) .addSummary(summaryOn) + .addBreadcrumbs(breadcrumbs) .addRank(rank) .addIcon(getIconForPackage(contextMap, pkgName, className, iconResStr)) .addPayload(payload); @@ -187,4 +209,24 @@ class CursorToSearchResultConverter { } return null; } + + private List getBreadcrumbs(Cursor cursor) { + return new ArrayList<>(); + } + + /** Uses the breadcrumbs to determine the offset to the base rank. + * There are two checks + * A) If the query matches the highest level menu title + * B) If the query matches a subsequent menu title + * + * If the query matches A and B, the offset is 0. + * If the query matches A only, the offset is 1. + * If the query matches neither A nor B, the offset is 2. + * @param crumbs from the Information Architecture + * @param baseRank of the result. Lower if it's a better result. + * @return + */ + private int getRank(List crumbs, int baseRank) { + return baseRank; + } } diff --git a/src/com/android/settings/search2/DatabaseIndexingManager.java b/src/com/android/settings/search2/DatabaseIndexingManager.java index fa482efab8b..e29ffeb9122 100644 --- a/src/com/android/settings/search2/DatabaseIndexingManager.java +++ b/src/com/android/settings/search2/DatabaseIndexingManager.java @@ -108,15 +108,15 @@ public class DatabaseIndexingManager { public boolean fullIndex; public UpdateData() { - dataToUpdate = new ArrayList(); - dataToDelete = new ArrayList(); - nonIndexableKeys = new HashMap>(); + dataToUpdate = new ArrayList<>(); + dataToDelete = new ArrayList<>(); + nonIndexableKeys = new HashMap<>(); } public UpdateData(DatabaseIndexingManager.UpdateData other) { - dataToUpdate = new ArrayList(other.dataToUpdate); - dataToDelete = new ArrayList(other.dataToDelete); - nonIndexableKeys = new HashMap>(other.nonIndexableKeys); + dataToUpdate = new ArrayList<>(other.dataToUpdate); + dataToDelete = new ArrayList<>(other.dataToDelete); + nonIndexableKeys = new HashMap<>(other.nonIndexableKeys); forceUpdate = other.forceUpdate; fullIndex = other.fullIndex; } diff --git a/src/com/android/settings/search2/DatabaseResultLoader.java b/src/com/android/settings/search2/DatabaseResultLoader.java index 201d76f7440..f7acd25d45b 100644 --- a/src/com/android/settings/search2/DatabaseResultLoader.java +++ b/src/com/android/settings/search2/DatabaseResultLoader.java @@ -16,31 +16,19 @@ package com.android.settings.search2; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.Resources; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.annotation.VisibleForTesting; -import android.text.TextUtils; -import android.util.Log; -import com.android.settings.SettingsActivity; -import com.android.settings.Utils; -import com.android.settings.search.Index; import com.android.settings.search.IndexDatabaseHelper; import com.android.settings.utils.AsyncLoader; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; +import java.util.Arrays; import java.util.List; -import java.util.Map; +import static com.android.settings.search.IndexDatabaseHelper.IndexColumns; +import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX; /** * AsyncTask to retrieve Settings, First party app and any intent based results. @@ -54,30 +42,68 @@ public class DatabaseResultLoader extends AsyncLoader> { private final CursorToSearchResultConverter mConverter; /* These indices are used to match the columns of the this loader's SELECT statement. - These are not necessarily the same order or coverage as the schema defined in + These are not necessarily the same order nor similar coverage as the schema defined in IndexDatabaseHelper */ - public static final int COLUMN_INDEX_RANK = 0; - public static final int COLUMN_INDEX_TITLE = 1; - public static final int COLUMN_INDEX_SUMMARY_ON = 2; - public static final int COLUMN_INDEX_SUMMARY_OFF = 3; - public static final int COLUMN_INDEX_ENTRIES = 4; - public static final int COLUMN_INDEX_KEYWORDS = 5; - public static final int COLUMN_INDEX_CLASS_NAME = 6; - public static final int COLUMN_INDEX_SCREEN_TITLE = 7; - public static final int COLUMN_INDEX_ICON = 8; - public static final int COLUMN_INDEX_INTENT_ACTION = 9; - public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 10; - public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 11; - public static final int COLUMN_INDEX_ENABLED = 12; - public static final int COLUMN_INDEX_KEY = 13; - public static final int COLUMN_INDEX_PAYLOAD_TYPE = 14; - public static final int COLUMN_INDEX_PAYLOAD = 15; + static final int COLUMN_INDEX_ID = 0; + static final int COLUMN_INDEX_TITLE = 1; + static final int COLUMN_INDEX_SUMMARY_ON = 2; + static final int COLUMN_INDEX_SUMMARY_OFF = 3; + static final int COLUMN_INDEX_CLASS_NAME = 4; + static final int COLUMN_INDEX_SCREEN_TITLE = 5; + static final int COLUMN_INDEX_ICON = 6; + static final int COLUMN_INDEX_INTENT_ACTION = 7; + static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 8; + static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 9; + static final int COLUMN_INDEX_KEY = 10; + static final int COLUMN_INDEX_PAYLOAD_TYPE = 11; + static final int COLUMN_INDEX_PAYLOAD = 12; + + public static final String[] SELECT_COLUMNS = { + IndexColumns.DOCID, + IndexColumns.DATA_TITLE, + IndexColumns.DATA_SUMMARY_ON, + IndexColumns.DATA_SUMMARY_OFF, + IndexColumns.CLASS_NAME, + IndexColumns.SCREEN_TITLE, + IndexColumns.ICON, + IndexColumns.INTENT_ACTION, + IndexColumns.INTENT_TARGET_PACKAGE, + IndexColumns.INTENT_TARGET_CLASS, + IndexColumns.DATA_KEY_REF, + IndexColumns.PAYLOAD_TYPE, + IndexColumns.PAYLOAD + }; + + public static final String[] MATCH_COLUMNS_PRIMARY = { + IndexColumns.DATA_TITLE, + IndexColumns.DATA_TITLE_NORMALIZED, + }; + + public static final String[] MATCH_COLUMNS_SECONDARY = { + IndexColumns.DATA_SUMMARY_ON, + IndexColumns.DATA_SUMMARY_ON_NORMALIZED, + IndexColumns.DATA_SUMMARY_OFF, + IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, + }; + + public static final String[] MATCH_COLUMNS_TERTIARY = { + IndexColumns.DATA_KEYWORDS, + IndexColumns.DATA_ENTRIES + }; + + /** + * Base ranks defines the best possible rank based on what the query matches. + * If the query matches the title, the best rank it can be is 1 + * If the query only matches the summary, the best rank it can be is 4 + * If the query only matches keywords or entries, the best rank it can be is 7 + */ + private static final int[] BASE_RANKS = {1, 4, 7}; public DatabaseResultLoader(Context context, String queryText) { super(context); mDatabase = IndexDatabaseHelper.getInstance(context).getReadableDatabase(); - mQueryText = queryText; - mConverter = new CursorToSearchResultConverter(context); + mQueryText = cleanQuery(queryText); + mConverter = new CursorToSearchResultConverter(context, mQueryText); } @Override @@ -91,10 +117,34 @@ public class DatabaseResultLoader extends AsyncLoader> { return null; } - String query = getSQLQuery(); - Cursor result = mDatabase.rawQuery(query, null); + final List primaryResults; + final List secondaryResults; + final List tertiaryResults; - return mConverter.convertCursor(result); + primaryResults = query(MATCH_COLUMNS_PRIMARY, BASE_RANKS[0]); + secondaryResults = query(MATCH_COLUMNS_SECONDARY, BASE_RANKS[1]); + tertiaryResults = query(MATCH_COLUMNS_TERTIARY, BASE_RANKS[2]); + + + final List results = new ArrayList<>(primaryResults.size() + + secondaryResults.size() + + tertiaryResults.size()); + + results.addAll(primaryResults); + results.addAll(secondaryResults); + results.addAll(tertiaryResults); + return results; + } + + private List query(String[] matchColumns, int baseRank) { + final String whereClause = buildWhereClause(matchColumns); + final String[] selection = new String[matchColumns.length]; + final String query = "%" + mQueryText + "%"; + Arrays.fill(selection, query); + + final Cursor resultCursor = mDatabase.query(TABLE_PREFS_INDEX, SELECT_COLUMNS, whereClause, + selection, null, null, null); + return mConverter.convertCursor(resultCursor, baseRank); } @Override @@ -103,17 +153,24 @@ public class DatabaseResultLoader extends AsyncLoader> { return super.onCancelLoad(); } - protected String getSQLQuery() { - return String.format("SELECT data_rank, data_title, data_summary_on, " + - "data_summary_off, data_entries, data_keywords, class_name, screen_title," - + " icon, " + - "intent_action, intent_target_package, intent_target_class, enabled, " + - "data_key_reference, payload_type, payload FROM prefs_index WHERE prefs_index MATCH " - + "'data_title:%s* " + - "OR data_title_normalized:%s* OR data_keywords:%s*' AND locale = 'en_US'", - mQueryText, mQueryText, mQueryText); + /** + * A generic method to make the query suitable for searching the database. + * @return the cleaned query string + */ + private static String cleanQuery(String query) { + return query.trim(); } - - + private static String buildWhereClause(String[] matchColumns) { + StringBuilder sb = new StringBuilder(" "); + final int count = matchColumns.length; + for (int n = 0; n < count; n++) { + sb.append(matchColumns[n]); + sb.append(" like ?"); + if (n < count - 1) { + sb.append(" OR "); + } + } + return sb.toString(); + } } diff --git a/src/com/android/settings/search2/SearchResult.java b/src/com/android/settings/search2/SearchResult.java index 5bf757f947f..e817a9d4f45 100644 --- a/src/com/android/settings/search2/SearchResult.java +++ b/src/com/android/settings/search2/SearchResult.java @@ -18,7 +18,7 @@ package com.android.settings.search2; import android.graphics.drawable.Drawable; -import java.util.ArrayList; +import java.util.List; import java.util.Objects; /** @@ -42,7 +42,7 @@ public class SearchResult implements Comparable { * An ordered list of the information hierarchy. * Intent Results: Displayed a hierarchy of selections to reach the setting from the home screen */ - public final ArrayList breadcrumbs; + public final List breadcrumbs; /** * A suggestion for the ranking of the result. @@ -96,7 +96,7 @@ public class SearchResult implements Comparable { public static class Builder { protected CharSequence mTitle; protected CharSequence mSummary; - protected ArrayList mBreadcrumbs; + protected List mBreadcrumbs; protected int mRank = 42; protected ResultPayload mResultPayload; protected Drawable mIcon; @@ -111,7 +111,7 @@ public class SearchResult implements Comparable { return this; } - public Builder addBreadcrumbs(ArrayList breadcrumbs) { + public Builder addBreadcrumbs(List breadcrumbs) { mBreadcrumbs = breadcrumbs; return this; } diff --git a/tests/robotests/src/com/android/settings/search/DatabaseResultLoaderTest.java b/tests/robotests/src/com/android/settings/search/DatabaseResultLoaderTest.java new file mode 100644 index 00000000000..c592aef8dbf --- /dev/null +++ b/tests/robotests/src/com/android/settings/search/DatabaseResultLoaderTest.java @@ -0,0 +1,246 @@ +/* + * 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; + +import android.content.ContentValues; +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; +import com.android.settings.search2.DatabaseIndexingUtils; +import com.android.settings.search2.DatabaseResultLoader; +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.lang.reflect.Field; + +import static com.google.common.truth.Truth.assertThat; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class DatabaseResultLoaderTest { + private Context mContext; + + private DatabaseResultLoader loader; + + SQLiteDatabase mDb; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + mDb = IndexDatabaseHelper.getInstance(mContext).getWritableDatabase(); + setUpDb(); + } + + @After + public void cleanUp() { + Field instance; + Class clazz = IndexDatabaseHelper.class; + try { + instance = clazz.getDeclaredField("sSingleton"); + instance.setAccessible(true); + instance.set(null, null); + } catch (Exception e) { + throw new RuntimeException(); + } + } + + @Test + public void testMatchTitle() { + loader = new DatabaseResultLoader(mContext, "title"); + assertThat(loader.loadInBackground().size()).isEqualTo(3); + } + + @Test + public void testMatchSummary() { + loader = new DatabaseResultLoader(mContext, "summary"); + assertThat(loader.loadInBackground().size()).isEqualTo(3); + } + + @Test + public void testMatchKeywords() { + loader = new DatabaseResultLoader(mContext, "keywords"); + assertThat(loader.loadInBackground().size()).isEqualTo(3); + } + + @Test + public void testMatchEntries() { + loader = new DatabaseResultLoader(mContext, "entries"); + assertThat(loader.loadInBackground().size()).isEqualTo(3); + } + + @Test + public void testSpecialCaseWord_MatchesNonPrefix() { + insertSpecialCase("Data usage"); + loader = new DatabaseResultLoader(mContext, "usage"); + assertThat(loader.loadInBackground().size()).isEqualTo(1); + } + + @Test + public void testSpecialCaseSpace_Matches() { + insertSpecialCase("space"); + loader = new DatabaseResultLoader(mContext, " space "); + assertThat(loader.loadInBackground().size()).isEqualTo(1); + } + + @Test + public void testSpecialCaseDash_MatchesWordNoDash() { + insertSpecialCase("wi-fi calling"); + loader = new DatabaseResultLoader(mContext, "wifi"); + assertThat(loader.loadInBackground().size()).isEqualTo(1); + } + + @Test + public void testSpecialCaseDash_MatchesWordWithDash() { + insertSpecialCase("priorités seulment"); + loader = new DatabaseResultLoader(mContext, "priorités"); + assertThat(loader.loadInBackground().size()).isEqualTo(1); + } + + @Test + public void testSpecialCaseDash_MatchesWordWithoutDash() { + insertSpecialCase("priorités seulment"); + loader = new DatabaseResultLoader(mContext, "priorites"); + assertThat(loader.loadInBackground().size()).isEqualTo(1); + } + + @Test + public void testSpecialCaseDash_MatchesEntireQueryWithoutDash() { + insertSpecialCase("wi-fi calling"); + loader = new DatabaseResultLoader(mContext, "wifi calling"); + assertThat(loader.loadInBackground().size()).isEqualTo(1); + } + + private void insertSpecialCase(String specialCase) { + String normalized = DatabaseIndexingUtils.normalizeHyphen(specialCase); + normalized = DatabaseIndexingUtils.normalizeString(normalized); + + ContentValues values = new ContentValues(); + values.put(IndexDatabaseHelper.IndexColumns.DOCID, 0); + values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1); + values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, specialCase); + values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, normalized); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, ""); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, ""); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, ""); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, ""); + values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, ""); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, ""); + values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME, + "com.android.settings.gestures.GestureSettings"); + values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves"); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, ""); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, ""); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, ""); + values.put(IndexDatabaseHelper.IndexColumns.ICON, ""); + values.put(IndexDatabaseHelper.IndexColumns.ENABLED, ""); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power"); + values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0); + values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0); + values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, (String) null); + + mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values); + } + + private void setUpDb() { + ContentValues values = new ContentValues(); + values.put(IndexDatabaseHelper.IndexColumns.DOCID, 0); + values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1); + values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, "alpha_title"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, "alpha title"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, "alpha_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, "alpha_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, "alpha_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, "alpha_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, "alpha_entries"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, "alpha_keywords"); + values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME, + "com.android.settings.gestures.GestureSettings"); + values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves"); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, ""); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, ""); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, ""); + values.put(IndexDatabaseHelper.IndexColumns.ICON, ""); + values.put(IndexDatabaseHelper.IndexColumns.ENABLED, ""); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power"); + values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0); + values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0); + values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, (String) null); + + mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values); + + values = new ContentValues(); + values.put(IndexDatabaseHelper.IndexColumns.DOCID, 1); + values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1); + values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, "bravo_title"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, "bravo title"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, "bravo_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, "bravo_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, "bravo_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, "bravo_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, "bravo_entries"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, "bravo_keywords"); + values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME, + "com.android.settings.gestures.GestureSettings"); + values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves"); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, ""); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, ""); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, ""); + values.put(IndexDatabaseHelper.IndexColumns.ICON, ""); + values.put(IndexDatabaseHelper.IndexColumns.ENABLED, ""); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power"); + values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0); + values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0); + values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, (String) null); + mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values); + + values = new ContentValues(); + values.put(IndexDatabaseHelper.IndexColumns.DOCID, 2); + values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1); + values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, "charlie_title"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, "charlie title"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, "charlie_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, "charlie_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, "charlie_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, "charlie_summary"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, "charlie_entries"); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, "charlie_keywords"); + values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME, + "com.android.settings.gestures.GestureSettings"); + values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves"); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, ""); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, ""); + values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, ""); + values.put(IndexDatabaseHelper.IndexColumns.ICON, ""); + values.put(IndexDatabaseHelper.IndexColumns.ENABLED, ""); + values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power"); + values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0); + values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0); + values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, (String) null); + + mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values); + } +} diff --git a/tests/robotests/src/com/android/settings/search2/CursorToSearchResultConverterTest.java b/tests/robotests/src/com/android/settings/search2/CursorToSearchResultConverterTest.java index 98b250d192a..1847d0eabc4 100644 --- a/tests/robotests/src/com/android/settings/search2/CursorToSearchResultConverterTest.java +++ b/tests/robotests/src/com/android/settings/search2/CursorToSearchResultConverterTest.java @@ -40,6 +40,8 @@ import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.List; +import static com.android.settings.search.IndexDatabaseHelper.IndexColumns; + import static com.google.common.truth.Truth.assertThat; @RunWith(SettingsRobolectricTestRunner.class) @@ -48,16 +50,32 @@ public class CursorToSearchResultConverterTest { private CursorToSearchResultConverter mConverter; - private static final String[] COLUMNS = new String[]{"rank", "title", "summary_on", - "summary off", "entries", "keywords", "class name", "screen title", "icon", - "intent action", "target package", "target class", "enabled", "key", - "payload_type", "payload"}; + private static final String[] COLUMNS = new String[]{ + IndexColumns.DOCID, + IndexColumns.DATA_TITLE, + IndexColumns.DATA_SUMMARY_ON, + IndexColumns.DATA_SUMMARY_OFF, + IndexColumns.CLASS_NAME, + IndexColumns.SCREEN_TITLE, + IndexColumns.ICON, + IndexColumns.INTENT_ACTION, + IndexColumns.INTENT_TARGET_PACKAGE, + IndexColumns.INTENT_TARGET_CLASS, + IndexColumns.DATA_KEY_REF, + IndexColumns.PAYLOAD_TYPE, + IndexColumns.PAYLOAD + }; - private static final String[] TITLES = new String[]{"title1", "title2", "title3"}; - private static final String SUMMARY = "SUMMARY"; + private static final String ID = "id"; + private static final String[] TITLES = {"title1", "title2", "title3"}; + private static final String SUMMARY = "summary"; + private static final String QUERY = "query"; + private final int BASE_RANK = 1; private static final int EXAMPLES = 3; + private static final Intent mIntent = new Intent("com.android.settings"); private static final int mIcon = R.drawable.ic_search_history; + private List mResults; private Drawable mDrawable; @@ -65,32 +83,33 @@ public class CursorToSearchResultConverterTest { public void setUp() { Context context = Robolectric.buildActivity(Activity.class).get(); mDrawable = context.getDrawable(mIcon); - mConverter = new CursorToSearchResultConverter(context); + mResults = new ArrayList<>(); + mConverter = new CursorToSearchResultConverter(context, QUERY); } @Test public void testParseNullResults_ReturnsNull() { - List results = mConverter.convertCursor(null); + List results = mConverter.convertCursor(null, BASE_RANK); assertThat(results).isNull(); } @Test public void testParseCursor_NotNull() { - List results = mConverter.convertCursor(getDummyCursor()); + List results = mConverter.convertCursor(getDummyCursor(), BASE_RANK); assertThat(results).isNotNull(); } @Test public void testParseCursor_MatchesRank() { - List results = mConverter.convertCursor(getDummyCursor()); + List results = mConverter.convertCursor(getDummyCursor(), BASE_RANK); for (int i = 0; i < EXAMPLES; i++) { - assertThat(results.get(i).rank).isEqualTo(i); + assertThat(results.get(i).rank).isEqualTo(BASE_RANK); } } @Test public void testParseCursor_MatchesTitle() { - List results = mConverter.convertCursor(getDummyCursor()); + List results = mConverter.convertCursor(getDummyCursor(), BASE_RANK); for (int i = 0; i < EXAMPLES; i++) { assertThat(results.get(i).title).isEqualTo(TITLES[i]); } @@ -98,7 +117,7 @@ public class CursorToSearchResultConverterTest { @Test public void testParseCursor_MatchesSummary() { - List results = mConverter.convertCursor(getDummyCursor()); + List results = mConverter.convertCursor(getDummyCursor(), BASE_RANK); for (int i = 0; i < EXAMPLES; i++) { assertThat(results.get(i).summary).isEqualTo(SUMMARY); } @@ -106,7 +125,7 @@ public class CursorToSearchResultConverterTest { @Test public void testParseCursor_MatchesIcon() { - List results = mConverter.convertCursor(getDummyCursor()); + List results = mConverter.convertCursor(getDummyCursor(), BASE_RANK); for (int i = 0; i < EXAMPLES; i++) { Drawable resultDrawable = results.get(i).icon; assertThat(resultDrawable.toString()).isEqualTo(mDrawable.toString()); @@ -116,7 +135,7 @@ public class CursorToSearchResultConverterTest { @Test public void testParseCursor_NoIcon() { List results = mConverter.convertCursor( - getDummyCursor(false /* hasIcon */)); + getDummyCursor(false /* hasIcon */), BASE_RANK); for (int i = 0; i < EXAMPLES; i++) { Drawable resultDrawable = results.get(i).icon; assertThat(resultDrawable).isNull(); @@ -125,7 +144,7 @@ public class CursorToSearchResultConverterTest { @Test public void testParseCursor_MatchesPayloadType() { - List results = mConverter.convertCursor(getDummyCursor()); + List results = mConverter.convertCursor(getDummyCursor(), BASE_RANK); ResultPayload payload; for (int i = 0; i < EXAMPLES; i++) { payload = results.get(i).payload; @@ -138,24 +157,21 @@ public class CursorToSearchResultConverterTest { MatrixCursor cursor = new MatrixCursor(COLUMNS); final String BLANK = ""; cursor.addRow(new Object[]{ - 0, // rank - TITLES[0], - SUMMARY, + ID, // Doc ID + TITLES[0], // Title + SUMMARY, // Summary on SUMMARY, // summary off - BLANK, // entries - BLANK, // Keywords GestureSettings.class.getName(), BLANK, // screen title null, // icon BLANK, // action null, // target package BLANK, // target class - BLANK, // enabled - BLANK, // key + BLANK, // Key 0, // Payload Type null // Payload }); - List results = mConverter.convertCursor(cursor); + List results = mConverter.convertCursor(cursor, BASE_RANK); IntentPayload payload = (IntentPayload) results.get(0).payload; Intent intent = payload.intent; assertThat(intent.getComponent().getClassName()).isEqualTo(SubSettings.class.getName()); @@ -163,7 +179,7 @@ public class CursorToSearchResultConverterTest { @Test public void testParseCursor_MatchesIntentPayload() { - List results = mConverter.convertCursor(getDummyCursor()); + List results = mConverter.convertCursor(getDummyCursor(), BASE_RANK); IntentPayload payload; for (int i = 0; i < EXAMPLES; i++) { payload = (IntentPayload) results.get(i).payload; @@ -185,24 +201,21 @@ public class CursorToSearchResultConverterTest { final InlineSwitchPayload payload = new InlineSwitchPayload(uri, source, map); cursor.addRow(new Object[]{ - 0, // rank - TITLES[0], - SUMMARY, + ID, // Doc ID + TITLES[0], // Title + SUMMARY, // Summary on SUMMARY, // summary off - BLANK, // entries - BLANK, // Keywords GestureSettings.class.getName(), BLANK, // screen title null, // icon BLANK, // action null, // target package BLANK, // target class - BLANK, // enabled - BLANK, // key + BLANK, // Key type, // Payload Type ResultPayloadUtils.marshall(payload) // Payload }); - List results = mConverter.convertCursor(cursor); + List results = mConverter.convertCursor(cursor, BASE_RANK); InlineSwitchPayload newPayload = (InlineSwitchPayload) results.get(0).payload; assertThat(newPayload.settingsUri).isEqualTo(uri); @@ -222,22 +235,17 @@ public class CursorToSearchResultConverterTest { for (int i = 0; i < EXAMPLES; i++) { ArrayList item = new ArrayList<>(COLUMNS.length); - item.add(Integer.toString(i)); - item.add(TITLES[i]); - item.add(SUMMARY); + item.add(ID + i); // Doc ID + item.add(TITLES[i]); // Title + item.add(SUMMARY); // Summary on item.add(BLANK); // summary off - item.add(BLANK); // entries - item.add(BLANK); // keywords item.add(BLANK); // classname item.add(BLANK); // screen title - item.add(hasIcon ? Integer.toString(mIcon) : null); - item.add(mIntent.getAction()); + item.add(hasIcon ? Integer.toString(mIcon) : null); // Icon + item.add(mIntent.getAction()); // Intent action item.add(BLANK); // target package item.add(BLANK); // target class - item.add(BLANK); // enabled - item.add(BLANK); // key - // Note there is no user id. This is omitted because it is not being - // queried. Should the queries change, so should this method. + item.add(BLANK); // Key item.add(Integer.toString(0)); // Payload Type item.add(null); // Payload diff --git a/tests/robotests/src/com/android/settings/search2/InstalledAppResultLoaderTest.java b/tests/robotests/src/com/android/settings/search2/InstalledAppResultLoaderTest.java index e3c2180c1b5..24aa94b70a7 100644 --- a/tests/robotests/src/com/android/settings/search2/InstalledAppResultLoaderTest.java +++ b/tests/robotests/src/com/android/settings/search2/InstalledAppResultLoaderTest.java @@ -46,7 +46,6 @@ import static org.mockito.Mockito.when; @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class InstalledAppResultLoaderTest { - @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock(answer = Answers.RETURNS_DEEP_STUBS)