QsbApplication.java revision 82bcf002f2f736afcd6cb548c19aa4e8ac12b421
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 com.android.quicksearchbox.ui.CorpusViewFactory; 20import com.android.quicksearchbox.ui.CorpusViewInflater; 21import com.android.quicksearchbox.ui.DelayingSuggestionsAdapter; 22import com.android.quicksearchbox.ui.EmptySuggestionsFooter; 23import com.android.quicksearchbox.ui.SuggestionViewFactory; 24import com.android.quicksearchbox.ui.SuggestionViewInflater; 25import com.android.quicksearchbox.ui.SuggestionsAdapter; 26import com.android.quicksearchbox.ui.SuggestionsFooter; 27import com.android.quicksearchbox.util.NamedTaskExecutor; 28import com.android.quicksearchbox.util.PerNameExecutor; 29import com.android.quicksearchbox.util.SingleThreadNamedTaskExecutor; 30 31import android.app.Application; 32import android.os.Handler; 33import android.os.Looper; 34 35import java.util.concurrent.ThreadFactory; 36 37public class QsbApplication extends Application { 38 39 private Handler mUiThreadHandler; 40 private Config mConfig; 41 private Corpora mCorpora; 42 private CorpusRanker mCorpusRanker; 43 private ShortcutRepository mShortcutRepository; 44 private ShortcutRefresher mShortcutRefresher; 45 private NamedTaskExecutor mSourceTaskExecutor; 46 private SuggestionsProvider mGlobalSuggestionsProvider; 47 private SuggestionViewFactory mSuggestionViewFactory; 48 private CorpusViewFactory mCorpusViewFactory; 49 private Logger mLogger; 50 51 @Override 52 public void onTerminate() { 53 close(); 54 super.onTerminate(); 55 } 56 57 protected void checkThread() { 58 if (Looper.myLooper() != Looper.getMainLooper()) { 59 throw new IllegalStateException("Accessed Application object from thread " 60 + Thread.currentThread().getName()); 61 } 62 } 63 64 protected void close() { 65 checkThread(); 66 if (mConfig != null) { 67 mConfig.close(); 68 mConfig = null; 69 } 70 if (mCorpora != null) { 71 mCorpora.close(); 72 mCorpora = null; 73 } 74 if (mShortcutRepository != null) { 75 mShortcutRepository.close(); 76 mShortcutRepository = null; 77 } 78 if (mSourceTaskExecutor != null) { 79 mSourceTaskExecutor.close(); 80 mSourceTaskExecutor = null; 81 } 82 if (mGlobalSuggestionsProvider != null) { 83 mGlobalSuggestionsProvider.close(); 84 mGlobalSuggestionsProvider = null; 85 } 86 } 87 88 public synchronized Handler getMainThreadHandler() { 89 if (mUiThreadHandler == null) { 90 mUiThreadHandler = new Handler(Looper.getMainLooper()); 91 } 92 return mUiThreadHandler; 93 } 94 95 /** 96 * Gets the QSB configuration object. 97 * May be called from any thread. 98 */ 99 public synchronized Config getConfig() { 100 if (mConfig == null) { 101 mConfig = createConfig(); 102 } 103 return mConfig; 104 } 105 106 protected Config createConfig() { 107 return new Config(this); 108 } 109 110 /** 111 * Gets the corpora. 112 * May only be called from the main thread. 113 */ 114 public Corpora getCorpora() { 115 checkThread(); 116 if (mCorpora == null) { 117 mCorpora = createCorpora(); 118 } 119 return mCorpora; 120 } 121 122 protected Corpora createCorpora() { 123 SearchableCorpora corpora = new SearchableCorpora(this, getConfig(), createSources(), 124 createCorpusFactory()); 125 corpora.load(); 126 return corpora; 127 } 128 129 protected Sources createSources() { 130 return new SearchableSources(this, getMainThreadHandler()); 131 } 132 133 protected CorpusFactory createCorpusFactory() { 134 return new SearchableCorpusFactory(this, getSourceTaskExecutor()); 135 } 136 137 /** 138 * Gets the corpus ranker. 139 * May only be called from the main thread. 140 */ 141 public CorpusRanker getCorpusRanker() { 142 checkThread(); 143 if (mCorpusRanker == null) { 144 mCorpusRanker = createCorpusRanker(); 145 } 146 return mCorpusRanker; 147 } 148 149 protected CorpusRanker createCorpusRanker() { 150 return new DefaultCorpusRanker(getShortcutRepository()); 151 } 152 153 /** 154 * Gets the shortcut repository. 155 * May only be called from the main thread. 156 */ 157 public ShortcutRepository getShortcutRepository() { 158 checkThread(); 159 if (mShortcutRepository == null) { 160 mShortcutRepository = createShortcutRepository(); 161 } 162 return mShortcutRepository; 163 } 164 165 protected ShortcutRepository createShortcutRepository() { 166 return ShortcutRepositoryImplLog.create(this, getConfig(), getCorpora(), 167 getShortcutRefresher(), getMainThreadHandler()); 168 } 169 170 /** 171 * Gets the shortcut refresher. 172 * May only be called from the main thread. 173 */ 174 public ShortcutRefresher getShortcutRefresher() { 175 checkThread(); 176 if (mShortcutRefresher == null) { 177 mShortcutRefresher = createShortcutRefresher(); 178 } 179 return mShortcutRefresher; 180 } 181 182 protected ShortcutRefresher createShortcutRefresher() { 183 // For now, ShortcutRefresher gets its own SourceTaskExecutor 184 return new SourceShortcutRefresher(createSourceTaskExecutor()); 185 } 186 187 /** 188 * Gets the source task executor. 189 * May only be called from the main thread. 190 */ 191 public NamedTaskExecutor getSourceTaskExecutor() { 192 checkThread(); 193 if (mSourceTaskExecutor == null) { 194 mSourceTaskExecutor = createSourceTaskExecutor(); 195 } 196 return mSourceTaskExecutor; 197 } 198 199 protected NamedTaskExecutor createSourceTaskExecutor() { 200 Config config = getConfig(); 201 ThreadFactory queryThreadFactory = 202 new QueryThreadFactory(config.getQueryThreadPriority()); 203 return new PerNameExecutor(SingleThreadNamedTaskExecutor.factory(queryThreadFactory)); 204 } 205 206 /** 207 * Gets the suggestion provider for a corpus. 208 * May only be called from the main thread. 209 */ 210 public SuggestionsProvider getSuggestionsProvider(Corpus corpus) { 211 checkThread(); 212 if (corpus == null) { 213 return getGlobalSuggestionsProvider(); 214 } 215 // TODO: Cache this to avoid creating a new one for each key press 216 return createSuggestionsProvider(corpus); 217 } 218 219 protected SuggestionsProvider createSuggestionsProvider(Corpus corpus) { 220 // TODO: We could use simpler promoter here 221 Promoter promoter = new ShortcutPromoter(new RoundRobinPromoter()); 222 SingleCorpusSuggestionsProvider provider = new SingleCorpusSuggestionsProvider(getConfig(), 223 corpus, 224 getSourceTaskExecutor(), 225 getMainThreadHandler(), 226 promoter, 227 getShortcutRepository()); 228 return provider; 229 } 230 231 protected SuggestionsProvider getGlobalSuggestionsProvider() { 232 checkThread(); 233 if (mGlobalSuggestionsProvider == null) { 234 mGlobalSuggestionsProvider = createGlobalSuggestionsProvider(); 235 } 236 return mGlobalSuggestionsProvider; 237 } 238 239 protected SuggestionsProvider createGlobalSuggestionsProvider() { 240 Promoter promoter = new ShortcutPromoter(new RankAwarePromoter()); 241 GlobalSuggestionsProvider provider = new GlobalSuggestionsProvider(getConfig(), 242 getCorpora(), 243 getSourceTaskExecutor(), 244 getMainThreadHandler(), 245 promoter, 246 getCorpusRanker(), 247 getShortcutRepository()); 248 return provider; 249 } 250 251 /** 252 * Gets the suggestion view factory. 253 * May only be called from the main thread. 254 */ 255 public SuggestionViewFactory getSuggestionViewFactory() { 256 checkThread(); 257 if (mSuggestionViewFactory == null) { 258 mSuggestionViewFactory = createSuggestionViewFactory(); 259 } 260 return mSuggestionViewFactory; 261 } 262 263 protected SuggestionViewFactory createSuggestionViewFactory() { 264 return new SuggestionViewInflater(this); 265 } 266 267 /** 268 * Gets the corpus view factory. 269 * May only be called from the main thread. 270 */ 271 public CorpusViewFactory getCorpusViewFactory() { 272 checkThread(); 273 if (mCorpusViewFactory == null) { 274 mCorpusViewFactory = createCorpusViewFactory(); 275 } 276 return mCorpusViewFactory; 277 } 278 279 protected CorpusViewFactory createCorpusViewFactory() { 280 return new CorpusViewInflater(this); 281 } 282 283 /** 284 * Creates a suggestions adapter. 285 * May only be called from the main thread. 286 */ 287 public SuggestionsAdapter createSuggestionsAdapter() { 288 Config config = getConfig(); 289 SuggestionViewFactory viewFactory = getSuggestionViewFactory(); 290 DelayingSuggestionsAdapter adapter = new DelayingSuggestionsAdapter(viewFactory); 291 return adapter; 292 } 293 294 /** 295 * Creates a footer view to add at the bottom of the search activity. 296 */ 297 public SuggestionsFooter createSuggestionsFooter() { 298 return new EmptySuggestionsFooter(this); 299 } 300 301 /** 302 * Gets the event logger. 303 * May only be called from the main thread. 304 */ 305 public Logger getLogger() { 306 checkThread(); 307 if (mLogger == null) { 308 mLogger = createLogger(); 309 } 310 return mLogger; 311 } 312 313 protected Logger createLogger() { 314 return new EventLogLogger(this); 315 } 316} 317