Merge "Add feature flag to control whether to inject fallback app results when AiAi fails to return app corpus results." into tm-qpr-dev
diff --git a/src/com/android/launcher3/search/StringMatcherUtility.java b/src/com/android/launcher3/search/StringMatcherUtility.java
index acab52b..c66f3a1 100644
--- a/src/com/android/launcher3/search/StringMatcherUtility.java
+++ b/src/com/android/launcher3/search/StringMatcherUtility.java
@@ -24,8 +24,8 @@
public class StringMatcherUtility {
/**
- * Returns {@code true} is {@code query} is a prefix substring of a complete word/phrase in
- * {@code target}.
+ * Returns {@code true} if {@code query} is a prefix of a substring in {@code target}. How to
+ * break target to valid substring is defined in the given {@code matcher}.
*/
public static boolean matches(String query, String target, StringMatcher matcher) {
int queryLength = query.length();
@@ -50,7 +50,7 @@
thisType = nextType;
nextType = i < (targetLength - 1)
? Character.getType(target.codePointAt(i + 1)) : Character.UNASSIGNED;
- if (isBreak(thisType, lastType, nextType)
+ if (matcher.isBreak(thisType, lastType, nextType)
&& matcher.matches(query, target.substring(i, i + queryLength))) {
return true;
}
@@ -59,52 +59,6 @@
}
/**
- * 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;
- }
- }
-
- /**
* Performs locale sensitive string comparison using {@link Collator}.
*/
public static class StringMatcher {
@@ -142,6 +96,75 @@
public static StringMatcher getInstance() {
return new StringMatcher();
}
+
+ /**
+ * 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
+ *
+ * E.g., "YouTube" matches the input "you" and "tube", but not "out".
+ */
+ protected 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;
+ }
+ }
+ }
+
+ /**
+ * Subclass of {@code StringMatcher} using simple space break for prefix matching.
+ * E.g., "YouTube" matches the input "you". "Play Store" matches the input "play".
+ */
+ public static class StringMatcherSpace extends StringMatcher {
+
+ public static StringMatcherSpace getInstance() {
+ return new StringMatcherSpace();
+ }
+
+ /**
+ * The first character or any character after a space is considered as a break point.
+ * Returns true if the current point should be a break point.
+ */
+ @Override
+ protected boolean isBreak(int thisType, int prevType, int nextType) {
+ return prevType == Character.UNASSIGNED || prevType == Character.SPACE_SEPARATOR;
+ }
}
/**
diff --git a/tests/src/com/android/launcher3/search/StringMatcherUtilityTest.java b/tests/src/com/android/launcher3/search/StringMatcherUtilityTest.java
index 413f404..3b53255 100644
--- a/tests/src/com/android/launcher3/search/StringMatcherUtilityTest.java
+++ b/tests/src/com/android/launcher3/search/StringMatcherUtilityTest.java
@@ -24,6 +24,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.search.StringMatcherUtility.StringMatcher;
+import com.android.launcher3.search.StringMatcherUtility.StringMatcherSpace;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,11 +35,12 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class StringMatcherUtilityTest {
- private static final StringMatcher MATCHER =
- StringMatcher.getInstance();
+ private static final StringMatcher MATCHER = StringMatcher.getInstance();
+ private static final StringMatcherSpace MATCHER_SPACE = StringMatcherSpace.getInstance();
@Test
public void testMatches() {
+ assertTrue(matches("white", "white cow", MATCHER));
assertTrue(matches("white ", "white cow", MATCHER));
assertTrue(matches("white c", "white cow", MATCHER));
assertTrue(matches("cow", "white cow", MATCHER));
@@ -93,4 +95,47 @@
assertFalse(matches("ㄷ", "로드라이브", MATCHER));
assertFalse(matches("åç", "abc", MATCHER));
}
+
+ @Test
+ public void testMatchesWithSpaceBreakOnly() {
+ assertTrue(matches("white", "white cow", MATCHER_SPACE));
+ assertTrue(matches("white ", "white cow", MATCHER_SPACE));
+ assertTrue(matches("white c", "white cow", MATCHER_SPACE));
+ assertTrue(matches("cow", "white cow", MATCHER_SPACE));
+ assertTrue(matches("cow", "whitecow cow", MATCHER_SPACE));
+
+ assertFalse(matches("cow", "whiteCow", MATCHER_SPACE));
+ assertFalse(matches("cow", "whiteCOW", MATCHER_SPACE));
+ assertFalse(matches("cow", "whitecowCOW", MATCHER_SPACE));
+ assertFalse(matches("cow", "white2cow", MATCHER_SPACE));
+ assertFalse(matches("cow", "whitecow", MATCHER_SPACE));
+ assertFalse(matches("cow", "whitEcow", MATCHER_SPACE));
+ assertFalse(matches("cow", "whitecowCow", MATCHER_SPACE));
+ assertFalse(matches("cow", "whitecowcow", MATCHER_SPACE));
+ assertFalse(matches("cow", "whit ecowcow", MATCHER_SPACE));
+
+ assertFalse(matches("dog", "cats&dogs", MATCHER_SPACE));
+ assertFalse(matches("dog", "cats&Dogs", MATCHER_SPACE));
+ assertFalse(matches("&", "cats&Dogs", MATCHER_SPACE));
+
+ assertFalse(matches("43", "2+43", MATCHER_SPACE));
+ assertFalse(matches("3", "2+43", MATCHER_SPACE));
+
+ assertTrue(matches("q", "Q", MATCHER_SPACE));
+ assertTrue(matches("q", " Q", MATCHER_SPACE));
+
+ // match lower case words
+ assertTrue(matches("e", "elephant", MATCHER_SPACE));
+ assertTrue(matches("eL", "Elephant", MATCHER_SPACE));
+
+ assertTrue(matches("电", "电子邮件", MATCHER_SPACE));
+ assertTrue(matches("电子", "电子邮件", MATCHER_SPACE));
+ assertTrue(matches("子", "电子邮件", MATCHER_SPACE));
+ assertTrue(matches("邮件", "电子邮件", MATCHER_SPACE));
+
+ assertFalse(matches("ba", "Bot", MATCHER_SPACE));
+ assertFalse(matches("ba", "bot", MATCHER_SPACE));
+ assertFalse(matches("phant", "elephant", MATCHER_SPACE));
+ assertFalse(matches("elephants", "elephant", MATCHER_SPACE));
+ }
}