1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.launcher3.allapps.search; 17 18 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_EMPTY_SEARCH; 19 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; 20 21 import android.content.Context; 22 import android.os.Handler; 23 24 import androidx.annotation.AnyThread; 25 26 import com.android.launcher3.LauncherAppState; 27 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem; 28 import com.android.launcher3.model.data.AppInfo; 29 import com.android.launcher3.search.SearchAlgorithm; 30 import com.android.launcher3.search.SearchCallback; 31 import com.android.launcher3.search.StringMatcherUtility; 32 33 import java.util.ArrayList; 34 import java.util.List; 35 36 /** 37 * The default search implementation. 38 */ 39 public class DefaultAppSearchAlgorithm implements SearchAlgorithm<AdapterItem> { 40 41 private static final int MAX_RESULTS_COUNT = 5; 42 43 private final LauncherAppState mAppState; 44 private final Handler mResultHandler; 45 private final boolean mAddNoResultsMessage; 46 DefaultAppSearchAlgorithm(Context context)47 public DefaultAppSearchAlgorithm(Context context) { 48 this(context, false); 49 } 50 DefaultAppSearchAlgorithm(Context context, boolean addNoResultsMessage)51 public DefaultAppSearchAlgorithm(Context context, boolean addNoResultsMessage) { 52 mAppState = LauncherAppState.getInstance(context); 53 mResultHandler = new Handler(MAIN_EXECUTOR.getLooper()); 54 mAddNoResultsMessage = addNoResultsMessage; 55 } 56 57 @Override cancel(boolean interruptActiveRequests)58 public void cancel(boolean interruptActiveRequests) { 59 if (interruptActiveRequests) { 60 mResultHandler.removeCallbacksAndMessages(null); 61 } 62 } 63 64 @Override doSearch(String query, SearchCallback<AdapterItem> callback)65 public void doSearch(String query, SearchCallback<AdapterItem> callback) { 66 mAppState.getModel().enqueueModelUpdateTask((taskController, dataModel, apps) -> { 67 ArrayList<AdapterItem> result = getTitleMatchResult(apps.data, query); 68 if (mAddNoResultsMessage && result.isEmpty()) { 69 result.add(getEmptyMessageAdapterItem(query)); 70 } 71 mResultHandler.post(() -> callback.onSearchResult(query, result)); 72 }); 73 } 74 getEmptyMessageAdapterItem(String query)75 private static AdapterItem getEmptyMessageAdapterItem(String query) { 76 AdapterItem item = new AdapterItem(VIEW_TYPE_EMPTY_SEARCH); 77 // Add a place holder info to propagate the query 78 AppInfo placeHolder = new AppInfo(); 79 placeHolder.title = query; 80 item.itemInfo = placeHolder; 81 return item; 82 } 83 84 /** 85 * Filters {@link AppInfo}s matching specified query 86 */ 87 @AnyThread getTitleMatchResult(List<AppInfo> apps, String query)88 public static ArrayList<AdapterItem> getTitleMatchResult(List<AppInfo> apps, String query) { 89 // Do an intersection of the words in the query and each title, and filter out all the 90 // apps that don't match all of the words in the query. 91 final String queryTextLower = query.toLowerCase(); 92 final ArrayList<AdapterItem> result = new ArrayList<>(); 93 StringMatcherUtility.StringMatcher matcher = 94 StringMatcherUtility.StringMatcher.getInstance(); 95 96 int resultCount = 0; 97 int total = apps.size(); 98 for (int i = 0; i < total && resultCount < MAX_RESULTS_COUNT; i++) { 99 AppInfo info = apps.get(i); 100 if (StringMatcherUtility.matches(queryTextLower, info.title.toString(), matcher)) { 101 result.add(AdapterItem.asApp(info)); 102 resultCount++; 103 } 104 } 105 return result; 106 } 107 } 108