13e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/*
23e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Copyright (C) 2009 The Android Open Source Project
33e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
43e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
53e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * you may not use this file except in compliance with the License.
63e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * You may obtain a copy of the License at
73e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
83e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *      http://www.apache.org/licenses/LICENSE-2.0
93e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert *
103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * See the License for the specific language governing permissions and
143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * limitations under the License.
153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */
163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpackage com.android.quicksearchbox;
183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1993bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringertimport com.android.quicksearchbox.google.GoogleSource;
2069494b842a3f907164a457852c385f86dbe71d15Bjorn Bringertimport com.android.quicksearchbox.google.GoogleSuggestClient;
21c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamathimport com.android.quicksearchbox.google.SearchBaseUrlHelper;
22c8a0a093832240f517f7fe4dbf8fe168b6e3ebf7Mathew Inwoodimport com.android.quicksearchbox.preferences.PreferenceControllerFactory;
2377909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringertimport com.android.quicksearchbox.ui.DefaultSuggestionViewFactory;
24185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringertimport com.android.quicksearchbox.ui.SuggestionViewFactory;
2572f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringertimport com.android.quicksearchbox.util.Factory;
26ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamathimport com.android.quicksearchbox.util.HttpHelper;
27ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamathimport com.android.quicksearchbox.util.JavaNetHttpHelper;
28a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertimport com.android.quicksearchbox.util.NamedTaskExecutor;
29a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertimport com.android.quicksearchbox.util.PerNameExecutor;
30148154b406d3e483018e98f8f0296b59302020a3Bjorn Bringertimport com.android.quicksearchbox.util.PriorityThreadFactory;
31a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringertimport com.android.quicksearchbox.util.SingleThreadNamedTaskExecutor;
32d2ad41eabb20e9407003a1b6e894c5c9ad0498b9Bjorn Bringertimport com.google.common.util.concurrent.ThreadFactoryBuilder;
33185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
34c8a0a093832240f517f7fe4dbf8fe168b6e3ebf7Mathew Inwoodimport android.app.Activity;
3549fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringertimport android.content.Context;
3649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringertimport android.content.pm.PackageInfo;
3749fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringertimport android.content.pm.PackageManager;
3849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringertimport android.os.Build;
393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.os.Handler;
403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.os.Looper;
41148154b406d3e483018e98f8f0296b59302020a3Bjorn Bringertimport android.os.Process;
42de143166eb775e9135ab73bcc2d7cd062f6cf6f6Bjorn Bringertimport android.view.ContextThemeWrapper;
433e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
4472f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringertimport java.util.concurrent.Executor;
4572f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringertimport java.util.concurrent.Executors;
463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport java.util.concurrent.ThreadFactory;
473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
4849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringertpublic class QsbApplication {
4949fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    private final Context mContext;
5049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
5149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    private int mVersionCode;
520484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    private Handler mUiThreadHandler;
533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private Config mConfig;
5496fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    private SearchSettings mSettings;
55848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    private Sources mSources;
56b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private Corpora mCorpora;
57b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private CorpusRanker mCorpusRanker;
583e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    private ShortcutRepository mShortcutRepository;
5994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney    private ShortcutRefresher mShortcutRefresher;
60a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    private NamedTaskExecutor mSourceTaskExecutor;
6172f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert    private ThreadFactory mQueryThreadFactory;
62b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    private SuggestionsProvider mSuggestionsProvider;
6377909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert    private SuggestionViewFactory mSuggestionViewFactory;
6493bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert    private GoogleSource mGoogleSource;
6549fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    private VoiceSearch mVoiceSearch;
66ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    private Logger mLogger;
672fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood    private SuggestionFormatter mSuggestionFormatter;
68132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood    private TextAppearanceFactory mTextAppearanceFactory;
69516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood    private NamedTaskExecutor mIconLoaderExecutor;
70ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath    private HttpHelper mHttpHelper;
71c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath    private SearchBaseUrlHelper mSearchBaseUrlHelper;
723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
7349fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    public QsbApplication(Context context) {
74de143166eb775e9135ab73bcc2d7cd062f6cf6f6Bjorn Bringert        // the application context does not use the theme from the <application> tag
75de143166eb775e9135ab73bcc2d7cd062f6cf6f6Bjorn Bringert        mContext = new ContextThemeWrapper(context, R.style.Theme_QuickSearchBox);
7649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    }
7749fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
7849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    public static boolean isFroyoOrLater() {
7949fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
8049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    }
8149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
8292180225a3c86c5f9cba04e2a6a7564fc1adeb94Mathew Inwood    public static boolean isHoneycombOrLater() {
8356f7e5cd8a8e4b7997a75f66d8263aa0f83eeab6Mathew Inwood        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
8492180225a3c86c5f9cba04e2a6a7564fc1adeb94Mathew Inwood    }
8592180225a3c86c5f9cba04e2a6a7564fc1adeb94Mathew Inwood
8649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    public static QsbApplication get(Context context) {
8749fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return ((QsbApplicationWrapper) context.getApplicationContext()).getApp();
8849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    }
8949fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
9049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    protected Context getContext() {
9149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return mContext;
9249fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    }
9349fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
9449fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    public int getVersionCode() {
9549fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        if (mVersionCode == 0) {
9649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert            try {
9749fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert                PackageManager pm = getContext().getPackageManager();
9849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert                PackageInfo pkgInfo = pm.getPackageInfo(getContext().getPackageName(), 0);
9949fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert                mVersionCode = pkgInfo.versionCode;
10049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert            } catch (PackageManager.NameNotFoundException ex) {
10149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert                // The current package should always exist, how else could we
10249fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert                // run code from it?
10349fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert                throw new RuntimeException(ex);
10449fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert            }
10549fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        }
10649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return mVersionCode;
1073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
109fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    protected void checkThread() {
110fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (Looper.myLooper() != Looper.getMainLooper()) {
111fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            throw new IllegalStateException("Accessed Application object from thread "
112fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                    + Thread.currentThread().getName());
113fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        }
114fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
115fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
1163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected void close() {
117fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        checkThread();
118af736c70f989ebd716e0e389a28c6604b218e14fBjorn Bringert        if (mConfig != null) {
119af736c70f989ebd716e0e389a28c6604b218e14fBjorn Bringert            mConfig.close();
120af736c70f989ebd716e0e389a28c6604b218e14fBjorn Bringert            mConfig = null;
121af736c70f989ebd716e0e389a28c6604b218e14fBjorn Bringert        }
1223e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mShortcutRepository != null) {
1233e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            mShortcutRepository.close();
1243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            mShortcutRepository = null;
1253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
1263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mSourceTaskExecutor != null) {
1273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            mSourceTaskExecutor.close();
1283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            mSourceTaskExecutor = null;
1293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
130b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        if (mSuggestionsProvider != null) {
131b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert            mSuggestionsProvider.close();
132b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert            mSuggestionsProvider = null;
1333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
1343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
136fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public synchronized Handler getMainThreadHandler() {
1370484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        if (mUiThreadHandler == null) {
138fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            mUiThreadHandler = new Handler(Looper.getMainLooper());
1390484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        }
1400484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert        return mUiThreadHandler;
1410484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert    }
1420484fb4d652bfa9d5c7fb238a7cec1a6f2244e44Bjorn Bringert
14381a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    public void runOnUiThread(Runnable action) {
14481a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert        getMainThreadHandler().post(action);
14581a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert    }
14681a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert
147516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood    public synchronized NamedTaskExecutor getIconLoaderExecutor() {
148516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood        if (mIconLoaderExecutor == null) {
149516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood            mIconLoaderExecutor = createIconLoaderExecutor();
150516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood        }
151516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood        return mIconLoaderExecutor;
152516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood    }
153516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood
154516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood    protected NamedTaskExecutor createIconLoaderExecutor() {
155516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood        ThreadFactory iconThreadFactory = new PriorityThreadFactory(
156516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood                    Process.THREAD_PRIORITY_BACKGROUND);
157516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood        return new PerNameExecutor(SingleThreadNamedTaskExecutor.factory(iconThreadFactory));
158516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood    }
159516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood
160fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /**
161b5560dbe16a8fb3148b0fb24c73836bf2e84dd61Mathew Inwood     * Indicates that construction of the QSB UI is now complete.
162b5560dbe16a8fb3148b0fb24c73836bf2e84dd61Mathew Inwood     */
163b5560dbe16a8fb3148b0fb24c73836bf2e84dd61Mathew Inwood    public void onStartupComplete() {
164b5560dbe16a8fb3148b0fb24c73836bf2e84dd61Mathew Inwood    }
165b5560dbe16a8fb3148b0fb24c73836bf2e84dd61Mathew Inwood
166b5560dbe16a8fb3148b0fb24c73836bf2e84dd61Mathew Inwood    /**
167fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * Gets the QSB configuration object.
168fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * May be called from any thread.
169fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     */
170fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public synchronized Config getConfig() {
1713e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mConfig == null) {
1723e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            mConfig = createConfig();
1733e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
1743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return mConfig;
1753e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
1773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    protected Config createConfig() {
17849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return new Config(getContext());
1793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
1803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
18196fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    public synchronized SearchSettings getSettings() {
18296fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        if (mSettings == null) {
18396fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert            mSettings = createSettings();
18496fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert            mSettings.upgradeSettingsIfNeeded();
18596fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        }
18696fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        return mSettings;
18796fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    }
18896fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert
18996fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    protected SearchSettings createSettings() {
19096fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        return new SearchSettingsImpl(getContext(), getConfig());
19196fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert    }
19296fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert
193fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /**
194b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert     * Gets all corpora.
195b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert     *
196fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * May only be called from the main thread.
197fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     */
198b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    public Corpora getCorpora() {
199fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        checkThread();
200b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        if (mCorpora == null) {
201b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert            mCorpora = createCorpora(getSources());
2023e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
203b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return mCorpora;
2043e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2053e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
206b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    protected Corpora createCorpora(Sources sources) {
20796fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        SearchableCorpora corpora = new SearchableCorpora(getContext(), getSettings(), sources,
208b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert                createCorpusFactory());
20921bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        corpora.update();
210fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return corpora;
2113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
21321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    /**
21421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert     * Updates the corpora, if they are loaded.
21521bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert     * May only be called from the main thread.
21621bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert     */
21721bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    public void updateCorpora() {
21821bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        checkThread();
219b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        if (mCorpora != null) {
220b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert            mCorpora.update();
22121bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        }
22221bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    }
22321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert
224848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    protected Sources getSources() {
225848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        checkThread();
226848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        if (mSources == null) {
227848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            mSources = createSources();
228848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
229848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        return mSources;
230848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
231848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
232883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert    protected Sources createSources() {
233cd4accc7899fa7b756e1c430d6b196525abd5c3cMathew Inwood        return new SearchableSources(getContext(), getMainThreadHandler(),
234cd4accc7899fa7b756e1c430d6b196525abd5c3cMathew Inwood                getIconLoaderExecutor(), getConfig());
235883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert    }
236883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert
237b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    protected CorpusFactory createCorpusFactory() {
23872f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert        int numWebCorpusThreads = getConfig().getNumWebCorpusThreads();
23996fec862c3d494aebcb4e1d93589a241385a2ba7Bjorn Bringert        return new SearchableCorpusFactory(getContext(), getConfig(), getSettings(),
24096c7058210699c82445169048b7c0fdfb16f59eeBjorn Bringert                createExecutorFactory(numWebCorpusThreads));
24172f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert    }
24272f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert
24372f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert    protected Factory<Executor> createExecutorFactory(final int numThreads) {
24472f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert        final ThreadFactory threadFactory = getQueryThreadFactory();
24572f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert        return new Factory<Executor>() {
24672f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert            public Executor create() {
24772f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert                return Executors.newFixedThreadPool(numThreads, threadFactory);
24872f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert            }
24972f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert        };
250883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert    }
251883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringert
252fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /**
253fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * Gets the corpus ranker.
254fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * May only be called from the main thread.
255fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     */
256b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    public CorpusRanker getCorpusRanker() {
257fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        checkThread();
258b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        if (mCorpusRanker == null) {
259b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert            mCorpusRanker = createCorpusRanker();
260fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        }
261b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return mCorpusRanker;
262fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
263fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
264b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    protected CorpusRanker createCorpusRanker() {
26522da5e41bec9a5d36388c1e6f99bca392c3ac63eBjorn Bringert        return new DefaultCorpusRanker(getCorpora(), getShortcutRepository());
266fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
267fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
268fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /**
269fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * Gets the shortcut repository.
270fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * May only be called from the main thread.
271fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     */
272b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    public ShortcutRepository getShortcutRepository() {
273fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        checkThread();
2743e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mShortcutRepository == null) {
275b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert            mShortcutRepository = createShortcutRepository();
2763e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
2773e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return mShortcutRepository;
2783e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
2793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
280b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    protected ShortcutRepository createShortcutRepository() {
281d2ad41eabb20e9407003a1b6e894c5c9ad0498b9Bjorn Bringert        ThreadFactory logThreadFactory =
282d2ad41eabb20e9407003a1b6e894c5c9ad0498b9Bjorn Bringert                new ThreadFactoryBuilder()
283d2ad41eabb20e9407003a1b6e894c5c9ad0498b9Bjorn Bringert                .setNameFormat("ShortcutRepository #%d")
284d2ad41eabb20e9407003a1b6e894c5c9ad0498b9Bjorn Bringert                .setThreadFactory(new PriorityThreadFactory(
285d2ad41eabb20e9407003a1b6e894c5c9ad0498b9Bjorn Bringert                        Process.THREAD_PRIORITY_BACKGROUND))
286d2ad41eabb20e9407003a1b6e894c5c9ad0498b9Bjorn Bringert                .build();
287148154b406d3e483018e98f8f0296b59302020a3Bjorn Bringert        Executor logExecutor = Executors.newSingleThreadExecutor(logThreadFactory);
288b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return ShortcutRepositoryImplLog.create(getContext(), getConfig(), getCorpora(),
289148154b406d3e483018e98f8f0296b59302020a3Bjorn Bringert            getShortcutRefresher(), getMainThreadHandler(), logExecutor);
290fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
291fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
292fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /**
293fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * Gets the shortcut refresher.
294fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * May only be called from the main thread.
295fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     */
29694e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney    public ShortcutRefresher getShortcutRefresher() {
297fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        checkThread();
29894e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney        if (mShortcutRefresher == null) {
29994e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney            mShortcutRefresher = createShortcutRefresher();
30094e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney        }
30194e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney        return mShortcutRefresher;
30294e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney    }
30394e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney
30494e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney    protected ShortcutRefresher createShortcutRefresher() {
30594e8a2be78530170f50e7895a558bf8011bbf8e8Bryan Mawhinney        // For now, ShortcutRefresher gets its own SourceTaskExecutor
30604a180b52fb4100a2f3747e795fb5d26e3207a4aBjorn Bringert        return new SourceShortcutRefresher(createSourceTaskExecutor());
3073e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3083e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
309fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /**
310fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * Gets the source task executor.
311fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * May only be called from the main thread.
312fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     */
313a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    public NamedTaskExecutor getSourceTaskExecutor() {
314fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        checkThread();
3153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        if (mSourceTaskExecutor == null) {
3163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert            mSourceTaskExecutor = createSourceTaskExecutor();
3173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        }
3183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert        return mSourceTaskExecutor;
3193e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3203e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
321a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert    protected NamedTaskExecutor createSourceTaskExecutor() {
32272f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert        ThreadFactory queryThreadFactory = getQueryThreadFactory();
323a48af083ff81555261f334a1e050eae3b02a746cBjorn Bringert        return new PerNameExecutor(SingleThreadNamedTaskExecutor.factory(queryThreadFactory));
3243e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert    }
3253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert
326fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /**
32772f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert     * Gets the query thread factory.
32872f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert     * May only be called from the main thread.
32972f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert     */
33072f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert    protected ThreadFactory getQueryThreadFactory() {
33172f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert        checkThread();
33272f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert        if (mQueryThreadFactory == null) {
33372f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert            mQueryThreadFactory = createQueryThreadFactory();
33472f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert        }
33572f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert        return mQueryThreadFactory;
33672f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert    }
33772f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert
33872f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert    protected ThreadFactory createQueryThreadFactory() {
339148154b406d3e483018e98f8f0296b59302020a3Bjorn Bringert        String nameFormat = "QSB #%d";
340148154b406d3e483018e98f8f0296b59302020a3Bjorn Bringert        int priority = getConfig().getQueryThreadPriority();
341d2ad41eabb20e9407003a1b6e894c5c9ad0498b9Bjorn Bringert        return new ThreadFactoryBuilder()
342d2ad41eabb20e9407003a1b6e894c5c9ad0498b9Bjorn Bringert                .setNameFormat(nameFormat)
343d2ad41eabb20e9407003a1b6e894c5c9ad0498b9Bjorn Bringert                .setThreadFactory(new PriorityThreadFactory(priority))
344d2ad41eabb20e9407003a1b6e894c5c9ad0498b9Bjorn Bringert                .build();
34572f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert    }
34672f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert
34772f9b08ce84d0e13daf2d1c112d4e6d1d3ada045Bjorn Bringert    /**
348b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert     * Gets the suggestion provider.
349848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani     *
350848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani     * May only be called from the main thread.
351848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani     */
352b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    protected SuggestionsProvider getSuggestionsProvider() {
353848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        checkThread();
354b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        if (mSuggestionsProvider == null) {
355b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert            mSuggestionsProvider = createSuggestionsProvider();
356848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
357b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return mSuggestionsProvider;
358848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
359848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
360b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    protected SuggestionsProvider createSuggestionsProvider() {
361b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return new SuggestionsProviderImpl(getConfig(),
362b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert              getSourceTaskExecutor(),
363b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert              getMainThreadHandler(),
364b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert              getLogger());
365848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani    }
366848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
367fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /**
3685229b06f00d20aac76cd8519b37f2a579d61c54fMathew Inwood     * Gets the default suggestion view factory.
369fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * May only be called from the main thread.
370fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     */
37177909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert    public SuggestionViewFactory getSuggestionViewFactory() {
372fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        checkThread();
37377909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert        if (mSuggestionViewFactory == null) {
37477909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert            mSuggestionViewFactory = createSuggestionViewFactory();
375185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert        }
37677909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert        return mSuggestionViewFactory;
377185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    }
378185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
37977909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert    protected SuggestionViewFactory createSuggestionViewFactory() {
38077909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert        return new DefaultSuggestionViewFactory(getContext());
381185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert    }
382185bb2e3881452c084fde44d9bee657f65881b0eBjorn Bringert
383f165f2d6c6f8173b94937ae3202f0b638348dffdBjorn Bringert    public Promoter createBlendingPromoter() {
38427691bfcdcf3d2918b45bfadd57b08547c317ce5Mathew Inwood        return new ShortcutPromoter(getConfig(),
38527691bfcdcf3d2918b45bfadd57b08547c317ce5Mathew Inwood                new RankAwarePromoter(getConfig(), null, null), null);
386b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    }
387b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert
3888b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    public Promoter createSingleCorpusPromoter(Corpus corpus) {
3898b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        return new SingleCorpusPromoter(corpus, Integer.MAX_VALUE);
3908b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    }
3918b2936607176720172aee068abc5631bdf77e843Bjorn Bringert
3928b2936607176720172aee068abc5631bdf77e843Bjorn Bringert    public Promoter createSingleCorpusResultsPromoter(Corpus corpus) {
3938b2936607176720172aee068abc5631bdf77e843Bjorn Bringert        return new SingleCorpusResultsPromoter(corpus, Integer.MAX_VALUE);
394f165f2d6c6f8173b94937ae3202f0b638348dffdBjorn Bringert    }
395f165f2d6c6f8173b94937ae3202f0b638348dffdBjorn Bringert
396f165f2d6c6f8173b94937ae3202f0b638348dffdBjorn Bringert    public Promoter createWebPromoter() {
397b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert        return new WebPromoter(getConfig().getMaxShortcutsPerWebSource());
398b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert    }
399b83882b9efa37ec0f20a0f1c85cf5ccc93194aeeBjorn Bringert
400f165f2d6c6f8173b94937ae3202f0b638348dffdBjorn Bringert    public Promoter createResultsPromoter() {
401af1ca2cc65a2c2fdf6f396126e235d64e4da0936Mathew Inwood        SuggestionFilter resultFilter = new ResultFilter();
402af1ca2cc65a2c2fdf6f396126e235d64e4da0936Mathew Inwood        return new ShortcutPromoter(getConfig(), null, resultFilter);
403816804b67619af133860a1e28e92f58bc642260dBjorn Bringert    }
404e72a6418e84a89d2bfd4e9d22282eca95357e0daBjorn Bringert
405dbdffd8316e75bc2813dbbcbef13d357970e8c84Bjorn Bringert    /**
40693bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert     * Gets the Google source.
40749fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert     * May only be called from the main thread.
40849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert     */
40993bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert    public GoogleSource getGoogleSource() {
41049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        checkThread();
41193bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert        if (mGoogleSource == null) {
41293bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert            mGoogleSource = createGoogleSource();
41349fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        }
41493bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert        return mGoogleSource;
41549fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    }
41649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
41793bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert    protected GoogleSource createGoogleSource() {
418516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood        return new GoogleSuggestClient(getContext(), getMainThreadHandler(),
419cd4accc7899fa7b756e1c430d6b196525abd5c3cMathew Inwood                getIconLoaderExecutor(), getConfig());
42049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    }
42149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
42249fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    /**
42349fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert     * Gets Voice Search utilities.
42449fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert     */
42549fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    public VoiceSearch getVoiceSearch() {
42649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        checkThread();
42749fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        if (mVoiceSearch == null) {
42849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert            mVoiceSearch = createVoiceSearch();
42949fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        }
43049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return mVoiceSearch;
43149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    }
43249fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
43349fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    protected VoiceSearch createVoiceSearch() {
43449fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return new VoiceSearch(getContext());
43549fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    }
43649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
43749fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    /**
438fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * Gets the event logger.
439fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * May only be called from the main thread.
440fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     */
441ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    public Logger getLogger() {
442fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        checkThread();
443ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        if (mLogger == null) {
444ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert            mLogger = createLogger();
445ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        }
446ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert        return mLogger;
447ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    }
448ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert
449ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    protected Logger createLogger() {
45049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return new EventLogLogger(getContext(), getConfig());
451ca78085bb2127559e6f55276a307bfa857018ecaBjorn Bringert    }
4522fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood
4532fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood    public SuggestionFormatter getSuggestionFormatter() {
4542fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood        if (mSuggestionFormatter == null) {
4552fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood            mSuggestionFormatter = createSuggestionFormatter();
4562fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood        }
4572fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood        return mSuggestionFormatter;
4582fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood    }
4592fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood
4602fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood    protected SuggestionFormatter createSuggestionFormatter() {
461132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood        return new LevenshteinSuggestionFormatter(getTextAppearanceFactory());
462132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood    }
463132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood
464132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood    public TextAppearanceFactory getTextAppearanceFactory() {
465132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood        if (mTextAppearanceFactory == null) {
466132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood            mTextAppearanceFactory = createTextAppearanceFactory();
467132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood        }
468132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood        return mTextAppearanceFactory;
469132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood    }
470132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood
471132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood    protected TextAppearanceFactory createTextAppearanceFactory() {
472132a8afcb4970d1b783a6dba7944dc0dd5063101Mathew Inwood        return new TextAppearanceFactory(getContext());
4732fb3a129925a42e72944b836e85a1a2d55a0d950Mathew Inwood    }
474848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani
475c8a0a093832240f517f7fe4dbf8fe168b6e3ebf7Mathew Inwood    public PreferenceControllerFactory createPreferenceControllerFactory(Activity activity) {
476c8a0a093832240f517f7fe4dbf8fe168b6e3ebf7Mathew Inwood        return new PreferenceControllerFactory(getSettings(), activity);
477c8a0a093832240f517f7fe4dbf8fe168b6e3ebf7Mathew Inwood    }
478c8a0a093832240f517f7fe4dbf8fe168b6e3ebf7Mathew Inwood
479c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath    public synchronized HttpHelper getHttpHelper() {
480ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath        if (mHttpHelper == null) {
481ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath            mHttpHelper = createHttpHelper();
482ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath        }
483ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath        return mHttpHelper;
484ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath    }
485ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath
486ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath    protected HttpHelper createHttpHelper() {
487ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath        return new JavaNetHttpHelper(
488ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath                new JavaNetHttpHelper.PassThroughRewriter(),
489ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath                getConfig().getUserAgent());
490ef6dbc776667219ac89bd5f80c181f65260457acNarayan Kamath    }
491c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath
492c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath    public synchronized SearchBaseUrlHelper getSearchBaseUrlHelper() {
493c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath        if (mSearchBaseUrlHelper == null) {
494c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath            mSearchBaseUrlHelper = createSearchBaseUrlHelper();
495c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath        }
496c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath
497c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath        return mSearchBaseUrlHelper;
498c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath    }
499c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath
500c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath    protected SearchBaseUrlHelper createSearchBaseUrlHelper() {
5011259cf7175b0eacac403fb5298684bdbf3ef672cNarayan Kamath        // This cast to "SearchSettingsImpl" is somewhat ugly.
502c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath        return new SearchBaseUrlHelper(getContext(), getHttpHelper(),
5031259cf7175b0eacac403fb5298684bdbf3ef672cNarayan Kamath                getSettings(), ((SearchSettingsImpl)getSettings()).getSearchPreferences());
504c953ef06f0fc1fb4157fe67aa145cf702ee204d0Narayan Kamath    }
50571f9f8ccd3c12d7d48e2fee4c55cd57e1970b797Bjorn Bringert
50671f9f8ccd3c12d7d48e2fee4c55cd57e1970b797Bjorn Bringert    public Help getHelp() {
50771f9f8ccd3c12d7d48e2fee4c55cd57e1970b797Bjorn Bringert        // No point caching this, it's super cheap.
50871f9f8ccd3c12d7d48e2fee4c55cd57e1970b797Bjorn Bringert        return new Help(getContext(), getConfig());
50971f9f8ccd3c12d7d48e2fee4c55cd57e1970b797Bjorn Bringert    }
5103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert}
511