SearchSettings.java revision dc2c74eef51811886e6f080eaa8692804a00a1f4
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.Context;
23import android.content.DialogInterface;
24import android.content.Intent;
25import android.content.SharedPreferences;
26import android.content.pm.PackageManager;
27import android.content.pm.ResolveInfo;
28import android.database.ContentObserver;
29import android.os.Bundle;
30import android.preference.CheckBoxPreference;
31import android.preference.Preference;
32import android.preference.PreferenceActivity;
33import android.preference.PreferenceGroup;
34import android.preference.PreferenceScreen;
35import android.preference.Preference.OnPreferenceChangeListener;
36import android.preference.Preference.OnPreferenceClickListener;
37import android.provider.Settings;
38import android.provider.Settings.System;
39import android.util.Log;
40import android.view.Menu;
41
42import java.util.List;
43
44/**
45 * Activity for setting global search preferences. Changes to search preferences trigger a broadcast
46 * intent that causes all SuggestionSources objects to be updated.
47 */
48public class SearchSettings extends PreferenceActivity
49        implements OnPreferenceClickListener, OnPreferenceChangeListener {
50
51    private static final boolean DBG = false;
52    private static final String TAG = "SearchSettings";
53
54    // Name of the preferences file used to store search preference
55    public static final String PREFERENCES_NAME = "SearchSettings";
56
57    // Only used to find the preferences after inflating
58    private static final String CLEAR_SHORTCUTS_PREF = "clear_shortcuts";
59    private static final String SEARCH_ENGINE_SETTINGS_PREF = "search_engine_settings";
60    private static final String SEARCH_CORPORA_PREF = "search_corpora";
61
62    // Preifx of per-corpus enable preference
63    private static final String CORPUS_ENABLED_PREF_PREFIX = "enable_corpus_";
64
65    // References to the top-level preference objects
66    private Preference mClearShortcutsPreference;
67    private PreferenceScreen mSearchEngineSettingsPreference;
68    private PreferenceGroup mSourcePreferences;
69
70    // Dialog ids
71    private static final int CLEAR_SHORTCUTS_CONFIRM_DIALOG = 0;
72
73    @Override
74    protected void onCreate(Bundle savedInstanceState) {
75        super.onCreate(savedInstanceState);
76
77        getPreferenceManager().setSharedPreferencesName(PREFERENCES_NAME);
78
79        addPreferencesFromResource(R.xml.preferences);
80
81        PreferenceScreen preferenceScreen = getPreferenceScreen();
82        mClearShortcutsPreference = preferenceScreen.findPreference(CLEAR_SHORTCUTS_PREF);
83        mSearchEngineSettingsPreference = (PreferenceScreen) preferenceScreen.findPreference(
84                SEARCH_ENGINE_SETTINGS_PREF);
85        mSourcePreferences = (PreferenceGroup) getPreferenceScreen().findPreference(
86                SEARCH_CORPORA_PREF);
87
88        mClearShortcutsPreference.setOnPreferenceClickListener(this);
89
90        updateClearShortcutsPreference();
91        populateSourcePreference();
92        populateSearchEnginePreference();
93    }
94
95    /**
96     * Gets the preference key of the preference for whether the given corpus
97     * is enabled. The preference is stored in the {@link #PREFERENCES_NAME}
98     * preferences file.
99     */
100    public static String getCorpusEnabledPreference(Corpus corpus) {
101        return CORPUS_ENABLED_PREF_PREFIX + corpus.getName();
102    }
103
104    public static SharedPreferences getSearchPreferences(Context context) {
105        return context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
106    }
107
108    private QsbApplication getQsbApplication() {
109        return (QsbApplication) getApplication();
110    }
111
112    private Corpora getCorpora() {
113        return getQsbApplication().getCorpora();
114    }
115
116    private ShortcutRepository getShortcuts() {
117        return getQsbApplication().getShortcutRepository();
118    }
119
120    /**
121     * Enables/disables the "Clear search shortcuts" preference depending
122     * on whether there is any search history.
123     */
124    private void updateClearShortcutsPreference() {
125        boolean hasHistory = getShortcuts().hasHistory();
126        if (DBG) Log.d(TAG, "hasHistory()=" + hasHistory);
127        mClearShortcutsPreference.setEnabled(hasHistory);
128    }
129
130    /**
131     * Populates the preference item for the web search engine, which links to further
132     * search settings.
133     */
134    private void populateSearchEnginePreference() {
135        Intent intent = new Intent(SearchManager.INTENT_ACTION_WEB_SEARCH_SETTINGS);
136        intent.setPackage(getPackageName());
137
138        CharSequence webSearchSettingsLabel = getActivityLabel(intent);
139        mSearchEngineSettingsPreference.setTitle(webSearchSettingsLabel);
140        mSearchEngineSettingsPreference.setIntent(intent);
141    }
142
143    private CharSequence getActivityLabel(Intent intent) {
144        PackageManager pm = getPackageManager();
145        List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
146        if (resolveInfos.size() == 0) {
147            Log.e(TAG, "No web search settings activity");
148            return null;
149        }
150        if (resolveInfos.size() > 1) {
151            Log.e(TAG, "More than one web search settings activity");
152            return null;
153        }
154        return resolveInfos.get(0).activityInfo.loadLabel(pm);
155    }
156
157    /**
158     * Fills the suggestion source list.
159     */
160    private void populateSourcePreference() {
161        mSourcePreferences.setOrderingAsAdded(false);
162        for (Corpus corpus : getCorpora().getAllCorpora()) {
163            Preference pref = createCorpusPreference(corpus);
164            if (pref != null) {
165                if (DBG) Log.d(TAG, "Adding corpus: " + corpus);
166                mSourcePreferences.addPreference(pref);
167            }
168        }
169    }
170
171    /**
172     * Adds a suggestion source to the list of suggestion source checkbox preferences.
173     */
174    private Preference createCorpusPreference(Corpus corpus) {
175        CheckBoxPreference sourcePref = new CheckBoxPreference(this);
176        sourcePref.setKey(getCorpusEnabledPreference(corpus));
177        // Put web corpus first. The rest are alphabetical.
178        if (corpus.isWebCorpus()) {
179            sourcePref.setOrder(0);
180        }
181        sourcePref.setDefaultValue(getCorpora().isCorpusDefaultEnabled(corpus));
182        sourcePref.setOnPreferenceChangeListener(this);
183        CharSequence label = corpus.getLabel();
184        sourcePref.setTitle(label);
185        CharSequence description = corpus.getSettingsDescription();
186        sourcePref.setSummaryOn(description);
187        sourcePref.setSummaryOff(description);
188        return sourcePref;
189    }
190
191    /**
192     * Handles clicks on the "Clear search shortcuts" preference.
193     */
194    public synchronized boolean onPreferenceClick(Preference preference) {
195        if (preference == mClearShortcutsPreference) {
196            showDialog(CLEAR_SHORTCUTS_CONFIRM_DIALOG);
197            return true;
198        }
199        return false;
200    }
201
202    @Override
203    protected Dialog onCreateDialog(int id, Bundle args) {
204        switch (id) {
205            case CLEAR_SHORTCUTS_CONFIRM_DIALOG:
206                return new AlertDialog.Builder(this)
207                        .setTitle(R.string.clear_shortcuts)
208                        .setMessage(R.string.clear_shortcuts_prompt)
209                        .setPositiveButton(R.string.agree, new DialogInterface.OnClickListener() {
210                            public void onClick(DialogInterface dialog, int whichButton) {
211                                if (DBG) Log.d(TAG, "Clearing history...");
212                                getShortcuts().clearHistory();
213                                updateClearShortcutsPreference();
214                            }
215                        })
216                        .setNegativeButton(R.string.disagree, null).create();
217            default:
218                Log.e(TAG, "unknown dialog" + id);
219                return null;
220        }
221    }
222
223    /**
224     * Informs our listeners about the updated settings data.
225     */
226    private void broadcastSettingsChanged() {
227        // We use a message broadcast since the listeners could be in multiple processes.
228        Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS_CHANGED);
229        Log.i(TAG, "Broadcasting: " + intent);
230        sendBroadcast(intent);
231    }
232
233    public synchronized boolean onPreferenceChange(Preference preference, Object newValue) {
234        broadcastSettingsChanged();
235        return true;
236    }
237
238    public static boolean getShowWebSuggestions(Context context) {
239        return (Settings.System.getInt(context.getContentResolver(),
240                Settings.System.SHOW_WEB_SUGGESTIONS,
241                1 /* default on until user actually changes it */) == 1);
242    }
243
244    public static void setShowWebSuggestions(Context context, boolean showWebSuggestions) {
245        System.putInt(context.getContentResolver(), System.SHOW_WEB_SUGGESTIONS,
246            showWebSuggestions ? 1 : 0);
247    }
248
249    public static void registerShowWebSuggestionsSettingObserver(
250            Context context, ContentObserver observer) {
251        context.getContentResolver().registerContentObserver(
252                Settings.System.getUriFor(Settings.System.SHOW_WEB_SUGGESTIONS),
253                false, observer);
254    }
255
256    public static void unregisterShowWebSuggestionsSettingObserver(
257            Context context, ContentObserver observer) {
258        context.getContentResolver().unregisterContentObserver(observer);
259    }
260
261    public static void addSearchSettingsMenuItem(Context context, Menu menu) {
262        Intent settings = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS);
263        settings.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
264        // Don't show activity chooser if there are multiple search settings activities,
265        // e.g. from different QSB implementations.
266        settings.setPackage(context.getPackageName());
267        menu.add(Menu.NONE, Menu.NONE, 0, R.string.menu_settings)
268                .setIcon(android.R.drawable.ic_menu_preferences).setAlphabeticShortcut('P')
269                .setIntent(settings);
270    }
271}
272