SuggestionsProviderImpl.java revision 0484fb4d652bfa9d5c7fb238a7cec1a6f2244e44
10484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert/* 20484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * Copyright (C) 2009 The Android Open Source Project 30484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * 40484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 50484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * you may not use this file except in compliance with the License. 60484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * You may obtain a copy of the License at 70484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * 80484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 90484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * 100484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * Unless required by applicable law or agreed to in writing, software 110484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 120484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * See the License for the specific language governing permissions and 140484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * limitations under the License. 150484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert */ 160484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 170484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringertpackage com.android.quicksearchbox; 180484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 190484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringertimport android.os.Handler; 200484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringertimport android.util.Log; 210484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 220484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringertimport java.util.ArrayList; 230484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 240484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert/** 250484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * Common suggestions provider base class. 260484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * 270484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * The provider will only handle a single query at a time. If a new query comes 280484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * in, the old one is canceled. 290484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert */ 300484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringertpublic abstract class AbstractSuggestionsProvider implements SuggestionsProvider { 310484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 320484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private static final boolean DBG = true; 330484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private static final String TAG = "QSB.AbstractSuggestionsProvider"; 340484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 350484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private final Config mConfig; 360484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 370484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private final SourceTaskExecutor mQueryExecutor; 380484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 390484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private final Handler mPublishThread; 400484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 410484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private final Promoter mPromoter; 420484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 430484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert public AbstractSuggestionsProvider(Config config, 440484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert SourceTaskExecutor queryExecutor, 450484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert Handler publishThread, 460484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert Promoter promoter) { 470484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mConfig = config; 480484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mQueryExecutor = queryExecutor; 490484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mPublishThread = publishThread; 500484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mPromoter = promoter; 510484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 520484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 530484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert public void close() { 540484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert cancelPendingTasks(); 550484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 560484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 570484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert /** 580484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * Cancels all pending query tasks. 590484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert */ 600484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private void cancelPendingTasks() { 610484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mQueryExecutor.cancelPendingTasks(); 620484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 630484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 640484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert public abstract ArrayList<Source> getOrderedSources(); 650484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 660484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert protected abstract SuggestionCursor getShortcutsForQuery(String query); 670484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 680484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert /** 690484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * Gets the sources that should be queried for the given query. 700484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * 710484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert */ 720484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private ArrayList<Source> getSourcesToQuery(String query) { 730484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert if (query.length() == 0) { 740484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert return new ArrayList<Source>(); 750484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 760484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert ArrayList<Source> orderedSources = getOrderedSources(); 770484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert ArrayList<Source> sourcesToQuery = new ArrayList<Source>(orderedSources.size()); 780484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert for (Source source : orderedSources) { 790484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert if (shouldQuerySource(source, query)) { 800484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert sourcesToQuery.add(source); 810484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 820484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 830484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert return sourcesToQuery; 840484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 850484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 860484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert protected boolean shouldQuerySource(Source source, String query) { 870484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert return query.length() >= source.getQueryThreshold(); 880484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 890484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 900484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert public Suggestions getSuggestions(String query) { 910484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert if (DBG) Log.d(TAG, "getSuggestions(" + query + ")"); 920484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert cancelPendingTasks(); 930484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert ArrayList<Source> sourcesToQuery = getSourcesToQuery(query); 940484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert final Suggestions suggestions = new Suggestions(mPromoter, 950484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mConfig.getMaxPromotedSuggestions(), 960484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert query, 970484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert sourcesToQuery.size()); 980484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert SuggestionCursor shortcuts = getShortcutsForQuery(query); 990484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert if (shortcuts != null) { 1000484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert suggestions.setShortcuts(shortcuts); 1010484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1020484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 1030484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert // Fast path for the zero sources case 1040484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert if (sourcesToQuery.size() == 0) { 1050484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert return suggestions; 1060484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1070484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 1080484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert SuggestionCursorReceiver receiver = new SuggestionCursorReceiver() { 1090484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert public void receiveSuggestionCursor(final SuggestionCursor cursor) { 1100484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mPublishThread.post(new Runnable() { 1110484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert public void run() { 1120484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert suggestions.addSourceResult(cursor); 1130484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1140484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert }); 1150484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1160484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert }; 1170484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 1180484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert int maxResultsPerSource = mConfig.getMaxResultsPerSource(); 1190484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert for (Source source : sourcesToQuery) { 1200484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert QueryTask task = new QueryTask(query, source, maxResultsPerSource, receiver); 1210484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mQueryExecutor.execute(task); 1220484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1230484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 1240484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert return suggestions; 1250484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1260484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 1270484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private interface SuggestionCursorReceiver { 1280484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert void receiveSuggestionCursor(SuggestionCursor cursor); 1290484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1300484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 1310484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert /** 1320484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * Gets suggestions from a given source. 1330484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert */ 1340484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private static class QueryTask implements SourceTask { 1350484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private final String mQuery; 1360484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private final Source mSource; 1370484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private final int mQueryLimit; 1380484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert private final SuggestionCursorReceiver mReceiver; 1390484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 1400484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert public QueryTask(String query, Source source, int queryLimit, 1410484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert SuggestionCursorReceiver receiver) { 1420484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mQuery = query; 1430484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mSource = source; 1440484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mQueryLimit = queryLimit; 1450484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mReceiver = receiver; 1460484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1470484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 1480484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert public Source getSource() { 1490484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert return mSource; 1500484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1510484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 1520484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert public void run() { 1530484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert SuggestionCursor cursor = mSource.getSuggestions(mQuery, mQueryLimit); 1540484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert mReceiver.receiveSuggestionCursor(cursor); 1550484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1560484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert 1570484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert @Override 1580484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert public String toString() { 1590484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert return mSource + "[" + mQuery + "]"; 1600484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1610484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert } 1620484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert} 163