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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user