/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.globalsearch; import android.app.AlertDialog; import android.app.Dialog; import android.app.SearchManager; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.server.search.SearchableInfo; import android.server.search.Searchables; import android.util.Log; import java.util.ArrayList; import java.util.List; /** * Activity for setting global search preferences. Changes to search preferences trigger a broadcast * intent that causes all SuggestionSources objects to be updated. */ public class SearchSettings extends PreferenceActivity implements OnPreferenceClickListener, OnPreferenceChangeListener { private static final boolean DBG = false; private static final String TAG = "SearchSettings"; // Only used to find the preferences after inflating private static final String CLEAR_SHORTCUTS_PREF = "clear_shortcuts"; private static final String SEARCH_ENGINE_SETTINGS_PREF = "search_engine_settings"; private static final String SEARCH_SOURCES_PREF = "search_sources"; // These instances are not shared with SuggestionProvider private Config mConfig; private SuggestionSources mSources; private ShortcutRepository mShortcuts; // References to the top-level preference objects private Preference mClearShortcutsPreference; private PreferenceScreen mSearchEngineSettingsPreference; private PreferenceGroup mSourcePreferences; // Dialog ids private static final int CLEAR_SHORTCUTS_CONFIRM_DIALOG = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mConfig = Config.getConfig(this); mSources = new SuggestionSources(this); mSources.load(); mShortcuts = ShortcutRepositoryImplLog.create(this, mConfig); getPreferenceManager().setSharedPreferencesName(SuggestionSources.PREFERENCES_NAME); addPreferencesFromResource(R.xml.preferences); PreferenceScreen preferenceScreen = getPreferenceScreen(); mClearShortcutsPreference = preferenceScreen.findPreference(CLEAR_SHORTCUTS_PREF); mSearchEngineSettingsPreference = (PreferenceScreen) preferenceScreen.findPreference( SEARCH_ENGINE_SETTINGS_PREF); mSourcePreferences = (PreferenceGroup) getPreferenceScreen().findPreference( SEARCH_SOURCES_PREF); mClearShortcutsPreference.setOnPreferenceClickListener(this); updateClearShortcutsPreference(); populateSourcePreference(); populateSearchEnginePreference(); } @Override protected void onDestroy() { mSources.close(); mShortcuts.close(); super.onDestroy(); } /** * Enables/disables the "Clear search shortcuts" preference depending * on whether there is any search history. */ private void updateClearShortcutsPreference() { boolean hasHistory = mShortcuts.hasHistory(); if (DBG) Log.d(TAG, "hasHistory()=" + hasHistory); mClearShortcutsPreference.setEnabled(hasHistory); } /** * Populates the preference item for the web search engine, which links to further * search settings. */ private void populateSearchEnginePreference() { PackageManager pm = getPackageManager(); // Try to find EnhancedGoogleSearch if installed. ComponentName webSearchComponent; try { webSearchComponent = ComponentName.unflattenFromString( Searchables.ENHANCED_GOOGLE_SEARCH_COMPONENT_NAME); pm.getActivityInfo(webSearchComponent, 0); } catch (PackageManager.NameNotFoundException e1) { // EnhancedGoogleSearch is not installed. Try to get GoogleSearch. try { webSearchComponent = ComponentName.unflattenFromString( Searchables.GOOGLE_SEARCH_COMPONENT_NAME); pm.getActivityInfo(webSearchComponent, 0); } catch (PackageManager.NameNotFoundException e2) { throw new RuntimeException("could not find a web search provider"); } } ResolveInfo matchedInfo = findWebSearchSettingsActivity(webSearchComponent); if (matchedInfo == null) { throw new RuntimeException("could not find settings for web search provider"); } Intent intent = createWebSearchSettingsIntent(matchedInfo); String searchEngineSettingsLabel = matchedInfo.activityInfo.loadLabel(pm).toString(); mSearchEngineSettingsPreference.setTitle(searchEngineSettingsLabel); mSearchEngineSettingsPreference.setIntent(intent); } /** * Returns the activity in the provided package that satisfies the * {@link SearchManager#INTENT_ACTION_WEB_SEARCH_SETTINGS} intent, or null * if none. */ private ResolveInfo findWebSearchSettingsActivity(ComponentName component) { // Get all the activities which satisfy the WEB_SEARCH_SETTINGS intent. PackageManager pm = getPackageManager(); Intent intent = new Intent(SearchManager.INTENT_ACTION_WEB_SEARCH_SETTINGS); List activitiesWithWebSearchSettings = pm.queryIntentActivities(intent, 0); String packageName = component.getPackageName(); String name = component.getClassName(); // Iterate through them and see if any of them are the activity we're looking for. for (ResolveInfo resolveInfo : activitiesWithWebSearchSettings) { if (packageName.equals(resolveInfo.activityInfo.packageName) && name.equals(resolveInfo.activityInfo.name)) { return resolveInfo; } } // If there is no exact match, look for one in the right package for (ResolveInfo resolveInfo : activitiesWithWebSearchSettings) { if (packageName.equals(resolveInfo.activityInfo.packageName)) { return resolveInfo; } } return null; } /** * Creates an intent for accessing the web search settings from the provided ResolveInfo * representing an activity. */ private Intent createWebSearchSettingsIntent(ResolveInfo info) { Intent intent = new Intent(SearchManager.INTENT_ACTION_WEB_SEARCH_SETTINGS); intent.setComponent( new ComponentName(info.activityInfo.packageName, info.activityInfo.name)); return intent; } /** * Fills the suggestion source list. */ private void populateSourcePreference() { for (SuggestionSource source : mSources.getSuggestionSources()) { Preference pref = createSourcePreference(source); if (pref != null) { if (DBG) Log.d(TAG, "Adding search source: " + source); mSourcePreferences.addPreference(pref); } } } /** * Adds a suggestion source to the list of suggestion source checkbox preferences. */ private Preference createSourcePreference(SuggestionSource source) { CheckBoxPreference sourcePref = new CheckBoxPreference(this); sourcePref.setKey(mSources.getSourceEnabledPreference(source)); sourcePref.setDefaultValue(mSources.isSourceDefaultEnabled(source)); sourcePref.setOnPreferenceChangeListener(this); String label = source.getLabel(); sourcePref.setTitle(label); sourcePref.setSummaryOn(source.getSettingsDescription()); sourcePref.setSummaryOff(source.getSettingsDescription()); return sourcePref; } /** * Handles clicks on the "Clear search shortcuts" preference. */ public synchronized boolean onPreferenceClick(Preference preference) { if (preference == mClearShortcutsPreference) { showDialog(CLEAR_SHORTCUTS_CONFIRM_DIALOG); return true; } return false; } @Override protected Dialog onCreateDialog(int id) { switch (id) { case CLEAR_SHORTCUTS_CONFIRM_DIALOG: return new AlertDialog.Builder(this) .setTitle(R.string.clear_shortcuts) .setMessage(R.string.clear_shortcuts_prompt) .setPositiveButton(R.string.agree, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { if (DBG) Log.d(TAG, "Clearing history..."); mShortcuts.clearHistory(); updateClearShortcutsPreference(); } }) .setNegativeButton(R.string.disagree, null).create(); default: Log.e(TAG, "unknown dialog" + id); return null; } } /** * Informs our listeners (SuggestionSources objects) about the updated settings data. */ private void broadcastSettingsChanged() { // We use a message broadcast since the listeners could be in multiple processes. Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS_CHANGED); Log.i(TAG, "Broadcasting: " + intent); sendBroadcast(intent); } public synchronized boolean onPreferenceChange(Preference preference, Object newValue) { broadcastSettingsChanged(); return true; } }