SearchableCorpora.java revision bd92263c4f8df5e68e9d806167534e7067a5e5ed
1/*
2 * Copyright (C) 2009 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
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.SharedPreferences;
22import android.database.DataSetObserver;
23import android.os.Handler;
24import android.text.TextUtils;
25import android.util.Log;
26
27import java.util.ArrayList;
28import java.util.Collection;
29import java.util.Collections;
30import java.util.HashMap;
31import java.util.List;
32
33/**
34 * Maintains the list of all suggestion sources.
35 */
36public class SearchableCorpora implements Corpora {
37
38    // set to true to enable the more verbose debug logging for this file
39    private static final boolean DBG = true;
40    private static final String TAG = "QSB.DefaultCorpora";
41
42    private final Context mContext;
43    private final Config mConfig;
44    private final SharedPreferences mPreferences;
45
46    private boolean mLoaded = false;
47
48    private SearchableSources mSources;
49    // Maps corpus names to corpora
50    private HashMap<String,Corpus> mCorporaByName;
51    // Maps sources to the corpus that contains them
52    private HashMap<Source,Corpus> mCorporaBySource;
53    // Enabled corpora
54    private List<Corpus> mEnabledCorpora;
55    private Corpus mWebCorpus;
56
57    /**
58     *
59     * @param context Used for looking up source information etc.
60     */
61    public SearchableCorpora(Context context, Config config, Handler uiThread) {
62        mContext = context;
63        mConfig = config;
64        mPreferences = SearchSettings.getSearchPreferences(context);
65
66        mSources = new SearchableSources(context, uiThread);
67    }
68
69    private void checkLoaded() {
70        if (!mLoaded) {
71            throw new IllegalStateException("corpora not loaded.");
72        }
73    }
74
75    public Collection<Corpus> getAllCorpora() {
76        checkLoaded();
77        return Collections.unmodifiableCollection(mCorporaByName.values());
78    }
79
80    public Collection<Corpus> getEnabledCorpora() {
81        checkLoaded();
82        return mEnabledCorpora;
83    }
84
85    public Corpus getCorpus(String name) {
86        checkLoaded();
87        return mCorporaByName.get(name);
88    }
89
90    public Corpus getCorpusForSource(Source source) {
91        checkLoaded();
92        return mCorporaBySource.get(source);
93    }
94
95    public Source getSource(ComponentName name) {
96        checkLoaded();
97        return mSources.getSource(name);
98    }
99
100    /**
101     * After calling, clients must call {@link #close()} when done with this object.
102     */
103    public void load() {
104        if (mLoaded) {
105            throw new IllegalStateException("load(): Already loaded.");
106        }
107
108        mSources.registerDataSetObserver(new DataSetObserver() {
109            @Override
110            public void onChanged() {
111                updateCorpora();
112            }
113        });
114
115        // will cause a callback to updateCorpora()
116        mSources.load();
117        mLoaded = true;
118    }
119
120    /**
121     * Releases all resources used by this object. It is possible to call
122     * {@link #load()} again after calling this method.
123     */
124    public void close() {
125        checkLoaded();
126
127        mSources.close();
128        mSources = null;
129        mLoaded = false;
130    }
131
132    private void updateCorpora() {
133        mCorporaByName = new HashMap<String,Corpus>();
134        mCorporaBySource = new HashMap<Source,Corpus>();
135        mEnabledCorpora = new ArrayList<Corpus>();
136
137        Source webSource = mSources.getWebSearchSource();
138        Source browserSource = mSources.getSource(getBrowserSearchComponent());
139        mWebCorpus = new WebCorpus(mContext, webSource, browserSource);
140        addCorpus(mWebCorpus);
141        mCorporaBySource.put(webSource, mWebCorpus);
142        mCorporaBySource.put(browserSource, mWebCorpus);
143
144        // Create corpora for all unclaimed sources
145        for (Source source : mSources.getSources()) {
146            if (!mCorporaBySource.containsKey(source)) {
147                Corpus corpus = new SingleSourceCorpus(source);
148                addCorpus(corpus);
149                mCorporaBySource.put(source, corpus);
150            }
151        }
152
153        if (DBG) Log.d(TAG, "Updated corpora: " + mCorporaBySource.values());
154
155        mEnabledCorpora = Collections.unmodifiableList(mEnabledCorpora);
156    }
157
158    private void addCorpus(Corpus corpus) {
159        mCorporaByName.put(corpus.getName(), corpus);
160        if (isCorpusEnabled(corpus)) {
161            mEnabledCorpora.add(corpus);
162        }
163    }
164
165    private ComponentName getBrowserSearchComponent() {
166        String name = mContext.getString(R.string.browser_search_component);
167        return TextUtils.isEmpty(name) ? null : ComponentName.unflattenFromString(name);
168    }
169
170    public boolean isCorpusEnabled(Corpus corpus) {
171        if (corpus == null) return false;
172        boolean defaultEnabled = isCorpusDefaultEnabled(corpus);
173        String sourceEnabledPref = SearchSettings.getCorpusEnabledPreference(corpus);
174        return mPreferences.getBoolean(sourceEnabledPref, defaultEnabled);
175    }
176
177    public boolean isCorpusDefaultEnabled(Corpus corpus) {
178        String name = corpus.getName();
179        return mConfig.isCorpusEnabledByDefault(name);
180    }
181
182}
183