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