Adding APIs for smart search ranking.

Test: RunSettingsRoboTests
Bug: 36866337

Change-Id: I20a26e5ac7a57582cea24951120717a4f2c93ce0
This commit is contained in:
Soroosh Mariooryad
2017-03-27 14:33:15 -07:00
parent b4e7b17223
commit 172f888ad5
6 changed files with 80 additions and 9 deletions

View File

@@ -51,6 +51,7 @@ public class IntentSearchViewHolder extends SearchViewHolder {
mMetricsFeatureProvider.action(v.getContext(),
MetricsEvent.ACTION_CLICK_SETTINGS_SEARCH_RESULT,
resultName, rank);
mSearchFeatureProvider.searchResultClicked(fragment.mQuery, result);
fragment.startActivity(intent);
});
}

View File

@@ -22,6 +22,8 @@ import android.view.Menu;
import android.view.View;
import com.android.settings.dashboard.SiteMapManager;
import java.util.List;
/**
* FeatureProvider for Settings Search
*/
@@ -89,5 +91,29 @@ public interface SearchFeatureProvider {
default void hideFeedbackButton() {
}
/**
* Ranks search results based on the input query.
*
* @param query input user query
* @param searchResults list of search results to be ranked
*/
default void rankSearchResults(String query, List<SearchResult> searchResults) {
}
/**
* Notify that a search result is clicked.
*
* @param query input user query
* @param searchResult clicked result
*/
default void searchResultClicked(String query, SearchResult searchResult) {
}
/**
* @return true to enable search ranking.
*/
default boolean isSmartSearchRankingEnabled(Context context) {
return false;
}
}

View File

@@ -117,7 +117,7 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
final LoaderManager loaderManager = getLoaderManager();
mSearchAdapter = new SearchResultsAdapter(this);
mSearchAdapter = new SearchResultsAdapter(this, mSearchFeatureProvider);
mSavedQueryController = new SavedQueryController(
getContext(), loaderManager, mSearchAdapter);
mSearchFeatureProvider.initFeedbackButton();
@@ -251,7 +251,7 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O
if (mUnfinishedLoadersCount.decrementAndGet() != 0) {
return;
}
final int resultCount = mSearchAdapter.displaySearchResults();
final int resultCount = mSearchAdapter.displaySearchResults(mQuery);
mNoResultsView.setVisibility(resultCount == 0 ? View.VISIBLE : View.GONE);
mSearchFeatureProvider.showFeedbackButton(this, getView());
}

View File

@@ -40,11 +40,14 @@ public class SearchResultsAdapter extends RecyclerView.Adapter<SearchViewHolder>
private final List<SearchResult> mSearchResults;
private final SearchFragment mFragment;
private Map<String, List<? extends SearchResult>> mResultsMap;
private final SearchFeatureProvider mSearchFeatureProvider;
public SearchResultsAdapter(SearchFragment fragment) {
public SearchResultsAdapter(SearchFragment fragment,
SearchFeatureProvider searchFeatureProvider) {
mFragment = fragment;
mSearchResults = new ArrayList<>();
mResultsMap = new ArrayMap<>();
mSearchFeatureProvider = searchFeatureProvider;
setHasStableIds(true);
}
@@ -119,9 +122,10 @@ public class SearchResultsAdapter extends RecyclerView.Adapter<SearchViewHolder>
* Merge the results from each of the loaders into one list for the adapter.
* Prioritizes results from the local database over installed apps.
*
* @param query user query corresponding to these results
* @return Number of matched results
*/
public int displaySearchResults() {
public int displaySearchResults(String query) {
final List<? extends SearchResult> databaseResults = mResultsMap
.get(DatabaseResultLoader.class.getName());
final List<? extends SearchResult> installedAppResults = mResultsMap
@@ -151,6 +155,12 @@ public class SearchResultsAdapter extends RecyclerView.Adapter<SearchViewHolder>
results.add(installedAppResults.get(appIndex++));
}
if (mSearchFeatureProvider
.isSmartSearchRankingEnabled(mFragment.getContext().getApplicationContext())) {
// TODO: run this in parallel to loading the results if takes too long
mSearchFeatureProvider.rankSearchResults(query, results);
}
mSearchResults.addAll(results);
notifyDataSetChanged();

View File

@@ -40,11 +40,14 @@ public abstract class SearchViewHolder extends RecyclerView.ViewHolder {
public final ImageView iconView;
protected final MetricsFeatureProvider mMetricsFeatureProvider;
protected final SearchFeatureProvider mSearchFeatureProvider;
public SearchViewHolder(View view) {
super(view);
mMetricsFeatureProvider = FeatureFactory.getFactory(view.getContext())
.getMetricsFeatureProvider();
final FeatureFactory featureFactory = FeatureFactory
.getFactory(view.getContext().getApplicationContext());
mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
mSearchFeatureProvider = featureFactory.getSearchFeatureProvider();
titleView = view.findViewById(android.R.id.title);
summaryView = view.findViewById(android.R.id.summary);
iconView = view.findViewById(android.R.id.icon);

View File

@@ -34,6 +34,7 @@ import com.android.settings.search2.InstalledAppResultLoader;
import com.android.settings.search2.IntentPayload;
import com.android.settings.search2.IntentSearchViewHolder;
import com.android.settings.search2.ResultPayload;
import com.android.settings.search2.SearchFeatureProvider;
import com.android.settings.search2.SearchFragment;
import com.android.settings.search2.SearchResult;
import com.android.settings.search2.SearchResult.Builder;
@@ -48,6 +49,14 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyList;
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 java.util.ArrayList;
import java.util.List;
@@ -59,6 +68,10 @@ public class SearchResultsAdapterTest {
@Mock
private SearchFragment mFragment;
@Mock
private SearchFeatureProvider mSearchFeatureProvider;
@Mock
private Context mMockContext;
private SearchResultsAdapter mAdapter;
private Context mContext;
private String mLoaderClassName;
@@ -67,8 +80,10 @@ public class SearchResultsAdapterTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = Robolectric.buildActivity(Activity.class).get();
mAdapter = new SearchResultsAdapter(mFragment);
mAdapter = new SearchResultsAdapter(mFragment, mSearchFeatureProvider);
mLoaderClassName = DatabaseResultLoader.class.getName();
when(mFragment.getContext()).thenReturn(mMockContext);
when(mMockContext.getApplicationContext()).thenReturn(mContext);
}
@Test
@@ -81,7 +96,7 @@ public class SearchResultsAdapterTest {
public void testSingleSourceMerge_ExactCopyReturned() {
ArrayList<SearchResult> intentResults = getIntentSampleResults();
mAdapter.addSearchResults(intentResults, mLoaderClassName);
mAdapter.displaySearchResults();
mAdapter.displaySearchResults("");
List<SearchResult> updatedResults = mAdapter.getSearchResults();
assertThat(updatedResults).containsAllIn(intentResults);
@@ -109,7 +124,7 @@ public class SearchResultsAdapterTest {
InstalledAppResultLoader.class.getName());
mAdapter.addSearchResults(getDummyDbResults(),
DatabaseResultLoader.class.getName());
int count = mAdapter.displaySearchResults();
int count = mAdapter.displaySearchResults("");
List<SearchResult> results = mAdapter.getSearchResults();
assertThat(results.get(0).title).isEqualTo("alpha");
@@ -121,6 +136,22 @@ public class SearchResultsAdapterTest {
assertThat(count).isEqualTo(6);
}
@Test
public void testDisplayResults_ShouldNotRunSmartRankingIfDisabled() {
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any()))
.thenReturn(false);
mAdapter.displaySearchResults("");
verify(mSearchFeatureProvider, never()).rankSearchResults(anyString(), anyList());
}
@Test
public void testDisplayResults_ShouldRunSmartRankingIfEnabled() {
when(mSearchFeatureProvider.isSmartSearchRankingEnabled(any()))
.thenReturn(true);
mAdapter.displaySearchResults("");
verify(mSearchFeatureProvider, times(1)).rankSearchResults(anyString(), anyList());
}
private List<SearchResult> getDummyDbResults() {
List<SearchResult> results = new ArrayList<>();
IntentPayload payload = new IntentPayload(new Intent());