• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.globalsearch;
18 
19 import android.app.AlertDialog;
20 import android.app.Dialog;
21 import android.app.SearchManager;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.pm.ActivityInfo;
27 import android.content.pm.PackageManager;
28 import android.content.pm.ResolveInfo;
29 import android.content.res.Resources;
30 import android.os.Bundle;
31 import android.preference.CheckBoxPreference;
32 import android.preference.ListPreference;
33 import android.preference.Preference;
34 import android.preference.PreferenceActivity;
35 import android.preference.PreferenceGroup;
36 import android.preference.PreferenceScreen;
37 import android.preference.Preference.OnPreferenceChangeListener;
38 import android.preference.Preference.OnPreferenceClickListener;
39 import android.provider.Settings;
40 import android.provider.Settings.SettingNotFoundException;
41 import android.server.search.SearchableInfo;
42 import android.server.search.Searchables;
43 import android.util.Log;
44 
45 import java.util.ArrayList;
46 import java.util.List;
47 
48 /**
49  * Activity for setting global search preferences. Changes to search preferences trigger a broadcast
50  * intent that causes all SuggestionSources objects to be updated.
51  */
52 public class SearchSettings extends PreferenceActivity
53         implements OnPreferenceClickListener, OnPreferenceChangeListener {
54 
55     private static final boolean DBG = false;
56     private static final String TAG = "SearchSettings";
57 
58     // Only used to find the preferences after inflating
59     private static final String CLEAR_SHORTCUTS_PREF = "clear_shortcuts";
60     private static final String SEARCH_ENGINE_SETTINGS_PREF = "search_engine_settings";
61     private static final String SEARCH_SOURCES_PREF = "search_sources";
62 
63     private SearchManager mSearchManager;
64 
65     // These instances are not shared with SuggestionProvider
66     private SuggestionSources mSources;
67     private ShortcutRepository mShortcuts;
68 
69     // References to the top-level preference objects
70     private Preference mClearShortcutsPreference;
71     private PreferenceScreen mSearchEngineSettingsPreference;
72     private PreferenceGroup mSourcePreferences;
73 
74     // Dialog ids
75     private static final int CLEAR_SHORTCUTS_CONFIRM_DIALOG = 0;
76 
77     @Override
onCreate(Bundle savedInstanceState)78     protected void onCreate(Bundle savedInstanceState) {
79         super.onCreate(savedInstanceState);
80 
81         mSearchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
82 
83         mSources = new SuggestionSources(this);
84         mSources.load();
85         mShortcuts = ShortcutRepositoryImplLog.create(this);
86         getPreferenceManager().setSharedPreferencesName(SuggestionSources.PREFERENCES_NAME);
87 
88         addPreferencesFromResource(R.xml.preferences);
89 
90         PreferenceScreen preferenceScreen = getPreferenceScreen();
91         mClearShortcutsPreference = preferenceScreen.findPreference(CLEAR_SHORTCUTS_PREF);
92         mSearchEngineSettingsPreference = (PreferenceScreen) preferenceScreen.findPreference(
93                 SEARCH_ENGINE_SETTINGS_PREF);
94         mSourcePreferences = (PreferenceGroup) getPreferenceScreen().findPreference(
95                 SEARCH_SOURCES_PREF);
96 
97         mClearShortcutsPreference.setOnPreferenceClickListener(this);
98 
99         updateClearShortcutsPreference();
100         populateSourcePreference();
101         populateSearchEnginePreference();
102     }
103 
104     @Override
onDestroy()105     protected void onDestroy() {
106         mSources.close();
107         mShortcuts.close();
108         super.onDestroy();
109     }
110 
111     /**
112      * Enables/disables the "Clear search shortcuts" preference depending
113      * on whether there is any search history.
114      */
updateClearShortcutsPreference()115     private void updateClearShortcutsPreference() {
116         boolean hasHistory = mShortcuts.hasHistory();
117         if (DBG) Log.d(TAG, "hasHistory()=" + hasHistory);
118         mClearShortcutsPreference.setEnabled(hasHistory);
119     }
120 
121     /**
122      * Populates the preference item for the web search engine, which links to further
123      * search settings.
124      */
populateSearchEnginePreference()125     private void populateSearchEnginePreference() {
126         PackageManager pm = getPackageManager();
127 
128         // Try to find EnhancedGoogleSearch if installed.
129         ComponentName webSearchComponent;
130         try {
131             webSearchComponent = ComponentName.unflattenFromString(
132                     Searchables.ENHANCED_GOOGLE_SEARCH_COMPONENT_NAME);
133             pm.getActivityInfo(webSearchComponent, 0);
134         } catch (PackageManager.NameNotFoundException e1) {
135             // EnhancedGoogleSearch is not installed. Try to get GoogleSearch.
136             try {
137                 webSearchComponent = ComponentName.unflattenFromString(
138                         Searchables.GOOGLE_SEARCH_COMPONENT_NAME);
139                 pm.getActivityInfo(webSearchComponent, 0);
140             } catch (PackageManager.NameNotFoundException e2) {
141                 throw new RuntimeException("could not find a web search provider");
142             }
143         }
144 
145         ResolveInfo matchedInfo = findWebSearchSettingsActivity(webSearchComponent);
146         if (matchedInfo == null) {
147             throw new RuntimeException("could not find settings for web search provider");
148         }
149 
150         Intent intent = createWebSearchSettingsIntent(matchedInfo);
151         String searchEngineSettingsLabel =
152                 matchedInfo.activityInfo.loadLabel(pm).toString();
153         mSearchEngineSettingsPreference.setTitle(searchEngineSettingsLabel);
154 
155         mSearchEngineSettingsPreference.setIntent(intent);
156     }
157 
158     /**
159      * Returns the activity in the provided package that satisfies the
160      * {@link SearchManager#INTENT_ACTION_WEB_SEARCH_SETTINGS} intent, or null
161      * if none.
162      */
findWebSearchSettingsActivity(ComponentName component)163     private ResolveInfo findWebSearchSettingsActivity(ComponentName component) {
164         // Get all the activities which satisfy the WEB_SEARCH_SETTINGS intent.
165         PackageManager pm = getPackageManager();
166         Intent intent = new Intent(SearchManager.INTENT_ACTION_WEB_SEARCH_SETTINGS);
167         List<ResolveInfo> activitiesWithWebSearchSettings = pm.queryIntentActivities(intent, 0);
168 
169         String packageName = component.getPackageName();
170         String name = component.getClassName();
171 
172         // Iterate through them and see if any of them are the activity we're looking for.
173         for (ResolveInfo resolveInfo : activitiesWithWebSearchSettings) {
174             if (packageName.equals(resolveInfo.activityInfo.packageName)
175                     && name.equals(resolveInfo.activityInfo.name)) {
176                 return resolveInfo;
177             }
178         }
179 
180         // If there is no exact match, look for one in the right package
181         for (ResolveInfo resolveInfo : activitiesWithWebSearchSettings) {
182             if (packageName.equals(resolveInfo.activityInfo.packageName)) {
183                 return resolveInfo;
184             }
185         }
186 
187         return null;
188     }
189 
190     /**
191      * Creates an intent for accessing the web search settings from the provided ResolveInfo
192      * representing an activity.
193      */
createWebSearchSettingsIntent(ResolveInfo info)194     private Intent createWebSearchSettingsIntent(ResolveInfo info) {
195         Intent intent = new Intent(SearchManager.INTENT_ACTION_WEB_SEARCH_SETTINGS);
196         intent.setComponent(
197                 new ComponentName(info.activityInfo.packageName, info.activityInfo.name));
198         return intent;
199     }
200 
201     /**
202      * Fills the suggestion source list.
203      */
populateSourcePreference()204     private void populateSourcePreference() {
205         for (SuggestionSource source : mSources.getSuggestionSources()) {
206             Preference pref = createSourcePreference(source);
207             if (pref != null) {
208                 if (DBG) Log.d(TAG, "Adding search source: " + source);
209                 mSourcePreferences.addPreference(pref);
210             }
211         }
212     }
213 
214     /**
215      * Adds a suggestion source to the list of suggestion source checkbox preferences.
216      */
createSourcePreference(SuggestionSource source)217     private Preference createSourcePreference(SuggestionSource source) {
218         CheckBoxPreference sourcePref = new CheckBoxPreference(this);
219         sourcePref.setKey(mSources.getSourceEnabledPreference(source));
220         sourcePref.setDefaultValue(mSources.isSourceDefaultEnabled(source));
221         sourcePref.setOnPreferenceChangeListener(this);
222         String label = source.getLabel();
223         sourcePref.setTitle(label);
224         sourcePref.setSummaryOn(source.getSettingsDescription());
225         sourcePref.setSummaryOff(source.getSettingsDescription());
226         return sourcePref;
227     }
228 
229     /**
230      * Handles clicks on the "Clear search shortcuts" preference.
231      */
onPreferenceClick(Preference preference)232     public synchronized boolean onPreferenceClick(Preference preference) {
233         if (preference == mClearShortcutsPreference) {
234             showDialog(CLEAR_SHORTCUTS_CONFIRM_DIALOG);
235             return true;
236         }
237         return false;
238     }
239 
240     @Override
onCreateDialog(int id)241     protected Dialog onCreateDialog(int id) {
242         switch (id) {
243             case CLEAR_SHORTCUTS_CONFIRM_DIALOG:
244                 return new AlertDialog.Builder(this)
245                         .setTitle(R.string.clear_shortcuts)
246                         .setMessage(R.string.clear_shortcuts_prompt)
247                         .setPositiveButton(R.string.agree, new DialogInterface.OnClickListener() {
248                             public void onClick(DialogInterface dialog, int whichButton) {
249                                 if (DBG) Log.d(TAG, "Clearing history...");
250                                 mShortcuts.clearHistory();
251                                 updateClearShortcutsPreference();
252                             }
253                         })
254                         .setNegativeButton(R.string.disagree, null).create();
255             default:
256                 Log.e(TAG, "unknown dialog" + id);
257                 return null;
258         }
259     }
260 
261     /**
262      * Informs our listeners (SuggestionSources objects) about the updated settings data.
263      */
264     private void broadcastSettingsChanged() {
265         // We use a message broadcast since the listeners could be in multiple processes.
266         Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS_CHANGED);
267         Log.i(TAG, "Broadcasting: " + intent);
268         sendBroadcast(intent);
269     }
270 
271     public synchronized boolean onPreferenceChange(Preference preference, Object newValue) {
272         broadcastSettingsChanged();
273         return true;
274     }
275 
276 }
277