MultiSourceCorpus.java revision b5fc08b7f16a32d3865f44b7f26d8aaa5304a2ad
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 Context mContext;
35
36    private final Executor mExecutor;
37
38    private final ArrayList<Source> mSources;
39
40    public MultiSourceCorpus(Context context, Executor executor, Source... sources) {
41        mContext = context;
42        mExecutor = executor;
43
44        mSources = new ArrayList<Source>();
45        for (Source source : sources) {
46            if (source != null) {
47                mSources.add(source);
48            }
49        }
50    }
51
52    protected Context getContext() {
53        return mContext;
54    }
55
56    public Collection<Source> getSources() {
57        return mSources;
58    }
59
60    /**
61     * Creates a corpus result object for a set of source results.
62     * This method should not call {@link Result#fill}.
63     *
64     * @param query The query text.
65     * @param results The results of the queries.
66     * @param latency Latency in milliseconds of the suggestion queries.
67     * @return An instance of {@link Result} or a subclass of it.
68     */
69    protected Result createResult(String query, ArrayList<SourceResult> results, int latency) {
70        return new Result(query, results, latency);
71    }
72
73    /**
74     * Gets the sources to query for the given input.
75     *
76     * @param query The current input.
77     * @return The sources to query.
78     */
79    protected List<Source> getSourcesToQuery(String query) {
80        return mSources;
81    }
82
83    public CorpusResult getSuggestions(String query, int queryLimit) {
84        LatencyTracker latencyTracker = new LatencyTracker();
85        List<Source> sources = getSourcesToQuery(query);
86        BarrierConsumer<SourceResult> consumer =
87                new BarrierConsumer<SourceResult>(sources.size());
88        for (Source source : sources) {
89            QueryTask<SourceResult> task = new QueryTask<SourceResult>(query, queryLimit,
90                    source, null, consumer);
91            mExecutor.execute(task);
92        }
93        ArrayList<SourceResult> results = consumer.getValues();
94        int latency = latencyTracker.getLatency();
95        Result result = createResult(query, results, latency);
96        result.fill();
97        return result;
98    }
99
100    /**
101     * Base class for results returned by {@link MultiSourceCorpus#getSuggestions}.
102     * Subclasses of {@link MultiSourceCorpus} should override
103     * {@link MultiSourceCorpus#createResult} and return an instance of this class or a
104     * subclass.
105     */
106    protected class Result extends ListSuggestionCursor implements CorpusResult {
107
108        private final ArrayList<SourceResult> mResults;
109
110        private final int mLatency;
111
112        public Result(String userQuery, ArrayList<SourceResult> results, int latency) {
113            super(userQuery);
114            mResults = results;
115            mLatency = latency;
116        }
117
118        protected ArrayList<SourceResult> getResults() {
119            return mResults;
120        }
121
122        /**
123         * Fills the list of suggestions using the list of results.
124         * The default implementation concatenates the results.
125         */
126        public void fill() {
127            for (SourceResult result : getResults()) {
128                int count = result.getCount();
129                for (int i = 0; i < count; i++) {
130                    result.moveTo(i);
131                    add(new SuggestionPosition(result));
132                }
133            }
134        }
135
136        public Corpus getCorpus() {
137            return MultiSourceCorpus.this;
138        }
139
140        public int getLatency() {
141            return mLatency;
142        }
143
144        @Override
145        public void close() {
146            super.close();
147            for (SourceResult result : mResults) {
148                result.close();
149            }
150        }
151
152        @Override
153        public String toString() {
154            return getCorpus() + "[" + getUserQuery() + "]";
155        }
156    }
157
158}
159