Update DatabaseLoader querying.

Change the way the queries are built and sorted for the
database loader. It now constructs 3 queries that match
different columns. Each query returns their results
and gets sorted, then merged into the master list of
results.

Change-Id: Id643422ddfe26bfec89e04ee9f5832b99148e22a
Test: make RunSettingsRoboTests
Bug: 32904057, 32903623
This commit is contained in:
Matthew Fritze
2016-12-20 15:50:56 -08:00
parent d5e2bfcc7a
commit 7fda314980
7 changed files with 462 additions and 110 deletions

View File

@@ -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<String> mKeys;
public CursorToSearchResultConverter(Context context, String queryText) {
mContext = context;
mKeys = new HashSet<>();
mQueryText = queryText;
}
public List<SearchResult> convertCursor(Cursor cursorResults) {
public List<SearchResult> convertCursor(Cursor cursorResults, int baseRank) {
if (cursorResults == null) {
return null;
}
final Map<String, Context> contextMap = new HashMap<>();
final ArrayList<SearchResult> results = new ArrayList<>();
final List<SearchResult> 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<String, Context> 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<String> 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<String> 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<String> crumbs, int baseRank) {
return baseRank;
}
}

View File

@@ -108,15 +108,15 @@ public class DatabaseIndexingManager {
public boolean fullIndex;
public UpdateData() {
dataToUpdate = new ArrayList<SearchIndexableData>();
dataToDelete = new ArrayList<SearchIndexableData>();
nonIndexableKeys = new HashMap<String, List<String>>();
dataToUpdate = new ArrayList<>();
dataToDelete = new ArrayList<>();
nonIndexableKeys = new HashMap<>();
}
public UpdateData(DatabaseIndexingManager.UpdateData other) {
dataToUpdate = new ArrayList<SearchIndexableData>(other.dataToUpdate);
dataToDelete = new ArrayList<SearchIndexableData>(other.dataToDelete);
nonIndexableKeys = new HashMap<String, List<String>>(other.nonIndexableKeys);
dataToUpdate = new ArrayList<>(other.dataToUpdate);
dataToDelete = new ArrayList<>(other.dataToDelete);
nonIndexableKeys = new HashMap<>(other.nonIndexableKeys);
forceUpdate = other.forceUpdate;
fullIndex = other.fullIndex;
}

View File

@@ -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<List<SearchResult>> {
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<List<SearchResult>> {
return null;
}
String query = getSQLQuery();
Cursor result = mDatabase.rawQuery(query, null);
final List<SearchResult> primaryResults;
final List<SearchResult> secondaryResults;
final List<SearchResult> 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<SearchResult> results = new ArrayList<>(primaryResults.size()
+ secondaryResults.size()
+ tertiaryResults.size());
results.addAll(primaryResults);
results.addAll(secondaryResults);
results.addAll(tertiaryResults);
return results;
}
private List<SearchResult> 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<List<SearchResult>> {
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();
}
}

View File

@@ -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<SearchResult> {
* 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<String> breadcrumbs;
public final List<String> breadcrumbs;
/**
* A suggestion for the ranking of the result.
@@ -96,7 +96,7 @@ public class SearchResult implements Comparable<SearchResult> {
public static class Builder {
protected CharSequence mTitle;
protected CharSequence mSummary;
protected ArrayList<String> mBreadcrumbs;
protected List<String> mBreadcrumbs;
protected int mRank = 42;
protected ResultPayload mResultPayload;
protected Drawable mIcon;
@@ -111,7 +111,7 @@ public class SearchResult implements Comparable<SearchResult> {
return this;
}
public Builder addBreadcrumbs(ArrayList<String> breadcrumbs) {
public Builder addBreadcrumbs(List<String> breadcrumbs) {
mBreadcrumbs = breadcrumbs;
return this;
}

View File

@@ -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);
}
}

View File

@@ -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<SearchResult> 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<SearchResult> results = mConverter.convertCursor(null);
List<SearchResult> results = mConverter.convertCursor(null, BASE_RANK);
assertThat(results).isNull();
}
@Test
public void testParseCursor_NotNull() {
List<SearchResult> results = mConverter.convertCursor(getDummyCursor());
List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
assertThat(results).isNotNull();
}
@Test
public void testParseCursor_MatchesRank() {
List<SearchResult> results = mConverter.convertCursor(getDummyCursor());
List<SearchResult> 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<SearchResult> results = mConverter.convertCursor(getDummyCursor());
List<SearchResult> 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<SearchResult> results = mConverter.convertCursor(getDummyCursor());
List<SearchResult> 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<SearchResult> results = mConverter.convertCursor(getDummyCursor());
List<SearchResult> 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<SearchResult> 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<SearchResult> results = mConverter.convertCursor(getDummyCursor());
List<SearchResult> 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<SearchResult> results = mConverter.convertCursor(cursor);
List<SearchResult> 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<SearchResult> results = mConverter.convertCursor(getDummyCursor());
List<SearchResult> 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<SearchResult> results = mConverter.convertCursor(cursor);
List<SearchResult> 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<String> 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

View File

@@ -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)