SuggestionsProviderImpl.java revision 233f899a01d805b27f17ce4f72fdbc7c279c6c36
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
19a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertimport com.android.quicksearchbox.util.BatchingNamedTaskExecutor;
20f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringertimport com.android.quicksearchbox.util.Consumer;
21a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertimport com.android.quicksearchbox.util.NamedTaskExecutor;
22233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontayimport com.android.quicksearchbox.util.NoOpConsumer;
23a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
240484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringertimport android.os.Handler;
250484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringertimport android.util.Log;
260484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
270484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringertimport java.util.ArrayList;
28ce4cdcf739b57563ddcdbed6944128b8c1f7522aBjorn Bringertimport java.util.List;
290484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
300484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert/**
3147d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert * Suggestions provider implementation.
320484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert *
330484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * The provider will only handle a single query at a time. If a new query comes
3454af8b26e73f9aa2a01473517cf6d9980a95fe55Mathew Inwood * in, the old one is cancelled.
350484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert */
36b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringertpublic class SuggestionsProviderImpl implements SuggestionsProvider {
370484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
38b5fc08b7f16a32d3865f44b7f26d8aaa5304a2adBjorn Bringert    private static final boolean DBG = false;
3947d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert    private static final String TAG = "QSB.SuggestionsProviderImpl";
400484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
410484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    private final Config mConfig;
420484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
43a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    private final NamedTaskExecutor mQueryExecutor;
440484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
450484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    private final Handler mPublishThread;
460484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
47e15fe38f0142174d223bfda0cd87d1a749a85facMathew Inwood    private final ShouldQueryStrategy mShouldQueryStrategy;
4853bf1409474f26ab0f3754ee9b4d2de901a6be00Bryan Mawhinney
4981a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    private final Logger mLogger;
5081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert
51a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    private BatchingNamedTaskExecutor mBatchingExecutor;
5227d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney
53b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    public SuggestionsProviderImpl(Config config,
54a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert            NamedTaskExecutor queryExecutor,
550484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert            Handler publishThread,
56f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            Logger logger) {
570484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        mConfig = config;
580484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        mQueryExecutor = queryExecutor;
590484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        mPublishThread = publishThread;
6081a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        mLogger = logger;
61e15fe38f0142174d223bfda0cd87d1a749a85facMathew Inwood        mShouldQueryStrategy = new ShouldQueryStrategy(mConfig);
620484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
630484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
640484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    public void close() {
650484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        cancelPendingTasks();
660484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
670484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
680484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    /**
690484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert     * Cancels all pending query tasks.
700484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert     */
710484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    private void cancelPendingTasks() {
7227d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney        if (mBatchingExecutor != null) {
7327d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney            mBatchingExecutor.cancelPendingTasks();
7427d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney            mBatchingExecutor = null;
7527d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney        }
760484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
770484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
780484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    /**
790484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert     * Gets the sources that should be queried for the given query.
800484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert     */
81b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private List<Corpus> filterCorpora(String query, List<Corpus> corpora) {
82b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        // If there is only one corpus, always query it
83b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        if (corpora.size() <= 1) return corpora;
84b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        ArrayList<Corpus> corporaToQuery = new ArrayList<Corpus>(corpora.size());
85b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        for (Corpus corpus : corpora) {
86fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            if (shouldQueryCorpus(corpus, query)) {
87a48053f425e7a65f48bcabe1e0cf0cfb54162167Mathew Inwood                if (DBG) Log.d(TAG, "should query corpus " + corpus);
88fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                corporaToQuery.add(corpus);
89a48053f425e7a65f48bcabe1e0cf0cfb54162167Mathew Inwood            } else {
90a48053f425e7a65f48bcabe1e0cf0cfb54162167Mathew Inwood                if (DBG) Log.d(TAG, "should NOT query corpus " + corpus);
910484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert            }
920484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        }
93a48053f425e7a65f48bcabe1e0cf0cfb54162167Mathew Inwood        if (DBG) Log.d(TAG, "getCorporaToQuery corporaToQuery=" + corporaToQuery);
94fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return corporaToQuery;
950484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
960484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
97fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    protected boolean shouldQueryCorpus(Corpus corpus, String query) {
98fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return mShouldQueryStrategy.shouldQueryCorpus(corpus, query);
990484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
1000484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
101fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private void updateShouldQueryStrategy(CorpusResult cursor) {
10227d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney        if (cursor.getCount() == 0) {
103fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            mShouldQueryStrategy.onZeroResults(cursor.getCorpus(),
10427d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney                    cursor.getUserQuery());
10527d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney        }
10627d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney    }
10727d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney
108b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    public Suggestions getSuggestions(String query, List<Corpus> corporaToQuery) {
1090484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        if (DBG) Log.d(TAG, "getSuggestions(" + query + ")");
110b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        corporaToQuery = filterCorpora(query, corporaToQuery);
111b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        final Suggestions suggestions = new Suggestions(query, corporaToQuery);
112f3f70e5ae88f06ff6dabdec9e7c71a19ca1e7108Bjorn Bringert        Log.i(TAG, "chars:" + query.length() + ",corpora:" + corporaToQuery);
1130484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
1140484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        // Fast path for the zero sources case
115fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (corporaToQuery.size() == 0) {
1160484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert            return suggestions;
1170484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        }
1180484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
11939bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney        int initialBatchSize = countDefaultCorpora(corporaToQuery);
12039bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney        if (initialBatchSize == 0) {
12139bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney            initialBatchSize = mConfig.getNumPromotedSources();
12239bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney        }
12339bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney
12439bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney        mBatchingExecutor = new BatchingNamedTaskExecutor(mQueryExecutor);
12527d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney
126ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert        long publishResultDelayMillis = mConfig.getPublishResultDelayMillis();
127233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay
128233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        Consumer<CorpusResult> receiver;
129233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        if (shouldDisplayResults(query)) {
130233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay            receiver = new SuggestionCursorReceiver(
131233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay                    mBatchingExecutor, suggestions, initialBatchSize,
132233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay                    publishResultDelayMillis);
133233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        } else {
134233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay            receiver = new NoOpConsumer<CorpusResult>();
135233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        }
1360484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
1370484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        int maxResultsPerSource = mConfig.getMaxResultsPerSource();
138f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert        QueryTask.startQueries(query, maxResultsPerSource, corporaToQuery, mBatchingExecutor,
139b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert                mPublishThread, receiver, corporaToQuery.size() == 1);
14039bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney        mBatchingExecutor.executeNextBatch(initialBatchSize);
1410484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
1420484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        return suggestions;
1430484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
1440484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
14539bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney    private int countDefaultCorpora(List<Corpus> corpora) {
14639bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney        int count = 0;
14739bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney        for (Corpus corpus : corpora) {
14896c7058210699c82445169048b7c0fdfb16f59eeBjorn Bringert            if (corpus.isCorpusDefaultEnabled()) {
14939bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney                count++;
15039bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney            }
15139bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney        }
15239bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney        return count;
15339bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney    }
15439bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney
155233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay    private boolean shouldDisplayResults(String query) {
156233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        if (query.length() == 0 && !mConfig.showSuggestionsForZeroQuery()) {
157233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay            // Note that even though we don't display such results, it's
158233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay            // useful to run the query itself because it warms up the network
159233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay            // connection.
160233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay            return false;
161233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        }
162233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        return true;
163233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay    }
164233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay
165233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay
166f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert    private class SuggestionCursorReceiver implements Consumer<CorpusResult> {
167a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        private final BatchingNamedTaskExecutor mExecutor;
168b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        private final Suggestions mSuggestions;
169ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert        private final long mResultPublishDelayMillis;
170ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert        private final ArrayList<CorpusResult> mPendingResults;
171ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert        private final Runnable mResultPublishTask = new Runnable () {
172ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert            public void run() {
173ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                if (DBG) Log.d(TAG, "Publishing delayed results");
174ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                publishPendingResults();
175ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert            }
176ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert        };
17727d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney
17839bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney        private int mCountAtWhichToExecuteNextBatch;
17939bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney
180a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        public SuggestionCursorReceiver(BatchingNamedTaskExecutor executor,
181b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert                Suggestions suggestions, int initialBatchSize,
182ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                long publishResultDelayMillis) {
18327d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney            mExecutor = executor;
18427d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney            mSuggestions = suggestions;
18539bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney            mCountAtWhichToExecuteNextBatch = initialBatchSize;
186ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert            mResultPublishDelayMillis = publishResultDelayMillis;
187ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert            mPendingResults = new ArrayList<CorpusResult>();
18827d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney        }
18927d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney
190f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert        public boolean consume(CorpusResult cursor) {
191848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            if (DBG) {
192848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                Log.d(TAG, "SuggestionCursorReceiver.consume(" + cursor + ") corpus=" +
193848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                        cursor.getCorpus() + " count = " + cursor.getCount());
194848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            }
19527d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney            updateShouldQueryStrategy(cursor);
196ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert            mPendingResults.add(cursor);
197ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert            if (mResultPublishDelayMillis > 0
198ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                    && !mSuggestions.isClosed()
199ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                    && mSuggestions.getResultCount() + mPendingResults.size()
200ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                            < mCountAtWhichToExecuteNextBatch) {
201ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                // This is not the last result of the batch, delay publishing
202ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                if (DBG) Log.d(TAG, "Delaying result by " + mResultPublishDelayMillis + " ms");
203ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                mPublishThread.removeCallbacks(mResultPublishTask);
204ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                mPublishThread.postDelayed(mResultPublishTask, mResultPublishDelayMillis);
205ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert            } else {
206ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                // This is the last result, publish immediately
207ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                if (DBG) Log.d(TAG, "Publishing result immediately");
208ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                mPublishThread.removeCallbacks(mResultPublishTask);
209ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert                publishPendingResults();
210ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert            }
211f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert            if (!mSuggestions.isClosed()) {
212f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert                executeNextBatchIfNeeded();
213f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert            }
214f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            if (cursor != null && mLogger != null) {
215f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert                mLogger.logLatency(cursor);
216f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            }
217f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert            return true;
21827d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney        }
21927d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney
220ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert        private void publishPendingResults() {
221ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert            mSuggestions.addCorpusResults(mPendingResults);
222ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert            mPendingResults.clear();
223ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert        }
224ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert
22527d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney        private void executeNextBatchIfNeeded() {
226ced9f76b761536341d739e9a243c98a4bf90638cBjorn Bringert            if (mSuggestions.getResultCount() == mCountAtWhichToExecuteNextBatch) {
227b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert                // We've just finished one batch, ask for more
228b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert                int nextBatchSize = mConfig.getNumPromotedSources();
229b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert                mCountAtWhichToExecuteNextBatch += nextBatchSize;
230b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert                mExecutor.executeNextBatch(nextBatchSize);
23127d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney            }
23227d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney        }
2330484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
2340484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert}
235