SearchManagerService.java revision 13bc602b2118af550c7ed99c4582fb7db7622002
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.server.search;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringertimport com.android.internal.content.PackageMonitor;
20ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.ISearchManager;
228d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringertimport android.app.SearchManager;
232126aac7f992b57fc52141a8bd09fa7a45ac2509Bjorn Bringertimport android.app.SearchableInfo;
242c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringertimport android.content.BroadcastReceiver;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ComponentName;
26ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.content.ContentResolver;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
292c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringertimport android.content.IntentFilter;
30ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.content.pm.ResolveInfo;
31ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.database.ContentObserver;
322c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringertimport android.os.Process;
33ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamathimport android.provider.Settings;
348d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringertimport android.util.Log;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
366d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringertimport java.util.List;
376d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
39444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert * The search manager service handles the search UI, and maintains a registry of searchable
40444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert * activities.
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
42444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringertpublic class SearchManagerService extends ISearchManager.Stub {
43444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert
44444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert    // general debugging support
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "SearchManagerService";
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
47444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert    // Context that the service is running in.
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
49f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
50ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert    // This field is initialized lazily in getSearchables(), and then never modified.
519bc75cb9c23e5df528a28acc1fbbb4b5be51c33dBjorn Bringert    private Searchables mSearchables;
523ed6a3342b89651e8359956cefcc0076b6a4a30aKarl Rosaen
53ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    private ContentObserver mGlobalSearchObserver;
54ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
56875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Initializes the Search Manager service in the provided system context.
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Only one instance of this object should be created!
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context to use for accessing DB, window manager, etc.
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
61f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    public SearchManagerService(Context context)  {
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
632c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert        mContext.registerReceiver(new BootCompletedReceiver(),
642c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert                new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
65ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        mGlobalSearchObserver = new GlobalSearchProviderObserver(
66ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                mContext.getContentResolver());
67444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert    }
68444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert
699bc75cb9c23e5df528a28acc1fbbb4b5be51c33dBjorn Bringert    private synchronized Searchables getSearchables() {
70ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert        if (mSearchables == null) {
712c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert            Log.i(TAG, "Building list of searchable activities");
722c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert            new MyPackageMonitor().register(mContext, true);
73ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert            mSearchables = new Searchables(mContext);
74ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert            mSearchables.buildSearchableList();
75ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert        }
769bc75cb9c23e5df528a28acc1fbbb4b5be51c33dBjorn Bringert        return mSearchables;
779bc75cb9c23e5df528a28acc1fbbb4b5be51c33dBjorn Bringert    }
783ed6a3342b89651e8359956cefcc0076b6a4a30aKarl Rosaen
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
802c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert     * Creates the initial searchables list after boot.
812c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert     */
822c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert    private final class BootCompletedReceiver extends BroadcastReceiver {
832c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert        @Override
842c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert        public void onReceive(Context context, Intent intent) {
852c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert            new Thread() {
862c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert                @Override
872c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert                public void run() {
882c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
892c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert                    mContext.unregisterReceiver(BootCompletedReceiver.this);
902c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert                    getSearchables();
912c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert                }
922c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert            }.start();
932c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert        }
942c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert    }
952c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert
962c7b197a4ab1aff671a6fa2e6db540d391f553e6Bjorn Bringert    /**
97444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert     * Refreshes the "searchables" list when packages are added/removed.
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
99ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert    class MyPackageMonitor extends PackageMonitor {
10013bc602b2118af550c7ed99c4582fb7db7622002Amith Yamasani
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
102ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert        public void onSomePackagesChanged() {
10313bc602b2118af550c7ed99c4582fb7db7622002Amith Yamasani            updateSearchables();
10413bc602b2118af550c7ed99c4582fb7db7622002Amith Yamasani        }
10513bc602b2118af550c7ed99c4582fb7db7622002Amith Yamasani
10613bc602b2118af550c7ed99c4582fb7db7622002Amith Yamasani        @Override
10713bc602b2118af550c7ed99c4582fb7db7622002Amith Yamasani        public void onPackageModified(String pkg) {
10813bc602b2118af550c7ed99c4582fb7db7622002Amith Yamasani            updateSearchables();
10913bc602b2118af550c7ed99c4582fb7db7622002Amith Yamasani        }
11013bc602b2118af550c7ed99c4582fb7db7622002Amith Yamasani
11113bc602b2118af550c7ed99c4582fb7db7622002Amith Yamasani        private void updateSearchables() {
112ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert            // Update list of searchable activities
113ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert            getSearchables().buildSearchableList();
114ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert            // Inform all listeners that the list of searchables has been updated.
115ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert            Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
116ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
117ab5d96c5daf4bcc9b7a0cde44357454a11a8e48aBjorn Bringert            mContext.sendBroadcast(intent);
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
121ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    class GlobalSearchProviderObserver extends ContentObserver {
122ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        private final ContentResolver mResolver;
123ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
124ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        public GlobalSearchProviderObserver(ContentResolver resolver) {
125ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            super(null);
126ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            mResolver = resolver;
127ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            mResolver.registerContentObserver(
128ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                    Settings.Secure.getUriFor(Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY),
129ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                    false /* notifyDescendants */,
130ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath                    this);
131ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
132ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
133ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        @Override
134ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        public void onChange(boolean selfChange) {
135ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            getSearchables().buildSearchableList();
136ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            Intent intent = new Intent(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
137ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
138ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath            mContext.sendBroadcast(intent);
139ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        }
140ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
141ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
142ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
143444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert    //
144444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert    // Searchable activities API
145444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert    //
146a48a5af931f2fb43c948416180b85dfe9ecdc9a1Bjorn Bringert
147a48a5af931f2fb43c948416180b85dfe9ecdc9a1Bjorn Bringert    /**
148444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert     * Returns the SearchableInfo for a given activity.
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param launchActivity The activity from which we're launching this search.
151875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @return Returns a SearchableInfo record describing the parameters of the search,
152875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * or null if no searchable metadata was available.
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1546cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    public SearchableInfo getSearchableInfo(final ComponentName launchActivity) {
1556cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        if (launchActivity == null) {
1566cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            Log.e(TAG, "getSearchableInfo(), activity == null");
1576cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert            return null;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1596cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return getSearchables().getSearchableInfo(launchActivity);
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
161f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
1626d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    /**
1636d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert     * Returns a list of the searchable activities that can be included in global search.
1646d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert     */
1656d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    public List<SearchableInfo> getSearchablesInGlobalSearch() {
1669bc75cb9c23e5df528a28acc1fbbb4b5be51c33dBjorn Bringert        return getSearchables().getSearchablesInGlobalSearchList();
1676d72e029cb6e5a9cf26aa3314c3dca83614fc91bBjorn Bringert    }
168875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
169ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    public List<ResolveInfo> getGlobalSearchActivities() {
170ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath        return getSearchables().getGlobalSearchActivities();
171ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath    }
172ee69ff4eaee9342843d5f25338288865dda2d36aNarayan Kamath
173f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    /**
1746cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Gets the name of the global search activity.
175f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     */
1766cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    public ComponentName getGlobalSearchActivity() {
1776cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return getSearchables().getGlobalSearchActivity();
178f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
179f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
180f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    /**
1816cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert     * Gets the name of the web search activity.
182f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath     */
1836cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert    public ComponentName getWebSearchActivity() {
1846cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        return getSearchables().getWebSearchActivity();
185f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath    }
186f9acde27486bcc6eea1092073f7b47c31749efd6Satish Sampath
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
188