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

Commit 43f7fb1b authored by Matthew Fritze's avatar Matthew Fritze
Browse files

Installed App loader only matches on prefixes

Change-Id: Iefc6d681a1b616acf3c1354ff4d0f6c2c268895e
Fixes:34688403
Test: make RunSettingsRoboTests
parent 4dfe53e1
Loading
Loading
Loading
Loading
+46 −21
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@ import java.util.List;
public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {

    private static final int NAME_NO_MATCH = -1;
    private static final int NAME_EXACT_MATCH = 0;
    private static final Intent LAUNCHER_PROBE = new Intent(Intent.ACTION_MAIN)
            .addCategory(Intent.CATEGORY_LAUNCHER);

@@ -131,39 +130,65 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {

    /**
     * Returns "difference" between appName and query string. appName must contain all
     * characters from query, in the same order. If not, returns NAME_NO_MATCH. If they do match,
     * returns an int value representing how different they are, NAME_EXACT_MATCH means they match
     * perfectly, and larger values means they are less similar.
     * characters from query as a prefix to a word, in the same order.
     * If not, returns NAME_NO_MATCH.
     * If they do match, returns an int value representing  how different they are,
     * and larger values means they are less similar.
     * <p/>
     * Example:
     * appName: Abcde, query: Abcde, Returns {@link #NAME_EXACT_MATCH}
     * appName: Abcde, query: ade, Returns 2
     * appName: Abcde, query: ae, Returns 3
     * appName: Abcde, query: ea, Returns NAME_NO_MATCH
     * appName: Abcde, query: Abcde, Returns 0
     * appName: Abcde, query: abc, Returns 2
     * appName: Abcde, query: ab, Returns 3
     * appName: Abcde, query: bc, Returns NAME_NO_MATCH
     * appName: Abcde, query: xyz, Returns NAME_NO_MATCH
     * appName: Abc de, query: de, Returns 4
     */
    private int getWordDifference(String appName, String query) {
        if (TextUtils.isEmpty(appName) || TextUtils.isEmpty(query)) {
            return NAME_NO_MATCH;
        }
        final char[] queryTokens = query.toString().toLowerCase().toCharArray();
        final char[] valueText = appName.toLowerCase().toCharArray();
        if (queryTokens.length > valueText.length) {

        final char[] queryTokens = query.toLowerCase().toCharArray();
        final char[] appTokens = appName.toLowerCase().toCharArray();
        final int appLength = appTokens.length;
        if (queryTokens.length > appLength) {
            return NAME_NO_MATCH;
        }

        int i = 0;
        int j = 0;
        while (i < valueText.length && j < queryTokens.length) {
            if (valueText[i++] == queryTokens[j]) {
                j++;
        int j;

        while (i < appLength) {
            j = 0;
            // Currently matching a prefix
            while ((i + j < appLength) && (queryTokens[j] == appTokens[i + j])) {
                // Matched the entire query
                if (++j >= queryTokens.length) {
                    // Use the diff in length as a proxy of how close the 2 words match.
                    // Value range from 0 to infinity.
                    return appLength - queryTokens.length;
                }
            }
        if (j != queryTokens.length) {

            i += j;

            // Remaining string is longer that the query or we have search the whole app name.
            if (queryTokens.length > appLength - i) {
                return NAME_NO_MATCH;
            }
        // Use the diff in length as a proxy of how close the 2 words match. Value range from 0
        // to infinity.
        return valueText.length - queryTokens.length;

            // This is the first index where app name and query name are different
            // Find the next space in the app name or the end of the app name.
            while ((i < appLength) && (!Character.isWhitespace(appTokens[i++]))) ;

            // Find the start of the next word
            while ((i < appLength) && !(Character.isLetter(appTokens[i])
                    || Character.isDigit(appTokens[i]))) {
                // Increment in body because we cannot guarantee which condition was true
                i++;
            }
        }
        return NAME_NO_MATCH;
    }

    private List<String> getBreadCrumb() {
+143 −0
Original line number Diff line number Diff line
@@ -188,4 +188,147 @@ public class InstalledAppResultLoaderTest {
        // Then partial match
        assertThat(results.get(1).title).isNotEqualTo(query);
    }

    @Test
    public void query_normalWord_MatchPrefix() {
        final String query = "ba";
        final String packageName = "Bananas";
        when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
                .thenReturn(Arrays.asList(
                        ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
                                0 /* targetSdkVersion */)));
        mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);

        assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
    }

    @Test
    public void query_CapitalCase_DoestMatchSecondWord() {
        final String query = "Apples";
        final String packageName = "BananasApples";
        when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
                .thenReturn(Arrays.asList(
                        ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
                                0 /* targetSdkVersion */)));
        mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);

        assertThat(mLoader.loadInBackground().size()).isEqualTo(0);
    }

    @Test
    public void query_TwoWords_MatchesFirstWord() {
        final String query = "Banana";
        final String packageName = "Bananas Apples";
        when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
                .thenReturn(Arrays.asList(
                        ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
                                0 /* targetSdkVersion */)));
        mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);

        assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
    }

    @Test
    public void query_TwoWords_MatchesSecondWord() {
        final String query = "Apple";
        final String packageName = "Bananas Apples";
        when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
                .thenReturn(Arrays.asList(
                        ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
                                0 /* targetSdkVersion */)));
        mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);

        assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
    }

    @Test
    public void query_ThreeWords_MatchesThirdWord() {
        final String query = "Pear";
        final String packageName = "Bananas Apples Pears";
        when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
                .thenReturn(Arrays.asList(
                        ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
                                0 /* targetSdkVersion */)));
        mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);

        assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
    }

    @Test
    public void query_DoubleSpacedWords_MatchesSecondWord() {
        final String query = "Apple";
        final String packageName = "Bananas  Apples";
        when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
                .thenReturn(Arrays.asList(
                        ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
                                0 /* targetSdkVersion */)));
        mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);

        assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
    }

    @Test
    public void query_SpecialChar_MatchesSecondWord() {
        final String query = "Apple";
        final String packageName = "Bananas & Apples";
        when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
                .thenReturn(Arrays.asList(
                        ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
                                0 /* targetSdkVersion */)));
        mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);

        assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
    }

    @Test
    public void query_TabSeparated_MatchesSecondWord() {
        final String query = "Apple";
        final String packageName = "Bananas\tApples";
        when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
                .thenReturn(Arrays.asList(
                        ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
                                0 /* targetSdkVersion */)));
        mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);

        assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
    }

    @Test
    public void query_LeadingNumber_MatchesWord() {
        final String query = "4";
        final String packageName = "4Bananas";
        when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
                .thenReturn(Arrays.asList(
                        ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
                                0 /* targetSdkVersion */)));
        mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);

        assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
    }

    @Test
    public void query_FirstWordPrefixOfQuery_NoMatch() {
        final String query = "Bananass";
        final String packageName = "Bananas Apples";
        when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
                .thenReturn(Arrays.asList(
                        ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
                                0 /* targetSdkVersion */)));
        mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);

        assertThat(mLoader.loadInBackground().size()).isEqualTo(0);
    }

    @Test
    public void query_QueryLongerThanAppName_NoMatch() {
        final String query = "BananasApples";
        final String packageName = "Bananas";
        when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
                .thenReturn(Arrays.asList(
                        ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */,
                                0 /* targetSdkVersion */)));
        mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);

        assertThat(mLoader.loadInBackground().size()).isEqualTo(0);
    }
}