Sync search result loaders
The loaders should be syncronized so the results can be properly ranked without sudden insertions. This means InstalledAppsLoader needs to finish faster, which is accomplished by delaying icon loading to bind time rather than as the apps are queried. Bug: 34772522 Test: make RunSettingsRoboTests Change-Id: I7f5244c574d37c6cfd8bbd0d3d40488f38211be3
This commit is contained in:
45
src/com/android/settings/search2/AppSearchResult.java
Normal file
45
src/com/android/settings/search2/AppSearchResult.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.search2;
|
||||||
|
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
|
||||||
|
public class AppSearchResult extends SearchResult {
|
||||||
|
/**
|
||||||
|
* Installed app's ApplicationInfo for delayed loading of icons
|
||||||
|
*/
|
||||||
|
public final ApplicationInfo info;
|
||||||
|
|
||||||
|
public AppSearchResult(Builder builder) {
|
||||||
|
super(builder);
|
||||||
|
info = builder.mInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder extends SearchResult.Builder {
|
||||||
|
protected ApplicationInfo mInfo;
|
||||||
|
|
||||||
|
public SearchResult.Builder setAppInfo(ApplicationInfo info) {
|
||||||
|
mInfo = info;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppSearchResult build() {
|
||||||
|
return new AppSearchResult(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -36,7 +36,7 @@ import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_PREFS
|
|||||||
/**
|
/**
|
||||||
* AsyncTask to retrieve Settings, First party app and any intent based results.
|
* AsyncTask to retrieve Settings, First party app and any intent based results.
|
||||||
*/
|
*/
|
||||||
public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
|
public class DatabaseResultLoader extends AsyncLoader<List<? extends SearchResult>> {
|
||||||
private static final String LOG = "DatabaseResultLoader";
|
private static final String LOG = "DatabaseResultLoader";
|
||||||
|
|
||||||
/* These indices are used to match the columns of the this loader's SELECT statement.
|
/* These indices are used to match the columns of the this loader's SELECT statement.
|
||||||
@@ -98,26 +98,25 @@ public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
private static final int[] BASE_RANKS = {1, 4, 7};
|
private static final int[] BASE_RANKS = {1, 4, 7};
|
||||||
|
|
||||||
private final String mQueryText;
|
private final String mQueryText;
|
||||||
private final SQLiteDatabase mDatabase;
|
private final Context mContext;
|
||||||
private final CursorToSearchResultConverter mConverter;
|
private final CursorToSearchResultConverter mConverter;
|
||||||
private final SiteMapManager mSiteMapManager;
|
private final SiteMapManager mSiteMapManager;
|
||||||
|
|
||||||
public DatabaseResultLoader(Context context, String queryText) {
|
public DatabaseResultLoader(Context context, String queryText, SiteMapManager mapManager) {
|
||||||
super(context);
|
super(context);
|
||||||
mSiteMapManager = FeatureFactory.getFactory(context)
|
mSiteMapManager = mapManager;
|
||||||
.getSearchFeatureProvider().getSiteMapManager();
|
mContext = context;
|
||||||
mDatabase = IndexDatabaseHelper.getInstance(context).getReadableDatabase();
|
|
||||||
mQueryText = cleanQuery(queryText);
|
mQueryText = cleanQuery(queryText);
|
||||||
mConverter = new CursorToSearchResultConverter(context, mQueryText);
|
mConverter = new CursorToSearchResultConverter(context, mQueryText);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDiscardResult(List<SearchResult> result) {
|
protected void onDiscardResult(List<? extends SearchResult> result) {
|
||||||
// TODO Search
|
// TODO Search
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SearchResult> loadInBackground() {
|
public List<? extends SearchResult> loadInBackground() {
|
||||||
if (mQueryText == null || mQueryText.isEmpty()) {
|
if (mQueryText == null || mQueryText.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -144,7 +143,9 @@ public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
final String whereClause = buildWhereClause(matchColumns);
|
final String whereClause = buildWhereClause(matchColumns);
|
||||||
final String[] selection = buildQuerySelection(matchColumns.length * 2);
|
final String[] selection = buildQuerySelection(matchColumns.length * 2);
|
||||||
|
|
||||||
final Cursor resultCursor = mDatabase.query(TABLE_PREFS_INDEX, SELECT_COLUMNS, whereClause,
|
final SQLiteDatabase database = IndexDatabaseHelper.getInstance(mContext)
|
||||||
|
.getReadableDatabase();
|
||||||
|
final Cursor resultCursor = database.query(TABLE_PREFS_INDEX, SELECT_COLUMNS, whereClause,
|
||||||
selection, null, null, null);
|
selection, null, null, null);
|
||||||
return mConverter.convertCursor(mSiteMapManager, resultCursor, baseRank);
|
return mConverter.convertCursor(mSiteMapManager, resultCursor, baseRank);
|
||||||
}
|
}
|
||||||
|
@@ -42,7 +42,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* Search loader for installed apps.
|
* Search loader for installed apps.
|
||||||
*/
|
*/
|
||||||
public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
|
public class InstalledAppResultLoader extends AsyncLoader<List<? extends SearchResult>> {
|
||||||
|
|
||||||
private static final int NAME_NO_MATCH = -1;
|
private static final int NAME_NO_MATCH = -1;
|
||||||
private static final Intent LAUNCHER_PROBE = new Intent(Intent.ACTION_MAIN)
|
private static final Intent LAUNCHER_PROBE = new Intent(Intent.ACTION_MAIN)
|
||||||
@@ -56,18 +56,17 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
|
|
||||||
|
|
||||||
public InstalledAppResultLoader(Context context, PackageManagerWrapper pmWrapper,
|
public InstalledAppResultLoader(Context context, PackageManagerWrapper pmWrapper,
|
||||||
String query) {
|
String query, SiteMapManager mapManager) {
|
||||||
super(context);
|
super(context);
|
||||||
mSiteMapManager = FeatureFactory.getFactory(context)
|
mSiteMapManager = mapManager;
|
||||||
.getSearchFeatureProvider().getSiteMapManager();
|
|
||||||
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||||
mPackageManager = pmWrapper;
|
mPackageManager = pmWrapper;
|
||||||
mQuery = query;
|
mQuery = query;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SearchResult> loadInBackground() {
|
public List<? extends SearchResult> loadInBackground() {
|
||||||
final List<SearchResult> results = new ArrayList<>();
|
final List<AppSearchResult> results = new ArrayList<>();
|
||||||
final PackageManager pm = mPackageManager.getPackageManager();
|
final PackageManager pm = mPackageManager.getPackageManager();
|
||||||
|
|
||||||
for (UserInfo user : getUsersToCount()) {
|
for (UserInfo user : getUsersToCount()) {
|
||||||
@@ -90,10 +89,10 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||||
.setData(Uri.fromParts("package", info.packageName, null));
|
.setData(Uri.fromParts("package", info.packageName, null));
|
||||||
|
|
||||||
final SearchResult.Builder builder = new SearchResult.Builder();
|
final AppSearchResult.Builder builder = new AppSearchResult.Builder();
|
||||||
builder.addIcon(info.loadIcon(pm))
|
builder.setAppInfo(info)
|
||||||
.addTitle(info.loadLabel(pm))
|
.addTitle(info.loadLabel(pm))
|
||||||
.addRank(wordDiff)
|
.addRank(getRank(wordDiff))
|
||||||
.addBreadcrumbs(getBreadCrumb())
|
.addBreadcrumbs(getBreadCrumb())
|
||||||
.addPayload(new IntentPayload(intent));
|
.addPayload(new IntentPayload(intent));
|
||||||
results.add(builder.build());
|
results.add(builder.build());
|
||||||
@@ -120,7 +119,7 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDiscardResult(List<SearchResult> result) {
|
protected void onDiscardResult(List<? extends SearchResult> result) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,4 +199,16 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
}
|
}
|
||||||
return mBreadcrumb;
|
return mBreadcrumb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A temporary ranking scheme for installed apps.
|
||||||
|
* @param wordDiff difference between query length and app name length.
|
||||||
|
* @return the ranking.
|
||||||
|
*/
|
||||||
|
private int getRank(int wordDiff) {
|
||||||
|
if (wordDiff < 6) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* Loader for recently searched queries.
|
* Loader for recently searched queries.
|
||||||
*/
|
*/
|
||||||
public class SavedQueryLoader extends AsyncLoader<List<SearchResult>> {
|
public class SavedQueryLoader extends AsyncLoader<List<? extends SearchResult>> {
|
||||||
|
|
||||||
// Max number of proposed suggestions
|
// Max number of proposed suggestions
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
@@ -45,12 +45,12 @@ public class SavedQueryLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDiscardResult(List<SearchResult> result) {
|
protected void onDiscardResult(List<? extends SearchResult> result) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SearchResult> loadInBackground() {
|
public List<? extends SearchResult> loadInBackground() {
|
||||||
Cursor cursor = mDatabase.query(IndexDatabaseHelper.Tables.TABLE_SAVED_QUERIES /* table */,
|
Cursor cursor = mDatabase.query(IndexDatabaseHelper.Tables.TABLE_SAVED_QUERIES /* table */,
|
||||||
new String[]{SavedQueriesColumns.QUERY} /* columns */,
|
new String[]{SavedQueriesColumns.QUERY} /* columns */,
|
||||||
null /* selection */,
|
null /* selection */,
|
||||||
|
@@ -65,13 +65,14 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DatabaseResultLoader getDatabaseSearchLoader(Context context, String query) {
|
public DatabaseResultLoader getDatabaseSearchLoader(Context context, String query) {
|
||||||
return new DatabaseResultLoader(context, query);
|
return new DatabaseResultLoader(context, query, getSiteMapManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InstalledAppResultLoader getInstalledAppSearchLoader(Context context, String query) {
|
public InstalledAppResultLoader getInstalledAppSearchLoader(Context context, String query) {
|
||||||
return new InstalledAppResultLoader(
|
return new InstalledAppResultLoader(
|
||||||
context, new PackageManagerWrapperImpl(context.getPackageManager()), query);
|
context, new PackageManagerWrapperImpl(context.getPackageManager()), query,
|
||||||
|
getSiteMapManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -41,9 +41,11 @@ import com.android.settings.core.instrumentation.MetricsFeatureProvider;
|
|||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public class SearchFragment extends InstrumentedFragment implements
|
public class SearchFragment extends InstrumentedFragment implements
|
||||||
SearchView.OnQueryTextListener, LoaderManager.LoaderCallbacks<List<SearchResult>> {
|
SearchView.OnQueryTextListener, LoaderManager.LoaderCallbacks<List<? extends SearchResult>>
|
||||||
|
{
|
||||||
private static final String TAG = "SearchFragment";
|
private static final String TAG = "SearchFragment";
|
||||||
|
|
||||||
// State values
|
// State values
|
||||||
@@ -56,6 +58,11 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
private static final int LOADER_ID_DATABASE = 1;
|
private static final int LOADER_ID_DATABASE = 1;
|
||||||
private static final int LOADER_ID_INSTALLED_APPS = 2;
|
private static final int LOADER_ID_INSTALLED_APPS = 2;
|
||||||
|
|
||||||
|
private static final int NUM_QUERY_LOADERS = 2;
|
||||||
|
|
||||||
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
|
AtomicInteger mUnfinishedLoadersCount = new AtomicInteger(NUM_QUERY_LOADERS);;
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
static final String RESULT_CLICK_COUNT = "settings_search_result_click_count";
|
static final String RESULT_CLICK_COUNT = "settings_search_result_click_count";
|
||||||
@@ -69,9 +76,13 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
private boolean mNeverEnteredQuery = true;
|
private boolean mNeverEnteredQuery = true;
|
||||||
private int mResultClickCount;
|
private int mResultClickCount;
|
||||||
private MetricsFeatureProvider mMetricsFeatureProvider;
|
private MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
private SearchFeatureProvider mSearchFeatureProvider;
|
|
||||||
|
|
||||||
private SearchResultsAdapter mSearchAdapter;
|
@VisibleForTesting (otherwise = VisibleForTesting.PRIVATE)
|
||||||
|
SearchFeatureProvider mSearchFeatureProvider;
|
||||||
|
|
||||||
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
|
SearchResultsAdapter mSearchAdapter;
|
||||||
|
|
||||||
private RecyclerView mResultsRecyclerView;
|
private RecyclerView mResultsRecyclerView;
|
||||||
private SearchView mSearchView;
|
private SearchView mSearchView;
|
||||||
|
|
||||||
@@ -92,7 +103,9 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
mSearchAdapter = new SearchResultsAdapter(this);
|
mSearchAdapter = new SearchResultsAdapter(this);
|
||||||
|
|
||||||
final LoaderManager loaderManager = getLoaderManager();
|
final LoaderManager loaderManager = getLoaderManager();
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
mQuery = savedInstanceState.getString(STATE_QUERY);
|
mQuery = savedInstanceState.getString(STATE_QUERY);
|
||||||
mNeverEnteredQuery = savedInstanceState.getBoolean(STATE_NEVER_ENTERED_QUERY);
|
mNeverEnteredQuery = savedInstanceState.getBoolean(STATE_NEVER_ENTERED_QUERY);
|
||||||
@@ -181,7 +194,7 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loader<List<SearchResult>> onCreateLoader(int id, Bundle args) {
|
public Loader<List<? extends SearchResult>> onCreateLoader(int id, Bundle args) {
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
@@ -197,12 +210,17 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadFinished(Loader<List<SearchResult>> loader, List<SearchResult> data) {
|
public void onLoadFinished(Loader<List<? extends SearchResult>> loader,
|
||||||
mSearchAdapter.mergeResults(data, loader.getClass().getName());
|
List<? extends SearchResult> data) {
|
||||||
|
mSearchAdapter.addResultsToMap(data, loader.getClass().getName());
|
||||||
|
|
||||||
|
if (mUnfinishedLoadersCount.decrementAndGet() == 0) {
|
||||||
|
mSearchAdapter.mergeResults();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaderReset(Loader<List<SearchResult>> loader) {
|
public void onLoaderReset(Loader<List<? extends SearchResult>> loader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSearchResultClicked() {
|
public void onSearchResultClicked() {
|
||||||
@@ -217,6 +235,7 @@ public class SearchFragment extends InstrumentedFragment implements
|
|||||||
|
|
||||||
private void restartLoaders() {
|
private void restartLoaders() {
|
||||||
final LoaderManager loaderManager = getLoaderManager();
|
final LoaderManager loaderManager = getLoaderManager();
|
||||||
|
mUnfinishedLoadersCount.set(NUM_QUERY_LOADERS);
|
||||||
loaderManager.restartLoader(LOADER_ID_DATABASE, null /* args */, this /* callback */);
|
loaderManager.restartLoader(LOADER_ID_DATABASE, null /* args */, this /* callback */);
|
||||||
loaderManager.restartLoader(LOADER_ID_INSTALLED_APPS, null /* args */, this /* callback */);
|
loaderManager.restartLoader(LOADER_ID_INSTALLED_APPS, null /* args */, this /* callback */);
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,12 @@ import java.util.Objects;
|
|||||||
*/
|
*/
|
||||||
public class SearchResult implements Comparable<SearchResult> {
|
public class SearchResult implements Comparable<SearchResult> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the max rank for a search result to be considered as ranked. Results with ranks
|
||||||
|
* higher than this have no guarantee for sorting order.
|
||||||
|
*/
|
||||||
|
public static final int MAX_RANK = 9;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The title of the result and main text displayed.
|
* The title of the result and main text displayed.
|
||||||
* Intent Results: Displays as the primary
|
* Intent Results: Displays as the primary
|
||||||
@@ -74,7 +80,7 @@ public class SearchResult implements Comparable<SearchResult> {
|
|||||||
*/
|
*/
|
||||||
public final long stableId;
|
public final long stableId;
|
||||||
|
|
||||||
private SearchResult(Builder builder) {
|
protected SearchResult(Builder builder) {
|
||||||
title = builder.mTitle;
|
title = builder.mTitle;
|
||||||
summary = builder.mSummary;
|
summary = builder.mSummary;
|
||||||
breadcrumbs = builder.mBreadcrumbs;
|
breadcrumbs = builder.mBreadcrumbs;
|
||||||
@@ -116,19 +122,19 @@ public class SearchResult implements Comparable<SearchResult> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder addRank(int rank) {
|
public Builder addRank(int rank) {
|
||||||
if (rank >= 0 && rank <= 9) {
|
if (rank >= 0 && rank <= 9) {
|
||||||
mRank = rank;
|
mRank = rank;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder addIcon(Drawable icon) {
|
public Builder addIcon(Drawable icon) {
|
||||||
mIcon = icon;
|
mIcon = icon;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder addPayload(ResultPayload payload) {
|
public Builder addPayload(ResultPayload payload) {
|
||||||
mResultPayload = payload;
|
mResultPayload = payload;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
package com.android.settings.search2;
|
package com.android.settings.search2;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.support.annotation.MainThread;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
import android.support.v7.widget.RecyclerView.Adapter;
|
import android.support.v7.widget.RecyclerView.Adapter;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
@@ -31,10 +32,13 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.android.settings.search2.SearchResult.MAX_RANK;
|
||||||
|
|
||||||
public class SearchResultsAdapter extends Adapter<SearchViewHolder> {
|
public class SearchResultsAdapter extends Adapter<SearchViewHolder> {
|
||||||
|
|
||||||
private final List<SearchResult> mSearchResults;
|
private final List<SearchResult> mSearchResults;
|
||||||
private final Map<String, List<SearchResult>> mResultsMap;
|
|
||||||
private final SearchFragment mFragment;
|
private final SearchFragment mFragment;
|
||||||
|
private Map<String, List<? extends SearchResult>> mResultsMap;
|
||||||
|
|
||||||
public SearchResultsAdapter(SearchFragment fragment) {
|
public SearchResultsAdapter(SearchFragment fragment) {
|
||||||
mFragment = fragment;
|
mFragment = fragment;
|
||||||
@@ -84,15 +88,56 @@ public class SearchResultsAdapter extends Adapter<SearchViewHolder> {
|
|||||||
return mSearchResults.size();
|
return mSearchResults.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void mergeResults(List<SearchResult> freshResults, String loaderClassName) {
|
/**
|
||||||
|
* Store the results from each of the loaders to be merged when all loaders are finished.
|
||||||
|
* @param freshResults are the results from the loader.
|
||||||
|
* @param loaderClassName class name of the loader.
|
||||||
|
*/
|
||||||
|
@MainThread
|
||||||
|
public void addResultsToMap(List<? extends SearchResult> freshResults,
|
||||||
|
String loaderClassName) {
|
||||||
if (freshResults == null) {
|
if (freshResults == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mResultsMap.put(loaderClassName, freshResults);
|
mResultsMap.put(loaderClassName, freshResults);
|
||||||
final int oldSize = mSearchResults.size();
|
}
|
||||||
mSearchResults.addAll(freshResults);
|
|
||||||
final int newSize = mSearchResults.size();
|
/**
|
||||||
notifyItemRangeInserted(oldSize, newSize - oldSize);
|
* Merge the results from each of the loaders into one list for the adapter.
|
||||||
|
* Prioritizes results from the local database over installed apps.
|
||||||
|
*/
|
||||||
|
public void mergeResults() {
|
||||||
|
final List<? extends SearchResult> databaseResults = mResultsMap
|
||||||
|
.get(DatabaseResultLoader.class.getName());
|
||||||
|
final List<? extends SearchResult> installedAppResults = mResultsMap
|
||||||
|
.get(InstalledAppResultLoader.class.getName());
|
||||||
|
final int dbSize = (databaseResults != null) ? databaseResults.size() : 0;
|
||||||
|
final int appSize = (installedAppResults != null) ? installedAppResults.size() : 0;
|
||||||
|
final List<SearchResult> results = new ArrayList<>(dbSize + appSize);
|
||||||
|
|
||||||
|
int dbIndex = 0;
|
||||||
|
int appIndex = 0;
|
||||||
|
int rank = 1;
|
||||||
|
|
||||||
|
while (rank <= MAX_RANK) {
|
||||||
|
while ((dbIndex < dbSize) && (databaseResults.get(dbIndex).rank == rank)) {
|
||||||
|
results.add(databaseResults.get(dbIndex++));
|
||||||
|
}
|
||||||
|
while ((appIndex < appSize) && (installedAppResults.get(appIndex).rank == rank)) {
|
||||||
|
results.add(installedAppResults.get(appIndex++));
|
||||||
|
}
|
||||||
|
rank ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (dbIndex < dbSize) {
|
||||||
|
results.add(databaseResults.get(dbIndex++));
|
||||||
|
}
|
||||||
|
while (appIndex < appSize) {
|
||||||
|
results.add(installedAppResults.get(appIndex++));
|
||||||
|
}
|
||||||
|
|
||||||
|
mSearchResults.addAll(results);
|
||||||
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearResults() {
|
public void clearResults() {
|
||||||
|
@@ -16,6 +16,9 @@
|
|||||||
package com.android.settings.search2;
|
package com.android.settings.search2;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -52,8 +55,14 @@ public abstract class SearchViewHolder extends RecyclerView.ViewHolder {
|
|||||||
summaryView.setText(result.summary);
|
summaryView.setText(result.summary);
|
||||||
summaryView.setVisibility(View.VISIBLE);
|
summaryView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
iconView.setImageDrawable(result.icon);
|
|
||||||
if (result.icon == null) {
|
if (result instanceof AppSearchResult) {
|
||||||
|
AppSearchResult appResult = (AppSearchResult) result;
|
||||||
|
PackageManager pm = fragment.getActivity().getPackageManager();
|
||||||
|
iconView.setImageDrawable(appResult.info.loadIcon(pm));
|
||||||
|
} else if (result.icon != null) {
|
||||||
|
iconView.setImageDrawable(result.icon);
|
||||||
|
} else {
|
||||||
iconView.setBackgroundResource(R.drawable.empty_icon);
|
iconView.setBackgroundResource(R.drawable.empty_icon);
|
||||||
}
|
}
|
||||||
bindBreadcrumbView(result);
|
bindBreadcrumbView(result);
|
||||||
|
@@ -79,124 +79,124 @@ public class DatabaseResultLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMatchTitle() {
|
public void testMatchTitle() {
|
||||||
loader = new DatabaseResultLoader(mContext, "title");
|
loader = new DatabaseResultLoader(mContext, "title", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(2);
|
assertThat(loader.loadInBackground().size()).isEqualTo(2);
|
||||||
verify(mSiteMapManager, times(2)).buildBreadCrumb(eq(mContext), anyString(), anyString());
|
verify(mSiteMapManager, times(2)).buildBreadCrumb(eq(mContext), anyString(), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMatchSummary() {
|
public void testMatchSummary() {
|
||||||
loader = new DatabaseResultLoader(mContext, "summary");
|
loader = new DatabaseResultLoader(mContext, "summary", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(2);
|
assertThat(loader.loadInBackground().size()).isEqualTo(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMatchKeywords() {
|
public void testMatchKeywords() {
|
||||||
loader = new DatabaseResultLoader(mContext, "keywords");
|
loader = new DatabaseResultLoader(mContext, "keywords", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(2);
|
assertThat(loader.loadInBackground().size()).isEqualTo(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMatchEntries() {
|
public void testMatchEntries() {
|
||||||
loader = new DatabaseResultLoader(mContext, "entries");
|
loader = new DatabaseResultLoader(mContext, "entries", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(2);
|
assertThat(loader.loadInBackground().size()).isEqualTo(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseWord_MatchesNonPrefix() {
|
public void testSpecialCaseWord_MatchesNonPrefix() {
|
||||||
insertSpecialCase("Data usage");
|
insertSpecialCase("Data usage");
|
||||||
loader = new DatabaseResultLoader(mContext, "usage");
|
loader = new DatabaseResultLoader(mContext, "usage", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseSpace_Matches() {
|
public void testSpecialCaseSpace_Matches() {
|
||||||
insertSpecialCase("space");
|
insertSpecialCase("space");
|
||||||
loader = new DatabaseResultLoader(mContext, " space ");
|
loader = new DatabaseResultLoader(mContext, " space ", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseDash_MatchesWordNoDash() {
|
public void testSpecialCaseDash_MatchesWordNoDash() {
|
||||||
insertSpecialCase("wi-fi calling");
|
insertSpecialCase("wi-fi calling");
|
||||||
loader = new DatabaseResultLoader(mContext, "wifi");
|
loader = new DatabaseResultLoader(mContext, "wifi", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseDash_MatchesWordWithDash() {
|
public void testSpecialCaseDash_MatchesWordWithDash() {
|
||||||
insertSpecialCase("priorités seulment");
|
insertSpecialCase("priorités seulment");
|
||||||
loader = new DatabaseResultLoader(mContext, "priorités");
|
loader = new DatabaseResultLoader(mContext, "priorités", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseDash_MatchesWordWithoutDash() {
|
public void testSpecialCaseDash_MatchesWordWithoutDash() {
|
||||||
insertSpecialCase("priorités seulment");
|
insertSpecialCase("priorités seulment");
|
||||||
loader = new DatabaseResultLoader(mContext, "priorites");
|
loader = new DatabaseResultLoader(mContext, "priorites", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseDash_MatchesEntireQueryWithoutDash() {
|
public void testSpecialCaseDash_MatchesEntireQueryWithoutDash() {
|
||||||
insertSpecialCase("wi-fi calling");
|
insertSpecialCase("wi-fi calling");
|
||||||
loader = new DatabaseResultLoader(mContext, "wifi calling");
|
loader = new DatabaseResultLoader(mContext, "wifi calling", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCasePrefix_MatchesPrefixOfEntry() {
|
public void testSpecialCasePrefix_MatchesPrefixOfEntry() {
|
||||||
insertSpecialCase("Photos");
|
insertSpecialCase("Photos");
|
||||||
loader = new DatabaseResultLoader(mContext, "pho");
|
loader = new DatabaseResultLoader(mContext, "pho", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCasePrefix_DoesNotMatchNonPrefixSubstring() {
|
public void testSpecialCasePrefix_DoesNotMatchNonPrefixSubstring() {
|
||||||
insertSpecialCase("Photos");
|
insertSpecialCase("Photos");
|
||||||
loader = new DatabaseResultLoader(mContext, "hot");
|
loader = new DatabaseResultLoader(mContext, "hot", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(0);
|
assertThat(loader.loadInBackground().size()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseMultiWordPrefix_MatchesPrefixOfEntry() {
|
public void testSpecialCaseMultiWordPrefix_MatchesPrefixOfEntry() {
|
||||||
insertSpecialCase("Apps Notifications");
|
insertSpecialCase("Apps Notifications");
|
||||||
loader = new DatabaseResultLoader(mContext, "Apps");
|
loader = new DatabaseResultLoader(mContext, "Apps", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseMultiWordPrefix_MatchesSecondWordPrefixOfEntry() {
|
public void testSpecialCaseMultiWordPrefix_MatchesSecondWordPrefixOfEntry() {
|
||||||
insertSpecialCase("Apps Notifications");
|
insertSpecialCase("Apps Notifications");
|
||||||
loader = new DatabaseResultLoader(mContext, "Not");
|
loader = new DatabaseResultLoader(mContext, "Not", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseMultiWordPrefix_DoesNotMatchMatchesPrefixOfFirstEntry() {
|
public void testSpecialCaseMultiWordPrefix_DoesNotMatchMatchesPrefixOfFirstEntry() {
|
||||||
insertSpecialCase("Apps Notifications");
|
insertSpecialCase("Apps Notifications");
|
||||||
loader = new DatabaseResultLoader(mContext, "pp");
|
loader = new DatabaseResultLoader(mContext, "pp", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(0);
|
assertThat(loader.loadInBackground().size()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseMultiWordPrefix_DoesNotMatchMatchesPrefixOfSecondEntry() {
|
public void testSpecialCaseMultiWordPrefix_DoesNotMatchMatchesPrefixOfSecondEntry() {
|
||||||
insertSpecialCase("Apps Notifications");
|
insertSpecialCase("Apps Notifications");
|
||||||
loader = new DatabaseResultLoader(mContext, "tion");
|
loader = new DatabaseResultLoader(mContext, "tion", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(0);
|
assertThat(loader.loadInBackground().size()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseMultiWordPrefixWithSpecial_MatchesPrefixOfEntry() {
|
public void testSpecialCaseMultiWordPrefixWithSpecial_MatchesPrefixOfEntry() {
|
||||||
insertSpecialCase("Apps & Notifications");
|
insertSpecialCase("Apps & Notifications");
|
||||||
loader = new DatabaseResultLoader(mContext, "App");
|
loader = new DatabaseResultLoader(mContext, "App", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpecialCaseMultiWordPrefixWithSpecial_MatchesPrefixOfSecondEntry() {
|
public void testSpecialCaseMultiWordPrefixWithSpecial_MatchesPrefixOfSecondEntry() {
|
||||||
insertSpecialCase("Apps & Notifications");
|
insertSpecialCase("Apps & Notifications");
|
||||||
loader = new DatabaseResultLoader(mContext, "No");
|
loader = new DatabaseResultLoader(mContext, "No", mSiteMapManager);
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
assertThat(loader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@ package com.android.settings.search;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -26,11 +27,14 @@ import android.widget.FrameLayout;
|
|||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsRobolectricTestRunner;
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.search2.AppSearchResult;
|
||||||
import com.android.settings.search2.DatabaseResultLoader;
|
import com.android.settings.search2.DatabaseResultLoader;
|
||||||
import com.android.settings.search2.InlineSwitchViewHolder;
|
import com.android.settings.search2.InlineSwitchViewHolder;
|
||||||
|
import com.android.settings.search2.InstalledAppResultLoader;
|
||||||
import com.android.settings.search2.IntentPayload;
|
import com.android.settings.search2.IntentPayload;
|
||||||
import com.android.settings.search2.IntentSearchViewHolder;
|
import com.android.settings.search2.IntentSearchViewHolder;
|
||||||
import com.android.settings.search2.ResultPayload;
|
import com.android.settings.search2.ResultPayload;
|
||||||
|
import com.android.settings.search2.SearchActivity;
|
||||||
import com.android.settings.search2.SearchFragment;
|
import com.android.settings.search2.SearchFragment;
|
||||||
import com.android.settings.search2.SearchResult;
|
import com.android.settings.search2.SearchResult;
|
||||||
import com.android.settings.search2.SearchResult.Builder;
|
import com.android.settings.search2.SearchResult.Builder;
|
||||||
@@ -46,11 +50,13 @@ import org.robolectric.Robolectric;
|
|||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.shadows.ShadowApplication;
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
import org.robolectric.shadows.ShadowViewGroup;
|
import org.robolectric.shadows.ShadowViewGroup;
|
||||||
|
import org.robolectric.util.ActivityController;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
|
||||||
@RunWith(SettingsRobolectricTestRunner.class)
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
@@ -79,17 +85,8 @@ public class SearchAdapterTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testSingleSourceMerge_ExactCopyReturned() {
|
public void testSingleSourceMerge_ExactCopyReturned() {
|
||||||
ArrayList<SearchResult> intentResults = getIntentSampleResults();
|
ArrayList<SearchResult> intentResults = getIntentSampleResults();
|
||||||
mAdapter.mergeResults(intentResults, mLoaderClassName);
|
mAdapter.addResultsToMap(intentResults, mLoaderClassName);
|
||||||
|
mAdapter.mergeResults();
|
||||||
List<SearchResult> updatedResults = mAdapter.getSearchResults();
|
|
||||||
assertThat(updatedResults).containsAllIn(intentResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDuplicateSourceMerge_ExactCopyReturned() {
|
|
||||||
ArrayList<SearchResult> intentResults = getIntentSampleResults();
|
|
||||||
mAdapter.mergeResults(intentResults, mLoaderClassName);
|
|
||||||
mAdapter.mergeResults(intentResults, mLoaderClassName);
|
|
||||||
|
|
||||||
List<SearchResult> updatedResults = mAdapter.getSearchResults();
|
List<SearchResult> updatedResults = mAdapter.getSearchResults();
|
||||||
assertThat(updatedResults).containsAllIn(intentResults);
|
assertThat(updatedResults).containsAllIn(intentResults);
|
||||||
@@ -111,6 +108,65 @@ public class SearchAdapterTest {
|
|||||||
assertThat(view).isInstanceOf(InlineSwitchViewHolder.class);
|
assertThat(view).isInstanceOf(InlineSwitchViewHolder.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEndToEndSearch_ProperResultsMerged() {
|
||||||
|
mAdapter.addResultsToMap(getDummyAppResults(),
|
||||||
|
InstalledAppResultLoader.class.getName());
|
||||||
|
mAdapter.addResultsToMap(getDummyDbResults(),
|
||||||
|
DatabaseResultLoader.class.getName());
|
||||||
|
mAdapter.mergeResults();
|
||||||
|
|
||||||
|
List<SearchResult> results = mAdapter.getSearchResults();
|
||||||
|
assertThat(results.get(0).title).isEqualTo("alpha");
|
||||||
|
assertThat(results.get(1).title).isEqualTo("appAlpha");
|
||||||
|
assertThat(results.get(2).title).isEqualTo("appBravo");
|
||||||
|
assertThat(results.get(3).title).isEqualTo("bravo");
|
||||||
|
assertThat(results.get(4).title).isEqualTo("appCharlie");
|
||||||
|
assertThat(results.get(5).title).isEqualTo("Charlie");
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SearchResult> getDummyDbResults() {
|
||||||
|
List<SearchResult> results = new ArrayList<>();
|
||||||
|
IntentPayload payload = new IntentPayload(new Intent());
|
||||||
|
SearchResult.Builder builder = new SearchResult.Builder();
|
||||||
|
builder.addPayload(payload);
|
||||||
|
|
||||||
|
builder.addTitle("alpha")
|
||||||
|
.addRank(1);
|
||||||
|
results.add(builder.build());
|
||||||
|
|
||||||
|
builder.addTitle("bravo")
|
||||||
|
.addRank(3);
|
||||||
|
results.add(builder.build());
|
||||||
|
|
||||||
|
builder.addTitle("Charlie")
|
||||||
|
.addRank(6);
|
||||||
|
results.add(builder.build());
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<AppSearchResult> getDummyAppResults() {
|
||||||
|
List<AppSearchResult> results = new ArrayList<>();
|
||||||
|
IntentPayload payload = new IntentPayload(new Intent());
|
||||||
|
AppSearchResult.Builder builder = new AppSearchResult.Builder();
|
||||||
|
builder.addPayload(payload);
|
||||||
|
|
||||||
|
builder.addTitle("appAlpha")
|
||||||
|
.addRank(1);
|
||||||
|
results.add(builder.build());
|
||||||
|
|
||||||
|
builder.addTitle("appBravo")
|
||||||
|
.addRank(2);
|
||||||
|
results.add(builder.build());
|
||||||
|
|
||||||
|
builder.addTitle("appCharlie")
|
||||||
|
.addRank(4);
|
||||||
|
results.add(builder.build());
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
private ArrayList<SearchResult> getIntentSampleResults() {
|
private ArrayList<SearchResult> getIntentSampleResults() {
|
||||||
ArrayList<SearchResult> sampleResults = new ArrayList<>();
|
ArrayList<SearchResult> sampleResults = new ArrayList<>();
|
||||||
ArrayList<String> breadcrumbs = new ArrayList<>();
|
ArrayList<String> breadcrumbs = new ArrayList<>();
|
||||||
|
@@ -94,6 +94,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
ApplicationTestUtils.buildInfo(0 /* uid */, "app4", 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, "app4", 0 /* flags */,
|
||||||
0 /* targetSdkVersion */),
|
0 /* targetSdkVersion */),
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, "app", 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, "app", 0 /* flags */,
|
||||||
|
0 /* targetSdkVersion */),
|
||||||
|
ApplicationTestUtils.buildInfo(0 /* uid */, "appBuffer", 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +103,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
public void query_noMatchingQuery_shouldReturnEmptyResult() {
|
public void query_noMatchingQuery_shouldReturnEmptyResult() {
|
||||||
final String query = "abc";
|
final String query = "abc";
|
||||||
|
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground()).isEmpty();
|
assertThat(mLoader.loadInBackground()).isEmpty();
|
||||||
}
|
}
|
||||||
@@ -110,12 +113,13 @@ public class InstalledAppResultLoaderTest {
|
|||||||
public void query_matchingQuery_shouldReturnNonSystemApps() {
|
public void query_matchingQuery_shouldReturnNonSystemApps() {
|
||||||
final String query = "app";
|
final String query = "app";
|
||||||
|
|
||||||
mLoader = spy(new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query));
|
mLoader = spy(new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager));
|
||||||
when(mLoader.getContext()).thenReturn(mContext);
|
when(mLoader.getContext()).thenReturn(mContext);
|
||||||
when(mSiteMapManager.buildBreadCrumb(eq(mContext), anyString(), anyString()))
|
when(mSiteMapManager.buildBreadCrumb(eq(mContext), anyString(), anyString()))
|
||||||
.thenReturn(Arrays.asList(new String[]{"123"}));
|
.thenReturn(Arrays.asList(new String[]{"123"}));
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(2);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(3);
|
||||||
verify(mSiteMapManager)
|
verify(mSiteMapManager)
|
||||||
.buildBreadCrumb(eq(mContext), anyString(), anyString());
|
.buildBreadCrumb(eq(mContext), anyString(), anyString());
|
||||||
}
|
}
|
||||||
@@ -128,7 +132,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
final String query = "app";
|
final String query = "app";
|
||||||
|
|
||||||
mLoader = spy(new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query));
|
mLoader = spy(new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager));
|
||||||
when(mLoader.getContext()).thenReturn(mContext);
|
when(mLoader.getContext()).thenReturn(mContext);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
||||||
@@ -150,7 +155,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
|
|
||||||
final String query = "app";
|
final String query = "app";
|
||||||
|
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
@@ -167,7 +173,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
|
|
||||||
final String query = "app";
|
final String query = "app";
|
||||||
|
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground()).isEmpty();
|
assertThat(mLoader.loadInBackground()).isEmpty();
|
||||||
verify(mSiteMapManager, never())
|
verify(mSiteMapManager, never())
|
||||||
@@ -178,15 +185,15 @@ public class InstalledAppResultLoaderTest {
|
|||||||
public void query_matchingQuery_shouldRankBasedOnSimilarity() {
|
public void query_matchingQuery_shouldRankBasedOnSimilarity() {
|
||||||
final String query = "app";
|
final String query = "app";
|
||||||
|
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
final List<SearchResult> results = mLoader.loadInBackground();
|
mSiteMapManager);
|
||||||
|
final List<? extends SearchResult> results = mLoader.loadInBackground();
|
||||||
|
|
||||||
// List is sorted by rank
|
// List is sorted by rank
|
||||||
assertThat(results.get(0).rank).isLessThan(results.get(1).rank);
|
assertThat(results.get(0).rank).isAtMost(results.get(1).rank);
|
||||||
// perfect match first
|
assertThat(results.get(0).title).isEqualTo("app4");
|
||||||
assertThat(results.get(0).title).isEqualTo(query);
|
assertThat(results.get(1).title).isEqualTo("app");
|
||||||
// Then partial match
|
assertThat(results.get(2).title).isEqualTo("appBuffer");
|
||||||
assertThat(results.get(1).title).isNotEqualTo(query);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -197,7 +204,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
@@ -210,7 +218,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(0);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
@@ -223,7 +232,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
@@ -236,7 +246,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
@@ -249,7 +260,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
@@ -262,7 +274,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
@@ -275,7 +288,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
@@ -288,7 +302,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
@@ -301,7 +316,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
@@ -314,7 +330,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(0);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
@@ -327,7 +344,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
|
||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query,
|
||||||
|
mSiteMapManager);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(0);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.search2;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mock loader to subvert the requirements of returning data while also driving the Loader
|
||||||
|
* lifecycle.
|
||||||
|
*/
|
||||||
|
class MockAppLoader extends InstalledAppResultLoader {
|
||||||
|
|
||||||
|
public MockAppLoader(Context context) {
|
||||||
|
super(context, null, "", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends SearchResult> loadInBackground() {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDiscardResult(List<? extends SearchResult> result) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.search2;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mock loader to subvert the requirements of returning data while also driving the Loader
|
||||||
|
* lifecycle.
|
||||||
|
*/
|
||||||
|
class MockDBLoader extends DatabaseResultLoader {
|
||||||
|
|
||||||
|
public MockDBLoader(Context context) {
|
||||||
|
super(context, "test", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends SearchResult> loadInBackground() {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDiscardResult(List<? extends SearchResult> result) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -60,7 +60,7 @@ public class SavedQueryLoaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loadInBackground_shouldReturnSavedQueries() {
|
public void loadInBackground_shouldReturnSavedQueries() {
|
||||||
final List<SearchResult> results = mLoader.loadInBackground();
|
final List<? extends SearchResult> results = mLoader.loadInBackground();
|
||||||
assertThat(results.size()).isEqualTo(SavedQueryLoader.MAX_PROPOSED_SUGGESTIONS);
|
assertThat(results.size()).isEqualTo(SavedQueryLoader.MAX_PROPOSED_SUGGESTIONS);
|
||||||
for (SearchResult result : results) {
|
for (SearchResult result : results) {
|
||||||
assertThat(result.viewType).isEqualTo(ResultPayload.PayloadType.SAVED_QUERY);
|
assertThat(result.viewType).isEqualTo(ResultPayload.PayloadType.SAVED_QUERY);
|
||||||
|
@@ -59,7 +59,7 @@ public class SavedQueryRecorderTest {
|
|||||||
mRecorder.loadInBackground();
|
mRecorder.loadInBackground();
|
||||||
|
|
||||||
final SavedQueryLoader loader = new SavedQueryLoader(mContext);
|
final SavedQueryLoader loader = new SavedQueryLoader(mContext);
|
||||||
List<SearchResult> results = loader.loadInBackground();
|
List<? extends SearchResult> results = loader.loadInBackground();
|
||||||
|
|
||||||
assertThat(results.size()).isEqualTo(1);
|
assertThat(results.size()).isEqualTo(1);
|
||||||
assertThat(results.get(0).title).isEqualTo(query);
|
assertThat(results.get(0).title).isEqualTo(query);
|
||||||
|
@@ -20,12 +20,16 @@ import android.content.Context;
|
|||||||
import android.content.Loader;
|
import android.content.Loader;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import android.os.UserManager;
|
||||||
import com.android.internal.logging.nano.MetricsProto;
|
import com.android.internal.logging.nano.MetricsProto;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsRobolectricTestRunner;
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
|
import com.android.settings.testutils.DatabaseTestUtils;
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -33,16 +37,20 @@ import org.mockito.Answers;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.Robolectric;
|
import org.robolectric.Robolectric;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.util.ActivityController;
|
import org.robolectric.util.ActivityController;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyString;
|
import static org.mockito.Matchers.anyString;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -57,6 +65,7 @@ public class SearchFragmentTest {
|
|||||||
private DatabaseResultLoader mDatabaseResultLoader;
|
private DatabaseResultLoader mDatabaseResultLoader;
|
||||||
@Mock
|
@Mock
|
||||||
private InstalledAppResultLoader mInstalledAppResultLoader;
|
private InstalledAppResultLoader mInstalledAppResultLoader;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private SavedQueryLoader mSavedQueryLoader;
|
private SavedQueryLoader mSavedQueryLoader;
|
||||||
|
|
||||||
@@ -65,8 +74,13 @@ public class SearchFragmentTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
FakeFeatureFactory.setupForTest(mContext);
|
FakeFeatureFactory.setupForTest(mContext);
|
||||||
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
|
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void screenRotate_shouldPersistQuery() {
|
||||||
when(mFeatureFactory.searchFeatureProvider
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
.getDatabaseSearchLoader(any(Context.class), anyString()))
|
.getDatabaseSearchLoader(any(Context.class), anyString()))
|
||||||
.thenReturn(mDatabaseResultLoader);
|
.thenReturn(mDatabaseResultLoader);
|
||||||
@@ -75,10 +89,7 @@ public class SearchFragmentTest {
|
|||||||
.thenReturn(mInstalledAppResultLoader);
|
.thenReturn(mInstalledAppResultLoader);
|
||||||
when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class)))
|
when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class)))
|
||||||
.thenReturn(mSavedQueryLoader);
|
.thenReturn(mSavedQueryLoader);
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void screenRotate_shouldPersistQuery() {
|
|
||||||
final Bundle bundle = new Bundle();
|
final Bundle bundle = new Bundle();
|
||||||
final String testQuery = "test";
|
final String testQuery = "test";
|
||||||
ActivityController<SearchActivity> activityController =
|
ActivityController<SearchActivity> activityController =
|
||||||
@@ -102,6 +113,15 @@ public class SearchFragmentTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void screenRotateEmptyString_ShouldNotCrash() {
|
public void screenRotateEmptyString_ShouldNotCrash() {
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getDatabaseSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(mDatabaseResultLoader);
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getInstalledAppSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(mInstalledAppResultLoader);
|
||||||
|
when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class)))
|
||||||
|
.thenReturn(mSavedQueryLoader);
|
||||||
|
|
||||||
final Bundle bundle = new Bundle();
|
final Bundle bundle = new Bundle();
|
||||||
ActivityController<SearchActivity> activityController =
|
ActivityController<SearchActivity> activityController =
|
||||||
Robolectric.buildActivity(SearchActivity.class);
|
Robolectric.buildActivity(SearchActivity.class);
|
||||||
@@ -124,6 +144,15 @@ public class SearchFragmentTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void queryTextChange_shouldTriggerLoader() {
|
public void queryTextChange_shouldTriggerLoader() {
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getDatabaseSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(mDatabaseResultLoader);
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getInstalledAppSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(mInstalledAppResultLoader);
|
||||||
|
when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class)))
|
||||||
|
.thenReturn(mSavedQueryLoader);
|
||||||
|
|
||||||
final String testQuery = "test";
|
final String testQuery = "test";
|
||||||
ActivityController<SearchActivity> activityController =
|
ActivityController<SearchActivity> activityController =
|
||||||
Robolectric.buildActivity(SearchActivity.class);
|
Robolectric.buildActivity(SearchActivity.class);
|
||||||
@@ -148,6 +177,15 @@ public class SearchFragmentTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void queryTextChangeToEmpty_shouldTriggerSavedQueryLoader() {
|
public void queryTextChangeToEmpty_shouldTriggerSavedQueryLoader() {
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getDatabaseSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(mDatabaseResultLoader);
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getInstalledAppSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(mInstalledAppResultLoader);
|
||||||
|
when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class)))
|
||||||
|
.thenReturn(mSavedQueryLoader);
|
||||||
|
|
||||||
ActivityController<SearchActivity> activityController =
|
ActivityController<SearchActivity> activityController =
|
||||||
Robolectric.buildActivity(SearchActivity.class);
|
Robolectric.buildActivity(SearchActivity.class);
|
||||||
activityController.setup();
|
activityController.setup();
|
||||||
@@ -169,6 +207,15 @@ public class SearchFragmentTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateIndex_TriggerOnCreate() {
|
public void updateIndex_TriggerOnCreate() {
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getDatabaseSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(mDatabaseResultLoader);
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getInstalledAppSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(mInstalledAppResultLoader);
|
||||||
|
when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class)))
|
||||||
|
.thenReturn(mSavedQueryLoader);
|
||||||
|
|
||||||
ActivityController<SearchActivity> activityController =
|
ActivityController<SearchActivity> activityController =
|
||||||
Robolectric.buildActivity(SearchActivity.class);
|
Robolectric.buildActivity(SearchActivity.class);
|
||||||
activityController.setup();
|
activityController.setup();
|
||||||
@@ -178,4 +225,28 @@ public class SearchFragmentTest {
|
|||||||
fragment.onAttach(null);
|
fragment.onAttach(null);
|
||||||
verify(mFeatureFactory.searchFeatureProvider).updateIndex(any(Context.class));
|
verify(mFeatureFactory.searchFeatureProvider).updateIndex(any(Context.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void syncLoaders_MergeWhenAllLoadersDone() {
|
||||||
|
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getDatabaseSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(new MockDBLoader(RuntimeEnvironment.application));
|
||||||
|
when(mFeatureFactory.searchFeatureProvider
|
||||||
|
.getInstalledAppSearchLoader(any(Context.class), anyString()))
|
||||||
|
.thenReturn(new MockAppLoader(RuntimeEnvironment.application));
|
||||||
|
|
||||||
|
ActivityController<SearchActivity> activityController =
|
||||||
|
Robolectric.buildActivity(SearchActivity.class);
|
||||||
|
activityController.setup();
|
||||||
|
SearchFragment fragment = (SearchFragment) spy(activityController.get().getFragmentManager()
|
||||||
|
.findFragmentById(R.id.main_content));
|
||||||
|
|
||||||
|
fragment.onQueryTextChange("non-empty");
|
||||||
|
|
||||||
|
Robolectric.flushForegroundThreadScheduler();
|
||||||
|
|
||||||
|
verify(fragment, times(2)).onLoadFinished(any(Loader.class), any(List.class));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user