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
19ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwoodimport android.os.Handler;
20ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwoodimport android.util.Log;
21ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood
22a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertimport com.android.quicksearchbox.util.BatchingNamedTaskExecutor;
23f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringertimport com.android.quicksearchbox.util.Consumer;
24a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertimport com.android.quicksearchbox.util.NamedTaskExecutor;
25233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontayimport com.android.quicksearchbox.util.NoOpConsumer;
26a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert
270484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert/**
2847d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert * Suggestions provider implementation.
290484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert *
300484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert * The provider will only handle a single query at a time. If a new query comes
3154af8b26e73f9aa2a01473517cf6d9980a95fe55Mathew Inwood * in, the old one is cancelled.
320484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert */
33b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringertpublic class SuggestionsProviderImpl implements SuggestionsProvider {
340484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
35b5fc08b7f16a32d3865f44b7f26d8aaa5304a2adBjorn Bringert    private static final boolean DBG = false;
3647d02f7285794bb39b2a2d828d32b5329dd8ecb0Bjorn Bringert    private static final String TAG = "QSB.SuggestionsProviderImpl";
370484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
380484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    private final Config mConfig;
390484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
40a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    private final NamedTaskExecutor mQueryExecutor;
410484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
420484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    private final Handler mPublishThread;
430484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
4481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    private final Logger mLogger;
4581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert
46b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    public SuggestionsProviderImpl(Config config,
47a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert            NamedTaskExecutor queryExecutor,
480484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert            Handler publishThread,
49f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            Logger logger) {
500484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        mConfig = config;
510484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        mQueryExecutor = queryExecutor;
520484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        mPublishThread = publishThread;
5381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        mLogger = logger;
540484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
550484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
56ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    @Override
570484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    public void close() {
580484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
590484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
60ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    @Override
61ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    public Suggestions getSuggestions(String query, Source sourceToQuery) {
620484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        if (DBG) Log.d(TAG, "getSuggestions(" + query + ")");
63ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        final Suggestions suggestions = new Suggestions(query, sourceToQuery);
64ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        Log.i(TAG, "chars:" + query.length() + ",source:" + sourceToQuery);
6539bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney
66ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        Consumer<SourceResult> receiver;
67233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        if (shouldDisplayResults(query)) {
68ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood            receiver = new SuggestionCursorReceiver(suggestions);
69233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        } else {
70ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood            receiver = new NoOpConsumer<SourceResult>();
713540e5a9eab6ff33e6d45f1d908bcaf4c4f49152Bjorn Bringert            suggestions.done();
72233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        }
730484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
74ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        int maxResults = mConfig.getMaxResultsPerSource();
75ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        QueryTask.startQuery(query, maxResults, sourceToQuery, mQueryExecutor,
76ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood                mPublishThread, receiver);
770484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
780484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        return suggestions;
790484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
800484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
81233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay    private boolean shouldDisplayResults(String query) {
82233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        if (query.length() == 0 && !mConfig.showSuggestionsForZeroQuery()) {
83233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay            // Note that even though we don't display such results, it's
84233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay            // useful to run the query itself because it warms up the network
85233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay            // connection.
86233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay            return false;
87233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        }
88233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay        return true;
89233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay    }
90233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay
91233f899a01d805b27f17ce4f72fdbc7c279c6c36Peter Visontay
92ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood    private class SuggestionCursorReceiver implements Consumer<SourceResult> {
93b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        private final Suggestions mSuggestions;
9439bbcdc1a485ded93059de4a3f70bfda85e9f304Bryan Mawhinney
95ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        public SuggestionCursorReceiver(Suggestions suggestions) {
9627d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney            mSuggestions = suggestions;
9727d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney        }
9827d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney
99ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        @Override
100ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood        public boolean consume(SourceResult cursor) {
101848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            if (DBG) {
102848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani                Log.d(TAG, "SuggestionCursorReceiver.consume(" + cursor + ") corpus=" +
103ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood                        cursor.getSource() + " count = " + cursor.getCount());
104f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert            }
105ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood            // publish immediately
106ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood            if (DBG) Log.d(TAG, "Publishing results");
107ecf356c15143ab0583c64682de16d94a57f7dd1cMathew Inwood            mSuggestions.addResults(cursor);
108f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            if (cursor != null && mLogger != null) {
109f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert                mLogger.logLatency(cursor);
110f95ce100dcbc77794b79b0187c566bb58b5978d3Bjorn Bringert            }
111f252dc7a25ba08b973ecc1cfbbce58eb78d42167Bjorn Bringert            return true;
11227d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney        }
11327d3d4eb3b0414cf7001020d8ddcfdde81fd516bBryan Mawhinney
1140484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
1150484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert}
116