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