Migrate AllAppsSearch [part 1/3]
[Video attached to bug report] Setup DeviceSearchAlgorithm to handle on device search Bug: 161801950 Test: Manual Change-Id: Ib55f415f9992ceab687bbbfe904d153157541648
This commit is contained in:
parent
0e649985e7
commit
df10ff46bd
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/section_title"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:fontFamily="@style/TextHeadline"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:layout_height="wrap_content"/>
|
|
@ -67,6 +67,10 @@
|
||||||
<!-- Label for an icon representing any generic app. [CHAR_LIMIT=50] -->
|
<!-- Label for an icon representing any generic app. [CHAR_LIMIT=50] -->
|
||||||
<string name="label_application">App</string>
|
<string name="label_application">App</string>
|
||||||
|
|
||||||
|
<!--All apps Search-->
|
||||||
|
<!-- Section title for apps [CHAR_LIMIT=50] -->
|
||||||
|
<string name="search_corpus_apps">Apps</string>
|
||||||
|
|
||||||
<!-- Popup items -->
|
<!-- Popup items -->
|
||||||
<!-- Text to display as the header above notifications. [CHAR_LIMIT=30] -->
|
<!-- Text to display as the header above notifications. [CHAR_LIMIT=30] -->
|
||||||
<string name="notifications_header">Notifications</string>
|
<string name="notifications_header">Notifications</string>
|
||||||
|
|
|
@ -66,6 +66,8 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||||
// A divider that separates the apps list and the search market button
|
// A divider that separates the apps list and the search market button
|
||||||
public static final int VIEW_TYPE_ALL_APPS_DIVIDER = 1 << 4;
|
public static final int VIEW_TYPE_ALL_APPS_DIVIDER = 1 << 4;
|
||||||
|
|
||||||
|
public static final int VIEW_TYPE_SEARCH_CORPUS_TITLE = 1 << 5;
|
||||||
|
|
||||||
// Common view type masks
|
// Common view type masks
|
||||||
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
|
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
|
||||||
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
|
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
|
||||||
|
@ -274,6 +276,9 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||||
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
||||||
return new ViewHolder(mLayoutInflater.inflate(
|
return new ViewHolder(mLayoutInflater.inflate(
|
||||||
R.layout.all_apps_divider, parent, false));
|
R.layout.all_apps_divider, parent, false));
|
||||||
|
case VIEW_TYPE_SEARCH_CORPUS_TITLE:
|
||||||
|
return new ViewHolder(
|
||||||
|
mLayoutInflater.inflate(R.layout.search_section_title, parent, false));
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("Unexpected view type");
|
throw new RuntimeException("Unexpected view type");
|
||||||
}
|
}
|
||||||
|
@ -302,6 +307,10 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
|
||||||
searchView.setVisibility(View.GONE);
|
searchView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case VIEW_TYPE_SEARCH_CORPUS_TITLE:
|
||||||
|
TextView titleView = (TextView) holder.itemView;
|
||||||
|
titleView.setText(mApps.getAdapterItems().get(position).searchSectionInfo.getTitle(
|
||||||
|
titleView.getContext()));
|
||||||
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -107,6 +107,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
|
||||||
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER, 1);
|
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ALL_APPS_DIVIDER, 1);
|
||||||
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET, 1);
|
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET, 1);
|
||||||
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, approxRows * mNumAppsPerRow);
|
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, approxRows * mNumAppsPerRow);
|
||||||
|
pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_SEARCH_CORPUS_TITLE, 1);
|
||||||
|
|
||||||
mViewHeights.clear();
|
mViewHeights.clear();
|
||||||
mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, grid.allAppsCellHeightPx);
|
mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, grid.allAppsCellHeightPx);
|
||||||
|
|
|
@ -19,8 +19,9 @@ package com.android.launcher3.allapps;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
|
import com.android.launcher3.allapps.search.SearchSectionInfo;
|
||||||
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.model.data.AppInfo;
|
import com.android.launcher3.model.data.AppInfo;
|
||||||
import com.android.launcher3.util.ComponentKey;
|
|
||||||
import com.android.launcher3.util.ItemInfoMatcher;
|
import com.android.launcher3.util.ItemInfoMatcher;
|
||||||
import com.android.launcher3.util.LabelComparator;
|
import com.android.launcher3.util.LabelComparator;
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The alphabetically sorted list of applications.
|
* The alphabetically sorted list of applications.
|
||||||
|
@ -82,6 +84,8 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
|
||||||
public AppInfo appInfo = null;
|
public AppInfo appInfo = null;
|
||||||
// The index of this app not including sections
|
// The index of this app not including sections
|
||||||
public int appIndex = -1;
|
public int appIndex = -1;
|
||||||
|
// Search section associated to result
|
||||||
|
public SearchSectionInfo searchSectionInfo = null;
|
||||||
|
|
||||||
public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo,
|
public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo,
|
||||||
int appIndex) {
|
int appIndex) {
|
||||||
|
@ -114,6 +118,17 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
|
||||||
item.position = pos;
|
item.position = pos;
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method for search section title AdapterItem
|
||||||
|
*/
|
||||||
|
public static AdapterItem asSearchTitle(SearchSectionInfo sectionInfo, int pos) {
|
||||||
|
AdapterItem item = new AdapterItem();
|
||||||
|
item.viewType = AllAppsGridAdapter.VIEW_TYPE_SEARCH_CORPUS_TITLE;
|
||||||
|
item.position = pos;
|
||||||
|
item.searchSectionInfo = sectionInfo;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final BaseDraggingActivity mLauncher;
|
private final BaseDraggingActivity mLauncher;
|
||||||
|
@ -132,7 +147,7 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
|
||||||
private final boolean mIsWork;
|
private final boolean mIsWork;
|
||||||
|
|
||||||
// The of ordered component names as a result of a search query
|
// The of ordered component names as a result of a search query
|
||||||
private ArrayList<ComponentKey> mSearchResults;
|
private ArrayList<AdapterItem> mSearchResults;
|
||||||
private AllAppsGridAdapter mAdapter;
|
private AllAppsGridAdapter mAdapter;
|
||||||
private AppInfoComparator mAppNameComparator;
|
private AppInfoComparator mAppNameComparator;
|
||||||
private final int mNumAppsPerRow;
|
private final int mNumAppsPerRow;
|
||||||
|
@ -210,10 +225,10 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the sorted list of filtered components.
|
* Sets results list for search
|
||||||
*/
|
*/
|
||||||
public boolean setOrderedFilter(ArrayList<ComponentKey> f) {
|
public boolean setSearchResults(ArrayList<AdapterItem> f) {
|
||||||
if (mSearchResults != f) {
|
if (f == null || mSearchResults != f) {
|
||||||
boolean same = mSearchResults != null && mSearchResults.equals(f);
|
boolean same = mSearchResults != null && mSearchResults.equals(f);
|
||||||
mSearchResults = f;
|
mSearchResults = f;
|
||||||
onAppsUpdated();
|
onAppsUpdated();
|
||||||
|
@ -298,35 +313,42 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
|
||||||
|
|
||||||
// Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
|
// Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
|
||||||
// ordered set of sections
|
// ordered set of sections
|
||||||
for (AppInfo info : getFiltersAppInfos()) {
|
if (!hasFilter()) {
|
||||||
String sectionName = info.sectionName;
|
for (AppInfo info : mApps) {
|
||||||
|
String sectionName = info.sectionName;
|
||||||
|
|
||||||
// Create a new section if the section names do not match
|
// Create a new section if the section names do not match
|
||||||
if (!sectionName.equals(lastSectionName)) {
|
if (!sectionName.equals(lastSectionName)) {
|
||||||
lastSectionName = sectionName;
|
lastSectionName = sectionName;
|
||||||
lastFastScrollerSectionInfo = new FastScrollSectionInfo(sectionName);
|
lastFastScrollerSectionInfo = new FastScrollSectionInfo(sectionName);
|
||||||
mFastScrollerSections.add(lastFastScrollerSectionInfo);
|
mFastScrollerSections.add(lastFastScrollerSectionInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create an app item
|
||||||
|
AdapterItem appItem = AdapterItem.asApp(position++, sectionName, info, appIndex++);
|
||||||
|
if (lastFastScrollerSectionInfo.fastScrollToItem == null) {
|
||||||
|
lastFastScrollerSectionInfo.fastScrollToItem = appItem;
|
||||||
|
}
|
||||||
|
mAdapterItems.add(appItem);
|
||||||
|
mFilteredApps.add(info);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mAdapterItems.addAll(mSearchResults);
|
||||||
|
List<AppInfo> appInfos = mSearchResults.stream().filter(
|
||||||
|
i -> AllAppsGridAdapter.isIconViewType(i.viewType)).map(i -> i.appInfo).collect(
|
||||||
|
Collectors.toList());
|
||||||
|
mFilteredApps.addAll(appInfos);
|
||||||
|
if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
|
||||||
|
// Append the search market item
|
||||||
|
if (hasNoFilteredResults()) {
|
||||||
|
mAdapterItems.add(AdapterItem.asEmptySearch(position++));
|
||||||
|
} else {
|
||||||
|
mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
|
||||||
|
}
|
||||||
|
mAdapterItems.add(AdapterItem.asMarketSearch(position++));
|
||||||
|
|
||||||
// Create an app item
|
|
||||||
AdapterItem appItem = AdapterItem.asApp(position++, sectionName, info, appIndex++);
|
|
||||||
if (lastFastScrollerSectionInfo.fastScrollToItem == null) {
|
|
||||||
lastFastScrollerSectionInfo.fastScrollToItem = appItem;
|
|
||||||
}
|
}
|
||||||
mAdapterItems.add(appItem);
|
|
||||||
mFilteredApps.add(info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasFilter()) {
|
|
||||||
// Append the search market item
|
|
||||||
if (hasNoFilteredResults()) {
|
|
||||||
mAdapterItems.add(AdapterItem.asEmptySearch(position++));
|
|
||||||
} else {
|
|
||||||
mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
|
|
||||||
}
|
|
||||||
mAdapterItems.add(AdapterItem.asMarketSearch(position++));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mNumAppsPerRow != 0) {
|
if (mNumAppsPerRow != 0) {
|
||||||
// Update the number of rows in the adapter after we do all the merging (otherwise, we
|
// Update the number of rows in the adapter after we do all the merging (otherwise, we
|
||||||
// would have to shift the values again)
|
// would have to shift the values again)
|
||||||
|
@ -381,18 +403,4 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<AppInfo> getFiltersAppInfos() {
|
|
||||||
if (mSearchResults == null) {
|
|
||||||
return mApps;
|
|
||||||
}
|
|
||||||
ArrayList<AppInfo> result = new ArrayList<>();
|
|
||||||
for (ComponentKey key : mSearchResults) {
|
|
||||||
AppInfo match = mAllAppsStore.getApp(key);
|
|
||||||
if (match != null) {
|
|
||||||
result.add(match);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import android.widget.TextView.OnEditorActionListener;
|
||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.ExtendedEditText;
|
import com.android.launcher3.ExtendedEditText;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.util.ComponentKey;
|
import com.android.launcher3.allapps.AlphabeticalAppsList;
|
||||||
import com.android.launcher3.util.PackageManagerHelper;
|
import com.android.launcher3.util.PackageManagerHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -50,6 +50,7 @@ public class AllAppsSearchBarController
|
||||||
public void setVisibility(int visibility) {
|
public void setVisibility(int visibility) {
|
||||||
mInput.setVisibility(visibility);
|
mInput.setVisibility(visibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the references to the apps model and the search result callback.
|
* Sets the references to the apps model and the search result callback.
|
||||||
*/
|
*/
|
||||||
|
@ -164,9 +165,9 @@ public class AllAppsSearchBarController
|
||||||
/**
|
/**
|
||||||
* Called when the search is complete.
|
* Called when the search is complete.
|
||||||
*
|
*
|
||||||
* @param apps sorted list of matching components or null if in case of failure.
|
* @param items sorted list of search result adapter items.
|
||||||
*/
|
*/
|
||||||
void onSearchResult(String query, ArrayList<ComponentKey> apps);
|
void onSearchResult(String query, ArrayList<AlphabeticalAppsList.AdapterItem> items);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the search results should be cleared.
|
* Called when the search results should be cleared.
|
||||||
|
|
|
@ -38,13 +38,13 @@ import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.ExtendedEditText;
|
import com.android.launcher3.ExtendedEditText;
|
||||||
import com.android.launcher3.Insettable;
|
import com.android.launcher3.Insettable;
|
||||||
|
import com.android.launcher3.LauncherAppState;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.allapps.AllAppsContainerView;
|
import com.android.launcher3.allapps.AllAppsContainerView;
|
||||||
import com.android.launcher3.allapps.AllAppsStore;
|
import com.android.launcher3.allapps.AllAppsStore;
|
||||||
import com.android.launcher3.allapps.AlphabeticalAppsList;
|
import com.android.launcher3.allapps.AlphabeticalAppsList;
|
||||||
import com.android.launcher3.allapps.SearchUiManager;
|
import com.android.launcher3.allapps.SearchUiManager;
|
||||||
import com.android.launcher3.anim.PropertySetter;
|
import com.android.launcher3.anim.PropertySetter;
|
||||||
import com.android.launcher3.util.ComponentKey;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@ -135,7 +135,8 @@ public class AppsSearchContainerLayout extends ExtendedEditText
|
||||||
mApps = appsView.getApps();
|
mApps = appsView.getApps();
|
||||||
mAppsView = appsView;
|
mAppsView = appsView;
|
||||||
mSearchBarController.initialize(
|
mSearchBarController.initialize(
|
||||||
new DefaultAppSearchAlgorithm(mApps.getApps()), this, mLauncher, this);
|
new DefaultAppSearchAlgorithm(LauncherAppState.getInstance(mLauncher)), this,
|
||||||
|
mLauncher, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -168,9 +169,9 @@ public class AppsSearchContainerLayout extends ExtendedEditText
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSearchResult(String query, ArrayList<ComponentKey> apps) {
|
public void onSearchResult(String query, ArrayList<AlphabeticalAppsList.AdapterItem> items) {
|
||||||
if (apps != null) {
|
if (items != null) {
|
||||||
mApps.setOrderedFilter(apps);
|
mApps.setSearchResults(items);
|
||||||
notifyResultChanged();
|
notifyResultChanged();
|
||||||
mAppsView.setLastSearchQuery(query);
|
mAppsView.setLastSearchQuery(query);
|
||||||
}
|
}
|
||||||
|
@ -178,7 +179,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearSearchResult() {
|
public void clearSearchResult() {
|
||||||
if (mApps.setOrderedFilter(null)) {
|
if (mApps.setSearchResults(null)) {
|
||||||
notifyResultChanged();
|
notifyResultChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.launcher3.allapps.search;
|
||||||
|
|
||||||
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
|
import com.android.launcher3.LauncherAppState;
|
||||||
|
import com.android.launcher3.R;
|
||||||
|
import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
|
||||||
|
import com.android.launcher3.model.AllAppsList;
|
||||||
|
import com.android.launcher3.model.BaseModelUpdateTask;
|
||||||
|
import com.android.launcher3.model.BgDataModel;
|
||||||
|
import com.android.launcher3.model.data.AppInfo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A device search section for handling app searches
|
||||||
|
*/
|
||||||
|
public class AppsSearchPipeline implements SearchPipeline {
|
||||||
|
|
||||||
|
private static final int MAX_RESULTS_COUNT = 5;
|
||||||
|
|
||||||
|
private final SearchSectionInfo mSearchSectionInfo;
|
||||||
|
private final LauncherAppState mLauncherAppState;
|
||||||
|
|
||||||
|
public AppsSearchPipeline(LauncherAppState launcherAppState) {
|
||||||
|
mLauncherAppState = launcherAppState;
|
||||||
|
mSearchSectionInfo = new SearchSectionInfo(R.string.search_corpus_apps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@WorkerThread
|
||||||
|
public void performSearch(String query, Consumer<ArrayList<AdapterItem>> callback) {
|
||||||
|
mLauncherAppState.getModel().enqueueModelUpdateTask(new BaseModelUpdateTask() {
|
||||||
|
@Override
|
||||||
|
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
|
||||||
|
callback.accept(getAdapterItems(getTitleMatchResult(apps.data, query)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters {@link AppInfo}s matching specified query
|
||||||
|
*/
|
||||||
|
public static ArrayList<AppInfo> getTitleMatchResult(List<AppInfo> apps, String query) {
|
||||||
|
// Do an intersection of the words in the query and each title, and filter out all the
|
||||||
|
// apps that don't match all of the words in the query.
|
||||||
|
final String queryTextLower = query.toLowerCase();
|
||||||
|
final ArrayList<AppInfo> result = new ArrayList<>();
|
||||||
|
DefaultAppSearchAlgorithm.StringMatcher matcher =
|
||||||
|
DefaultAppSearchAlgorithm.StringMatcher.getInstance();
|
||||||
|
for (AppInfo info : apps) {
|
||||||
|
if (DefaultAppSearchAlgorithm.matches(info, queryTextLower, matcher)) {
|
||||||
|
result.add(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<AdapterItem> getAdapterItems(List<AppInfo> matchingApps) {
|
||||||
|
ArrayList<AdapterItem> items = new ArrayList<>();
|
||||||
|
if (matchingApps.isEmpty()) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
items.add(AdapterItem.asSearchTitle(mSearchSectionInfo, 0));
|
||||||
|
int existingItems = items.size();
|
||||||
|
int searchResultsCount = Math.min(matchingApps.size(), MAX_RESULTS_COUNT);
|
||||||
|
for (int i = 0; i < searchResultsCount; i++) {
|
||||||
|
AdapterItem appItem = AdapterItem.asApp(i + existingItems, "", matchingApps.get(i), i);
|
||||||
|
appItem.searchSectionInfo = mSearchSectionInfo;
|
||||||
|
items.add(appItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,24 +17,22 @@ package com.android.launcher3.allapps.search;
|
||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import com.android.launcher3.LauncherAppState;
|
||||||
import com.android.launcher3.model.data.AppInfo;
|
import com.android.launcher3.model.data.AppInfo;
|
||||||
import com.android.launcher3.util.ComponentKey;
|
|
||||||
|
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default search implementation.
|
* The default search implementation.
|
||||||
*/
|
*/
|
||||||
public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
|
public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
|
||||||
|
|
||||||
private final List<AppInfo> mApps;
|
|
||||||
protected final Handler mResultHandler;
|
protected final Handler mResultHandler;
|
||||||
|
private final AppsSearchPipeline mAppsSearchPipeline;
|
||||||
|
|
||||||
public DefaultAppSearchAlgorithm(List<AppInfo> apps) {
|
public DefaultAppSearchAlgorithm(LauncherAppState launcherAppState) {
|
||||||
mApps = apps;
|
|
||||||
mResultHandler = new Handler();
|
mResultHandler = new Handler();
|
||||||
|
mAppsSearchPipeline = new AppsSearchPipeline(launcherAppState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -47,28 +45,8 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
|
||||||
@Override
|
@Override
|
||||||
public void doSearch(final String query,
|
public void doSearch(final String query,
|
||||||
final AllAppsSearchBarController.Callbacks callback) {
|
final AllAppsSearchBarController.Callbacks callback) {
|
||||||
final ArrayList<ComponentKey> result = getTitleMatchResult(query);
|
mAppsSearchPipeline.performSearch(query,
|
||||||
mResultHandler.post(new Runnable() {
|
results -> mResultHandler.post(() -> callback.onSearchResult(query, results)));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
callback.onSearchResult(query, result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArrayList<ComponentKey> getTitleMatchResult(String query) {
|
|
||||||
// Do an intersection of the words in the query and each title, and filter out all the
|
|
||||||
// apps that don't match all of the words in the query.
|
|
||||||
final String queryTextLower = query.toLowerCase();
|
|
||||||
final ArrayList<ComponentKey> result = new ArrayList<>();
|
|
||||||
StringMatcher matcher = StringMatcher.getInstance();
|
|
||||||
for (AppInfo info : mApps) {
|
|
||||||
if (matches(info, queryTextLower, matcher)) {
|
|
||||||
result.add(info.toComponentKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean matches(AppInfo info, String query, StringMatcher matcher) {
|
public static boolean matches(AppInfo info, String query, StringMatcher matcher) {
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.launcher3.allapps.search;
|
||||||
|
|
||||||
|
import com.android.launcher3.allapps.AlphabeticalAppsList;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for handling search within pipeline
|
||||||
|
*/
|
||||||
|
public interface SearchPipeline {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform query
|
||||||
|
*/
|
||||||
|
void performSearch(String query, Consumer<ArrayList<AlphabeticalAppsList.AdapterItem>> cb);
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.launcher3.allapps.search;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Info class for a search section
|
||||||
|
*/
|
||||||
|
public class SearchSectionInfo {
|
||||||
|
private final int mTitleResId;
|
||||||
|
|
||||||
|
public SearchSectionInfo(int titleResId) {
|
||||||
|
mTitleResId = titleResId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the section's title
|
||||||
|
*/
|
||||||
|
public String getTitle(Context context) {
|
||||||
|
return context.getString(mTitleResId);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue