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