QsbApplication.java revision ce4cdcf739b57563ddcdbed6944128b8c1f7522a
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(getCorpora(), 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 getSourceTaskExecutor(), 243 getMainThreadHandler(), 244 promoter, 245 getCorpusRanker(), 246 getShortcutRepository()); 247 return provider; 248 } 249 250 /** 251 * Gets the suggestion view factory. 252 * May only be called from the main thread. 253 */ 254 public SuggestionViewFactory getSuggestionViewFactory() { 255 checkThread(); 256 if (mSuggestionViewFactory == null) { 257 mSuggestionViewFactory = createSuggestionViewFactory(); 258 } 259 return mSuggestionViewFactory; 260 } 261 262 protected SuggestionViewFactory createSuggestionViewFactory() { 263 return new SuggestionViewInflater(this); 264 } 265 266 /** 267 * Gets the corpus view factory. 268 * May only be called from the main thread. 269 */ 270 public CorpusViewFactory getCorpusViewFactory() { 271 checkThread(); 272 if (mCorpusViewFactory == null) { 273 mCorpusViewFactory = createCorpusViewFactory(); 274 } 275 return mCorpusViewFactory; 276 } 277 278 protected CorpusViewFactory createCorpusViewFactory() { 279 return new CorpusViewInflater(this); 280 } 281 282 /** 283 * Creates a suggestions adapter. 284 * May only be called from the main thread. 285 */ 286 public SuggestionsAdapter createSuggestionsAdapter() { 287 Config config = getConfig(); 288 SuggestionViewFactory viewFactory = getSuggestionViewFactory(); 289 DelayingSuggestionsAdapter adapter = new DelayingSuggestionsAdapter(viewFactory); 290 return adapter; 291 } 292 293 /** 294 * Creates a footer view to add at the bottom of the search activity. 295 */ 296 public SuggestionsFooter createSuggestionsFooter() { 297 return new EmptySuggestionsFooter(this); 298 } 299 300 /** 301 * Gets the event logger. 302 * May only be called from the main thread. 303 */ 304 public Logger getLogger() { 305 checkThread(); 306 if (mLogger == null) { 307 mLogger = createLogger(); 308 } 309 return mLogger; 310 } 311 312 protected Logger createLogger() { 313 return new EventLogLogger(this); 314 } 315} 316