Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 426428eb authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic 'am-3df8d75d-ddd8-4045-a20e-f35d57b86835' into ub-launcher3-master

* changes:
  Using collator for string matching am: 05d2df16 am: eb297820
  Using collator for string matching am: 05d2df16
  Using collator for string matching
parents b56b553d 3f6dc7f9
Loading
Loading
Loading
Loading
+53 −4
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.os.Handler;
import com.android.launcher3.AppInfo;
import com.android.launcher3.util.ComponentKey;

import java.text.Collator;
import java.util.ArrayList;
import java.util.List;

@@ -61,8 +62,9 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
        // apps that don't match all of the words in the query.
        final String queryTextLower = query.toLowerCase();
        final ArrayList<ComponentKey> result = new ArrayList<>();
        StringMatcher matcher = StringMatcher.getInstance();
        for (AppInfo info : mApps) {
            if (matches(info, queryTextLower)) {
            if (matches(info, queryTextLower, matcher)) {
                result.add(info.toComponentKey());
            }
        }
@@ -70,6 +72,10 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
    }

    public static boolean matches(AppInfo info, String query) {
        return matches(info, query, StringMatcher.getInstance());
    }

    public static boolean matches(AppInfo info, String query, StringMatcher matcher) {
        int queryLength = query.length();

        String title = info.title.toString();
@@ -90,7 +96,7 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
            nextType = i < (titleLength - 1) ?
                    Character.getType(title.codePointAt(i + 1)) : Character.UNASSIGNED;
            if (isBreak(thisType, lastType, nextType) &&
                    title.substring(i, i + queryLength).equalsIgnoreCase(query)) {
                    matcher.matches(query, title.substring(i, i + queryLength))) {
                return true;
            }
        }
@@ -106,6 +112,13 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
     *      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) {
@@ -132,8 +145,44 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
                // Always a break point for a symbol
                return true;
            default:
                // Always a break point at first character
                return  prevType == Character.UNASSIGNED;
                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();
        }
    }
}
+20 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import android.content.ComponentName;
import android.test.InstrumentationTestCase;

import com.android.launcher3.AppInfo;
import com.android.launcher3.Utilities;

import java.util.ArrayList;
import java.util.List;
@@ -75,6 +76,25 @@ public class DefaultAppSearchAlgorithmTest extends InstrumentationTestCase {
        assertTrue(mAlgorithm.matches(getInfo("电子邮件"), "电子"));
        assertFalse(mAlgorithm.matches(getInfo("电子邮件"), "子"));
        assertFalse(mAlgorithm.matches(getInfo("电子邮件"), "邮件"));

        assertFalse(mAlgorithm.matches(getInfo("Bot"), "ba"));
        assertFalse(mAlgorithm.matches(getInfo("bot"), "ba"));
    }

    public void testMatchesVN() {
        if (!Utilities.ATLEAST_NOUGAT) {
            return;
        }
        assertTrue(mAlgorithm.matches(getInfo("다운로드"), "다"));
        assertTrue(mAlgorithm.matches(getInfo("드라이브"), "드"));
        assertTrue(mAlgorithm.matches(getInfo("다운로드 드라이브"), "ㄷ"));
        assertTrue(mAlgorithm.matches(getInfo("운로 드라이브"), "ㄷ"));
        assertTrue(mAlgorithm.matches(getInfo("abc"), "åbç"));
        assertTrue(mAlgorithm.matches(getInfo("Alpha"), "ål"));

        assertFalse(mAlgorithm.matches(getInfo("다운로드 드라이브"), "ㄷㄷ"));
        assertFalse(mAlgorithm.matches(getInfo("로드라이브"), "ㄷ"));
        assertFalse(mAlgorithm.matches(getInfo("abc"), "åç"));
    }

    private AppInfo getInfo(String title) {