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.util.Executors.MAIN_EXECUTOR; 19 20 import android.content.Context; 21 import android.os.Handler; 22 23 import androidx.annotation.AnyThread; 24 25 import com.android.launcher3.LauncherAppState; 26 import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem; 27 import com.android.launcher3.model.AllAppsList; 28 import com.android.launcher3.model.BaseModelUpdateTask; 29 import com.android.launcher3.model.BgDataModel; 30 import com.android.launcher3.model.data.AppInfo; 31 import com.android.launcher3.search.SearchAlgorithm; 32 import com.android.launcher3.search.SearchCallback; 33 import com.android.launcher3.search.StringMatcherUtility; 34 35 import java.util.ArrayList; 36 import java.util.List; 37 38 /** 39 * The default search implementation. 40 */ 41 public class DefaultAppSearchAlgorithm implements SearchAlgorithm<AdapterItem> { 42 43 private static final int MAX_RESULTS_COUNT = 5; 44 45 private final LauncherAppState mAppState; 46 private final Handler mResultHandler; 47 DefaultAppSearchAlgorithm(Context context)48 public DefaultAppSearchAlgorithm(Context context) { 49 mAppState = LauncherAppState.getInstance(context); 50 mResultHandler = new Handler(MAIN_EXECUTOR.getLooper()); 51 } 52 53 @Override cancel(boolean interruptActiveRequests)54 public void cancel(boolean interruptActiveRequests) { 55 if (interruptActiveRequests) { 56 mResultHandler.removeCallbacksAndMessages(null); 57 } 58 } 59 60 @Override doSearch(String query, SearchCallback<AdapterItem> callback)61 public void doSearch(String query, SearchCallback<AdapterItem> callback) { 62 mAppState.getModel().enqueueModelUpdateTask(new BaseModelUpdateTask() { 63 @Override 64 public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { 65 ArrayList<AdapterItem> result = getTitleMatchResult(apps.data, query); 66 mResultHandler.post(() -> callback.onSearchResult(query, result)); 67 } 68 }); 69 } 70 71 /** 72 * Filters {@link AppInfo}s matching specified query 73 */ 74 @AnyThread getTitleMatchResult(List<AppInfo> apps, String query)75 public static ArrayList<AdapterItem> getTitleMatchResult(List<AppInfo> apps, String query) { 76 // Do an intersection of the words in the query and each title, and filter out all the 77 // apps that don't match all of the words in the query. 78 final String queryTextLower = query.toLowerCase(); 79 final ArrayList<AdapterItem> result = new ArrayList<>(); 80 StringMatcherUtility.StringMatcher matcher = 81 StringMatcherUtility.StringMatcher.getInstance(); 82 83 int resultCount = 0; 84 int total = apps.size(); 85 for (int i = 0; i < total && resultCount < MAX_RESULTS_COUNT; i++) { 86 AppInfo info = apps.get(i); 87 if (StringMatcherUtility.matches(queryTextLower, info.title.toString(), matcher)) { 88 AdapterItem appItem = AdapterItem.asApp(resultCount, "", info, resultCount); 89 result.add(appItem); 90 resultCount++; 91 } 92 } 93 return result; 94 } 95 } 96