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