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