1fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert/*
2fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * Copyright (C) 2009 The Android Open Source Project
3fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert *
4fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
5fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * you may not use this file except in compliance with the License.
6fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * You may obtain a copy of the License at
7fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert *
8fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert *      http://www.apache.org/licenses/LICENSE-2.0
9fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert *
10fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * Unless required by applicable law or agreed to in writing, software
11fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
12fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * See the License for the specific language governing permissions and
14fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * limitations under the License.
15fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert */
16fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
17fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertpackage com.android.quicksearchbox;
18fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
19516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwoodimport com.android.quicksearchbox.util.NamedTaskExecutor;
20516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood
21fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.app.SearchManager;
22fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.app.SearchableInfo;
23fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.content.ComponentName;
24fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.content.Context;
25fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.content.pm.PackageManager.NameNotFoundException;
26e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport android.os.Handler;
27fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport android.util.Log;
28fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
29fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport java.util.Collection;
30fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringertimport java.util.HashMap;
31b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringertimport java.util.List;
32fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
33fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert/**
34fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert * Maintains a list of search sources.
35fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert */
36883c1bf364e38c5b133afb55f8493a14b65f4dd4Bjorn Bringertpublic class SearchableSources implements Sources {
37fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
38fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    // set to true to enable the more verbose debug logging for this file
39fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private static final boolean DBG = false;
40fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private static final String TAG = "QSB.SearchableSources";
41fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
42fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private final Context mContext;
43fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private final SearchManager mSearchManager;
44e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood    private final Handler mUiThread;
45cd4accc7899fa7b756e1c430d6b196525abd5c3cMathew Inwood    private final Config mConfig;
46fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
4762adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert    // All suggestion sources, by name.
4862adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert    private HashMap<String, Source> mSources;
49fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
50fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    // The web search source to use.
51fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    private Source mWebSearchSource;
52fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
53516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood    private final NamedTaskExecutor mIconLoaderExecutor;
54516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood
55fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /**
56fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     *
57fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     * @param context Used for looking up source information etc.
58fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     */
59cd4accc7899fa7b756e1c430d6b196525abd5c3cMathew Inwood    public SearchableSources(Context context, Handler uiThread,
60cd4accc7899fa7b756e1c430d6b196525abd5c3cMathew Inwood            NamedTaskExecutor iconLoader, Config config) {
61fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        mContext = context;
62fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        mSearchManager = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
63e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood        mUiThread = uiThread;
64516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood        mIconLoaderExecutor = iconLoader;
65cd4accc7899fa7b756e1c430d6b196525abd5c3cMathew Inwood        mConfig = config;
66fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
67fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
6849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    protected Context getContext() {
6949fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return mContext;
7049fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    }
7149fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
72e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood    protected Handler getUiThreadHandler() {
73e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood        return mUiThread;
74e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood    }
75e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood
7649fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    protected SearchManager getSearchManager() {
7749fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert        return mSearchManager;
7849fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    }
7949fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert
80516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood    protected NamedTaskExecutor getIconLoaderExecutor() {
81516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood        return mIconLoaderExecutor;
82516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood    }
83516781305d7427e79928c95c6ea2b7689a4bf6ceMathew Inwood
84cd4accc7899fa7b756e1c430d6b196525abd5c3cMathew Inwood    protected Config getConfig() {
85cd4accc7899fa7b756e1c430d6b196525abd5c3cMathew Inwood        return mConfig;
86cd4accc7899fa7b756e1c430d6b196525abd5c3cMathew Inwood    }
87cd4accc7899fa7b756e1c430d6b196525abd5c3cMathew Inwood
88fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public Collection<Source> getSources() {
89fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return mSources.values();
90fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
91fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
9262adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert    public Source getSource(String name) {
93fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return mSources.get(name);
94fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
95fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
96fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    public Source getWebSearchSource() {
97fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        return mWebSearchSource;
98fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
99fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
100fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    /**
10121bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert     * Updates the list of suggestion sources.
102fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert     */
10321bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert    public void update() {
10421bff9bbf4286907b01d3153bff2fbd6b5ec5df8Bjorn Bringert        if (DBG) Log.d(TAG, "update()");
10562adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert        mSources = new HashMap<String,Source>();
106b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert
107b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert        addSearchableSources();
108b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert
109f3f70e5ae88f06ff6dabdec9e7c71a19ca1e7108Bjorn Bringert        addInternalSources();
110f3f70e5ae88f06ff6dabdec9e7c71a19ca1e7108Bjorn Bringert
111b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert        mWebSearchSource = createWebSearchSource();
112848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        if (mWebSearchSource != null) {
113848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani            addSource(mWebSearchSource);
114848fa7a19abedc372452073abaf52780c7b6d78dAmith Yamasani        }
115b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert    }
116b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert
117f3f70e5ae88f06ff6dabdec9e7c71a19ca1e7108Bjorn Bringert    protected void addInternalSources() {
118f3f70e5ae88f06ff6dabdec9e7c71a19ca1e7108Bjorn Bringert    }
119f3f70e5ae88f06ff6dabdec9e7c71a19ca1e7108Bjorn Bringert
120b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert    private void addSearchableSources() {
121b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert        List<SearchableInfo> searchables = mSearchManager.getSearchablesInGlobalSearch();
122b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert        if (searchables == null) {
123b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert            Log.e(TAG, "getSearchablesInGlobalSearch() returned null");
124b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert            return;
125b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert        }
126b46040af250f9d5cf65ea4e39595c7b88531241aBjorn Bringert        for (SearchableInfo searchable : searchables) {
127cc10dcf07c4e787abd66f4e2cfed31a09580a3b0Bjorn Bringert            SearchableSource source = createSearchableSource(searchable);
12881a0897ff9685f3313c58294bf7973700c468b2bBjorn Bringert            if (source != null) {
129fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                if (DBG) Log.d(TAG, "Created source " + source);
130fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert                addSource(source);
131fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            }
132fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        }
133fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
134fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
135f3f70e5ae88f06ff6dabdec9e7c71a19ca1e7108Bjorn Bringert    protected void addSource(Source source) {
13662adab88055fd0ef6779242245cdc8c3ae5f999cBjorn Bringert        mSources.put(source.getName(), source);
137fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
138fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
13949fd8e0994577badc6194c2c3b5f771f2b793fe4Bjorn Bringert    protected Source createWebSearchSource() {
14093bd2e70b8b08da1ec37fd0e990dac05551d2e90Bjorn Bringert        return QsbApplication.get(getContext()).getGoogleSource();
141fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
142fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert
14325cbd7d054b92df1fe857d155ccc12f8191c12cfMathew Inwood    protected SearchableSource createSearchableSource(SearchableInfo searchable) {
144fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        if (searchable == null) return null;
145fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        try {
14677909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert            return new SearchableSource(mContext, searchable, getUiThreadHandler(),
14777909685887bd6db7454b73cf274afc3aca2f58dBjorn Bringert                    getIconLoaderExecutor());
148fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        } catch (NameNotFoundException ex) {
149fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            Log.e(TAG, "Source not found: " + ex);
150fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert            return null;
151fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert        }
152fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert    }
1531e53e72fbfc32995a97bbd25ae44bfea7b8781deMathew Inwood
1541e53e72fbfc32995a97bbd25ae44bfea7b8781deMathew Inwood    public Source createSourceFor(ComponentName component) {
1551e53e72fbfc32995a97bbd25ae44bfea7b8781deMathew Inwood        SearchableInfo info = mSearchManager.getSearchableInfo(component);
1561e53e72fbfc32995a97bbd25ae44bfea7b8781deMathew Inwood        SearchableSource source = createSearchableSource(info);
1572fd5aa82682f077660faa8ec60c04238026a8731Mathew Inwood        if (DBG) Log.d(TAG, "SearchableSource for " + component + ": " + source);
1581e53e72fbfc32995a97bbd25ae44bfea7b8781deMathew Inwood        return source;
1591e53e72fbfc32995a97bbd25ae44bfea7b8781deMathew Inwood    }
160fde948e69f59589cf0d217ea414af7947de600bbBjorn Bringert}
161