• 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.quicksearchbox;
18 
19 import com.android.common.SharedPreferencesCompat;
20 
21 import android.app.SearchManager;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.SharedPreferences;
25 import android.content.SharedPreferences.Editor;
26 import android.util.Log;
27 import android.view.Menu;
28 import android.view.MenuInflater;
29 import android.view.MenuItem;
30 
31 /**
32  * Manages user settings.
33  */
34 public class SearchSettingsImpl implements SearchSettings {
35 
36     private static final boolean DBG = false;
37     private static final String TAG = "QSB.SearchSettingsImpl";
38 
39     // Name of the preferences file used to store search preference
40     public static final String PREFERENCES_NAME = "SearchSettings";
41 
42     // Intent action that opens the "Searchable Items" preference
43     private static final String ACTION_SEARCHABLE_ITEMS =
44             "com.android.quicksearchbox.action.SEARCHABLE_ITEMS";
45 
46     /**
47      * Preference key used for storing the index of the next voice search hint to show.
48      */
49     private static final String NEXT_VOICE_SEARCH_HINT_INDEX_PREF = "next_voice_search_hint";
50 
51     /**
52      * Preference key used to store the time at which the first voice search hint was displayed.
53      */
54     private static final String FIRST_VOICE_HINT_DISPLAY_TIME = "first_voice_search_hint_time";
55 
56     /**
57      * Preference key for the version of voice search we last got hints from.
58      */
59     private static final String LAST_SEEN_VOICE_SEARCH_VERSION = "voice_search_version";
60 
61     /**
62      * Preference key for storing whether searches always go to google.com. Public
63      * so that it can be used by PreferenceControllers.
64      */
65     public static final String USE_GOOGLE_COM_PREF = "use_google_com";
66 
67     /**
68      * Preference key for the base search URL. This value is normally set by
69      * a SearchBaseUrlHelper instance. Public so classes can listen to changes
70      * on this key.
71      */
72     public static final String SEARCH_BASE_DOMAIN_PREF = "search_base_domain";
73 
74     /**
75      * This is the time at which the base URL was stored, and is set using
76      * @link{System.currentTimeMillis()}.
77      */
78     private static final String SEARCH_BASE_DOMAIN_APPLY_TIME = "search_base_domain_apply_time";
79 
80     /**
81      * Prefix of per-corpus enable preference
82      */
83     private static final String CORPUS_ENABLED_PREF_PREFIX = "enable_corpus_";
84 
85     private final Context mContext;
86 
87     private final Config mConfig;
88 
SearchSettingsImpl(Context context, Config config)89     public SearchSettingsImpl(Context context, Config config) {
90         mContext = context;
91         mConfig = config;
92     }
93 
getContext()94     protected Context getContext() {
95         return mContext;
96     }
97 
getConfig()98     protected Config getConfig() {
99         return mConfig;
100     }
101 
upgradeSettingsIfNeeded()102     public void upgradeSettingsIfNeeded() {
103     }
104 
getSearchableItemsIntent()105     public Intent getSearchableItemsIntent() {
106         Intent intent = new Intent(ACTION_SEARCHABLE_ITEMS);
107         intent.setPackage(getContext().getPackageName());
108         return intent;
109     }
110 
111     /**
112      * Gets the preference key of the preference for whether the given corpus
113      * is enabled. The preference is stored in the {@link #PREFERENCES_NAME}
114      * preferences file.
115      */
getCorpusEnabledPreference(Corpus corpus)116     public static String getCorpusEnabledPreference(Corpus corpus) {
117         return CORPUS_ENABLED_PREF_PREFIX + corpus.getName();
118     }
119 
isCorpusEnabled(Corpus corpus)120     public boolean isCorpusEnabled(Corpus corpus) {
121         boolean defaultEnabled = corpus.isCorpusDefaultEnabled();
122         String sourceEnabledPref = getCorpusEnabledPreference(corpus);
123         return getSearchPreferences().getBoolean(sourceEnabledPref, defaultEnabled);
124     }
125 
getSearchPreferences()126     public SharedPreferences getSearchPreferences() {
127         return getContext().getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
128     }
129 
storeBoolean(String name, boolean value)130     protected void storeBoolean(String name, boolean value) {
131         SharedPreferencesCompat.apply(getSearchPreferences().edit().putBoolean(name, value));
132     }
133 
storeInt(String name, int value)134     protected void storeInt(String name, int value) {
135         SharedPreferencesCompat.apply(getSearchPreferences().edit().putInt(name, value));
136     }
137 
storeLong(String name, long value)138     protected void storeLong(String name, long value) {
139         SharedPreferencesCompat.apply(getSearchPreferences().edit().putLong(name, value));
140     }
141 
storeString(String name, String value)142     protected void storeString(String name, String value) {
143         SharedPreferencesCompat.apply(getSearchPreferences().edit().putString(name, value));
144     }
145 
removePref(String name)146     protected void removePref(String name) {
147         SharedPreferencesCompat.apply(getSearchPreferences().edit().remove(name));
148     }
149 
150     /**
151      * Informs our listeners about the updated settings data.
152      */
broadcastSettingsChanged()153     public void broadcastSettingsChanged() {
154         // We use a message broadcast since the listeners could be in multiple processes.
155         Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS_CHANGED);
156         Log.i(TAG, "Broadcasting: " + intent);
157         getContext().sendBroadcast(intent);
158     }
159 
addMenuItems(Menu menu, boolean showDisabled)160     public void addMenuItems(Menu menu, boolean showDisabled) {
161         MenuInflater inflater = new MenuInflater(getContext());
162         inflater.inflate(R.menu.settings, menu);
163         MenuItem item = menu.findItem(R.id.menu_settings);
164         item.setIntent(getSearchSettingsIntent());
165     }
166 
getSearchSettingsIntent()167     public Intent getSearchSettingsIntent() {
168         Intent settings = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS);
169         settings.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
170         settings.setPackage(getContext().getPackageName());
171         return settings;
172     }
173 
getNextVoiceSearchHintIndex(int size)174     public int getNextVoiceSearchHintIndex(int size) {
175             int i = getAndIncrementIntPreference(getSearchPreferences(),
176                     NEXT_VOICE_SEARCH_HINT_INDEX_PREF);
177             return i % size;
178     }
179 
180     // TODO: Could this be made atomic to avoid races?
getAndIncrementIntPreference(SharedPreferences prefs, String name)181     private int getAndIncrementIntPreference(SharedPreferences prefs, String name) {
182         int i = prefs.getInt(name, 0);
183         storeInt(name, i + 1);
184         return i;
185     }
186 
resetVoiceSearchHintFirstSeenTime()187     public void resetVoiceSearchHintFirstSeenTime() {
188         storeLong(FIRST_VOICE_HINT_DISPLAY_TIME, System.currentTimeMillis());
189     }
190 
haveVoiceSearchHintsExpired(int currentVoiceSearchVersion)191     public boolean haveVoiceSearchHintsExpired(int currentVoiceSearchVersion) {
192         SharedPreferences prefs = getSearchPreferences();
193 
194         if (currentVoiceSearchVersion != 0) {
195             long currentTime = System.currentTimeMillis();
196             int lastVoiceSearchVersion = prefs.getInt(LAST_SEEN_VOICE_SEARCH_VERSION, 0);
197             long firstHintTime = prefs.getLong(FIRST_VOICE_HINT_DISPLAY_TIME, 0);
198             if (firstHintTime == 0 || currentVoiceSearchVersion != lastVoiceSearchVersion) {
199                 SharedPreferencesCompat.apply(prefs.edit()
200                         .putInt(LAST_SEEN_VOICE_SEARCH_VERSION, currentVoiceSearchVersion)
201                         .putLong(FIRST_VOICE_HINT_DISPLAY_TIME, currentTime));
202                 firstHintTime = currentTime;
203             }
204             if (currentTime - firstHintTime > getConfig().getVoiceSearchHintActivePeriod()) {
205                 if (DBG) Log.d(TAG, "Voice seach hint period expired; not showing hints.");
206                 return true;
207             } else {
208                 return false;
209             }
210         } else {
211             if (DBG) Log.d(TAG, "Could not determine voice search version; not showing hints.");
212             return true;
213         }
214     }
215 
allowWebSearchShortcuts()216     public boolean allowWebSearchShortcuts() {
217         return true;
218     }
219 
220     /**
221      * @return true if user searches should always be based at google.com, false
222      *     otherwise.
223      */
224     @Override
shouldUseGoogleCom()225     public boolean shouldUseGoogleCom() {
226         // Note that this preserves the old behaviour of using google.com
227         // for searches, with the gl= parameter set.
228         return getSearchPreferences().getBoolean(USE_GOOGLE_COM_PREF, true);
229     }
230 
231     @Override
setUseGoogleCom(boolean useGoogleCom)232     public void setUseGoogleCom(boolean useGoogleCom) {
233         storeBoolean(USE_GOOGLE_COM_PREF, useGoogleCom);
234     }
235 
236     @Override
getSearchBaseDomainApplyTime()237     public long getSearchBaseDomainApplyTime() {
238         return getSearchPreferences().getLong(SEARCH_BASE_DOMAIN_APPLY_TIME, -1);
239     }
240 
241     @Override
getSearchBaseDomain()242     public String getSearchBaseDomain() {
243         // Note that the only time this will return null is on the first run
244         // of the app, or when settings have been cleared. Callers should
245         // ideally check that getSearchBaseDomainApplyTime() is not -1 before
246         // calling this function.
247         return getSearchPreferences().getString(SEARCH_BASE_DOMAIN_PREF, null);
248     }
249 
250     @Override
setSearchBaseDomain(String searchBaseUrl)251     public void setSearchBaseDomain(String searchBaseUrl) {
252         Editor sharedPrefEditor = getSearchPreferences().edit();
253         sharedPrefEditor.putString(SEARCH_BASE_DOMAIN_PREF, searchBaseUrl);
254         sharedPrefEditor.putLong(SEARCH_BASE_DOMAIN_APPLY_TIME, System.currentTimeMillis());
255 
256         SharedPreferencesCompat.apply(sharedPrefEditor);
257     }
258 }
259