Add a WidgetsSearchBar(Launcher3) and a WidgetsSearchController.
- Make WidgetsSearchBar in Launcher3 initialize WidgetsSearchController with SimpleWidgetsSearchPipeline - Modify SimpleWidgetsSearchPipeline to filter widgets entries on widgets/shortcut labels also. Test: Tested prototype locally. Also added robolectric test. Bug: b/157286785 Change-Id: I65f5fa0240ffb6d22023167e4e86d94d83bbd9f7
This commit is contained in:
@@ -20,12 +20,9 @@ import android.os.Handler;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.search.SearchAlgorithm;
|
||||
import com.android.launcher3.search.SearchCallback;
|
||||
|
||||
import java.text.Collator;
|
||||
|
||||
/**
|
||||
* The default search implementation.
|
||||
*/
|
||||
@@ -54,132 +51,4 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm<AdapterItem> {
|
||||
() -> callback.onSearchResult(query, results)),
|
||||
null);
|
||||
}
|
||||
|
||||
public static boolean matches(AppInfo info, String query, StringMatcher matcher) {
|
||||
int queryLength = query.length();
|
||||
|
||||
String title = info.title.toString();
|
||||
int titleLength = title.length();
|
||||
|
||||
if (titleLength < queryLength || queryLength <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (requestSimpleFuzzySearch(query)) {
|
||||
return title.toLowerCase().contains(query);
|
||||
}
|
||||
|
||||
int lastType;
|
||||
int thisType = Character.UNASSIGNED;
|
||||
int nextType = Character.getType(title.codePointAt(0));
|
||||
|
||||
int end = titleLength - queryLength;
|
||||
for (int i = 0; i <= end; i++) {
|
||||
lastType = thisType;
|
||||
thisType = nextType;
|
||||
nextType = i < (titleLength - 1) ?
|
||||
Character.getType(title.codePointAt(i + 1)) : Character.UNASSIGNED;
|
||||
if (isBreak(thisType, lastType, nextType) &&
|
||||
matcher.matches(query, title.substring(i, i + queryLength))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current point should be a break point. Following cases
|
||||
* are considered as break points:
|
||||
* 1) Any non space character after a space character
|
||||
* 2) Any digit after a non-digit character
|
||||
* 3) Any capital character after a digit or small character
|
||||
* 4) Any capital character before a small character
|
||||
*/
|
||||
private static boolean isBreak(int thisType, int prevType, int nextType) {
|
||||
switch (prevType) {
|
||||
case Character.UNASSIGNED:
|
||||
case Character.SPACE_SEPARATOR:
|
||||
case Character.LINE_SEPARATOR:
|
||||
case Character.PARAGRAPH_SEPARATOR:
|
||||
return true;
|
||||
}
|
||||
switch (thisType) {
|
||||
case Character.UPPERCASE_LETTER:
|
||||
if (nextType == Character.UPPERCASE_LETTER) {
|
||||
return true;
|
||||
}
|
||||
// Follow through
|
||||
case Character.TITLECASE_LETTER:
|
||||
// Break point if previous was not a upper case
|
||||
return prevType != Character.UPPERCASE_LETTER;
|
||||
case Character.LOWERCASE_LETTER:
|
||||
// Break point if previous was not a letter.
|
||||
return prevType > Character.OTHER_LETTER || prevType <= Character.UNASSIGNED;
|
||||
case Character.DECIMAL_DIGIT_NUMBER:
|
||||
case Character.LETTER_NUMBER:
|
||||
case Character.OTHER_NUMBER:
|
||||
// Break point if previous was not a number
|
||||
return !(prevType == Character.DECIMAL_DIGIT_NUMBER
|
||||
|| prevType == Character.LETTER_NUMBER
|
||||
|| prevType == Character.OTHER_NUMBER);
|
||||
case Character.MATH_SYMBOL:
|
||||
case Character.CURRENCY_SYMBOL:
|
||||
case Character.OTHER_PUNCTUATION:
|
||||
case Character.DASH_PUNCTUATION:
|
||||
// Always a break point for a symbol
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringMatcher {
|
||||
|
||||
private static final char MAX_UNICODE = '\uFFFF';
|
||||
|
||||
private final Collator mCollator;
|
||||
|
||||
StringMatcher() {
|
||||
// On android N and above, Collator uses ICU implementation which has a much better
|
||||
// support for non-latin locales.
|
||||
mCollator = Collator.getInstance();
|
||||
mCollator.setStrength(Collator.PRIMARY);
|
||||
mCollator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@param query} is a prefix of {@param target}
|
||||
*/
|
||||
public boolean matches(String query, String target) {
|
||||
switch (mCollator.compare(query, target)) {
|
||||
case 0:
|
||||
return true;
|
||||
case -1:
|
||||
// The target string can contain a modifier which would make it larger than
|
||||
// the query string (even though the length is same). If the query becomes
|
||||
// larger after appending a unicode character, it was originally a prefix of
|
||||
// the target string and hence should match.
|
||||
return mCollator.compare(query + MAX_UNICODE, target) > -1;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static StringMatcher getInstance() {
|
||||
return new StringMatcher();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean requestSimpleFuzzySearch(String s) {
|
||||
for (int i = 0; i < s.length(); ) {
|
||||
int codepoint = s.codePointAt(i);
|
||||
i += Character.charCount(codepoint);
|
||||
switch (Character.UnicodeScript.of(codepoint)) {
|
||||
case HAN:
|
||||
//Character.UnicodeScript.HAN: use String.contains to match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user