MultiSourceCorpus.java revision 96c7058210699c82445169048b7c0fdfb16f59ee
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.quicksearchbox;
18
19
20import com.android.quicksearchbox.util.BarrierConsumer;
21
22import android.content.Context;
23
24import java.util.ArrayList;
25import java.util.Collection;
26import java.util.List;
27import java.util.concurrent.Executor;
28
29/**
30 * Base class for corpora backed by multiple sources.
31 */
32public abstract class MultiSourceCorpus extends AbstractCorpus {
33
34    private final Executor mExecutor;
35
36    private final ArrayList<Source> mSources;
37
38    public MultiSourceCorpus(Context context, Config config,
39            Executor executor, Source... sources) {
40        super(context, config);
41        mExecutor = executor;
42
43        mSources = new ArrayList<Source>();
44        for (Source source : sources) {
45            if (source != null) {
46                mSources.add(source);
47            }
48        }
49    }
50
51    public Collection<Source> getSources() {
52        return mSources;
53    }
54
55    /**
56     * Creates a corpus result object for a set of source results.
57     * This method should not call {@link Result#fill}.
58     *
59     * @param query The query text.
60     * @param results The results of the queries.
61     * @param latency Latency in milliseconds of the suggestion queries.
62     * @return An instance of {@link Result} or a subclass of it.
63     */
64    protected Result createResult(String query, ArrayList<SourceResult> results, int latency) {
65        return new Result(query, results, latency);
66    }
67
68    /**
69     * Gets the sources to query for the given input.
70     *
71     * @param query The current input.
72     * @return The sources to query.
73     */
74    protected List<Source> getSourcesToQuery(String query) {
75        return mSources;
76    }
77
78    public CorpusResult getSuggestions(String query, int queryLimit) {
79        LatencyTracker latencyTracker = new LatencyTracker();
80        List<Source> sources = getSourcesToQuery(query);
81        BarrierConsumer<SourceResult> consumer =
82                new BarrierConsumer<SourceResult>(sources.size());
83        for (Source source : sources) {
84            QueryTask<SourceResult> task = new QueryTask<SourceResult>(query, queryLimit,
85                    source, null, consumer);
86            mExecutor.execute(task);
87        }
88        ArrayList<SourceResult> results = consumer.getValues();
89        int latency = latencyTracker.getLatency();
90        Result result = createResult(query, results, latency);
91        result.fill();
92        return result;
93    }
94
95    /**
96     * Base class for results returned by {@link MultiSourceCorpus#getSuggestions}.
97     * Subclasses of {@link MultiSourceCorpus} should override
98     * {@link MultiSourceCorpus#createResult} and return an instance of this class or a
99     * subclass.
100     */
101    protected class Result extends ListSuggestionCursor implements CorpusResult {
102
103        private final ArrayList<SourceResult> mResults;
104
105        private final int mLatency;
106
107        public Result(String userQuery, ArrayList<SourceResult> results, int latency) {
108            super(userQuery);
109            mResults = results;
110            mLatency = latency;
111        }
112
113        protected ArrayList<SourceResult> getResults() {
114            return mResults;
115        }
116
117        /**
118         * Fills the list of suggestions using the list of results.
119         * The default implementation concatenates the results.
120         */
121        public void fill() {
122            for (SourceResult result : getResults()) {
123                int count = result.getCount();
124                for (int i = 0; i < count; i++) {
125                    result.moveTo(i);
126                    add(new SuggestionPosition(result));
127                }
128            }
129        }
130
131        public Corpus getCorpus() {
132            return MultiSourceCorpus.this;
133        }
134
135        public int getLatency() {
136            return mLatency;
137        }
138
139        @Override
140        public void close() {
141            super.close();
142            for (SourceResult result : mResults) {
143                result.close();
144            }
145        }
146
147        @Override
148        public String toString() {
149            return getCorpus() + "[" + getUserQuery() + "]";
150        }
151    }
152
153}
154