DefaultAppSearchAlgorithm.java revision e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091
15683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal/* 25683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * Copyright (C) 2015 The Android Open Source Project 35683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * 45683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * Licensed under the Apache License, Version 2.0 (the "License"); 55683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * you may not use this file except in compliance with the License. 65683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * You may obtain a copy of the License at 75683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * 85683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * http://www.apache.org/licenses/LICENSE-2.0 95683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * 105683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * Unless required by applicable law or agreed to in writing, software 115683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * distributed under the License is distributed on an "AS IS" BASIS, 125683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * See the License for the specific language governing permissions and 145683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal * limitations under the License. 155683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal */ 165683f871722254e4e357cf3fb77cd28156278e51Sunny Goyalpackage com.android.launcher3.allapps; 175683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal 185683f871722254e4e357cf3fb77cd28156278e51Sunny Goyalimport android.os.Handler; 195183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal 205683f871722254e4e357cf3fb77cd28156278e51Sunny Goyalimport com.android.launcher3.AppInfo; 215183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyalimport com.android.launcher3.util.ComponentKey; 225683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal 235683f871722254e4e357cf3fb77cd28156278e51Sunny Goyalimport java.util.ArrayList; 245683f871722254e4e357cf3fb77cd28156278e51Sunny Goyalimport java.util.List; 255683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal 265683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal/** 27ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung * The default search implementation. 285683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal */ 29ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chungpublic class DefaultAppSearchAlgorithm { 305683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal 315683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal private final List<AppInfo> mApps; 32d730f9d74f87b90616e0f0a9c7b6a4c78976f41aSunny Goyal protected final Handler mResultHandler; 335683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal 34ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung public DefaultAppSearchAlgorithm(List<AppInfo> apps) { 355683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal mApps = apps; 365683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal mResultHandler = new Handler(); 375683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal } 385683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal 395683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal public void cancel(boolean interruptActiveRequests) { 405683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal if (interruptActiveRequests) { 415683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal mResultHandler.removeCallbacksAndMessages(null); 425683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal } 435683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal } 445683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal 45ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung public void doSearch(final String query, 46ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung final AllAppsSearchBarController.Callbacks callback) { 475183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal final ArrayList<ComponentKey> result = getTitleMatchResult(query); 485683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal mResultHandler.post(new Runnable() { 495683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal 505683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal @Override 515683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal public void run() { 52ef7f874a889b609bd34e692b9c9a1f8cefd1ea95Winson Chung callback.onSearchResult(query, result); 535683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal } 545683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal }); 555683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal } 565683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal 575183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal protected ArrayList<ComponentKey> getTitleMatchResult(String query) { 585183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal // Do an intersection of the words in the query and each title, and filter out all the 595183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal // apps that don't match all of the words in the query. 605183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal final String queryTextLower = query.toLowerCase(); 615183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal final ArrayList<ComponentKey> result = new ArrayList<>(); 625183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal for (AppInfo info : mApps) { 63e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal if (matches(info, queryTextLower)) { 645183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal result.add(info.toComponentKey()); 655183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal } 665183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal } 675183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal return result; 685183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal } 695183285847816cee9d0db6a8a7ab1a5929163e4eSunny Goyal 70e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal protected boolean matches(AppInfo info, String query) { 71e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal int queryLength = query.length(); 72e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal 735683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal String title = info.title.toString(); 74e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal int titleLength = title.length(); 75e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal 76e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal if (titleLength < queryLength || queryLength <= 0) { 77e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal return false; 78e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal } 79e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal 80e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal int lastType; 81e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal int thisType = Character.UNASSIGNED; 82e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal int nextType = Character.getType(title.codePointAt(0)); 83e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal 84e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal int end = titleLength - queryLength; 85e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal for (int i = 0; i <= end; i++) { 86e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal lastType = thisType; 87e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal thisType = nextType; 88e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal nextType = i < (titleLength - 1) ? 89e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal Character.getType(title.codePointAt(i + 1)) : Character.UNASSIGNED; 90e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal if (isBreak(thisType, lastType, nextType) && 91e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal title.substring(i, i + queryLength).equalsIgnoreCase(query)) { 92e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal return true; 935683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal } 94e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal } 95e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal return false; 96e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal } 97e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal 98e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal /** 99e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal * Returns true if the current point should be a break point. Following cases 100e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal * are considered as break points: 101e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal * 1) Any non space character after a space character 102e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal * 2) Any digit after a non-digit character 103e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal * 3) Any capital character after a digit or small character 104e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal * 4) Any capital character before a small character 105e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal */ 106e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal protected boolean isBreak(int thisType, int prevType, int nextType) { 107e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal switch (thisType) { 108e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal case Character.UPPERCASE_LETTER: 109e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal if (nextType == Character.UPPERCASE_LETTER) { 110e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal return true; 111e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal } 112e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal // Follow through 113e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal case Character.TITLECASE_LETTER: 114e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal // Break point if previous was not a upper case 115e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal return prevType != Character.UPPERCASE_LETTER; 116e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal case Character.LOWERCASE_LETTER: 117e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal // Break point if previous was not a letter. 118e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal return prevType > Character.OTHER_LETTER; 119e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal case Character.DECIMAL_DIGIT_NUMBER: 120e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal case Character.LETTER_NUMBER: 121e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal case Character.OTHER_NUMBER: 122e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal // Break point if previous was not a number 123e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal return !(prevType == Character.DECIMAL_DIGIT_NUMBER 124e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal || prevType == Character.LETTER_NUMBER 125e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal || prevType == Character.OTHER_NUMBER); 126e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal case Character.MATH_SYMBOL: 127e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal case Character.CURRENCY_SYMBOL: 128e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal case Character.OTHER_PUNCTUATION: 129e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal case Character.DASH_PUNCTUATION: 130e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal // Always a break point for a symbol 131e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal return true; 132e4a3e0cfaf5b72a54e99bcebdc03eda8aef53091Sunny Goyal default: 1335683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal return false; 1345683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal } 1355683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal } 1365683f871722254e4e357cf3fb77cd28156278e51Sunny Goyal} 137