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

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

Merge "Move search querying into a single API"

parents 374b295d fb772248
Loading
Loading
Loading
Loading
+89 −82
Original line number Diff line number Diff line
@@ -30,24 +30,36 @@ import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;
import android.support.v4.content.ContextCompat;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.view.accessibility.AccessibilityManager;

import com.android.settings.R;
import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.dashboard.SiteMapManager;
import com.android.settings.utils.AsyncLoader;

import java.util.HashSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class AccessibilityServiceResultLoader extends AsyncLoader<Set<? extends SearchResult>> {
public class AccessibilityServiceResultLoader extends
        FutureTask<List<? extends SearchResult>> {

    private static final String TAG = "A11yResultFutureTask";

    public AccessibilityServiceResultLoader(Context context, String query,
            SiteMapManager manager) {
        super(new AccessibilityServiceResultCallable(context, query, manager));
    }

    static class AccessibilityServiceResultCallable implements
            Callable<List<? extends SearchResult>> {

        private static final int NAME_NO_MATCH = -1;

        private final Context mContext;

        private List<String> mBreadcrumb;
        private SiteMapManager mSiteMapManager;
        @VisibleForTesting
@@ -56,12 +68,10 @@ public class AccessibilityServiceResultLoader extends AsyncLoader<Set<? extends
        private final PackageManager mPackageManager;
        private final int mUserId;


    public AccessibilityServiceResultLoader(Context context, String query,
        public AccessibilityServiceResultCallable(Context context, String query,
                SiteMapManager mapManager) {
        super(context);
        mContext = context;
            mUserId = UserHandle.myUserId();
            mContext = context;
            mSiteMapManager = mapManager;
            mPackageManager = context.getPackageManager();
            mAccessibilityManager =
@@ -70,13 +80,13 @@ public class AccessibilityServiceResultLoader extends AsyncLoader<Set<? extends
        }

        @Override
    public Set<? extends SearchResult> loadInBackground() {
        final Set<SearchResult> results = new HashSet<>();
        final Context context = getContext();
        public List<? extends SearchResult> call() throws Exception {
            long startTime = System.currentTimeMillis();
            final List<SearchResult> results = new ArrayList<>();
            final List<AccessibilityServiceInfo> services = mAccessibilityManager
                    .getInstalledAccessibilityServiceList();
            final IconDrawableFactory iconFactory = IconDrawableFactory.newInstance(mContext);
        final String screenTitle = context.getString(R.string.accessibility_settings);
            final String screenTitle = mContext.getString(R.string.accessibility_settings);
            for (AccessibilityServiceInfo service : services) {
                if (service == null) {
                    continue;
@@ -93,7 +103,7 @@ public class AccessibilityServiceResultLoader extends AsyncLoader<Set<? extends
                }
                final Drawable icon;
                if (resolveInfo.getIconResource() == 0) {
                icon = ContextCompat.getDrawable(context, R.mipmap.ic_accessibility_generic);
                    icon = ContextCompat.getDrawable(mContext, R.mipmap.ic_accessibility_generic);
                } else {
                    icon = iconFactory.getBadgedIcon(
                            resolveInfo.serviceInfo,
@@ -102,7 +112,7 @@ public class AccessibilityServiceResultLoader extends AsyncLoader<Set<? extends
                }
                final String componentName = new ComponentName(serviceInfo.packageName,
                        serviceInfo.name).flattenToString();
            final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
                final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(mContext,
                        AccessibilitySettings.class.getName(), componentName, screenTitle);

                results.add(new SearchResult.Builder()
@@ -114,21 +124,18 @@ public class AccessibilityServiceResultLoader extends AsyncLoader<Set<? extends
                        .setStableId(Objects.hash(screenTitle, componentName))
                        .build());
            }
            Collections.sort(results);
            Log.i(TAG, "A11y search loading took:" + (System.currentTimeMillis() - startTime));
            return results;
        }

        private List<String> getBreadCrumb() {
            if (mBreadcrumb == null || mBreadcrumb.isEmpty()) {
            final Context context = getContext();
                mBreadcrumb = mSiteMapManager.buildBreadCrumb(
                    context, AccessibilitySettings.class.getName(),
                    context.getString(R.string.accessibility_settings));
                        mContext, AccessibilitySettings.class.getName(),
                        mContext.getString(R.string.accessibility_settings));
            }
            return mBreadcrumb;
        }

    @Override
    protected void onDiscardResult(Set<? extends SearchResult> result) {

    }
}
+19 −10
Original line number Diff line number Diff line
@@ -36,16 +36,6 @@ import java.util.Map;
import java.util.Set;

import static com.android.settings.search.DatabaseResultLoader.BASE_RANKS;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_CLASS_NAME;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_ICON;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_ID;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_KEY;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_PAYLOAD;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_PAYLOAD_TYPE;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_SCREEN_TITLE;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_SUMMARY_ON;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_TITLE;
import static com.android.settings.search.SearchResult.TOP_RANK;

/**
@@ -62,6 +52,25 @@ public class CursorToSearchResultConverter {

    private static final String TAG = "CursorConverter";

    /**
     * These indices are used to match the columns of the this loader's SELECT statement.
     * These are not necessarily the same order nor similar coverage as the schema defined in
     * IndexDatabaseHelper
     */
    public static final int COLUMN_INDEX_ID = 0;
    public static final int COLUMN_INDEX_TITLE = 1;
    public static final int COLUMN_INDEX_SUMMARY_ON = 2;
    public static final int COLUMN_INDEX_SUMMARY_OFF = 3;
    public static final int COLUMN_INDEX_CLASS_NAME = 4;
    public static final int COLUMN_INDEX_SCREEN_TITLE = 5;
    public static final int COLUMN_INDEX_ICON = 6;
    public static final int COLUMN_INDEX_INTENT_ACTION = 7;
    public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 8;
    public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 9;
    public static final int COLUMN_INDEX_KEY = 10;
    public static final int COLUMN_INDEX_PAYLOAD_TYPE = 11;
    public static final int COLUMN_INDEX_PAYLOAD = 12;

    private final Context mContext;

    private final int LONG_TITLE_LENGTH = 20;
+5 −4
Original line number Diff line number Diff line
@@ -17,11 +17,13 @@

package com.android.settings.search;

import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_ID;
import static com.android.settings.search.DatabaseResultLoader

import static com.android.settings.search.CursorToSearchResultConverter.COLUMN_INDEX_ID;
import static com.android.settings.search.CursorToSearchResultConverter
        .COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE;
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_KEY;
import static com.android.settings.search.CursorToSearchResultConverter.COLUMN_INDEX_KEY;
import static com.android.settings.search.DatabaseResultLoader.SELECT_COLUMNS;
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DOCID;
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.CLASS_NAME;
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_ENTRIES;
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS;
@@ -31,7 +33,6 @@ import static com.android.settings.search.IndexDatabaseHelper.IndexColumns
        .DATA_SUMMARY_ON_NORMALIZED;
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE;
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED;
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DOCID;
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ENABLED;
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ICON;
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_ACTION;
+247 −178
Original line number Diff line number Diff line
@@ -24,35 +24,31 @@ import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.util.Pair;

import com.android.settings.dashboard.SiteMapManager;
import com.android.settings.utils.AsyncLoader;
import com.android.settings.overlay.FeatureFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * AsyncTask to retrieve Settings, First party app and any intent based results.
 * AsyncTask to retrieve Settings, first party app and any intent based results.
 */
public class DatabaseResultLoader extends AsyncLoader<Set<? extends SearchResult>> {
    private static final String LOG = "DatabaseResultLoader";

    /* These indices are used to match the columns of the this loader's SELECT statement.
     These are not necessarily the same order nor similar coverage as the schema defined in
     IndexDatabaseHelper */
    public static final int COLUMN_INDEX_ID = 0;
    public static final int COLUMN_INDEX_TITLE = 1;
    public static final int COLUMN_INDEX_SUMMARY_ON = 2;
    public static final int COLUMN_INDEX_SUMMARY_OFF = 3;
    public static final int COLUMN_INDEX_CLASS_NAME = 4;
    public static final int COLUMN_INDEX_SCREEN_TITLE = 5;
    public static final int COLUMN_INDEX_ICON = 6;
    public static final int COLUMN_INDEX_INTENT_ACTION = 7;
    public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 8;
    public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 9;
    public static final int COLUMN_INDEX_KEY = 10;
    public static final int COLUMN_INDEX_PAYLOAD_TYPE = 11;
    public static final int COLUMN_INDEX_PAYLOAD = 12;
public class DatabaseResultLoader extends FutureTask<List<? extends SearchResult>> {

    private static final String TAG = "DatabaseResultLoader";

    public static final String[] SELECT_COLUMNS = {
            IndexColumns.DOCID,
@@ -82,62 +78,92 @@ public class DatabaseResultLoader extends AsyncLoader<Set<? extends SearchResult
            IndexColumns.DATA_SUMMARY_OFF_NORMALIZED,
    };

    public static final String[] MATCH_COLUMNS_TERTIARY = {
            IndexColumns.DATA_KEYWORDS,
            IndexColumns.DATA_ENTRIES
    };

    /**
     * Base ranks defines the best possible rank based on what the query matches.
     * If the query matches the prefix of the first word in the title, the best rank it can be is 1
     * If the query matches the prefix of the other words in the title, the best rank it can be is 3
     * If the query matches the prefix of the first word in the title, the best rank it can be
     * is 1
     * If the query matches the prefix of the other words in the title, the best rank it can be
     * is 3
     * If the query only matches the summary, the best rank it can be is 7
     * If the query only matches keywords or entries, the best rank it can be is 9
     */
    public static final int[] BASE_RANKS = {1, 3, 7, 9};

    public DatabaseResultLoader(Context context, String query, SiteMapManager manager) {
        super(new StaticSearchResultCallable(context, query, manager));
    }

    static class StaticSearchResultCallable implements
            Callable<List<? extends SearchResult>> {

        public final String[] MATCH_COLUMNS_TERTIARY = {
                IndexColumns.DATA_KEYWORDS,
                IndexColumns.DATA_ENTRIES
        };

        @VisibleForTesting
        final String mQueryText;
        private final Context mContext;
        private final CursorToSearchResultConverter mConverter;
        private final SiteMapManager mSiteMapManager;
        private final SearchFeatureProvider mFeatureProvider;

    public DatabaseResultLoader(Context context, String queryText, SiteMapManager mapManager) {
        super(context);
        mSiteMapManager = mapManager;
        public StaticSearchResultCallable(Context context, String queryText,
                SiteMapManager mapManager) {
            mContext = context;
            mSiteMapManager = mapManager;
            mQueryText = queryText;
            mConverter = new CursorToSearchResultConverter(context);
            mFeatureProvider = FeatureFactory.getFactory(context).getSearchFeatureProvider();
        }

        @Override
    protected void onDiscardResult(Set<? extends SearchResult> result) {
        // TODO Search
    }

    @Override
    public Set<? extends SearchResult> loadInBackground() {
        public List<? extends SearchResult> call() {
            if (mQueryText == null || mQueryText.isEmpty()) {
            return null;
                return new ArrayList<>();
            }

        final Set<SearchResult> results = new HashSet<>();
            // TODO (b/68656233) Consolidate timing metrics
            long startTime = System.currentTimeMillis();
            // Start a Future to get search result scores.
            FutureTask<List<Pair<String, Float>>> rankerTask = mFeatureProvider.getRankerTask(
                    mContext, mQueryText);

        results.addAll(firstWordQuery(MATCH_COLUMNS_PRIMARY, BASE_RANKS[0]));
        results.addAll(secondaryWordQuery(MATCH_COLUMNS_PRIMARY, BASE_RANKS[1]));
        results.addAll(anyWordQuery(MATCH_COLUMNS_SECONDARY, BASE_RANKS[2]));
        results.addAll(anyWordQuery(MATCH_COLUMNS_TERTIARY, BASE_RANKS[3]));
        return results;
            if (rankerTask != null) {
                ExecutorService executorService = mFeatureProvider.getExecutorService();
                executorService.execute(rankerTask);
            }

    @Override
    protected boolean onCancelLoad() {
        // TODO
        return super.onCancelLoad();
            final Set<SearchResult> resultSet = new HashSet<>();

            resultSet.addAll(firstWordQuery(MATCH_COLUMNS_PRIMARY, BASE_RANKS[0]));
            resultSet.addAll(secondaryWordQuery(MATCH_COLUMNS_PRIMARY, BASE_RANKS[1]));
            resultSet.addAll(anyWordQuery(MATCH_COLUMNS_SECONDARY, BASE_RANKS[2]));
            resultSet.addAll(anyWordQuery(MATCH_COLUMNS_TERTIARY, BASE_RANKS[3]));

            // Try to retrieve the scores in time. Otherwise use static ranking.
            if (rankerTask != null) {
                try {
                    final long timeoutMs = mFeatureProvider.smartSearchRankingTimeoutMs(mContext);
                    List<Pair<String, Float>> searchRankScores = rankerTask.get(timeoutMs,
                            TimeUnit.MILLISECONDS);
                    return getDynamicRankedResults(resultSet, searchRankScores);
                } catch (TimeoutException | InterruptedException | ExecutionException e) {
                    Log.d(TAG, "Error waiting for result scores: " + e);
                }
            }

            List<SearchResult> resultList = new ArrayList<>(resultSet);
            Collections.sort(resultList);
            Log.i(TAG, "Static search loading took:" + (System.currentTimeMillis() - startTime));
            return resultList;
        }

        // TODO (b/33577327) Retrieve all search results with a single query.

        /**
     * Creates and executes the query which matches prefixes of the first word of the given columns.
         * Creates and executes the query which matches prefixes of the first word of the given
         * columns.
         *
         * @param matchColumns The columns to match on
         * @param baseRank     The highest rank achievable by these results
@@ -168,7 +194,8 @@ public class DatabaseResultLoader extends AsyncLoader<Set<? extends SearchResult
        }

        /**
     * Creates and executes the query which matches prefixes of the any word of the given columns.
         * Creates and executes the query which matches prefixes of the any word of the given
         * columns.
         *
         * @param matchColumns The columns to match on
         * @param baseRank     The highest rank achievable by these results
@@ -192,7 +219,8 @@ public class DatabaseResultLoader extends AsyncLoader<Set<? extends SearchResult
        private Set<SearchResult> query(String whereClause, String[] selection, int baseRank) {
            final SQLiteDatabase database =
                    IndexDatabaseHelper.getInstance(mContext).getReadableDatabase();
        try (Cursor resultCursor = database.query(TABLE_PREFS_INDEX, SELECT_COLUMNS, whereClause,
            try (Cursor resultCursor = database.query(TABLE_PREFS_INDEX, SELECT_COLUMNS,
                    whereClause,
                    selection, null, null, null)) {
                return mConverter.convertCursor(mSiteMapManager, resultCursor, baseRank);
            }
@@ -257,7 +285,8 @@ public class DatabaseResultLoader extends AsyncLoader<Set<? extends SearchResult
        /**
         * Fills out the selection array to match the query as the prefix of a word.
         *
     * @param size is twice the number of columns to be matched. The first match is for the prefix
         * @param size is twice the number of columns to be matched. The first match is for the
         *             prefix
         *             of the first word in the column. The second match is for any subsequent word
         *             prefix match.
         */
@@ -272,4 +301,44 @@ public class DatabaseResultLoader extends AsyncLoader<Set<? extends SearchResult
            }
            return selection;
        }

        private List<SearchResult> getDynamicRankedResults(Set<SearchResult> unsortedSet,
                List<Pair<String, Float>> searchRankScores) {
            TreeSet<SearchResult> dbResultsSortedByScores = new TreeSet<>(
                    (o1, o2) -> {
                        float score1 = getRankingScoreByStableId(searchRankScores, o1.stableId);
                        float score2 = getRankingScoreByStableId(searchRankScores, o2.stableId);
                        if (score1 > score2) {
                            return -1;
                        } else if (score1 == score2) {
                            return 0;
                        } else {
                            return 1;
                        }
                    });
            dbResultsSortedByScores.addAll(unsortedSet);

            return new ArrayList<>(dbResultsSortedByScores);
        }

        /**
         * Looks up ranking score for stableId
         *
         * @param stableId String of stableId
         * @return the ranking score corresponding to the given stableId. If there is no score
         * available for this stableId, -Float.MAX_VALUE is returned.
         */
        @VisibleForTesting
        Float getRankingScoreByStableId(List<Pair<String, Float>> searchRankScores, int stableId) {
            for (Pair<String, Float> rankingScore : searchRankScores) {
                if (Integer.toString(stableId).compareTo(rankingScore.first) == 0) {
                    return rankingScore.second;
                }
            }
            // If stableId not found in the list, we assign the minimum score so it will appear at
            // the end of the list.
            Log.w(TAG, "stableId " + stableId + " was not in the ranking scores.");
            return -Float.MAX_VALUE;
        }
    }
}
 No newline at end of file
+133 −122

File changed.

Preview size limit exceeded, changes collapsed.

Loading