Move search querying into a single API
Settings now collects search results from a single loader which fetches from an aggregator. This is to facilitate the separation of search functionalitiy, where "query" becomes a single synchronous call. In this case, the aggregator will move to the unbundled app and would be called on the other end of the Query call. i.e. the new search result loader will just call query, and unbundled search will handle everything else. An important implication is that the results will be returned in a ranked order. Thus the ranking and merging logic has been moved out of the RecyclerView adapter (which is a good clean-up, anyway). The SearchResultAggregator starts a Future for each of the data sources: - Static Results - Installed Apps - Input Devices - Accessibility Services We allow up to 500ms to collect the static results, and then an additional 150ms for each subsequent loader. In my quick tests, the static results take about 20-30ms to load. The longest loader is installed apps which takes roughly 50-60ms seconds (note that this will be improved with dynamic result caching). To handle the ranking in DatabaseResultLoader, we start a Future to collect the dynamic ranking before we start the SQL queries. When the SQL is done, we wait the same timeout as before. Then we merge the results, as before. For now we have not changed how the Dynamic results are collected, but eventually they will be a cache of dynamic results. Bug: 33577327 Bug: 67360547 Test: robotests Change-Id: I91fb03f9fd059672a970f48bea21c8d655007fa3
This commit is contained in:
@@ -18,44 +18,32 @@
|
||||
package com.android.settings.search;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.Pair;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.search.SearchResult.Builder;
|
||||
import com.android.settings.search.ranking.SearchResultsRankerCallback;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowLooper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
@@ -67,25 +55,18 @@ public class SearchResultsAdapterTest {
|
||||
private SearchFeatureProvider mSearchFeatureProvider;
|
||||
@Mock
|
||||
private Context mMockContext;
|
||||
@Captor
|
||||
private ArgumentCaptor<Integer> mSearchResultsCountCaptor =
|
||||
ArgumentCaptor.forClass(Integer.class);
|
||||
private SearchResultsAdapter mAdapter;
|
||||
private Context mContext;
|
||||
private String mLoaderClassName;
|
||||
|
||||
private String[] TITLES = {"alpha", "bravo", "charlie", "appAlpha", "appBravo", "appCharlie"};
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = Robolectric.buildActivity(Activity.class).get();
|
||||
mLoaderClassName = DatabaseResultLoader.class.getName();
|
||||
when(mFragment.getContext()).thenReturn(mMockContext);
|
||||
when(mMockContext.getApplicationContext()).thenReturn(mContext);
|
||||
when(mSearchFeatureProvider.smartSearchRankingTimeoutMs(any(Context.class)))
|
||||
.thenReturn(300L);
|
||||
mAdapter = new SearchResultsAdapter(mFragment, mSearchFeatureProvider);
|
||||
mAdapter = new SearchResultsAdapter(mFragment);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -94,17 +75,6 @@ public class SearchResultsAdapterTest {
|
||||
assertThat(updatedResults).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleSourceMerge_exactCopyReturned() {
|
||||
Set<SearchResult> intentResults = getIntentSampleResults();
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(intentResults, mLoaderClassName);
|
||||
mAdapter.notifyResultsLoaded();
|
||||
|
||||
List<SearchResult> updatedResults = mAdapter.getSearchResults();
|
||||
assertThat(updatedResults).containsAllIn(intentResults);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateViewHolder_returnsIntentResult() {
|
||||
ViewGroup group = new FrameLayout(mContext);
|
||||
@@ -123,387 +93,13 @@ public class SearchResultsAdapterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndSearch_properResultsMerged_correctOrder() {
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(new HashSet<>(getDummyAppResults()),
|
||||
InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(new HashSet<>(getDummyDbResults()),
|
||||
DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
public void testPostSearchResults_addsDataAndDisplays() {
|
||||
List<SearchResult> results = getDummyDbResults();
|
||||
|
||||
List<SearchResult> results = mAdapter.getSearchResults();
|
||||
assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha
|
||||
assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha
|
||||
assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo
|
||||
assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo
|
||||
assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie
|
||||
assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie
|
||||
verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture());
|
||||
assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6);
|
||||
}
|
||||
mAdapter.postSearchResults(results);
|
||||
|
||||
@Test
|
||||
public void testEndToEndSearch_addResults_resultsAddedInOrder() {
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
// Add two individual items
|
||||
mAdapter.addSearchResults(new HashSet<>(appResults.subList(0, 1)),
|
||||
InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(new HashSet<>(dbResults.subList(0, 1)),
|
||||
DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
// Add super-set of items
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(appResults), InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(dbResults), DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
|
||||
List<SearchResult> results = mAdapter.getSearchResults();
|
||||
assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha
|
||||
assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha
|
||||
assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo
|
||||
assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo
|
||||
assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie
|
||||
assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie
|
||||
verify(mFragment, times(2)).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture());
|
||||
assertThat(mSearchResultsCountCaptor.getAllValues().toArray())
|
||||
.isEqualTo(new Integer[] {2, 6});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndSearch_removeResults_resultsAdded() {
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
// Add list of items
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(new HashSet<>(appResults),
|
||||
InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(new HashSet<>(dbResults),
|
||||
DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
// Add subset of items
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(new HashSet<>(appResults.subList(0, 1)),
|
||||
InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(new HashSet<>(dbResults.subList(0, 1)),
|
||||
DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
|
||||
List<SearchResult> results = mAdapter.getSearchResults();
|
||||
assertThat(results.get(0).title).isEqualTo(TITLES[0]);
|
||||
assertThat(results.get(1).title).isEqualTo(TITLES[3]);
|
||||
verify(mFragment, times(2)).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture());
|
||||
assertThat(mSearchResultsCountCaptor.getAllValues().toArray())
|
||||
.isEqualTo(new Integer[] {6, 2});
|
||||
}
|
||||
@Test
|
||||
public void testEndToEndSearch_smartSearchRankingEnabledAndSucceededAfterResultsLoaded() {
|
||||
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true);
|
||||
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(appResults), InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(dbResults), DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
mAdapter.onRankingScoresAvailable(getDummyRankingScores());
|
||||
|
||||
List<SearchResult> results = mAdapter.getSearchResults();
|
||||
assertThat(results.get(0).title).isEqualTo(TITLES[2]); // charlie
|
||||
assertThat(results.get(1).title).isEqualTo(TITLES[0]); // alpha
|
||||
assertThat(results.get(2).title).isEqualTo(TITLES[1]); // bravo
|
||||
assertThat(results.get(3).title).isEqualTo(TITLES[3]); // appAlpha
|
||||
assertThat(results.get(4).title).isEqualTo(TITLES[4]); // appBravo
|
||||
assertThat(results.get(5).title).isEqualTo(TITLES[5]); // appCharlie
|
||||
verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture());
|
||||
assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6);
|
||||
assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.SUCCEEDED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndSearch_smartSearchRankingEnabledAndSucceededBeforeResultsLoaded() {
|
||||
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true);
|
||||
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.onRankingScoresAvailable(getDummyRankingScores());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(appResults), InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(dbResults), DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
|
||||
List<SearchResult> results = mAdapter.getSearchResults();
|
||||
assertThat(results.get(0).title).isEqualTo(TITLES[2]); // charlie
|
||||
assertThat(results.get(1).title).isEqualTo(TITLES[0]); // alpha
|
||||
assertThat(results.get(2).title).isEqualTo(TITLES[1]); // bravo
|
||||
assertThat(results.get(3).title).isEqualTo(TITLES[3]); // appAlpha
|
||||
assertThat(results.get(4).title).isEqualTo(TITLES[4]); // appBravo
|
||||
assertThat(results.get(5).title).isEqualTo(TITLES[5]); // appCharlie
|
||||
verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture());
|
||||
assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6);
|
||||
assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.SUCCEEDED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndSearch_smartSearchRankingEnabledAndFailedAfterResultsLoaded() {
|
||||
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true);
|
||||
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(appResults), InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(dbResults), DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
mAdapter.onRankingFailed();
|
||||
|
||||
List<SearchResult> results = mAdapter.getSearchResults();
|
||||
assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha
|
||||
assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha
|
||||
assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo
|
||||
assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo
|
||||
assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie
|
||||
assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie
|
||||
verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture());
|
||||
assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6);
|
||||
assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.FAILED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndSearch_smartSearchRankingEnabledAndFailedBeforeResultsLoaded() {
|
||||
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true);
|
||||
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.onRankingFailed();
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(appResults), InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(dbResults), DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
|
||||
List<SearchResult> results = mAdapter.getSearchResults();
|
||||
assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha
|
||||
assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha
|
||||
assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo
|
||||
assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo
|
||||
assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie
|
||||
assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie
|
||||
verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture());
|
||||
assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6);
|
||||
assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.FAILED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndSearch_smartSearchRankingEnabledAndTimedoutAfterResultsLoaded() {
|
||||
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true);
|
||||
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(appResults), InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(dbResults), DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
|
||||
waitUntilRankingTimesOut();
|
||||
|
||||
List<SearchResult> results = mAdapter.getSearchResults();
|
||||
assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha
|
||||
assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha
|
||||
assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo
|
||||
assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo
|
||||
assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie
|
||||
assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie
|
||||
verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture());
|
||||
assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6);
|
||||
assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.TIMED_OUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndSearch_smartSearchRankingEnabledAndTimedoutBeforeResultsLoaded() {
|
||||
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true);
|
||||
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
|
||||
waitUntilRankingTimesOut();
|
||||
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(appResults), InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(dbResults), DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
|
||||
List<SearchResult> results = mAdapter.getSearchResults();
|
||||
assertThat(results.get(0).title).isEqualTo(TITLES[0]); // alpha
|
||||
assertThat(results.get(1).title).isEqualTo(TITLES[3]); // appAlpha
|
||||
assertThat(results.get(2).title).isEqualTo(TITLES[4]); // appBravo
|
||||
assertThat(results.get(3).title).isEqualTo(TITLES[1]); // bravo
|
||||
assertThat(results.get(4).title).isEqualTo(TITLES[5]); // appCharlie
|
||||
assertThat(results.get(5).title).isEqualTo(TITLES[2]); // charlie
|
||||
verify(mFragment).onSearchResultsDisplayed(mSearchResultsCountCaptor.capture());
|
||||
assertThat(mSearchResultsCountCaptor.getValue()).isEqualTo(6);
|
||||
assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.TIMED_OUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoSmartRanking_shouldRankAppResultsAfterDbResults() {
|
||||
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true);
|
||||
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(appResults), InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(dbResults), DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
mAdapter.onRankingScoresAvailable(getDummyRankingScores());
|
||||
List<SearchResult> results = mAdapter.doAsyncRanking();
|
||||
assertThat(results.get(0).title).isEqualTo(TITLES[2]); // charlie
|
||||
assertThat(results.get(1).title).isEqualTo(TITLES[0]); // alpha
|
||||
assertThat(results.get(2).title).isEqualTo(TITLES[1]); // bravo
|
||||
assertThat(results.get(3).title).isEqualTo(TITLES[3]); // appAlpha
|
||||
assertThat(results.get(4).title).isEqualTo(TITLES[4]); // appBravo
|
||||
assertThat(results.get(5).title).isEqualTo(TITLES[5]); // appCharlie
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoSmartRanking_shouldRankResultsWithMissingScoresAfterScoredResults() {
|
||||
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true);
|
||||
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(appResults), InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(dbResults), DatabaseResultLoader.class.getName());
|
||||
mAdapter.notifyResultsLoaded();
|
||||
List<Pair<String, Float>> rankingScores = getDummyRankingScores();
|
||||
rankingScores.remove(1); // no ranking score for alpha
|
||||
mAdapter.onRankingScoresAvailable(rankingScores);
|
||||
List<SearchResult> results = mAdapter.doAsyncRanking();
|
||||
assertThat(results.get(0).title).isEqualTo(TITLES[2]); // charlie
|
||||
assertThat(results.get(1).title).isEqualTo(TITLES[1]); // bravo
|
||||
assertThat(results.get(2).title).isEqualTo(TITLES[0]); // alpha
|
||||
assertThat(results.get(3).title).isEqualTo(TITLES[3]); // appAlpha
|
||||
assertThat(results.get(4).title).isEqualTo(TITLES[4]); // appBravo
|
||||
assertThat(results.get(5).title).isEqualTo(TITLES[5]); // appCharlie
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUnsortedLoadedResults () {
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(appResults), InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(dbResults), DatabaseResultLoader.class.getName());
|
||||
Set<CharSequence> expectedDbTitles = new HashSet<>(
|
||||
Arrays.asList("alpha", "bravo", "charlie"));
|
||||
Set<CharSequence> expectedAppTitles = new HashSet<>(
|
||||
Arrays.asList("appAlpha", "appBravo", "appCharlie"));
|
||||
Set<CharSequence> actualDbTitles = new HashSet<>();
|
||||
Set<CharSequence> actualAppTitles = new HashSet<>();
|
||||
for (SearchResult result : mAdapter.getUnsortedLoadedResults(SearchResultsAdapter
|
||||
.DB_RESULTS_LOADER_KEY)) {
|
||||
actualDbTitles.add(result.title);
|
||||
}
|
||||
for (SearchResult result : mAdapter.getUnsortedLoadedResults(SearchResultsAdapter
|
||||
.APP_RESULTS_LOADER_KEY)) {
|
||||
actualAppTitles.add(result.title);
|
||||
}
|
||||
assertThat(actualDbTitles).isEqualTo(expectedDbTitles);
|
||||
assertThat(actualAppTitles).isEqualTo(expectedAppTitles);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSortedLoadedResults() {
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(appResults), InstalledAppResultLoader.class.getName());
|
||||
mAdapter.addSearchResults(
|
||||
new HashSet<>(dbResults), DatabaseResultLoader.class.getName());
|
||||
List<? extends SearchResult> actualDbResults =
|
||||
mAdapter.getSortedLoadedResults(SearchResultsAdapter.DB_RESULTS_LOADER_KEY);
|
||||
List<? extends SearchResult> actualAppResults =
|
||||
mAdapter.getSortedLoadedResults(SearchResultsAdapter.APP_RESULTS_LOADER_KEY);
|
||||
assertThat(actualDbResults.get(0).title).isEqualTo(TITLES[0]); // charlie
|
||||
assertThat(actualDbResults.get(1).title).isEqualTo(TITLES[1]); // bravo
|
||||
assertThat(actualDbResults.get(2).title).isEqualTo(TITLES[2]); // alpha
|
||||
assertThat(actualAppResults.get(0).title).isEqualTo(TITLES[3]); // appAlpha
|
||||
assertThat(actualAppResults.get(1).title).isEqualTo(TITLES[4]); // appBravo
|
||||
assertThat(actualAppResults.get(2).title).isEqualTo(TITLES[5]); // appCharlie
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializeSearch_shouldNotRunSmartRankingIfDisabled() {
|
||||
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(false);
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.notifyResultsLoaded();
|
||||
verify(mSearchFeatureProvider, never()).querySearchResults(
|
||||
any(Context.class), anyString(), any(SearchResultsRankerCallback.class));
|
||||
assertThat(mAdapter.getAsyncRankingState()).isEqualTo(SearchResultsAdapter.DISABLED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitialSearch_shouldRunSmartRankingIfEnabled() {
|
||||
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true);
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.notifyResultsLoaded();
|
||||
verify(mSearchFeatureProvider, times(1)).querySearchResults(
|
||||
any(Context.class), anyString(), any(SearchResultsRankerCallback.class));
|
||||
assertThat(mAdapter.getAsyncRankingState())
|
||||
.isEqualTo(SearchResultsAdapter.PENDING_RESULTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRankingScoreByStableId() {
|
||||
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any())).thenReturn(true);
|
||||
|
||||
List<SearchResult> appResults = getDummyAppResults();
|
||||
List<SearchResult> dbResults = getDummyDbResults();
|
||||
mAdapter.initializeSearch("");
|
||||
mAdapter.onRankingScoresAvailable(getDummyRankingScores());
|
||||
assertThat(mAdapter.getRankingScoreByStableId(dbResults.get(0).stableId))
|
||||
.isWithin(1e-10f).of(0.8f);
|
||||
assertThat(mAdapter.getRankingScoreByStableId(dbResults.get(1).stableId))
|
||||
.isWithin(1e-10f).of(0.2f);
|
||||
assertThat(mAdapter.getRankingScoreByStableId(dbResults.get(2).stableId))
|
||||
.isWithin(1e-10f).of(0.9f);
|
||||
assertThat(mAdapter.getRankingScoreByStableId(appResults.get(0).stableId))
|
||||
.isEqualTo(-Float.MAX_VALUE);
|
||||
assertThat(mAdapter.getRankingScoreByStableId(appResults.get(1).stableId))
|
||||
.isEqualTo(-Float.MAX_VALUE);
|
||||
assertThat(mAdapter.getRankingScoreByStableId(appResults.get(2).stableId))
|
||||
.isEqualTo(-Float.MAX_VALUE);
|
||||
}
|
||||
|
||||
private void waitUntilRankingTimesOut() {
|
||||
while (mAdapter.getHandler().hasMessages(mAdapter.MSG_RANKING_TIMED_OUT)) {
|
||||
try {
|
||||
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
assertThat(mAdapter.getSearchResults()).containsExactlyElementsIn(results);
|
||||
verify(mFragment).onSearchResultsDisplayed(anyInt());
|
||||
}
|
||||
|
||||
private List<SearchResult> getDummyDbResults() {
|
||||
@@ -511,78 +107,21 @@ public class SearchResultsAdapterTest {
|
||||
ResultPayload payload = new ResultPayload(new Intent());
|
||||
SearchResult.Builder builder = new SearchResult.Builder();
|
||||
builder.setPayload(payload)
|
||||
.setTitle(TITLES[0])
|
||||
.setTitle("one")
|
||||
.setRank(1)
|
||||
.setStableId(Objects.hash(TITLES[0], "db"));
|
||||
.setStableId(Objects.hash("one", "db"));
|
||||
results.add(builder.build());
|
||||
|
||||
builder.setTitle(TITLES[1])
|
||||
builder.setTitle("two")
|
||||
.setRank(3)
|
||||
.setStableId(Objects.hash(TITLES[1], "db"));
|
||||
.setStableId(Objects.hash("two", "db"));
|
||||
results.add(builder.build());
|
||||
|
||||
builder.setTitle(TITLES[2])
|
||||
builder.setTitle("three")
|
||||
.setRank(6)
|
||||
.setStableId(Objects.hash(TITLES[2], "db"));
|
||||
.setStableId(Objects.hash("three", "db"));
|
||||
results.add(builder.build());
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<SearchResult> getDummyAppResults() {
|
||||
List<SearchResult> results = new ArrayList<>();
|
||||
ResultPayload payload = new ResultPayload(new Intent());
|
||||
AppSearchResult.Builder builder = new AppSearchResult.Builder();
|
||||
builder.setPayload(payload)
|
||||
.setTitle(TITLES[3])
|
||||
.setRank(1)
|
||||
.setStableId(Objects.hash(TITLES[3], "app"));
|
||||
results.add(builder.build());
|
||||
|
||||
builder.setTitle(TITLES[4])
|
||||
.setRank(2)
|
||||
.setStableId(Objects.hash(TITLES[4], "app"));
|
||||
results.add(builder.build());
|
||||
|
||||
builder.setTitle(TITLES[5])
|
||||
.setRank(4)
|
||||
.setStableId(Objects.hash(TITLES[5], "app"));
|
||||
results.add(builder.build());
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private Set<SearchResult> getIntentSampleResults() {
|
||||
Set<SearchResult> sampleResults = new HashSet<>();
|
||||
ArrayList<String> breadcrumbs = new ArrayList<>();
|
||||
final Drawable icon = mContext.getDrawable(R.drawable.ic_search_24dp);
|
||||
final ResultPayload payload = new ResultPayload(null);
|
||||
final SearchResult.Builder builder = new Builder();
|
||||
builder.setTitle("title")
|
||||
.setSummary("summary")
|
||||
.setRank(1)
|
||||
.addBreadcrumbs(breadcrumbs)
|
||||
.setIcon(icon)
|
||||
.setPayload(payload)
|
||||
.setStableId(Objects.hash("title", "summary", 1));
|
||||
sampleResults.add(builder.build());
|
||||
|
||||
builder.setRank(2)
|
||||
.setStableId(Objects.hash("title", "summary", 2));
|
||||
sampleResults.add(builder.build());
|
||||
|
||||
builder.setRank(3)
|
||||
.setStableId(Objects.hash("title", "summary", 3));
|
||||
sampleResults.add(builder.build());
|
||||
return sampleResults;
|
||||
}
|
||||
|
||||
private List<Pair<String, Float>> getDummyRankingScores() {
|
||||
List<SearchResult> results = getDummyDbResults();
|
||||
List<Pair<String, Float>> scores = new ArrayList<>();
|
||||
scores.add(new Pair<>(Long.toString(results.get(2).stableId), 0.9f)); // charlie
|
||||
scores.add(new Pair<>(Long.toString(results.get(0).stableId), 0.8f)); // alpha
|
||||
scores.add(new Pair<>(Long.toString(results.get(1).stableId), 0.2f)); // bravo
|
||||
return scores;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user