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